You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Rewrite ["modularized" lodash packages](https://www.npmjs.com/search?q=keywords%3Alodash-modularized) such as `lodash.isnil` / `lodash.camelcase` / `lodash.clonedeep` to use the standard `lodash` / `lodash-es` packages. This enables tree-shaking of modularized imports for significant size savings.
8
+
9
+
This feature can be disabled by setting `optimizeModularizedImports` to `false` (it is on by default).
Copy file name to clipboardExpand all lines: packages/esbuild-plugin/README.md
+44-3Lines changed: 44 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -12,7 +12,7 @@ _**This is a proof of concept! esbuild loader plugins are "greedy" and need addi
12
12
13
13
There are [multiple](https://github.com/webpack/webpack/issues/6925)[issues](https://github.com/lodash/lodash/issues/3839)[surrounding](https://github.com/rollup/rollup/issues/1403)[tree-shaking](https://github.com/rollup/rollup/issues/691) of lodash. Minifiers, even with dead-code elimination, cannot currently solve this problem. With this plugin, bundled code output will _only_ include the specific lodash methods your code requires.
14
14
15
-
There is also an option to use [lodash-es](https://www.npmjs.com/package/lodash-es) for projects which ship CommonJS and ES builds: the ES build will be transformed to import from `lodash-es`.
15
+
There is also an option to use [lodash-es](https://www.npmjs.com/package/lodash-es) for projects which ship ESM: transform all your `lodash` imports to use `lodash-es` which is tree-shakable.
16
16
17
17
Versions of this plugin _before_ 3.x did not support Typescript. 3.x and later support Typescript, although Typescript support is considered experimental.
18
18
@@ -21,6 +21,7 @@ Versions of this plugin _before_ 3.x did not support Typescript. 3.x and later s
21
21
```javascript
22
22
import { isNil, isString } from"lodash";
23
23
import { padStartaspadStartFp } from"lodash/fp";
24
+
importkebabCasefrom"lodash.kebabcase";
24
25
```
25
26
26
27
### Becomes this output
@@ -29,32 +30,63 @@ import { padStart as padStartFp } from "lodash/fp";
29
30
importisNilfrom"lodash/isNil.js";
30
31
importisStringfrom"lodash/isString.js";
31
32
importpadStartFpfrom"lodash/fp/padStart.js";
33
+
importkebabCasefrom"lodash/kebabCase.js";
32
34
```
33
35
34
36
## `useLodashEs` for ES Module Output
35
37
36
-
While `lodash-es` is not usable from CommonJS modules, some projects use Rollup to create two outputs: one for ES and one for CommonJS.
38
+
While `lodash-es` is not usable in CommonJS modules, some projects only need ESM output or build both CommonJS and ESM outputs.
37
39
38
-
In this case, you can offer your users the best of both:
40
+
In these cases, you can optimize by transforming `lodash` imports to `lodash-es` imports:
39
41
40
42
### Your source input
41
43
42
44
```javascript
43
45
import { isNil } from"lodash";
46
+
importkebabCasefrom"lodash.kebabcase";
44
47
```
45
48
46
49
#### CommonJS output
47
50
48
51
```javascript
49
52
importisNilfrom"lodash/isNil.js";
53
+
importkebabCasefrom"lodash/kebabCase.js";
50
54
```
51
55
52
56
#### ES output (with `useLodashEs: true`)
53
57
54
58
```javascript
55
59
import { isNil } from"lodash-es";
60
+
import { kebabCase } from"lodash-es";
56
61
```
57
62
63
+
## Individual `lodash.*` Method Packages
64
+
65
+
Imports from individual lodash method packages like `lodash.isnil` or `lodash.flattendeep` are transformed to use the optimized import path of `lodash` or `lodash-es`, consolidating your lodash usage to a single, tree-shakable ESM package.
66
+
67
+
### Your source input
68
+
69
+
```javascript
70
+
importisNilfrom"lodash.isnil";
71
+
importflattenDeepfrom"lodash.flattendeep";
72
+
```
73
+
74
+
#### CommonJS output
75
+
76
+
```javascript
77
+
importisNilfrom"lodash/isNil.js";
78
+
importflattenDeepfrom"lodash/flattenDeep.js";
79
+
```
80
+
81
+
#### ES output (with `useLodashEs: true`)
82
+
83
+
```javascript
84
+
import { isNil } from"lodash-es";
85
+
import { flattenDeep } from"lodash-es";
86
+
```
87
+
88
+
Aliased local names are supported (`import checkNull from "lodash.isnil"` becomes `import checkNull from "lodash/isNil.js"`).
89
+
58
90
## Usage
59
91
60
92
_Please see the [esbuild docs for the most up to date info on using plugins](https://esbuild.github.io/plugins/#using-plugins)._
@@ -89,6 +121,15 @@ If `true`, the plugin will append `.js` to the end of CommonJS lodash imports.
89
121
90
122
Set to `false` if you don't want the `.js` suffix added (prior to v2.x, this was the default).
91
123
124
+
### `optimizeModularizedImports`
125
+
126
+
Type: `boolean`<br>
127
+
Default: `true`
128
+
129
+
When `true`, imports from individual lodash method packages (e.g., `lodash.isnil`, `lodash.kebabcase`) are transformed to optimized imports from `lodash` or `lodash-es`.
130
+
131
+
Set to `false` if you need to disable this behavior (prior to 6.x, this transformation did not ooccur).

12
12
13
-
There are [multiple](https://github.com/webpack/webpack/issues/6925)[issues](https://github.com/lodash/lodash/issues/3839)[surrounding](https://github.com/rollup/rollup/issues/1403)[tree-shaking](https://github.com/rollup/rollup/issues/691) of lodash. Minifiers, even with dead-code elimination, cannot currently solve this problem. Check out the test showing that even with terser as a minifier, [this plugin can still reduce bundle size by 70%](https://github.com/kyle-johnson/rollup-plugin-optimize-lodash-imports/blob/main/packages/rollup-plugin/tests/bundle-size.test.ts) for [an example input](https://github.com/kyle-johnson/rollup-plugin-optimize-lodash-imports/blob/main/packages/rollup-plugin/tests/fixtures/standard-and-fp.js). With this plugin, bundled code output will _only_ include the specific lodash methods your code requires.
13
+
There are [multiple](https://github.com/webpack/webpack/issues/6925)[issues](https://github.com/lodash/lodash/issues/3839)[surrounding](https://github.com/rollup/rollup/issues/1403)[tree-shaking](https://github.com/rollup/rollup/issues/691) of lodash. Minifiers, even with dead-code elimination, cannot currently solve this problem. Check out the test showing [this plugin can reduce bundle size by 70%](https://github.com/kyle-johnson/rollup-plugin-optimize-lodash-imports/blob/main/packages/rollup-plugin/tests/bundle-size.test.ts) for [an example input](https://github.com/kyle-johnson/rollup-plugin-optimize-lodash-imports/blob/main/packages/rollup-plugin/tests/fixtures/standard-and-fp.js) (and that's with a minifier enabled!). With this plugin, bundled code output will _only_ include the specific lodash methods your code requires.
14
14
15
-
There is also an option to use [lodash-es](https://www.npmjs.com/package/lodash-es) for projects which ship CommonJS and ES builds: the ES build will be transformed to import from `lodash-es`.
15
+
There is also an option to use [lodash-es](https://www.npmjs.com/package/lodash-es) for projects which ship ESM: transform all your `lodash` imports to use `lodash-es` which is tree-shakable.
16
16
17
-
Note: versions of this plugin prior to 5.x supported NodeJS 12 and Rollup 2.x - 3.x. If you need support for these older versions, please use the 4.x release. [Rollup 4.x contains significant performance improvements](https://github.com/rollup/rollup/releases/tag/v4.0.0) over previous versions and is highly recommended.
17
+
Version 6.x introduces a new feature: imports of ["modularized" lodash packages](https://www.npmjs.com/search?q=keywords%3Alodash-modularized), such as [`lodash.camelcase`](https://www.npmjs.com/package/lodash.camelcase) are rewritten to use optimized imports of `lodash` or `lodash-es`. This can _significantly_ reduce bundle size when using third-party dependencies that require these modularized imports: you no longer have to ship copies of the same lodash functions simply because one comes from `lodash` and another from `lodash.camelcase`. Applying this to [`kebabCase`](https://github.com/kyle-johnson/rollup-plugin-optimize-lodash-imports/blob/a05bd96a451cf2b4eb7065c83bfe25969ab5282a/packages/rollup-plugin/tests/fixtures/mixed-lodash.js) saves ~3.5kB after minification.
18
18
19
19
### This input
20
20
21
21
```javascript
22
22
import { isNil, isString } from"lodash";
23
23
import { padStartaspadStartFp } from"lodash/fp";
24
+
importkebabCasefrom"lodash.kebabcase";
24
25
```
25
26
26
27
### Becomes this output
@@ -29,32 +30,63 @@ import { padStart as padStartFp } from "lodash/fp";
29
30
importisNilfrom"lodash/isNil.js";
30
31
importisStringfrom"lodash/isString.js";
31
32
importpadStartFpfrom"lodash/fp/padStart.js";
33
+
importkebabCasefrom"lodash/kebabCase.js";
32
34
```
33
35
34
36
## `useLodashEs` for ES Module Output
35
37
36
-
While `lodash-es` is not usable from CommonJS modules, some projects use Rollup to create two outputs: one for ES and one for CommonJS.
38
+
While `lodash-es` is not usable in CommonJS modules, some projects only need ESM output or build both CommonJS and ESM outputs.
37
39
38
-
In this case, you can offer your users the best of both:
40
+
In these cases, you can optimize by transforming `lodash` imports to `lodash-es` imports:
39
41
40
42
### Your source input
41
43
42
44
```javascript
43
45
import { isNil } from"lodash";
46
+
importkebabCasefrom"lodash.kebabcase";
44
47
```
45
48
46
49
#### CommonJS output
47
50
48
51
```javascript
49
52
importisNilfrom"lodash/isNil.js";
53
+
importkebabCasefrom"lodash/kebabCase.js";
50
54
```
51
55
52
56
#### ES output (with `useLodashEs: true`)
53
57
54
58
```javascript
55
59
import { isNil } from"lodash-es";
60
+
import { kebabCase } from"lodash-es";
56
61
```
57
62
63
+
## Individual `lodash.*` Method Packages
64
+
65
+
Imports from individual lodash method packages like `lodash.isnil` or `lodash.flattendeep` are transformed to use the optimized import path of `lodash` or `lodash-es`, consolidating your lodash usage to a single, tree-shakable ESM package.
66
+
67
+
### Your source input
68
+
69
+
```javascript
70
+
importisNilfrom"lodash.isnil";
71
+
importflattenDeepfrom"lodash.flattendeep";
72
+
```
73
+
74
+
#### CommonJS output
75
+
76
+
```javascript
77
+
importisNilfrom"lodash/isNil.js";
78
+
importflattenDeepfrom"lodash/flattenDeep.js";
79
+
```
80
+
81
+
#### ES output (with `useLodashEs: true`)
82
+
83
+
```javascript
84
+
import { isNil } from"lodash-es";
85
+
import { flattenDeep } from"lodash-es";
86
+
```
87
+
88
+
Aliased local names are supported (`import checkNull from "lodash.isnil"` becomes `import checkNull from "lodash/isNil.js"`).
89
+
58
90
## Usage
59
91
60
92
```javascript
@@ -108,7 +140,7 @@ Set to `false` if you don't want the `.js` suffix added (prior to v3.x, this was
If defined as a static object, this is passed to rollup's internal `parse` method. This can be combined with [`jsx.mode`](https://rollupjs.org/configuration-options/#jsx) to enable jsx parsing: `parseOptions: { jsx: true }`
@@ -119,26 +151,18 @@ If defined as a function, it is called with the filename. For instance, opt-in t
For basic use, this plugin "just works" with [Rolldown](https://rolldown.rs/). There is [a small test suite verifying it](https://github.com/kyle-johnson/rollup-plugin-optimize-lodash-imports/tree/main/packages/rollup-plugin/tests/rolldown).
156
+
Type: `boolean`<br>
157
+
Default: `true`
125
158
126
-
If you're relying on Rolldown to handle ts/tsx internally, you may need to use `parseOptions` to configure `lang` or [other parsing options](https://github.com/rolldown/rolldown/blob/f46e1d61d0de6f1d6c1968f3d20898e43fa3d2d7/packages/rolldown/src/binding.d.cts#L314):
159
+
When `true`, imports from individual lodash method packages (e.g., `lodash.isnil`, `lodash.kebabcase`) are transformed to optimized imports from `lodash` or `lodash-es`.
127
160
128
-
```javascript
129
-
optimizeLodashImports({
130
-
// static
131
-
parseOptions: { lang:"ts" },
132
-
// or, dynamically by filename
133
-
parseOptions: (filename) => ({
134
-
lang:filename.endsWith(".ts") ?"ts":"js",
135
-
}),
136
-
});
137
-
```
161
+
Set to `false` if you need to disable this behavior (prior to 6.x, this transformation did not ooccur).
138
162
139
163
## Vite Compatibility
140
164
141
-
This plugin "just works" as a [Vite 3.x plugin](https://vitejs.dev/guide/api-plugin.html#rollup-plugin-compatibility). Simply add it to `plugins` in your [Vite config](https://vitejs.dev/config/):
165
+
This plugin "just works" as a [Vite plugin](https://vitejs.dev/guide/api-plugin.html#rollup-plugin-compatibility). Simply add it to `plugins` in your [Vite config](https://vitejs.dev/config/):
142
166
143
167
```javascript
144
168
import { defineConfig } from"vite";
@@ -159,6 +183,23 @@ Example Vite output for a use of [kebabCase](https://lodash.com/docs/4.17.15#keb
159
183
160
184
A ~23 KiB reduction in compressed size!
161
185
186
+
## Rolldown Compatibility
187
+
188
+
For basic use, this plugin "just works" with [Rolldown](https://rolldown.rs/). There is [a small test suite verifying it](https://github.com/kyle-johnson/rollup-plugin-optimize-lodash-imports/tree/main/packages/rollup-plugin/tests/rolldown).
189
+
190
+
If you're relying on Rolldown to handle ts/tsx internally, you may need to use `parseOptions` to configure `lang` or [other parsing options](https://github.com/rolldown/rolldown/blob/f46e1d61d0de6f1d6c1968f3d20898e43fa3d2d7/packages/rolldown/src/binding.d.cts#L314):
191
+
192
+
```javascript
193
+
optimizeLodashImports({
194
+
// static
195
+
parseOptions: { lang:"ts" },
196
+
// or, dynamically by filename
197
+
parseOptions: (filename) => ({
198
+
lang:filename.endsWith(".ts") ?"ts":"js",
199
+
}),
200
+
});
201
+
```
202
+
162
203
## Limitations
163
204
164
205
### Default imports are not optimized
@@ -191,8 +232,12 @@ export function testX(x) {
191
232
192
233
The `chain()` method from `lodash` cannot be successfully imported from `"lodash/chain"` without also importing from `"lodash"`. Imports which include `chain()` are _not modified_ and the plugin prints a warning.
193
234
235
+
## NodeJS 12 and Rollup 2.x / 3.x support
236
+
237
+
versions of this plugin prior to 5.x supported NodeJS 12 and Rollup 2.x - 3.x. If you need support for these older versions, please use the 4.x release.
238
+
194
239
## Alternatives
195
240
196
-
[`babel-plugin-lodash`](https://www.npmjs.com/package/babel-plugin-lodash) solves the issue for CommonJS outputs and modifies default imports as well. However, it doesn't enable transparent `lodash-es` use and may not make sense for projects using [@rollup/plugin-typescript](https://www.npmjs.com/package/@rollup/plugin-typescript) which don't wish to add a Babel step.
241
+
[`babel-plugin-lodash`](https://www.npmjs.com/package/babel-plugin-lodash) solves the issue for CommonJS outputs and modifies default imports as well. However, it doesn't enable transparent `lodash-es` use and may not make sense for projects using [@rollup/plugin-typescript](https://www.npmjs.com/package/@rollup/plugin-typescript) which don't wish to add a Babel step. It also does not modify modularized package imports (`lodash.isnil`, etc).
197
242
198
243
Other alternatives include `eslint-plugin-lodash` with the [`import-scope` rule enabled](https://github.com/wix/eslint-plugin-lodash/blob/HEAD/docs/rules/import-scope.md). This works for CommonJS outputs, but may require manual effort to stay on top of imports.
0 commit comments