UNPKG

10.8 kBMarkdownView Raw
1<div align="center">
2 <a href="https://github.com/webpack/webpack">
3 <img width="200" height="200" src="https://webpack.js.org/assets/icon-square-big.svg">
4 </a>
5 <h1>Transpile Webpack Plugin</h1>
6</div>
7
8[![npm][npm]][npm-url]
9[![node][node]][node-url]
10[![download][download]][npm-url]
11[![license][license]][license-url]
12[![size][size]][size-url]
13[![cicd][cicd]][cicd-url]
14
15# Transpile Webpack Plugin
16
17The webpack plugin that transpiles input files into output files individually without bundling together.
18
19Input files are collected from files directly or indirectly imported by the [entry](https://webpack.js.org/configuration/entry-context/#entry), then get compiled and ouputted keeping the same directory structure in the output directory.
20
21Transpiling with webpack is especially helpful when both user interface logics and source file path related logics are involved, such as building SSR(server side rendering) in a heavyweight NodeJS server. Please make best of it.
22
23Note that this plugin replies on features of webpack v5. The latest webpack is supposed to be used when possible.
24
25## Getting Started
26
27To begin, you'll need to install `transpile-webpack-plugin`:
28
29```sh
30npm i -D transpile-webpack-plugin
31```
32
33Or, with any package manager you prefer.
34
35Then, add the plugin to your webpack config. For example:
36
37```js
38const TranspilePlugin = require('transpile-webpack-plugin');
39
40module.exports = {
41 entry: './src/index.js',
42 output: {
43 path: __dirname + '/dist',
44 },
45 plugins: [new TranspilePlugin(/* options */)],
46};
47```
48
49Assuming the entry `src/index.js` imports another file `src/constants/greeting.js`, input files will be `src/index.js` `src/constants/greeting.js`. After compilation, output files will be `dist/index.js` `dist/constants/greeting.js`. The common dir of input files is used as the base dir to evaluate the relative paths of output files in output dir.
50
51Just a reminder, if to run output files with NodeJS, don't forget to set the [target](https://webpack.js.org/configuration/target/) as `node` or a node-compatible value so that no breaking code is generated by webpack unexpectedly.
52
53## Blogs
54
55- [Transpile Webpack Plugin: transpiling files with webpack without bundling](https://medium.com/@licg9999/introducing-transpile-webpack-plugin-b8c86c7b0a21)
56- [Transpile Webpack Plugin: 让 Webpack 按照源文件的目录结构输出](https://segmentfault.com/a/1190000043177608)
57
58## Options
59
60- **[exclude](#exclude)**
61- **[hoistNodeModules](#hoistnodemodules)**
62- **[longestCommonDir](#longestcommondir)**
63- **[extentionMapping](#extentionmapping)**
64- **[preferResolveByDependencyAsCjs](#preferresolvebydependencyascjs)**
65
66### `exclude`
67
68Type: `{string|RegExp|((p: string) => boolean)|string[]|RegExp[]|((p: string) => boolean)[]}`
69
70Default: `[]`
71
72Option `exclude` indicates files to be excluded. Import statements to the excluded in input files are properly adjusted in output files and kept workable. It's similar to the [externals](https://webpack.js.org/configuration/externals/) except that the import path auto adjustment. It'll be useful when you copy some third-party files and want to use them as they are.
73
74By the way, excluding `node_modules` with this option is a bit trivial because some helpers of webpack loaders also living there are not runnable before compiled. If you need to exclude dependencies in `node_modules`, using [webpack-node-externals](https://github.com/liady/webpack-node-externals) might be a better choice.
75
76With this option as string, input files whose aboslute paths begin with it will be excluded. With this option as regular expression, input files whose absolute paths match it will be excluded. With this option as function, input files whose absolute paths are passed into the call of it and end up with `true` will be excluded.
77
78### `hoistNodeModules`
79
80Type: `{boolean}`
81
82Default: `true`
83
84Option `hoistNodeModules` indicates whether to evaluate output paths for input files from or not from `node_modules` separately, and keep input files from `node_modules` outputted into `node_modules` just under output dir. It's usable to flatten the output directory structure a little bit.
85
86Given input files `src/index.js` `node_modules/lodash/lodash.js` and output dir `dist`, with this option `true`, output files will be `dist/index.js` `dist/node_modules/lodash/lodash.js`. But with this option `false`, output files will be `dist/src/index.js` `dist/node_modules/lodash/lodash.js`.
87
88### `longestCommonDir`
89
90Type: `{string|undefined}`
91
92Default: `undefined`
93
94Option `longestCommonDir` indicates the limit of the common dir to evaluate relative paths of output files in output dir. When this option is shorter than the common dir of input files, this option is used against input files to evaluate relative paths of output files in output dir. Otherwise, the common dir of input files is used.
95
96Given input files `src/server/index.js` `src/server/constants/greeting.js` and output dir `dist`, with this option `undefined`, output files will be `dist/index.js` `dist/constants/greeting.js`. But with this option `'./src'`, output files will be `dist/server/index.js` `dist/server/constants/greeting.js`.
97
98Though, given input files `src/index.js` `src/server/constants/greeting.js` and output dir `dist`, with this option `'./src/server'`, output files will still be `dist/index.js` `dist/server/constants/greeting.js` because the common dir of input files is shorter than this option.
99
100### `extentionMapping`
101
102Type: `{Record<string, string>}`
103
104Default: `{}`
105
106Option `extentionMapping` indicates how file extensions are mapped from input to output. By default, one output file will have exactly the same file extension as the input file. But you may change it by this option. With this option `{ '.ts': '.js' }`, any input file with ext `.ts` will have the output file with ext `.js`.
107
108### `preferResolveByDependencyAsCjs`
109
110Type: `boolean`
111
112Default: `true`
113
114Options `preferResolveByDependencyAsCjs` indicates whether to try to resolve dependencies by CommonJS [exports](https://nodejs.org/api/packages.html#conditional-exports) regardless of types of import statements. It's useful when the target is `node` because `.mjs` files are treated as ES modules in NodeJS and [can't be required](https://nodejs.org/api/esm.html#require) by webpack generated CommonJS files.
115
116Given `{ "exports": { "import": "index.mjs", "require": "index.cjs" } }` in `package.json` of a dependency, with this option `true`, either `import` or `require` to this dependency will end up with `index.cjs`. And with this option `false`, `import` is with `index.mjs` and `require` is with `index.cjs`(, which is also the default behavior of webpack).
117
118## Known limits
119
120**<a name="known-limit-01" href="#known-limit-01">01:</a> Can't handle circular dependencies in the same way as NodeJS.**
121
122In NodeJS, top-level logics in a file run exactly at the time when it's required, which makes circular dependencies possible to work. Take an example of files `a.js` and `b.js`:
123
124```js
125// In file 'a.js'
126const b = require('./b');
127
128function main() {
129 b.goo();
130}
131
132function foo() {
133 console.log('lorem ipsum');
134}
135
136module.exports = { foo };
137
138main();
139
140// In file 'b.js'
141
142const a = require('./a');
143
144function goo() {
145 a.foo();
146}
147
148module.exports = { goo };
149```
150
151When `a.js` runs, an error of `TypeError: a.foo is not a function` thrown from `b.js`. But putting the line `const b = require('./b');` just after `module.exports = { foo };` resolves the problem:
152
153```diff
154// In file 'a.js'
155-
156-const b = require('./b');
157
158function main() {
159 b.goo();
160}
161
162function foo() {
163 console.log('lorem ipsum');
164}
165
166module.exports = { foo };
167+
168+const b = require('./b');
169
170main();
171```
172
173Though, for a webpack generated file, the real exporting is always done in the end of it. Webpack collects all the exports into an internal variable `__webpack_exports__`, then exports it at last, which makes circular dependencies always break.
174
175Making circular dependencies is a bad practice. But you might have to face them if using some libs that are popular but maintained since the early releases of NodeJS, like [jsdom](https://github.com/jsdom/jsdom). When this happens, please use the [externals](https://webpack.js.org/configuration/externals/) to leave the libs untouched.
176
177**<a name="known-limit-02" href="#known-limit-02">02:</a> Can't conditionally import not-yet-installed dependencies.**
178
179Webpack always detects and resolves import statements regardless of whether they run conditionally. Logics as below end up with the conditionally imported dependency `colorette` resolved:
180
181```js
182function print(message, color) {
183 if (typeof color === 'string') {
184 message = require('colorette')[color](message);
185 }
186 console.log(message);
187}
188```
189
190Besides, conditionally importing any not-yet-installed dependency causes the compile-time error of `Module not found` in webpack. As a result, either, you need to make sure the conditionally imported dependency installed. Or, use the [externals](https://webpack.js.org/configuration/externals/) to leave it untouched.
191
192**<a name="known-limit-03" href="#known-limit-03">03:</a> Can't import `.node` files directly.**
193
194By default, importing `.node` files causes the compile-time error of `Module parse failed` in webpack. Using [node-loader](http://github.com/webpack-contrib/node-loader) along with the plugin option [extentionMapping](#extentionmapping) as `{ '.node': '.js' }` might resolve some very basic cases but the node-loader itself doesn't handle paths well so it's not recommeneded. Instead, you may use the [externals](https://webpack.js.org/configuration/externals/) to leave the JS files that use the `.node` files untouched.
195
196## Contributing
197
198Please take a moment to read our contributing guidelines if you haven't yet done so.
199[CONTRIBUTING][contributing-url]
200
201## License
202
203[MIT][license-url]
204
205[npm]: https://img.shields.io/npm/v/transpile-webpack-plugin.svg
206[npm-url]: https://npmjs.com/package/transpile-webpack-plugin
207[node-url]: https://nodejs.org/
208[node]: https://img.shields.io/node/v/transpile-webpack-plugin.svg
209[download]: https://img.shields.io/npm/dw/transpile-webpack-plugin
210[license]: https://img.shields.io/github/license/licg9999/transpile-webpack-plugin
211[license-url]: https://github.com/licg9999/transpile-webpack-plugin/blob/master/LICENSE
212[size]: https://packagephobia.com/badge?p=transpile-webpack-plugin
213[size-url]: https://packagephobia.com/result?p=transpile-webpack-plugin
214[cicd]: https://github.com/licg9999/transpile-webpack-plugin/actions/workflows/verify-and-release.yml/badge.svg
215[cicd-url]: https://github.com/licg9999/transpile-webpack-plugin/actions/workflows/verify-and-release.yml
216[contributing-url]: https://github.com/licg9999/transpile-webpack-plugin/blob/master/CONTRIBUTING.md