Skip to content

Commit cfd4377

Browse files
authored
Merge pull request #1070 from byteme980/dynamic-import-chunkname-rule
[New] add Dynamic import chunkname rule
2 parents 2495356 + 115b6fb commit cfd4377

File tree

5 files changed

+415
-0
lines changed

5 files changed

+415
-0
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ This plugin intends to support linting of ES2015+ (ES6+) import/export syntax, a
8686
* Forbid default exports ([`no-default-export`])
8787
* Forbid anonymous values as default exports ([`no-anonymous-default-export`])
8888
* Prefer named exports to be grouped together in a single export declaration ([`group-exports`])
89+
* Enforce a leading comment with the webpackChunkName for dynamic imports ([`dynamic-import-chunkname`])
8990

9091
[`first`]: ./docs/rules/first.md
9192
[`exports-last`]: ./docs/rules/exports-last.md
@@ -101,6 +102,7 @@ This plugin intends to support linting of ES2015+ (ES6+) import/export syntax, a
101102
[`no-anonymous-default-export`]: ./docs/rules/no-anonymous-default-export.md
102103
[`group-exports`]: ./docs/rules/group-exports.md
103104
[`no-default-export`]: ./docs/rules/no-default-export.md
105+
[`dynamic-import-chunkname`]: ./docs/rules/dynamic-import-chunkname.md
104106

105107
## Installation
106108

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# dynamic imports require a leading comment with a webpackChunkName (dynamic-import-chunkname)
2+
3+
This rule reports any dynamic imports without a webpackChunkName specified in a leading block comment in the proper format.
4+
5+
This rule enforces naming of webpack chunks in dynamic imports. When you don't explicitly name chunks, webpack will autogenerate chunk names that are not consistent across builds, which prevents long-term browser caching.
6+
7+
## Rule Details
8+
This rule runs against `import()` by default, but can be configured to also run against an alternative dynamic-import function, e.g. 'dynamicImport.'
9+
You can also configure the regex format you'd like to accept for the webpackChunkName - for example, if we don't want the number 6 to show up in our chunk names:
10+
```javascript
11+
{
12+
"dynamic-import-chunkname": [2, {
13+
importFunctions: ["dynamicImport"],
14+
webpackChunknameFormat: "[a-zA-Z0-57-9-/_]"
15+
}]
16+
}
17+
```
18+
19+
### invalid
20+
The following patterns are invalid:
21+
22+
```javascript
23+
// no leading comment
24+
import('someModule');
25+
26+
// incorrectly formatted comment
27+
import(
28+
/*webpackChunkName:"someModule"*/
29+
'someModule',
30+
);
31+
32+
// chunkname contains a 6 (forbidden by rule config)
33+
import(
34+
/* webpackChunkName: "someModule6" */
35+
'someModule',
36+
);
37+
38+
// using single quotes instead of double quotes
39+
import(
40+
/* webpackChunkName: 'someModule' */
41+
'someModule',
42+
);
43+
44+
// single-line comment, not a block-style comment
45+
import(
46+
// webpackChunkName: "someModule"
47+
'someModule',
48+
);
49+
```
50+
### valid
51+
The following patterns are valid:
52+
53+
```javascript
54+
import(
55+
/* webpackChunkName: "someModule" */
56+
'someModule',
57+
);
58+
import(
59+
/* webpackChunkName: "someOtherModule12345789" */
60+
'someModule',
61+
);
62+
```
63+
64+
## When Not To Use It
65+
66+
If you don't care that webpack will autogenerate chunk names and may blow up browser caches and bundle size reports.

src/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export const rules = {
3535
'unambiguous': require('./rules/unambiguous'),
3636
'no-unassigned-import': require('./rules/no-unassigned-import'),
3737
'no-useless-path-segments': require('./rules/no-useless-path-segments'),
38+
'dynamic-import-chunkname': require('./rules/dynamic-import-chunkname'),
3839

3940
// export
4041
'exports-last': require('./rules/exports-last'),
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import docsUrl from '../docsUrl'
2+
3+
module.exports = {
4+
meta: {
5+
docs: {
6+
url: docsUrl('dynamic-import-chunkname'),
7+
},
8+
schema: [{
9+
type: 'object',
10+
properties: {
11+
importFunctions: {
12+
type: 'array',
13+
uniqueItems: true,
14+
items: {
15+
type: 'string',
16+
},
17+
},
18+
webpackChunknameFormat: {
19+
type: 'string',
20+
},
21+
},
22+
}],
23+
},
24+
25+
create: function (context) {
26+
const config = context.options[0]
27+
const { importFunctions = [] } = config || {}
28+
const { webpackChunknameFormat = '[0-9a-zA-Z-_/.]+' } = config || {}
29+
30+
const commentFormat = ` webpackChunkName: "${webpackChunknameFormat}" `
31+
const commentRegex = new RegExp(commentFormat)
32+
33+
return {
34+
CallExpression(node) {
35+
if (node.callee.type !== 'Import' && importFunctions.indexOf(node.callee.name) < 0) {
36+
return
37+
}
38+
39+
const sourceCode = context.getSourceCode()
40+
const arg = node.arguments[0]
41+
const leadingComments = sourceCode.getComments(arg).leading
42+
43+
if (!leadingComments || leadingComments.length !== 1) {
44+
context.report({
45+
node,
46+
message: 'dynamic imports require a leading comment with the webpack chunkname',
47+
})
48+
return
49+
}
50+
51+
const comment = leadingComments[0]
52+
if (comment.type !== 'Block') {
53+
context.report({
54+
node,
55+
message: 'dynamic imports require a /* foo */ style comment, not a // foo comment',
56+
})
57+
return
58+
}
59+
60+
const webpackChunkDefinition = comment.value
61+
if (!webpackChunkDefinition.match(commentRegex)) {
62+
context.report({
63+
node,
64+
message: `dynamic imports require a leading comment in the form /*${commentFormat}*/`,
65+
})
66+
}
67+
},
68+
}
69+
},
70+
}

0 commit comments

Comments
 (0)