UNPKG

11.4 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 source file path based logics are involved, such as registering events in AWS Lambda, or migrations managing with Sequelize CLI.
22
23Notice 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, any other package manager you prefer, like `yarn` or `pnpm`, would work, too.
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
49Now, assuming in the dir `src`, the entry file `src/index.js` imports another file `src/constants/greeting.js`:
50
51```sh
52src
53├── constants
54│   └── greeting.js
55└── index.js
56```
57
58With the webpack config above, after compilation, output files will be:
59
60```sh
61dist
62├── constants
63│   └── greeting.js
64└── index.js
65```
66
67Files `src/index.js` and `src/constants/greeting.js` are collected as input files. Then, the common dir of input files is used as the base dir to evaluate the relative paths of output files in the output dir `dist`, which results in output files `dist/index.js` and `dist/constants/greeting.js`.
68
69Just 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.
70
71## Blogs
72
73- [Server-side rendering for any React app on any FaaS provider - elaborating by a demo app of SSR with CRA on Netlify](https://github.com/licg9999/server-side-rendering-with-cra-on-netlify)
74- [Transpile Webpack Plugin: transpiling files with webpack without bundling](https://medium.com/@licg9999/introducing-transpile-webpack-plugin-b8c86c7b0a21) ([中文版本](https://segmentfault.com/a/1190000043177608))
75
76## Options
77
78- **[exclude](#exclude)**
79- **[hoistNodeModules](#hoistnodemodules)**
80- **[longestCommonDir](#longestcommondir)**
81- **[extentionMapping](#extentionmapping)**
82- **[preferResolveByDependencyAsCjs](#preferresolvebydependencyascjs)**
83
84### `exclude`
85
86Type: `{string|RegExp|((p: string) => boolean)|string[]|RegExp[]|((p: string) => boolean)[]}`
87
88Default: `[]`
89
90Option `exclude` indicates files to be excluded. It's similar to the [externals](https://webpack.js.org/configuration/externals/) except that the import paths to the excluded are properly adjusted automatically. It's useful when you copy some third-party files and want to use them as they are.
91
92Though, excluding `node_modules` with this option is not a good idea. Some helpers of webpack loaders have to be compiled before they become runnable. 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 because it doesn't exclude helpers of webpack loaders.
93
94With this option as a string (or strings), input files whose aboslute paths begin with it will be excluded. With this option as a regular expression (or regular expression), input files whose absolute paths match it will be excluded. With this option as a function (or functions), input files whose absolute paths are passed into the call of it and end up with `true` will be excluded.
95
96### `hoistNodeModules`
97
98Type: `{boolean}`
99
100Default: `true`
101
102Option `hoistNodeModules` indicates whether to evaluate output paths for input files inside or outside `node_modules` separately, then keep input files from `node_modules` outputted into `node_modules` just under the output dir. It's usable to flatten the output directory structure a little bit.
103
104Given input files `src/index.js`, `node_modules/lodash/lodash.js` and the output dir `dist`, with this option `true`, output files will be `dist/index.js` and `dist/node_modules/lodash/lodash.js`. But with this option `false`, output files will be `dist/src/index.js` and `dist/node_modules/lodash/lodash.js`.
105
106### `longestCommonDir`
107
108Type: `{string|undefined}`
109
110Default: `undefined`
111
112Option `longestCommonDir` indicates the limit of the common dir to evaluate relative paths of output files in the output dir. When the dir that this option represents is the parent dir of the common dir of input files, this option is used against input files to evaluate relative paths of output files in the output dir. Otherwise, the common dir of input files is used.
113
114Given input files `src/server/index.js`, `src/server/constants/greeting.js` and the 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`.
115
116Though, given input files `src/index.js`, `src/server/constants/greeting.js` and the output dir `dist`, with this option `'./src/server'`, output files will still be `dist/index.js` `dist/server/constants/greeting.js` because the dir that this options represents is not the parent dir of the common dir of input files.
117
118### `extentionMapping`
119
120Type: `{Record<string, string>}`
121
122Default: `{}`
123
124Option `extentionMapping` indicates how file extensions are mapped from the input to the output. By default, an output file will have exactly the same file extension as its input file. But you may change the behavior by this option. With this option `{ '.ts': '.js' }`, any input file with ext `.ts` will have the output file with ext `.js`.
125
126### `preferResolveByDependencyAsCjs`
127
128Type: `boolean`
129
130Default: `true`
131
132Options `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.
133
134Given `{ "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` imported. While, with this option `false`, `import` ends up with `index.mjs` imported and `require` ends up with `index.cjs` imported (, which is the default behavior of webpack).
135
136## Known limits
137
138**<a name="known-limit-01" href="#known-limit-01">01:</a> Can't handle circular dependencies in the same way as NodeJS.**
139
140In NodeJS, top-level logics in a file run exactly at the time when it's imported, which makes circular dependencies possible to work. Take an example of files `a.js` and `b.js`:
141
142```js
143// In file 'a.js'
144const b = require('./b');
145
146function main() {
147 b.goo();
148}
149
150function foo() {
151 console.log('lorem ipsum');
152}
153
154module.exports = { foo };
155
156main();
157
158// In file 'b.js'
159
160const a = require('./a');
161
162function goo() {
163 a.foo();
164}
165
166module.exports = { goo };
167```
168
169When `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:
170
171```diff
172// In file 'a.js'
173-
174-const b = require('./b');
175
176function main() {
177 b.goo();
178}
179
180function foo() {
181 console.log('lorem ipsum');
182}
183
184module.exports = { foo };
185+
186+const b = require('./b');
187
188main();
189```
190
191Though, 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.
192
193Making 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.
194
195**<a name="known-limit-02" href="#known-limit-02">02:</a> Can't conditionally import not-yet-installed dependencies.**
196
197Webpack always detects and resolves import statements regardless of whether they run conditionally. Logics as below end up with the conditionally imported dependency `colorette` resolved:
198
199```js
200function print(message, color) {
201 if (typeof color === 'string') {
202 message = require('colorette')[color](message);
203 }
204 console.log(message);
205}
206```
207
208As a result, conditionally importing any not-yet-installed dependency causes the compile-time error of `Module not found` in webpack. So, 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.
209
210**<a name="known-limit-03" href="#known-limit-03">03:</a> Can't import `.node` files directly.**
211
212By 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' }` resolves some very basic cases. But as the node-loader itself doesn't handle paths well, the practice is 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.
213
214## Contributing
215
216Please take a moment to read our contributing guidelines if you haven't yet done so.
217[CONTRIBUTING][contributing-url]
218
219## License
220
221[MIT][license-url]
222
223[npm]: https://img.shields.io/npm/v/transpile-webpack-plugin.svg
224[npm-url]: https://npmjs.com/package/transpile-webpack-plugin
225[node-url]: https://nodejs.org/
226[node]: https://img.shields.io/node/v/transpile-webpack-plugin.svg
227[download]: https://img.shields.io/npm/dw/transpile-webpack-plugin
228[license]: https://img.shields.io/github/license/licg9999/transpile-webpack-plugin
229[license-url]: https://github.com/licg9999/transpile-webpack-plugin/blob/master/LICENSE
230[size]: https://packagephobia.com/badge?p=transpile-webpack-plugin
231[size-url]: https://packagephobia.com/result?p=transpile-webpack-plugin
232[cicd]: https://github.com/licg9999/transpile-webpack-plugin/actions/workflows/verify-and-release.yml/badge.svg
233[cicd-url]: https://github.com/licg9999/transpile-webpack-plugin/actions/workflows/verify-and-release.yml
234[contributing-url]: https://github.com/licg9999/transpile-webpack-plugin/blob/master/CONTRIBUTING.md