Skip to content

Commit

Permalink
Merge pull request #1070 from byteme980/dynamic-import-chunkname-rule
Browse files Browse the repository at this point in the history
[New] add Dynamic import chunkname rule
  • Loading branch information
ljharb authored Apr 10, 2018
2 parents 2495356 + 115b6fb commit cfd4377
Show file tree
Hide file tree
Showing 5 changed files with 415 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ This plugin intends to support linting of ES2015+ (ES6+) import/export syntax, a
* Forbid default exports ([`no-default-export`])
* Forbid anonymous values as default exports ([`no-anonymous-default-export`])
* Prefer named exports to be grouped together in a single export declaration ([`group-exports`])
* Enforce a leading comment with the webpackChunkName for dynamic imports ([`dynamic-import-chunkname`])

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

## Installation

Expand Down
66 changes: 66 additions & 0 deletions docs/rules/dynamic-import-chunkname.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# dynamic imports require a leading comment with a webpackChunkName (dynamic-import-chunkname)

This rule reports any dynamic imports without a webpackChunkName specified in a leading block comment in the proper format.

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.

## Rule Details
This rule runs against `import()` by default, but can be configured to also run against an alternative dynamic-import function, e.g. 'dynamicImport.'
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:
```javascript
{
"dynamic-import-chunkname": [2, {
importFunctions: ["dynamicImport"],
webpackChunknameFormat: "[a-zA-Z0-57-9-/_]"
}]
}
```

### invalid
The following patterns are invalid:

```javascript
// no leading comment
import('someModule');

// incorrectly formatted comment
import(
/*webpackChunkName:"someModule"*/
'someModule',
);

// chunkname contains a 6 (forbidden by rule config)
import(
/* webpackChunkName: "someModule6" */
'someModule',
);

// using single quotes instead of double quotes
import(
/* webpackChunkName: 'someModule' */
'someModule',
);

// single-line comment, not a block-style comment
import(
// webpackChunkName: "someModule"
'someModule',
);
```
### valid
The following patterns are valid:

```javascript
import(
/* webpackChunkName: "someModule" */
'someModule',
);
import(
/* webpackChunkName: "someOtherModule12345789" */
'someModule',
);
```

## When Not To Use It

If you don't care that webpack will autogenerate chunk names and may blow up browser caches and bundle size reports.
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export const rules = {
'unambiguous': require('./rules/unambiguous'),
'no-unassigned-import': require('./rules/no-unassigned-import'),
'no-useless-path-segments': require('./rules/no-useless-path-segments'),
'dynamic-import-chunkname': require('./rules/dynamic-import-chunkname'),

// export
'exports-last': require('./rules/exports-last'),
Expand Down
70 changes: 70 additions & 0 deletions src/rules/dynamic-import-chunkname.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import docsUrl from '../docsUrl'

module.exports = {
meta: {
docs: {
url: docsUrl('dynamic-import-chunkname'),
},
schema: [{
type: 'object',
properties: {
importFunctions: {
type: 'array',
uniqueItems: true,
items: {
type: 'string',
},
},
webpackChunknameFormat: {
type: 'string',
},
},
}],
},

create: function (context) {
const config = context.options[0]
const { importFunctions = [] } = config || {}
const { webpackChunknameFormat = '[0-9a-zA-Z-_/.]+' } = config || {}

const commentFormat = ` webpackChunkName: "${webpackChunknameFormat}" `
const commentRegex = new RegExp(commentFormat)

return {
CallExpression(node) {
if (node.callee.type !== 'Import' && importFunctions.indexOf(node.callee.name) < 0) {
return
}

const sourceCode = context.getSourceCode()
const arg = node.arguments[0]
const leadingComments = sourceCode.getComments(arg).leading

if (!leadingComments || leadingComments.length !== 1) {
context.report({
node,
message: 'dynamic imports require a leading comment with the webpack chunkname',
})
return
}

const comment = leadingComments[0]
if (comment.type !== 'Block') {
context.report({
node,
message: 'dynamic imports require a /* foo */ style comment, not a // foo comment',
})
return
}

const webpackChunkDefinition = comment.value
if (!webpackChunkDefinition.match(commentRegex)) {
context.report({
node,
message: `dynamic imports require a leading comment in the form /*${commentFormat}*/`,
})
}
},
}
},
}
Loading

0 comments on commit cfd4377

Please sign in to comment.