close

dynamic-import-chunkname

Unreleased

Configuration

rslint.config.ts
import { defineConfig, importPlugin } from '@rslint/core';

export default defineConfig([
  importPlugin.configs.recommended,
  {
    rules: {
      'import/dynamic-import-chunkname': 'error',
    },
  },
]);

Rule Details

Reports dynamic imports that do not have a webpack magic comment naming the chunk. When a chunk is not named, the bundler generates a name that changes between builds, which prevents long-term browser caching and makes bundle size reports harder to read.

The rule checks import() by default. Use importFunctions to check calls to other functions as well.

Each comment before the first argument must be a block comment padded with spaces on both sides, such as /* webpackChunkName: "name" */, and must contain only webpack magic comment settings. At least one comment must name the chunk. Rspack's rspack-prefixed magic comments are accepted wherever the webpack-prefixed ones are.

Examples of incorrect code for this rule:

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

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

// invalid syntax for webpack comment
import(
  /* totally not webpackChunkName: "someModule" */
  'someModule',
);

// single-line comment, not a block comment
import(
  // webpackChunkName: "someModule"
  'someModule',
);

// chunk names are not needed when eager mode is set
import(
  /* webpackMode: "eager" */
  /* webpackChunkName: "someModule" */
  'someModule',
);

Examples of correct code for this rule:

import(
  /* webpackChunkName: "someModule" */
  'someModule',
);
import(
  /* webpackChunkName: "someModule" */
  /* webpackPrefetch: true */
  'someModule',
);
import(
  /* webpackChunkName: "someModule", webpackPrefetch: true */
  'someModule',
);

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

// Rspack's prefix
import(
  /* rspackChunkName: "someModule" */
  'someModule',
);

Recognized magic comments

webpack prefixrspack prefixAccepted value
webpackChunkNamerspackChunkNameany text; a chunk name must also match webpackChunknameFormat
webpackPrefetchrspackPrefetchtrue, false or an integer
webpackPreloadrspackPreloadtrue, false or an integer
webpackIgnorerspackIgnoretrue or false
webpackIncluderspackIncludea regular expression literal
webpackExcluderspackExcludea regular expression literal
webpackModerspackMode"lazy", "lazy-once", "eager" or "weak"
webpackExportsrspackExportsa quoted export name or an array of quoted export names
webpackFetchPriorityrspackFetchPriority"low", "high" or "auto"

The two prefixes can be mixed in the same file and in the same comment.

Eager mode

A chunk is not created for an import in eager mode, so a chunk name next to webpackMode: "eager" (or rspackMode: "eager") is reported. The report has two suggestions: remove the chunk name, or remove the mode. A comment that becomes empty is deleted; the surrounding whitespace stays in place.

Options

{
  "import/dynamic-import-chunkname": [
    "error",
    {
      "importFunctions": ["dynamicImport"],
      "webpackChunknameFormat": "[a-zA-Z0-57-9-/_]+",
      "allowEmpty": false
    }
  ]
}

importFunctions

An array of function names whose first argument is checked in the same way as the argument of import(). The default is [].

webpackChunknameFormat

A regular expression source that a chunk name must match. The default is ([0-9a-zA-Z-_/.]|\[(request|index)\])+. With the configuration above, a chunk name containing the digit 6 is reported:

import(
  /* webpackChunkName: "someModule6" */
  'someModule',
);

The pattern is matched between the quotes of the chunk name, so anchors such as ^ and $ never match. If the pattern is not a valid regular expression, the rule reports nothing.

allowEmpty

When true, imports without a leading comment, or without a chunk name, are allowed. Comments that are present must still be well formed. The default is false.

Examples of correct code with { "allowEmpty": true }:

import('someModule');

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

Examples of incorrect code with { "allowEmpty": true }:

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

When Not To Use It

If you do not care that webpack may generate chunk names that change between builds, and may invalidate browser caches and bundle size reports.

Differences from upstream

  • Every magic comment accepts the Rspack rspack prefix as well as the webpack prefix, and webpackFetchPriority / rspackFetchPriority is recognized. Upstream recognizes only the webpack prefix and reports /* rspackChunkName: "someModule" */ as an invalid comment, and also /* webpackFetchPriority: "high" */. The diagnostics themselves keep the upstream wording, which names webpackChunkName.

  • Upstream checks that a comment is valid by running it with vm.runInNewContext. rslint does not run code, so it reports the failures that can be decided from the source:

    • syntax errors anywhere in the comment, including TypeScript-only syntax such as "a" as string, invalid regular expression literals such as /(/, and strict-mode errors in class bodies;
    • reads of names that do not exist in a fresh JavaScript context, such as /* webpackChunkName: someModule */, and writes to undeclared names in class code;
    • destructuring null or undefined.

    A read is reported only when it is certain to run. Code skipped by ||, &&, ??, their assignment forms, a conditional or ?. is not searched, and neither is code that a condition which is not a constant may skip. The same applies to a destructuring default, which is checked only when the value is known to be undefined, so [a = missing] = values is not reported when values is not a literal. Of the code in a class, what runs when the class is defined is searched (the extends clause, computed keys, static initializers, and the statements of a static block that are certain to run); method bodies, loop and switch bodies, and try blocks are not. Errors that only occur while running other code are not detected. For example, with { "allowEmpty": true }, /* webpackChunkName: (() => missing)() */ is reported as invalid syntax by upstream and is not reported by rslint; without allowEmpty, rslint reports that no chunk name was found instead.

  • A call without arguments, such as dynamicImport() for a function listed in importFunctions, is ignored. Upstream throws a TypeError for it.

  • An invalid webpackChunknameFormat produces no diagnostics. Upstream fails the lint run.

Original Documentation