Merge branch 'main' into main

This commit is contained in:
Yadunandan Bhat 2022-08-01 10:33:10 +05:30 committed by GitHub
commit d0c699651b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
92 changed files with 1838 additions and 351 deletions

View File

@ -13,13 +13,16 @@ on:
- main - main
- dev-1 - dev-1
permissions:
contents: read
jobs: jobs:
lint: lint:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Use Node.js - name: Use Node.js
uses: actions/setup-node@v2 uses: actions/setup-node@v3
with: with:
node-version: 17.x node-version: 17.x
cache: "yarn" cache: "yarn"
@ -33,9 +36,9 @@ jobs:
basic: basic:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Use Node.js - name: Use Node.js
uses: actions/setup-node@v2 uses: actions/setup-node@v3
with: with:
node-version: 17.x node-version: 17.x
cache: "yarn" cache: "yarn"
@ -43,16 +46,16 @@ jobs:
- run: yarn link --frozen-lockfile || true - run: yarn link --frozen-lockfile || true
- run: yarn link webpack --frozen-lockfile - run: yarn link webpack --frozen-lockfile
- run: yarn test:basic --ci - run: yarn test:basic --ci
- uses: codecov/codecov-action@v1 - uses: codecov/codecov-action@v3
with: with:
flags: basic flags: basic
functionalities: gcov functionalities: gcov
unit: unit:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Use Node.js - name: Use Node.js
uses: actions/setup-node@v2 uses: actions/setup-node@v3
with: with:
node-version: 17.x node-version: 17.x
cache: "yarn" cache: "yarn"
@ -65,7 +68,7 @@ jobs:
key: jest-unit-${{ env.GITHUB_SHA }} key: jest-unit-${{ env.GITHUB_SHA }}
restore-keys: jest-unit- restore-keys: jest-unit-
- run: yarn cover:unit --ci --cacheDirectory .jest-cache - run: yarn cover:unit --ci --cacheDirectory .jest-cache
- uses: codecov/codecov-action@v1 - uses: codecov/codecov-action@v3
with: with:
flags: unit flags: unit
functionalities: gcov functionalities: gcov
@ -89,23 +92,23 @@ jobs:
part: a part: a
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2 uses: actions/setup-node@v3
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
cache: "yarn" cache: "yarn"
- run: yarn --frozen-lockfile - run: yarn --frozen-lockfile
- run: yarn link --frozen-lockfile || true - run: yarn link --frozen-lockfile || true
- run: yarn link webpack --frozen-lockfile - run: yarn link webpack --frozen-lockfile
- uses: actions/cache@v1 - uses: actions/cache@v2
with: with:
path: .jest-cache path: .jest-cache
key: jest-integration-${{ env.GITHUB_SHA }} key: jest-integration-${{ env.GITHUB_SHA }}
restore-keys: jest-integration- restore-keys: jest-integration-
- run: yarn cover:integration:${{ matrix.part }} --ci --cacheDirectory .jest-cache || yarn cover:integration:${{ matrix.part }} --ci --cacheDirectory .jest-cache -f - run: yarn cover:integration:${{ matrix.part }} --ci --cacheDirectory .jest-cache || yarn cover:integration:${{ matrix.part }} --ci --cacheDirectory .jest-cache -f
- run: yarn cover:merge - run: yarn cover:merge
- uses: codecov/codecov-action@v1 - uses: codecov/codecov-action@v3
with: with:
flags: integration flags: integration
functionalities: gcov functionalities: gcov

View File

@ -15,6 +15,9 @@
[![PR's welcome][prs]][prs-url] [![PR's welcome][prs]][prs-url]
<br> <br>
<a href="https://docs.github.com/en/code-security/dependabot/dependabot-security-updates/about-dependabot-security-updates#about-compatibility-scores">
<img src="https://api.dependabot.com/badges/compatibility_score?dependency-name=webpack&package-manager=npm_and_yarn&previous-version=5.72.1&new-version=5.73.0">
</a>
<a href="https://npmcharts.com/compare/webpack?minimal=true"> <a href="https://npmcharts.com/compare/webpack?minimal=true">
<img src="https://img.shields.io/npm/dm/webpack.svg"> <img src="https://img.shields.io/npm/dm/webpack.svg">
</a> </a>
@ -110,6 +113,7 @@ within webpack itself use this plugin interface. This makes webpack very
| [mini-css-extract-plugin][mini-css] | ![mini-css-npm] | ![mini-css-size] | Extracts CSS into separate files. It creates a CSS file per JS file which contains CSS. | | [mini-css-extract-plugin][mini-css] | ![mini-css-npm] | ![mini-css-size] | Extracts CSS into separate files. It creates a CSS file per JS file which contains CSS. |
| [compression-webpack-plugin][compression] | ![compression-npm] | ![compression-size] | Prepares compressed versions of assets to serve them with Content-Encoding | | [compression-webpack-plugin][compression] | ![compression-npm] | ![compression-size] | Prepares compressed versions of assets to serve them with Content-Encoding |
| [html-webpack-plugin][html-plugin] | ![html-plugin-npm] | ![html-plugin-size] | Simplifies creation of HTML files (`index.html`) to serve your bundles | | [html-webpack-plugin][html-plugin] | ![html-plugin-npm] | ![html-plugin-size] | Simplifies creation of HTML files (`index.html`) to serve your bundles |
| [pug-plugin][pug-plugin] | ![pug-plugin-npm] | ![pug-plugin-size] | Renders Pug files to HTML, extracts JS and CSS from sources specified directly in Pug. |
[common-npm]: https://img.shields.io/npm/v/webpack.svg [common-npm]: https://img.shields.io/npm/v/webpack.svg
[mini-css]: https://github.com/webpack-contrib/mini-css-extract-plugin [mini-css]: https://github.com/webpack-contrib/mini-css-extract-plugin
@ -124,6 +128,9 @@ within webpack itself use this plugin interface. This makes webpack very
[html-plugin]: https://github.com/jantimon/html-webpack-plugin [html-plugin]: https://github.com/jantimon/html-webpack-plugin
[html-plugin-npm]: https://img.shields.io/npm/v/html-webpack-plugin.svg [html-plugin-npm]: https://img.shields.io/npm/v/html-webpack-plugin.svg
[html-plugin-size]: https://packagephobia.com/badge?p=html-webpack-plugin [html-plugin-size]: https://packagephobia.com/badge?p=html-webpack-plugin
[pug-plugin]: https://github.com/webdiscus/pug-plugin
[pug-plugin-npm]: https://img.shields.io/npm/v/pug-plugin.svg
[pug-plugin-size]: https://packagephobia.com/badge?p=pug-plugin
### [Loaders](https://webpack.js.org/loaders/) ### [Loaders](https://webpack.js.org/loaders/)
@ -171,9 +178,10 @@ or are automatically applied via regex from your webpack configuration.
#### Templating #### Templating
| Name | Status | Install Size | Description | | Name | Status | Install Size | Description |
| :-------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------: | :--------------: | :-------------------------------------------------------------------------------------- | | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------: | :--------------: | :-------------------------------------------------------------------------------------- |
| <a href="https://github.com/webpack-contrib/html-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/html5.svg"></a> | ![html-npm] | ![html-size] | Exports HTML as string, requires references to static resources | | <a href="https://github.com/webpack-contrib/html-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/html5.svg"></a> | ![html-npm] | ![html-size] | Exports HTML as string, requires references to static resources |
| <a href="https://github.com/pugjs/pug-loader"><img width="48" height="48" src="https://cdn.rawgit.com/pugjs/pug-logo/master/SVG/pug-final-logo-_-colour-128.svg"></a> | ![pug-npm] | ![pug-size] | Loads Pug templates and returns a function | | <a href="https://github.com/pugjs/pug-loader"><img width="48" height="48" src="https://cdn.rawgit.com/pugjs/pug-logo/master/SVG/pug-final-logo-_-colour-128.svg"></a> | ![pug-npm] | ![pug-size] | Loads Pug templates and returns a function |
| <a href="https://github.com/webdiscus/pug-loader"><img width="48" height="48" src="https://cdn.rawgit.com/pugjs/pug-logo/master/SVG/pug-final-logo-_-colour-128.svg"></a> | ![pug3-npm] | ![pug3-size] | Compiles Pug to a function or HTML string, useful for use with Vue, React, Angular |
| <a href="https://github.com/peerigon/markdown-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/markdown.svg"></a> | ![md-npm] | ![md-size] | Compiles Markdown to HTML | | <a href="https://github.com/peerigon/markdown-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/markdown.svg"></a> | ![md-npm] | ![md-size] | Compiles Markdown to HTML |
| <a href="https://github.com/posthtml/posthtml-loader"><img width="48" height="48" src="https://posthtml.github.io/posthtml/logo.svg"></a> | ![posthtml-npm] | ![posthtml-size] | Loads and transforms a HTML file using [PostHTML](https://github.com/posthtml/posthtml) | | <a href="https://github.com/posthtml/posthtml-loader"><img width="48" height="48" src="https://posthtml.github.io/posthtml/logo.svg"></a> | ![posthtml-npm] | ![posthtml-size] | Loads and transforms a HTML file using [PostHTML](https://github.com/posthtml/posthtml) |
| <a href="https://github.com/pcardune/handlebars-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/handlebars-1.svg"></a> | ![hbs-npm] | ![hbs-size] | Compiles Handlebars to HTML | | <a href="https://github.com/pcardune/handlebars-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/handlebars-1.svg"></a> | ![hbs-npm] | ![hbs-size] | Compiles Handlebars to HTML |
@ -182,6 +190,8 @@ or are automatically applied via regex from your webpack configuration.
[html-size]: https://packagephobia.com/badge?p=html-loader [html-size]: https://packagephobia.com/badge?p=html-loader
[pug-npm]: https://img.shields.io/npm/v/pug-loader.svg [pug-npm]: https://img.shields.io/npm/v/pug-loader.svg
[pug-size]: https://packagephobia.com/badge?p=pug-loader [pug-size]: https://packagephobia.com/badge?p=pug-loader
[pug3-npm]: https://img.shields.io/npm/v/@webdiscus/pug-loader.svg
[pug3-size]: https://packagephobia.com/badge?p=@webdiscus/pug-loader
[jade-npm]: https://img.shields.io/npm/v/jade-loader.svg [jade-npm]: https://img.shields.io/npm/v/jade-loader.svg
[jade-size]: https://packagephobia.com/badge?p=jade-loader [jade-size]: https://packagephobia.com/badge?p=jade-loader
[md-npm]: https://img.shields.io/npm/v/markdown-loader.svg [md-npm]: https://img.shields.io/npm/v/markdown-loader.svg

View File

@ -1505,6 +1505,15 @@ export interface ResolveOptions {
* Field names from the description file (usually package.json) which are used to provide entry points of a package. * Field names from the description file (usually package.json) which are used to provide entry points of a package.
*/ */
exportsFields?: string[]; exportsFields?: string[];
/**
* An object which maps extension to extension aliases.
*/
extensionAlias?: {
/**
* Extension alias.
*/
[k: string]: string[] | string;
};
/** /**
* Extensions added to the request when trying to find the file. * Extensions added to the request when trying to find the file.
*/ */
@ -2929,6 +2938,22 @@ export interface JavascriptParserOptions {
* Enable/disable parsing of magic comments in CommonJs syntax. * Enable/disable parsing of magic comments in CommonJs syntax.
*/ */
commonjsMagicComments?: boolean; commonjsMagicComments?: boolean;
/**
* Enable/disable parsing "import { createRequire } from "module"" and evaluating createRequire().
*/
createRequire?: boolean | string;
/**
* Specifies global mode for dynamic import.
*/
dynamicImportMode?: "eager" | "weak" | "lazy" | "lazy-once";
/**
* Specifies global prefetch for dynamic import.
*/
dynamicImportPrefetch?: number | boolean;
/**
* Specifies global preload for dynamic import.
*/
dynamicImportPreload?: number | boolean;
/** /**
* Specifies the behavior of invalid export names in "import ... from ..." and "export ... from ...". * Specifies the behavior of invalid export names in "import ... from ..." and "export ... from ...".
*/ */
@ -3498,11 +3523,11 @@ export interface ExperimentsNormalizedExtra {
/** /**
* Enable css support. * Enable css support.
*/ */
css?: CssExperimentOptions; css?: false | CssExperimentOptions;
/** /**
* Compile entrypoints and import()s only when they are accessed. * Compile entrypoints and import()s only when they are accessed.
*/ */
lazyCompilation?: LazyCompilationOptions; lazyCompilation?: false | LazyCompilationOptions;
} }
/** /**
* If an dependency matches exactly a property of the object, the property value is used as dependency. * If an dependency matches exactly a property of the object, the property value is used as dependency.

View File

@ -4241,7 +4241,11 @@ This prevents using hashes of each other and should be avoided.`);
if (!isSourceEqual(this.assets[file], source)) { if (!isSourceEqual(this.assets[file], source)) {
this.errors.push( this.errors.push(
new WebpackError( new WebpackError(
`Conflict: Multiple assets emit different content to the same filename ${file}` `Conflict: Multiple assets emit different content to the same filename ${file}${
assetInfo.sourceFilename
? `. Original source ${assetInfo.sourceFilename}`
: ""
}`
) )
); );
this.assets[file] = source; this.assets[file] = source;

View File

@ -8,6 +8,7 @@
const { create: createResolver } = require("enhanced-resolve"); const { create: createResolver } = require("enhanced-resolve");
const nodeModule = require("module"); const nodeModule = require("module");
const asyncLib = require("neo-async"); const asyncLib = require("neo-async");
const { isAbsolute } = require("path");
const AsyncQueue = require("./util/AsyncQueue"); const AsyncQueue = require("./util/AsyncQueue");
const StackedCacheMap = require("./util/StackedCacheMap"); const StackedCacheMap = require("./util/StackedCacheMap");
const createHash = require("./util/createHash"); const createHash = require("./util/createHash");
@ -207,6 +208,12 @@ class SnapshotIterable {
class Snapshot { class Snapshot {
constructor() { constructor() {
this._flags = 0; this._flags = 0;
/** @type {Iterable<string> | undefined} */
this._cachedFileIterable = undefined;
/** @type {Iterable<string> | undefined} */
this._cachedContextIterable = undefined;
/** @type {Iterable<string> | undefined} */
this._cachedMissingIterable = undefined;
/** @type {number | undefined} */ /** @type {number | undefined} */
this.startTime = undefined; this.startTime = undefined;
/** @type {Map<string, FileSystemInfoEntry | null> | undefined} */ /** @type {Map<string, FileSystemInfoEntry | null> | undefined} */
@ -417,31 +424,43 @@ class Snapshot {
* @returns {Iterable<string>} iterable * @returns {Iterable<string>} iterable
*/ */
getFileIterable() { getFileIterable() {
return this._createIterable(s => [ if (this._cachedFileIterable === undefined) {
this._cachedFileIterable = this._createIterable(s => [
s.fileTimestamps, s.fileTimestamps,
s.fileHashes, s.fileHashes,
s.fileTshs, s.fileTshs,
s.managedFiles s.managedFiles
]); ]);
} }
return this._cachedFileIterable;
}
/** /**
* @returns {Iterable<string>} iterable * @returns {Iterable<string>} iterable
*/ */
getContextIterable() { getContextIterable() {
return this._createIterable(s => [ if (this._cachedContextIterable === undefined) {
this._cachedContextIterable = this._createIterable(s => [
s.contextTimestamps, s.contextTimestamps,
s.contextHashes, s.contextHashes,
s.contextTshs, s.contextTshs,
s.managedContexts s.managedContexts
]); ]);
} }
return this._cachedContextIterable;
}
/** /**
* @returns {Iterable<string>} iterable * @returns {Iterable<string>} iterable
*/ */
getMissingIterable() { getMissingIterable() {
return this._createIterable(s => [s.missingExistence, s.managedMissing]); if (this._cachedMissingIterable === undefined) {
this._cachedMissingIterable = this._createIterable(s => [
s.missingExistence,
s.managedMissing
]);
}
return this._cachedMissingIterable;
} }
} }
@ -1633,7 +1652,9 @@ class FileSystemInfo {
let request = relative(this.fs, context, childPath); let request = relative(this.fs, context, childPath);
if (request.endsWith(".js")) request = request.slice(0, -3); if (request.endsWith(".js")) request = request.slice(0, -3);
request = request.replace(/\\/g, "/"); request = request.replace(/\\/g, "/");
if (!request.startsWith("../")) request = `./${request}`; if (!request.startsWith("../") && !isAbsolute(request)) {
request = `./${request}`;
}
push({ push({
type: RBDT_RESOLVE_CJS_FILE, type: RBDT_RESOLVE_CJS_FILE,
context, context,

View File

@ -64,7 +64,7 @@ class NodeStuffPlugin {
new NodeStuffInWebError( new NodeStuffInWebError(
dep.loc, dep.loc,
"global", "global",
"The global namespace object is Node.js feature and doesn't present in browser." "The global namespace object is a Node.js feature and isn't available in browsers."
) )
); );
} }
@ -117,7 +117,7 @@ class NodeStuffPlugin {
setConstant( setConstant(
"__filename", "__filename",
"/index.js", "/index.js",
"The __filename is Node.js feature and doesn't present in browser." "__filename is a Node.js feature and isn't available in browsers."
); );
break; break;
case true: case true:
@ -144,7 +144,7 @@ class NodeStuffPlugin {
setConstant( setConstant(
"__dirname", "__dirname",
"/", "/",
"The __dirname is Node.js feature and doesn't present in browser." "__dirname is a Node.js feature and isn't available in browsers."
); );
break; break;
case true: case true:

View File

@ -26,6 +26,7 @@ const GlobalRuntimeModule = require("./runtime/GlobalRuntimeModule");
const HasOwnPropertyRuntimeModule = require("./runtime/HasOwnPropertyRuntimeModule"); const HasOwnPropertyRuntimeModule = require("./runtime/HasOwnPropertyRuntimeModule");
const LoadScriptRuntimeModule = require("./runtime/LoadScriptRuntimeModule"); const LoadScriptRuntimeModule = require("./runtime/LoadScriptRuntimeModule");
const MakeNamespaceObjectRuntimeModule = require("./runtime/MakeNamespaceObjectRuntimeModule"); const MakeNamespaceObjectRuntimeModule = require("./runtime/MakeNamespaceObjectRuntimeModule");
const NonceRuntimeModule = require("./runtime/NonceRuntimeModule");
const OnChunksLoadedRuntimeModule = require("./runtime/OnChunksLoadedRuntimeModule"); const OnChunksLoadedRuntimeModule = require("./runtime/OnChunksLoadedRuntimeModule");
const PublicPathRuntimeModule = require("./runtime/PublicPathRuntimeModule"); const PublicPathRuntimeModule = require("./runtime/PublicPathRuntimeModule");
const RelativeUrlRuntimeModule = require("./runtime/RelativeUrlRuntimeModule"); const RelativeUrlRuntimeModule = require("./runtime/RelativeUrlRuntimeModule");
@ -431,6 +432,12 @@ class RuntimePlugin {
return true; return true;
} }
}); });
compilation.hooks.runtimeRequirementInTree
.for(RuntimeGlobals.scriptNonce)
.tap("RuntimePlugin", chunk => {
compilation.addRuntimeModule(chunk, new NonceRuntimeModule());
return true;
});
// TODO webpack 6: remove CompatRuntimeModule // TODO webpack 6: remove CompatRuntimeModule
compilation.hooks.additionalTreeRuntimeRequirements.tap( compilation.hooks.additionalTreeRuntimeRequirements.tap(
"RuntimePlugin", "RuntimePlugin",

View File

@ -190,7 +190,8 @@ const applyWebpackOptionsDefaults = options => {
syncWebAssembly: options.experiments.syncWebAssembly, syncWebAssembly: options.experiments.syncWebAssembly,
asyncWebAssembly: options.experiments.asyncWebAssembly, asyncWebAssembly: options.experiments.asyncWebAssembly,
css: options.experiments.css, css: options.experiments.css,
futureDefaults futureDefaults,
isNode: targetProperties && targetProperties.node === true
}); });
applyOutputDefaults(options.output, { applyOutputDefaults(options.output, {
@ -451,11 +452,12 @@ const applySnapshotDefaults = (snapshot, { production, futureDefaults }) => {
* @param {JavascriptParserOptions} parserOptions parser options * @param {JavascriptParserOptions} parserOptions parser options
* @param {Object} options options * @param {Object} options options
* @param {boolean} options.futureDefaults is future defaults enabled * @param {boolean} options.futureDefaults is future defaults enabled
* @param {boolean} options.isNode is node target platform
* @returns {void} * @returns {void}
*/ */
const applyJavascriptParserOptionsDefaults = ( const applyJavascriptParserOptionsDefaults = (
parserOptions, parserOptions,
{ futureDefaults } { futureDefaults, isNode }
) => { ) => {
D(parserOptions, "unknownContextRequest", "."); D(parserOptions, "unknownContextRequest", ".");
D(parserOptions, "unknownContextRegExp", false); D(parserOptions, "unknownContextRegExp", false);
@ -470,6 +472,10 @@ const applyJavascriptParserOptionsDefaults = (
D(parserOptions, "wrappedContextCritical", false); D(parserOptions, "wrappedContextCritical", false);
D(parserOptions, "strictThisContextOnImports", false); D(parserOptions, "strictThisContextOnImports", false);
D(parserOptions, "importMeta", true); D(parserOptions, "importMeta", true);
D(parserOptions, "dynamicImportMode", "lazy");
D(parserOptions, "dynamicImportPrefetch", false);
D(parserOptions, "dynamicImportPreload", false);
D(parserOptions, "createRequire", isNode);
if (futureDefaults) D(parserOptions, "exportsPresence", "error"); if (futureDefaults) D(parserOptions, "exportsPresence", "error");
}; };
@ -479,13 +485,14 @@ const applyJavascriptParserOptionsDefaults = (
* @param {boolean} options.cache is caching enabled * @param {boolean} options.cache is caching enabled
* @param {boolean} options.syncWebAssembly is syncWebAssembly enabled * @param {boolean} options.syncWebAssembly is syncWebAssembly enabled
* @param {boolean} options.asyncWebAssembly is asyncWebAssembly enabled * @param {boolean} options.asyncWebAssembly is asyncWebAssembly enabled
* @param {CssExperimentOptions} options.css is css enabled * @param {CssExperimentOptions|false} options.css is css enabled
* @param {boolean} options.futureDefaults is future defaults enabled * @param {boolean} options.futureDefaults is future defaults enabled
* @param {boolean} options.isNode is node target platform
* @returns {void} * @returns {void}
*/ */
const applyModuleDefaults = ( const applyModuleDefaults = (
module, module,
{ cache, syncWebAssembly, asyncWebAssembly, css, futureDefaults } { cache, syncWebAssembly, asyncWebAssembly, css, futureDefaults, isNode }
) => { ) => {
if (cache) { if (cache) {
D(module, "unsafeCache", module => { D(module, "unsafeCache", module => {
@ -504,7 +511,8 @@ const applyModuleDefaults = (
F(module.parser, "javascript", () => ({})); F(module.parser, "javascript", () => ({}));
applyJavascriptParserOptionsDefaults(module.parser.javascript, { applyJavascriptParserOptionsDefaults(module.parser.javascript, {
futureDefaults futureDefaults,
isNode
}); });
A(module, "defaultRules", () => { A(module, "defaultRules", () => {
@ -1114,7 +1122,7 @@ const applyPerformanceDefaults = (performance, { production }) => {
* @param {Object} options options * @param {Object} options options
* @param {boolean} options.production is production * @param {boolean} options.production is production
* @param {boolean} options.development is development * @param {boolean} options.development is development
* @param {CssExperimentOptions} options.css is css enabled * @param {CssExperimentOptions|false} options.css is css enabled
* @param {boolean} options.records using records * @param {boolean} options.records using records
* @returns {void} * @returns {void}
*/ */

View File

@ -178,11 +178,10 @@ const getNormalizedWebpackOptions = config => {
), ),
lazyCompilation: optionalNestedConfig( lazyCompilation: optionalNestedConfig(
experiments.lazyCompilation, experiments.lazyCompilation,
options => options => (options === true ? {} : options)
options === true ? {} : options === false ? undefined : options
), ),
css: optionalNestedConfig(experiments.css, options => css: optionalNestedConfig(experiments.css, options =>
options === true ? {} : options === false ? undefined : options options === true ? {} : options
) )
})), })),
externals: config.externals, externals: config.externals,

View File

@ -65,6 +65,7 @@ class ModuleFederationPlugin {
library, library,
filename: options.filename, filename: options.filename,
runtime: options.runtime, runtime: options.runtime,
shareScope: options.shareScope,
exposes: options.exposes exposes: options.exposes
}).apply(compiler); }).apply(compiler);
} }
@ -76,6 +77,7 @@ class ModuleFederationPlugin {
) { ) {
new ContainerReferencePlugin({ new ContainerReferencePlugin({
remoteType, remoteType,
shareScope: options.shareScope,
remotes: options.remotes remotes: options.remotes
}).apply(compiler); }).apply(compiler);
} }

View File

@ -108,7 +108,9 @@ class CssLoadingRuntimeModule extends RuntimeModule {
'link.rel = "stylesheet";', 'link.rel = "stylesheet";',
"link.href = url;", "link.href = url;",
crossOriginLoading crossOriginLoading
? Template.asString([ ? crossOriginLoading === "use-credentials"
? 'link.crossOrigin = "use-credentials";'
: Template.asString([
"if (link.src.indexOf(window.location.origin + '/') !== 0) {", "if (link.src.indexOf(window.location.origin + '/') !== 0) {",
Template.indent( Template.indent(
`link.crossOrigin = ${JSON.stringify(crossOriginLoading)};` `link.crossOrigin = ${JSON.stringify(crossOriginLoading)};`

View File

@ -5,9 +5,12 @@
"use strict"; "use strict";
const { fileURLToPath } = require("url");
const CommentCompilationWarning = require("../CommentCompilationWarning"); const CommentCompilationWarning = require("../CommentCompilationWarning");
const RuntimeGlobals = require("../RuntimeGlobals"); const RuntimeGlobals = require("../RuntimeGlobals");
const UnsupportedFeatureWarning = require("../UnsupportedFeatureWarning"); const UnsupportedFeatureWarning = require("../UnsupportedFeatureWarning");
const WebpackError = require("../WebpackError");
const BasicEvaluatedExpression = require("../javascript/BasicEvaluatedExpression");
const { const {
evaluateToIdentifier, evaluateToIdentifier,
evaluateToString, evaluateToString,
@ -26,8 +29,12 @@ const RequireResolveContextDependency = require("./RequireResolveContextDependen
const RequireResolveDependency = require("./RequireResolveDependency"); const RequireResolveDependency = require("./RequireResolveDependency");
const RequireResolveHeaderDependency = require("./RequireResolveHeaderDependency"); const RequireResolveHeaderDependency = require("./RequireResolveHeaderDependency");
/** @typedef {import("estree").CallExpression} CallExpressionNode */
/** @typedef {import("../../declarations/WebpackOptions").JavascriptParserOptions} JavascriptParserOptions */ /** @typedef {import("../../declarations/WebpackOptions").JavascriptParserOptions} JavascriptParserOptions */
const createRequireSpecifierTag = Symbol("createRequire");
const createdRequireIdentifierTag = Symbol("createRequire()");
class CommonJsImportsParserPlugin { class CommonJsImportsParserPlugin {
/** /**
* @param {JavascriptParserOptions} options parser options * @param {JavascriptParserOptions} options parser options
@ -39,30 +46,51 @@ class CommonJsImportsParserPlugin {
apply(parser) { apply(parser) {
const options = this.options; const options = this.options;
// metadata // const getContext = () => {
if (parser.currentTagData) {
const { context } = parser.currentTagData;
return context;
}
};
//#region metadata
const tapRequireExpression = (expression, getMembers) => { const tapRequireExpression = (expression, getMembers) => {
parser.hooks.typeof parser.hooks.typeof
.for(expression) .for(expression)
.tap( .tap(
"CommonJsPlugin", "CommonJsImportsParserPlugin",
toConstantDependency(parser, JSON.stringify("function")) toConstantDependency(parser, JSON.stringify("function"))
); );
parser.hooks.evaluateTypeof parser.hooks.evaluateTypeof
.for(expression) .for(expression)
.tap("CommonJsPlugin", evaluateToString("function")); .tap("CommonJsImportsParserPlugin", evaluateToString("function"));
parser.hooks.evaluateIdentifier parser.hooks.evaluateIdentifier
.for(expression) .for(expression)
.tap( .tap(
"CommonJsPlugin", "CommonJsImportsParserPlugin",
evaluateToIdentifier(expression, "require", getMembers, true) evaluateToIdentifier(expression, "require", getMembers, true)
); );
}; };
const tapRequireExpressionTag = tag => {
parser.hooks.typeof
.for(tag)
.tap(
"CommonJsImportsParserPlugin",
toConstantDependency(parser, JSON.stringify("function"))
);
parser.hooks.evaluateTypeof
.for(tag)
.tap("CommonJsImportsParserPlugin", evaluateToString("function"));
};
tapRequireExpression("require", () => []); tapRequireExpression("require", () => []);
tapRequireExpression("require.resolve", () => ["resolve"]); tapRequireExpression("require.resolve", () => ["resolve"]);
tapRequireExpression("require.resolveWeak", () => ["resolveWeak"]); tapRequireExpression("require.resolveWeak", () => ["resolveWeak"]);
//#endregion
// Weird stuff // // Weird stuff //
parser.hooks.assign.for("require").tap("CommonJsPlugin", expr => { parser.hooks.assign
.for("require")
.tap("CommonJsImportsParserPlugin", expr => {
// to not leak to global "require", we need to define a local require here. // to not leak to global "require", we need to define a local require here.
const dep = new ConstDependency("var require;", 0); const dep = new ConstDependency("var require;", 0);
dep.loc = expr.loc; dep.loc = expr.loc;
@ -70,20 +98,20 @@ class CommonJsImportsParserPlugin {
return true; return true;
}); });
// Unsupported // //#region Unsupported
parser.hooks.expression parser.hooks.expression
.for("require.main.require") .for("require.main")
.tap( .tap(
"CommonJsPlugin", "CommonJsImportsParserPlugin",
expressionIsUnsupported( expressionIsUnsupported(
parser, parser,
"require.main.require is not supported by webpack." "require.main is not supported by webpack."
) )
); );
parser.hooks.call parser.hooks.call
.for("require.main.require") .for("require.main.require")
.tap( .tap(
"CommonJsPlugin", "CommonJsImportsParserPlugin",
expressionIsUnsupported( expressionIsUnsupported(
parser, parser,
"require.main.require is not supported by webpack." "require.main.require is not supported by webpack."
@ -92,7 +120,7 @@ class CommonJsImportsParserPlugin {
parser.hooks.expression parser.hooks.expression
.for("module.parent.require") .for("module.parent.require")
.tap( .tap(
"CommonJsPlugin", "CommonJsImportsParserPlugin",
expressionIsUnsupported( expressionIsUnsupported(
parser, parser,
"module.parent.require is not supported by webpack." "module.parent.require is not supported by webpack."
@ -101,39 +129,48 @@ class CommonJsImportsParserPlugin {
parser.hooks.call parser.hooks.call
.for("module.parent.require") .for("module.parent.require")
.tap( .tap(
"CommonJsPlugin", "CommonJsImportsParserPlugin",
expressionIsUnsupported( expressionIsUnsupported(
parser, parser,
"module.parent.require is not supported by webpack." "module.parent.require is not supported by webpack."
) )
); );
//#endregion
// renaming // //#region Renaming
parser.hooks.canRename.for("require").tap("CommonJsPlugin", () => true); const defineUndefined = expr => {
parser.hooks.rename.for("require").tap("CommonJsPlugin", expr => {
// To avoid "not defined" error, replace the value with undefined // To avoid "not defined" error, replace the value with undefined
const dep = new ConstDependency("undefined", expr.range); const dep = new ConstDependency("undefined", expr.range);
dep.loc = expr.loc; dep.loc = expr.loc;
parser.state.module.addPresentationalDependency(dep); parser.state.module.addPresentationalDependency(dep);
return false; return false;
}); };
parser.hooks.canRename
.for("require")
.tap("CommonJsImportsParserPlugin", () => true);
parser.hooks.rename
.for("require")
.tap("CommonJsImportsParserPlugin", defineUndefined);
//#endregion
// inspection // //#region Inspection
parser.hooks.expression const requireCache = toConstantDependency(
.for("require.cache") parser,
.tap( RuntimeGlobals.moduleCache,
"CommonJsImportsParserPlugin", [
toConstantDependency(parser, RuntimeGlobals.moduleCache, [
RuntimeGlobals.moduleCache, RuntimeGlobals.moduleCache,
RuntimeGlobals.moduleId, RuntimeGlobals.moduleId,
RuntimeGlobals.moduleLoaded RuntimeGlobals.moduleLoaded
]) ]
); );
// require as expression //
parser.hooks.expression parser.hooks.expression
.for("require") .for("require.cache")
.tap("CommonJsImportsParserPlugin", expr => { .tap("CommonJsImportsParserPlugin", requireCache);
//#endregion
//#region Require as expression
const requireAsExpressionHandler = expr => {
const dep = new CommonJsRequireContextDependency( const dep = new CommonJsRequireContextDependency(
{ {
request: options.unknownContextRequest, request: options.unknownContextRequest,
@ -143,7 +180,8 @@ class CommonJsImportsParserPlugin {
}, },
expr.range, expr.range,
undefined, undefined,
parser.scope.inShorthand parser.scope.inShorthand,
getContext()
); );
dep.critical = dep.critical =
options.unknownContextCritical && options.unknownContextCritical &&
@ -152,12 +190,20 @@ class CommonJsImportsParserPlugin {
dep.optional = !!parser.scope.inTry; dep.optional = !!parser.scope.inTry;
parser.state.current.addDependency(dep); parser.state.current.addDependency(dep);
return true; return true;
}); };
parser.hooks.expression
.for("require")
.tap("CommonJsImportsParserPlugin", requireAsExpressionHandler);
//#endregion
// require // //#region Require
const processRequireItem = (expr, param) => { const processRequireItem = (expr, param) => {
if (param.isString()) { if (param.isString()) {
const dep = new CommonJsRequireDependency(param.string, param.range); const dep = new CommonJsRequireDependency(
param.string,
param.range,
getContext()
);
dep.loc = expr.loc; dep.loc = expr.loc;
dep.optional = !!parser.scope.inTry; dep.optional = !!parser.scope.inTry;
parser.state.current.addDependency(dep); parser.state.current.addDependency(dep);
@ -174,7 +220,9 @@ class CommonJsImportsParserPlugin {
{ {
category: "commonjs" category: "commonjs"
}, },
parser parser,
undefined,
getContext()
); );
if (!dep) return; if (!dep) return;
dep.loc = expr.loc; dep.loc = expr.loc;
@ -268,8 +316,9 @@ class CommonJsImportsParserPlugin {
parser.hooks.new parser.hooks.new
.for("module.require") .for("module.require")
.tap("CommonJsImportsParserPlugin", createRequireHandler(true)); .tap("CommonJsImportsParserPlugin", createRequireHandler(true));
//#endregion
// require with property access // //#region Require with property access
const chainHandler = (expr, calleeMembers, callExpr, members) => { const chainHandler = (expr, calleeMembers, callExpr, members) => {
if (callExpr.arguments.length !== 1) return; if (callExpr.arguments.length !== 1) return;
const param = parser.evaluateExpression(callExpr.arguments[0]); const param = parser.evaluateExpression(callExpr.arguments[0]);
@ -316,8 +365,9 @@ class CommonJsImportsParserPlugin {
parser.hooks.callMemberChainOfCallMemberChain parser.hooks.callMemberChainOfCallMemberChain
.for("module.require") .for("module.require")
.tap("CommonJsImportsParserPlugin", callChainHandler); .tap("CommonJsImportsParserPlugin", callChainHandler);
//#endregion
// require.resolve // //#region Require.resolve
const processResolve = (expr, weak) => { const processResolve = (expr, weak) => {
if (expr.arguments.length !== 1) return; if (expr.arguments.length !== 1) return;
const param = parser.evaluateExpression(expr.arguments[0]); const param = parser.evaluateExpression(expr.arguments[0]);
@ -345,7 +395,11 @@ class CommonJsImportsParserPlugin {
}; };
const processResolveItem = (expr, param, weak) => { const processResolveItem = (expr, param, weak) => {
if (param.isString()) { if (param.isString()) {
const dep = new RequireResolveDependency(param.string, param.range); const dep = new RequireResolveDependency(
param.string,
param.range,
getContext()
);
dep.loc = expr.loc; dep.loc = expr.loc;
dep.optional = !!parser.scope.inTry; dep.optional = !!parser.scope.inTry;
dep.weak = weak; dep.weak = weak;
@ -364,7 +418,8 @@ class CommonJsImportsParserPlugin {
category: "commonjs", category: "commonjs",
mode: weak ? "weak" : "sync" mode: weak ? "weak" : "sync"
}, },
parser parser,
getContext()
); );
if (!dep) return; if (!dep) return;
dep.loc = expr.loc; dep.loc = expr.loc;
@ -375,14 +430,240 @@ class CommonJsImportsParserPlugin {
parser.hooks.call parser.hooks.call
.for("require.resolve") .for("require.resolve")
.tap("RequireResolveDependencyParserPlugin", expr => { .tap("CommonJsImportsParserPlugin", expr => {
return processResolve(expr, false); return processResolve(expr, false);
}); });
parser.hooks.call parser.hooks.call
.for("require.resolveWeak") .for("require.resolveWeak")
.tap("RequireResolveDependencyParserPlugin", expr => { .tap("CommonJsImportsParserPlugin", expr => {
return processResolve(expr, true); return processResolve(expr, true);
}); });
//#endregion
//#region Create require
if (!options.createRequire) return;
let moduleName;
let specifierName;
if (options.createRequire === true) {
moduleName = "module";
specifierName = "createRequire";
} else {
const match = /^(.*) from (.*)$/.exec(options.createRequire);
if (match) {
[, specifierName, moduleName] = match;
}
if (!specifierName || !moduleName) {
const err = new WebpackError(
`Parsing javascript parser option "createRequire" failed, got ${JSON.stringify(
options.createRequire
)}`
);
err.details =
'Expected string in format "createRequire from module", where "createRequire" is specifier name and "module" name of the module';
throw err;
}
}
tapRequireExpressionTag(createdRequireIdentifierTag);
tapRequireExpressionTag(createRequireSpecifierTag);
parser.hooks.evaluateCallExpression
.for(createRequireSpecifierTag)
.tap("CommonJsImportsParserPlugin", expr => {
const context = parseCreateRequireArguments(expr);
if (context === undefined) return;
const ident = parser.evaluatedVariable({
tag: createdRequireIdentifierTag,
data: { context },
next: undefined
});
return new BasicEvaluatedExpression()
.setIdentifier(ident, ident, () => [])
.setSideEffects(false)
.setRange(expr.range);
});
parser.hooks.unhandledExpressionMemberChain
.for(createdRequireIdentifierTag)
.tap("CommonJsImportsParserPlugin", (expr, members) => {
return expressionIsUnsupported(
parser,
`createRequire().${members.join(".")} is not supported by webpack.`
)(expr);
});
parser.hooks.canRename
.for(createdRequireIdentifierTag)
.tap("CommonJsImportsParserPlugin", () => true);
parser.hooks.canRename
.for(createRequireSpecifierTag)
.tap("CommonJsImportsParserPlugin", () => true);
parser.hooks.rename
.for(createRequireSpecifierTag)
.tap("CommonJsImportsParserPlugin", defineUndefined);
parser.hooks.expression
.for(createdRequireIdentifierTag)
.tap("CommonJsImportsParserPlugin", requireAsExpressionHandler);
parser.hooks.call
.for(createdRequireIdentifierTag)
.tap("CommonJsImportsParserPlugin", createRequireHandler(false));
/**
* @param {CallExpressionNode} expr call expression
* @returns {string} context
*/
const parseCreateRequireArguments = expr => {
const args = expr.arguments;
if (args.length !== 1) {
const err = new WebpackError(
"module.createRequire supports only one argument."
);
err.loc = expr.loc;
parser.state.module.addWarning(err);
return;
}
const arg = args[0];
const evaluated = parser.evaluateExpression(arg);
if (!evaluated.isString()) {
const err = new WebpackError(
"module.createRequire failed parsing argument."
);
err.loc = arg.loc;
parser.state.module.addWarning(err);
return;
}
const ctx = evaluated.string.startsWith("file://")
? fileURLToPath(evaluated.string)
: evaluated.string;
// argument always should be a filename
return ctx.slice(0, ctx.lastIndexOf(ctx.startsWith("/") ? "/" : "\\"));
};
parser.hooks.import.tap(
{
name: "CommonJsImportsParserPlugin",
stage: -10
},
(statement, source) => {
if (
source !== moduleName ||
statement.specifiers.length !== 1 ||
statement.specifiers[0].type !== "ImportSpecifier" ||
statement.specifiers[0].imported.type !== "Identifier" ||
statement.specifiers[0].imported.name !== specifierName
)
return;
// clear for 'import { createRequire as x } from "module"'
// if any other specifier was used import module
const clearDep = new ConstDependency(
parser.isAsiPosition(statement.range[0]) ? ";" : "",
statement.range
);
clearDep.loc = statement.loc;
parser.state.module.addPresentationalDependency(clearDep);
parser.unsetAsiPosition(statement.range[1]);
return true;
}
);
parser.hooks.importSpecifier.tap(
{
name: "CommonJsImportsParserPlugin",
stage: -10
},
(statement, source, id, name) => {
if (source !== moduleName || id !== specifierName) return;
parser.tagVariable(name, createRequireSpecifierTag);
return true;
}
);
parser.hooks.preDeclarator.tap(
"CommonJsImportsParserPlugin",
declarator => {
if (
declarator.id.type !== "Identifier" ||
!declarator.init ||
declarator.init.type !== "CallExpression" ||
declarator.init.callee.type !== "Identifier"
)
return;
const variableInfo = parser.getVariableInfo(
declarator.init.callee.name
);
if (
variableInfo &&
variableInfo.tagInfo &&
variableInfo.tagInfo.tag === createRequireSpecifierTag
) {
const context = parseCreateRequireArguments(declarator.init);
if (context === undefined) return;
parser.tagVariable(declarator.id.name, createdRequireIdentifierTag, {
name: declarator.id.name,
context
});
return true;
}
}
);
parser.hooks.memberChainOfCallMemberChain
.for(createRequireSpecifierTag)
.tap(
"CommonJsImportsParserPlugin",
(expr, calleeMembers, callExpr, members) => {
if (
calleeMembers.length !== 0 ||
members.length !== 1 ||
members[0] !== "cache"
)
return;
// createRequire().cache
const context = parseCreateRequireArguments(callExpr);
if (context === undefined) return;
return requireCache(expr);
}
);
parser.hooks.callMemberChainOfCallMemberChain
.for(createRequireSpecifierTag)
.tap(
"CommonJsImportsParserPlugin",
(expr, calleeMembers, innerCallExpression, members) => {
if (
calleeMembers.length !== 0 ||
members.length !== 1 ||
members[0] !== "resolve"
)
return;
// createRequire().resolve()
return processResolve(expr, false);
}
);
parser.hooks.expressionMemberChain
.for(createdRequireIdentifierTag)
.tap("CommonJsImportsParserPlugin", (expr, members) => {
// require.cache
if (members.length === 1 && members[0] === "cache") {
return requireCache(expr);
}
});
parser.hooks.callMemberChain
.for(createdRequireIdentifierTag)
.tap("CommonJsImportsParserPlugin", (expr, members) => {
// require.resolve()
if (members.length === 1 && members[0] === "resolve") {
return processResolve(expr, false);
}
});
parser.hooks.call
.for(createRequireSpecifierTag)
.tap("CommonJsImportsParserPlugin", expr => {
const clearDep = new ConstDependency(
"/* createRequire() */ undefined",
expr.range
);
clearDep.loc = expr.loc;
parser.state.module.addPresentationalDependency(clearDep);
return true;
});
//#endregion
} }
} }
module.exports = CommonJsImportsParserPlugin; module.exports = CommonJsImportsParserPlugin;

View File

@ -10,8 +10,8 @@ const ContextDependency = require("./ContextDependency");
const ContextDependencyTemplateAsRequireCall = require("./ContextDependencyTemplateAsRequireCall"); const ContextDependencyTemplateAsRequireCall = require("./ContextDependencyTemplateAsRequireCall");
class CommonJsRequireContextDependency extends ContextDependency { class CommonJsRequireContextDependency extends ContextDependency {
constructor(options, range, valueRange, inShorthand) { constructor(options, range, valueRange, inShorthand, context) {
super(options); super(options, context);
this.range = range; this.range = range;
this.valueRange = valueRange; this.valueRange = valueRange;

View File

@ -10,9 +10,10 @@ const ModuleDependency = require("./ModuleDependency");
const ModuleDependencyTemplateAsId = require("./ModuleDependencyTemplateAsId"); const ModuleDependencyTemplateAsId = require("./ModuleDependencyTemplateAsId");
class CommonJsRequireDependency extends ModuleDependency { class CommonJsRequireDependency extends ModuleDependency {
constructor(request, range) { constructor(request, range, context) {
super(request); super(request);
this.range = range; this.range = range;
this._context = context;
} }
get type() { get type() {

View File

@ -26,8 +26,9 @@ const regExpToString = r => (r ? r + "" : "");
class ContextDependency extends Dependency { class ContextDependency extends Dependency {
/** /**
* @param {ContextDependencyOptions} options options for the context module * @param {ContextDependencyOptions} options options for the context module
* @param {string=} context request context
*/ */
constructor(options) { constructor(options, context) {
super(); super();
this.options = options; this.options = options;
@ -50,6 +51,14 @@ class ContextDependency extends Dependency {
this.inShorthand = undefined; this.inShorthand = undefined;
// TODO refactor this // TODO refactor this
this.replaces = undefined; this.replaces = undefined;
this._requestContext = context;
}
/**
* @returns {string | undefined} a request context
*/
getContext() {
return this._requestContext;
} }
get category() { get category() {
@ -68,7 +77,9 @@ class ContextDependency extends Dependency {
*/ */
getResourceIdentifier() { getResourceIdentifier() {
return ( return (
`context${this.options.request} ${this.options.recursive} ` + `context${this._requestContext || ""}|ctx request${
this.options.request
} ${this.options.recursive} ` +
`${regExpToString(this.options.regExp)} ${regExpToString( `${regExpToString(this.options.regExp)} ${regExpToString(
this.options.include this.options.include
)} ${regExpToString(this.options.exclude)} ` + )} ${regExpToString(this.options.exclude)} ` +
@ -112,6 +123,7 @@ class ContextDependency extends Dependency {
write(this.critical); write(this.critical);
write(this.hadGlobalOrStickyRegExp); write(this.hadGlobalOrStickyRegExp);
write(this.request); write(this.request);
write(this._requestContext);
write(this.range); write(this.range);
write(this.valueRange); write(this.valueRange);
write(this.prepend); write(this.prepend);
@ -128,6 +140,7 @@ class ContextDependency extends Dependency {
this.critical = read(); this.critical = read();
this.hadGlobalOrStickyRegExp = read(); this.hadGlobalOrStickyRegExp = read();
this.request = read(); this.request = read();
this._requestContext = read();
this.range = read(); this.range = read();
this.valueRange = read(); this.valueRange = read();
this.prepend = read(); this.prepend = read();

View File

@ -39,7 +39,7 @@ const splitContextFromPrefix = prefix => {
/** @typedef {Partial<Omit<ContextDependencyOptions, "resource">>} PartialContextDependencyOptions */ /** @typedef {Partial<Omit<ContextDependencyOptions, "resource">>} PartialContextDependencyOptions */
/** @typedef {{ new(options: ContextDependencyOptions, range: [number, number], valueRange: [number, number]): ContextDependency }} ContextDependencyConstructor */ /** @typedef {{ new(options: ContextDependencyOptions, range: [number, number], valueRange: [number, number], ...args: any[]): ContextDependency }} ContextDependencyConstructor */
/** /**
* @param {ContextDependencyConstructor} Dep the Dependency class * @param {ContextDependencyConstructor} Dep the Dependency class
@ -49,9 +49,19 @@ const splitContextFromPrefix = prefix => {
* @param {Pick<JavascriptParserOptions, `${"expr"|"wrapped"}Context${"Critical"|"Recursive"|"RegExp"}` | "exprContextRequest">} options options for context creation * @param {Pick<JavascriptParserOptions, `${"expr"|"wrapped"}Context${"Critical"|"Recursive"|"RegExp"}` | "exprContextRequest">} options options for context creation
* @param {PartialContextDependencyOptions} contextOptions options for the ContextModule * @param {PartialContextDependencyOptions} contextOptions options for the ContextModule
* @param {JavascriptParser} parser the parser * @param {JavascriptParser} parser the parser
* @param {...any} depArgs depArgs
* @returns {ContextDependency} the created Dependency * @returns {ContextDependency} the created Dependency
*/ */
exports.create = (Dep, range, param, expr, options, contextOptions, parser) => { exports.create = (
Dep,
range,
param,
expr,
options,
contextOptions,
parser,
...depArgs
) => {
if (param.isTemplateString()) { if (param.isTemplateString()) {
let prefixRaw = param.quasis[0].string; let prefixRaw = param.quasis[0].string;
let postfixRaw = let postfixRaw =
@ -97,7 +107,8 @@ exports.create = (Dep, range, param, expr, options, contextOptions, parser) => {
...contextOptions ...contextOptions
}, },
range, range,
valueRange valueRange,
...depArgs
); );
dep.loc = expr.loc; dep.loc = expr.loc;
const replaces = []; const replaces = [];
@ -180,7 +191,8 @@ exports.create = (Dep, range, param, expr, options, contextOptions, parser) => {
...contextOptions ...contextOptions
}, },
range, range,
valueRange valueRange,
...depArgs
); );
dep.loc = expr.loc; dep.loc = expr.loc;
const replaces = []; const replaces = [];
@ -218,7 +230,8 @@ exports.create = (Dep, range, param, expr, options, contextOptions, parser) => {
...contextOptions ...contextOptions
}, },
range, range,
param.range param.range,
...depArgs
); );
dep.loc = expr.loc; dep.loc = expr.loc;
dep.critical = dep.critical =

View File

@ -49,20 +49,6 @@ class ContextElementDependency extends ModuleDependency {
return "context element"; return "context element";
} }
/**
* @returns {string | undefined} a request context
*/
getContext() {
return this._context;
}
/**
* @returns {string | null} an identifier to merge equal requests
*/
getResourceIdentifier() {
return `context${this._context || ""}|${super.getResourceIdentifier()}`;
}
get category() { get category() {
return this._category; return this._category;
} }
@ -86,7 +72,6 @@ class ContextElementDependency extends ModuleDependency {
const { write } = context; const { write } = context;
write(this._typePrefix); write(this._typePrefix);
write(this._category); write(this._category);
write(this._context);
write(this.referencedExports); write(this.referencedExports);
super.serialize(context); super.serialize(context);
} }
@ -95,7 +80,6 @@ class ContextElementDependency extends ModuleDependency {
const { read } = context; const { read } = context;
this._typePrefix = read(); this._typePrefix = read();
this._category = read(); this._category = read();
this._context = read();
this.referencedExports = read(); this.referencedExports = read();
super.deserialize(context); super.deserialize(context);
} }

View File

@ -14,10 +14,14 @@ const ImportDependency = require("./ImportDependency");
const ImportEagerDependency = require("./ImportEagerDependency"); const ImportEagerDependency = require("./ImportEagerDependency");
const ImportWeakDependency = require("./ImportWeakDependency"); const ImportWeakDependency = require("./ImportWeakDependency");
/** @typedef {import("../../declarations/WebpackOptions").JavascriptParserOptions} JavascriptParserOptions */
/** @typedef {import("../ChunkGroup").RawChunkGroupOptions} RawChunkGroupOptions */ /** @typedef {import("../ChunkGroup").RawChunkGroupOptions} RawChunkGroupOptions */
/** @typedef {import("../ContextModule").ContextMode} ContextMode */ /** @typedef {import("../ContextModule").ContextMode} ContextMode */
class ImportParserPlugin { class ImportParserPlugin {
/**
* @param {JavascriptParserOptions} options options
*/
constructor(options) { constructor(options) {
this.options = options; this.options = options;
} }
@ -28,7 +32,7 @@ class ImportParserPlugin {
let chunkName = null; let chunkName = null;
/** @type {ContextMode} */ /** @type {ContextMode} */
let mode = "lazy"; let mode = this.options.dynamicImportMode;
let include = null; let include = null;
let exclude = null; let exclude = null;
/** @type {string[][] | null} */ /** @type {string[][] | null} */
@ -36,6 +40,17 @@ class ImportParserPlugin {
/** @type {RawChunkGroupOptions} */ /** @type {RawChunkGroupOptions} */
const groupOptions = {}; const groupOptions = {};
const { dynamicImportPreload, dynamicImportPrefetch } = this.options;
if (dynamicImportPreload !== undefined && dynamicImportPreload !== false)
groupOptions.preloadOrder =
dynamicImportPreload === true ? 0 : dynamicImportPreload;
if (
dynamicImportPrefetch !== undefined &&
dynamicImportPrefetch !== false
)
groupOptions.prefetchOrder =
dynamicImportPrefetch === true ? 0 : dynamicImportPrefetch;
const { options: importOptions, errors: commentErrors } = const { options: importOptions, errors: commentErrors } =
parser.parseCommentOptions(expr.range); parser.parseCommentOptions(expr.range);
@ -175,16 +190,22 @@ class ImportParserPlugin {
} }
} }
if (param.isString()) { if (
if (mode !== "lazy" && mode !== "eager" && mode !== "weak") { mode !== "lazy" &&
mode !== "lazy-once" &&
mode !== "eager" &&
mode !== "weak"
) {
parser.state.module.addWarning( parser.state.module.addWarning(
new UnsupportedFeatureWarning( new UnsupportedFeatureWarning(
`\`webpackMode\` expected 'lazy', 'eager' or 'weak', but received: ${mode}.`, `\`webpackMode\` expected 'lazy', 'lazy-once', 'eager' or 'weak', but received: ${mode}.`,
expr.loc expr.loc
) )
); );
mode = "lazy";
} }
if (param.isString()) {
if (mode === "eager") { if (mode === "eager") {
const dep = new ImportEagerDependency( const dep = new ImportEagerDependency(
param.string, param.string,
@ -215,21 +236,6 @@ class ImportParserPlugin {
} }
return true; return true;
} else { } else {
if (
mode !== "lazy" &&
mode !== "lazy-once" &&
mode !== "eager" &&
mode !== "weak"
) {
parser.state.module.addWarning(
new UnsupportedFeatureWarning(
`\`webpackMode\` expected 'lazy', 'lazy-once', 'eager' or 'weak', but received: ${mode}.`,
expr.loc
)
);
mode = "lazy";
}
if (mode === "weak") { if (mode === "weak") {
mode = "async-weak"; mode = "async-weak";
} }

View File

@ -13,18 +13,21 @@ const NullDependency = require("./NullDependency");
/** @typedef {import("../Dependency").ExportsSpec} ExportsSpec */ /** @typedef {import("../Dependency").ExportsSpec} ExportsSpec */
/** @typedef {import("../Dependency").UpdateHashContext} UpdateHashContext */ /** @typedef {import("../Dependency").UpdateHashContext} UpdateHashContext */
/** @typedef {import("../ModuleGraph")} ModuleGraph */ /** @typedef {import("../ModuleGraph")} ModuleGraph */
/** @typedef {import("../json/JsonData")} JsonData */
/** @typedef {import("../util/Hash")} Hash */ /** @typedef {import("../util/Hash")} Hash */
const getExportsFromData = data => { const getExportsFromData = data => {
if (data && typeof data === "object") { if (data && typeof data === "object") {
if (Array.isArray(data)) { if (Array.isArray(data)) {
return data.map((item, idx) => { return data.length < 100
? data.map((item, idx) => {
return { return {
name: `${idx}`, name: `${idx}`,
canMangle: true, canMangle: true,
exports: getExportsFromData(item) exports: getExportsFromData(item)
}; };
}); })
: undefined;
} else { } else {
const exports = []; const exports = [];
for (const key of Object.keys(data)) { for (const key of Object.keys(data)) {
@ -42,12 +45,11 @@ const getExportsFromData = data => {
class JsonExportsDependency extends NullDependency { class JsonExportsDependency extends NullDependency {
/** /**
* @param {(string | ExportSpec)[]} exports json exports * @param {JsonData=} data json data
*/ */
constructor(exports) { constructor(data) {
super(); super();
this.exports = exports; this.data = data;
this._hashUpdate = undefined;
} }
get type() { get type() {
@ -61,7 +63,7 @@ class JsonExportsDependency extends NullDependency {
*/ */
getExports(moduleGraph) { getExports(moduleGraph) {
return { return {
exports: this.exports, exports: getExportsFromData(this.data && this.data.get()),
dependencies: undefined dependencies: undefined
}; };
} }
@ -73,23 +75,18 @@ class JsonExportsDependency extends NullDependency {
* @returns {void} * @returns {void}
*/ */
updateHash(hash, context) { updateHash(hash, context) {
if (this._hashUpdate === undefined) { this.data.updateHash(hash);
this._hashUpdate = this.exports
? JSON.stringify(this.exports)
: "undefined";
}
hash.update(this._hashUpdate);
} }
serialize(context) { serialize(context) {
const { write } = context; const { write } = context;
write(this.exports); write(this.data);
super.serialize(context); super.serialize(context);
} }
deserialize(context) { deserialize(context) {
const { read } = context; const { read } = context;
this.exports = read(); this.data = read();
super.deserialize(context); super.deserialize(context);
} }
} }
@ -100,4 +97,3 @@ makeSerializable(
); );
module.exports = JsonExportsDependency; module.exports = JsonExportsDependency;
module.exports.getExportsFromData = getExportsFromData;

View File

@ -26,13 +26,21 @@ class ModuleDependency extends Dependency {
// assertions must be serialized by subclasses that use it // assertions must be serialized by subclasses that use it
/** @type {Record<string, any> | undefined} */ /** @type {Record<string, any> | undefined} */
this.assertions = undefined; this.assertions = undefined;
this._context = undefined;
}
/**
* @returns {string | undefined} a request context
*/
getContext() {
return this._context;
} }
/** /**
* @returns {string | null} an identifier to merge equal requests * @returns {string | null} an identifier to merge equal requests
*/ */
getResourceIdentifier() { getResourceIdentifier() {
let str = `module${this.request}`; let str = `context${this._context || ""}|module${this.request}`;
if (this.assertions !== undefined) { if (this.assertions !== undefined) {
str += JSON.stringify(this.assertions); str += JSON.stringify(this.assertions);
} }
@ -63,6 +71,7 @@ class ModuleDependency extends Dependency {
const { write } = context; const { write } = context;
write(this.request); write(this.request);
write(this.userRequest); write(this.userRequest);
write(this._context);
write(this.range); write(this.range);
super.serialize(context); super.serialize(context);
} }
@ -71,6 +80,7 @@ class ModuleDependency extends Dependency {
const { read } = context; const { read } = context;
this.request = read(); this.request = read();
this.userRequest = read(); this.userRequest = read();
this._context = read();
this.range = read(); this.range = read();
super.deserialize(context); super.deserialize(context);
} }

View File

@ -5,19 +5,21 @@
"use strict"; "use strict";
const Dependency = require("../Dependency");
const InitFragment = require("../InitFragment"); const InitFragment = require("../InitFragment");
const makeSerializable = require("../util/makeSerializable"); const makeSerializable = require("../util/makeSerializable");
const ModuleDependency = require("./ModuleDependency"); const ModuleDependency = require("./ModuleDependency");
/** @typedef {import("webpack-sources").ReplaceSource} ReplaceSource */ /** @typedef {import("webpack-sources").ReplaceSource} ReplaceSource */
/** @typedef {import("../ChunkGraph")} ChunkGraph */ /** @typedef {import("../ChunkGraph")} ChunkGraph */
/** @typedef {import("../Dependency")} Dependency */ /** @typedef {import("../Dependency").ReferencedExport} ReferencedExport */
/** @typedef {import("../Dependency").UpdateHashContext} UpdateHashContext */ /** @typedef {import("../Dependency").UpdateHashContext} UpdateHashContext */
/** @typedef {import("../DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */ /** @typedef {import("../DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */
/** @typedef {import("../DependencyTemplates")} DependencyTemplates */ /** @typedef {import("../DependencyTemplates")} DependencyTemplates */
/** @typedef {import("../ModuleGraph")} ModuleGraph */ /** @typedef {import("../ModuleGraph")} ModuleGraph */
/** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */ /** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */
/** @typedef {import("../util/Hash")} Hash */ /** @typedef {import("../util/Hash")} Hash */
/** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */
/** /**
* @param {string[]|null} path the property path array * @param {string[]|null} path the property path array
@ -29,10 +31,16 @@ const pathToString = path =>
: ""; : "";
class ProvidedDependency extends ModuleDependency { class ProvidedDependency extends ModuleDependency {
constructor(request, identifier, path, range) { /**
* @param {string} request request
* @param {string} identifier identifier
* @param {string[]} ids ids
* @param {[number, number]} range range
*/
constructor(request, identifier, ids, range) {
super(request); super(request);
this.identifier = identifier; this.identifier = identifier;
this.path = path; this.ids = ids;
this.range = range; this.range = range;
this._hashUpdate = undefined; this._hashUpdate = undefined;
} }
@ -45,6 +53,18 @@ class ProvidedDependency extends ModuleDependency {
return "esm"; return "esm";
} }
/**
* Returns list of exports referenced by this dependency
* @param {ModuleGraph} moduleGraph module graph
* @param {RuntimeSpec} runtime the runtime for which the module is analysed
* @returns {(string[] | ReferencedExport)[]} referenced exports
*/
getReferencedExports(moduleGraph, runtime) {
let ids = this.ids;
if (ids.length === 0) return Dependency.EXPORTS_OBJECT_REFERENCED;
return [ids];
}
/** /**
* Update the hash * Update the hash
* @param {Hash} hash hash to be updated * @param {Hash} hash hash to be updated
@ -53,8 +73,7 @@ class ProvidedDependency extends ModuleDependency {
*/ */
updateHash(hash, context) { updateHash(hash, context) {
if (this._hashUpdate === undefined) { if (this._hashUpdate === undefined) {
this._hashUpdate = this._hashUpdate = this.identifier + (this.ids ? this.ids.join(",") : "");
this.identifier + (this.path ? this.path.join(",") : "null");
} }
hash.update(this._hashUpdate); hash.update(this._hashUpdate);
} }
@ -62,14 +81,14 @@ class ProvidedDependency extends ModuleDependency {
serialize(context) { serialize(context) {
const { write } = context; const { write } = context;
write(this.identifier); write(this.identifier);
write(this.path); write(this.ids);
super.serialize(context); super.serialize(context);
} }
deserialize(context) { deserialize(context) {
const { read } = context; const { read } = context;
this.identifier = read(); this.identifier = read();
this.path = read(); this.ids = read();
super.deserialize(context); super.deserialize(context);
} }
} }
@ -90,6 +109,7 @@ class ProvidedDependencyTemplate extends ModuleDependency.Template {
dependency, dependency,
source, source,
{ {
runtime,
runtimeTemplate, runtimeTemplate,
moduleGraph, moduleGraph,
chunkGraph, chunkGraph,
@ -98,6 +118,9 @@ class ProvidedDependencyTemplate extends ModuleDependency.Template {
} }
) { ) {
const dep = /** @type {ProvidedDependency} */ (dependency); const dep = /** @type {ProvidedDependency} */ (dependency);
const connection = moduleGraph.getConnection(dep);
const exportsInfo = moduleGraph.getExportsInfo(connection.module);
const usedName = exportsInfo.getUsedName(dep.ids, runtime);
initFragments.push( initFragments.push(
new InitFragment( new InitFragment(
`/* provided dependency */ var ${ `/* provided dependency */ var ${
@ -107,7 +130,7 @@ class ProvidedDependencyTemplate extends ModuleDependency.Template {
chunkGraph, chunkGraph,
request: dep.request, request: dep.request,
runtimeRequirements runtimeRequirements
})}${pathToString(dep.path)};\n`, })}${pathToString(/** @type {string[]} */ (usedName))};\n`,
InitFragment.STAGE_PROVIDES, InitFragment.STAGE_PROVIDES,
1, 1,
`provided ${dep.identifier}` `provided ${dep.identifier}`

View File

@ -10,8 +10,8 @@ const ContextDependency = require("./ContextDependency");
const ContextDependencyTemplateAsId = require("./ContextDependencyTemplateAsId"); const ContextDependencyTemplateAsId = require("./ContextDependencyTemplateAsId");
class RequireResolveContextDependency extends ContextDependency { class RequireResolveContextDependency extends ContextDependency {
constructor(options, range, valueRange) { constructor(options, range, valueRange, context) {
super(options); super(options, context);
this.range = range; this.range = range;
this.valueRange = valueRange; this.valueRange = valueRange;

View File

@ -15,10 +15,11 @@ const ModuleDependencyAsId = require("./ModuleDependencyTemplateAsId");
/** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */ /** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */
class RequireResolveDependency extends ModuleDependency { class RequireResolveDependency extends ModuleDependency {
constructor(request, range) { constructor(request, range, context) {
super(request); super(request);
this.range = range; this.range = range;
this._context = context;
} }
get type() { get type() {

View File

@ -5,12 +5,15 @@
"use strict"; "use strict";
const { pathToFileURL } = require("url");
const BasicEvaluatedExpression = require("../javascript/BasicEvaluatedExpression");
const { approve } = require("../javascript/JavascriptParserHelpers"); const { approve } = require("../javascript/JavascriptParserHelpers");
const InnerGraph = require("../optimize/InnerGraph"); const InnerGraph = require("../optimize/InnerGraph");
const URLDependency = require("./URLDependency"); const URLDependency = require("./URLDependency");
/** @typedef {import("estree").NewExpression} NewExpressionNode */ /** @typedef {import("estree").NewExpression} NewExpressionNode */
/** @typedef {import("../Compiler")} Compiler */ /** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../NormalModule")} NormalModule */
/** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */ /** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */
class URLPlugin { class URLPlugin {
@ -27,6 +30,13 @@ class URLPlugin {
new URLDependency.Template() new URLDependency.Template()
); );
/**
* @param {NormalModule} module module
* @returns {URL} file url
*/
const getUrl = module => {
return pathToFileURL(module.resource);
};
/** /**
* @param {JavascriptParser} parser parser * @param {JavascriptParser} parser parser
* @param {object} parserOptions options * @param {object} parserOptions options
@ -67,6 +77,17 @@ class URLPlugin {
}; };
parser.hooks.canRename.for("URL").tap("URLPlugin", approve); parser.hooks.canRename.for("URL").tap("URLPlugin", approve);
parser.hooks.evaluateNewExpression
.for("URL")
.tap("URLPlugin", expr => {
const request = getUrlRequest(expr);
if (!request) return;
const url = new URL(request, getUrl(parser.state.module));
return new BasicEvaluatedExpression()
.setString(url.toString())
.setRange(expr.range);
});
parser.hooks.new.for("URL").tap("URLPlugin", _expr => { parser.hooks.new.for("URL").tap("URLPlugin", _expr => {
const expr = /** @type {NewExpressionNode} */ (_expr); const expr = /** @type {NewExpressionNode} */ (_expr);

View File

@ -28,6 +28,7 @@ const memoize = require("./util/memoize");
/** @typedef {import("./Compilation").Asset} Asset */ /** @typedef {import("./Compilation").Asset} Asset */
/** @typedef {import("./Compilation").AssetInfo} AssetInfo */ /** @typedef {import("./Compilation").AssetInfo} AssetInfo */
/** @typedef {import("./Compilation").EntryOptions} EntryOptions */ /** @typedef {import("./Compilation").EntryOptions} EntryOptions */
/** @typedef {import("./Compilation").PathData} PathData */
/** @typedef {import("./Compiler").AssetEmittedInfo} AssetEmittedInfo */ /** @typedef {import("./Compiler").AssetEmittedInfo} AssetEmittedInfo */
/** @typedef {import("./MultiStats")} MultiStats */ /** @typedef {import("./MultiStats")} MultiStats */
/** @typedef {import("./Parser").ParserState} ParserState */ /** @typedef {import("./Parser").ParserState} ParserState */
@ -341,6 +342,9 @@ module.exports = mergeExports(fn, {
get ModuleDependency() { get ModuleDependency() {
return require("./dependencies/ModuleDependency"); return require("./dependencies/ModuleDependency");
}, },
get HarmonyImportDependency() {
return require("./dependencies/HarmonyImportDependency");
},
get ConstDependency() { get ConstDependency() {
return require("./dependencies/ConstDependency"); return require("./dependencies/ConstDependency");
}, },

View File

@ -165,6 +165,14 @@ class JavascriptParser extends Parser {
evaluateDefinedIdentifier: new HookMap( evaluateDefinedIdentifier: new HookMap(
() => new SyncBailHook(["expression"]) () => new SyncBailHook(["expression"])
), ),
/** @type {HookMap<SyncBailHook<[NewExpressionNode], BasicEvaluatedExpression | undefined | null>>} */
evaluateNewExpression: new HookMap(
() => new SyncBailHook(["expression"])
),
/** @type {HookMap<SyncBailHook<[CallExpressionNode], BasicEvaluatedExpression | undefined | null>>} */
evaluateCallExpression: new HookMap(
() => new SyncBailHook(["expression"])
),
/** @type {HookMap<SyncBailHook<[CallExpressionNode, BasicEvaluatedExpression | undefined], BasicEvaluatedExpression | undefined | null>>} */ /** @type {HookMap<SyncBailHook<[CallExpressionNode, BasicEvaluatedExpression | undefined], BasicEvaluatedExpression | undefined | null>>} */
evaluateCallExpressionMember: new HookMap( evaluateCallExpressionMember: new HookMap(
() => new SyncBailHook(["expression", "param"]) () => new SyncBailHook(["expression", "param"])
@ -361,9 +369,14 @@ class JavascriptParser extends Parser {
this.hooks.evaluate.for("NewExpression").tap("JavascriptParser", _expr => { this.hooks.evaluate.for("NewExpression").tap("JavascriptParser", _expr => {
const expr = /** @type {NewExpressionNode} */ (_expr); const expr = /** @type {NewExpressionNode} */ (_expr);
const callee = expr.callee; const callee = expr.callee;
if ( if (callee.type !== "Identifier") return;
callee.type !== "Identifier" || if (callee.name !== "RegExp") {
callee.name !== "RegExp" || return this.callHooksForName(
this.hooks.evaluateNewExpression,
callee.name,
expr
);
} else if (
expr.arguments.length > 2 || expr.arguments.length > 2 ||
this.getVariableInfo("RegExp") !== "RegExp" this.getVariableInfo("RegExp") !== "RegExp"
) )
@ -1036,13 +1049,10 @@ class JavascriptParser extends Parser {
this.hooks.evaluate.for("CallExpression").tap("JavascriptParser", _expr => { this.hooks.evaluate.for("CallExpression").tap("JavascriptParser", _expr => {
const expr = /** @type {CallExpressionNode} */ (_expr); const expr = /** @type {CallExpressionNode} */ (_expr);
if ( if (
expr.callee.type !== "MemberExpression" || expr.callee.type === "MemberExpression" &&
expr.callee.property.type !== expr.callee.property.type ===
(expr.callee.computed ? "Literal" : "Identifier") (expr.callee.computed ? "Literal" : "Identifier")
) { ) {
return;
}
// type Super also possible here // type Super also possible here
const param = this.evaluateExpression( const param = this.evaluateExpression(
/** @type {ExpressionNode} */ (expr.callee.object) /** @type {ExpressionNode} */ (expr.callee.object)
@ -1055,6 +1065,13 @@ class JavascriptParser extends Parser {
if (hook !== undefined) { if (hook !== undefined) {
return hook.call(expr, param); return hook.call(expr, param);
} }
} else if (expr.callee.type === "Identifier") {
return this.callHooksForName(
this.hooks.evaluateCallExpression,
expr.callee.name,
expr
);
}
}); });
this.hooks.evaluateCallExpressionMember this.hooks.evaluateCallExpressionMember
.for("indexOf") .for("indexOf")
@ -1430,6 +1447,11 @@ class JavascriptParser extends Parser {
this.walkExpression(classElement.value); this.walkExpression(classElement.value);
this.scope.topLevelScope = wasTopLevel; this.scope.topLevelScope = wasTopLevel;
} }
} else if (classElement.type === "StaticBlock") {
const wasTopLevel = this.scope.topLevelScope;
this.scope.topLevelScope = false;
this.walkBlockStatement(classElement);
this.scope.topLevelScope = wasTopLevel;
} }
} }
} }
@ -1886,7 +1908,7 @@ class JavascriptParser extends Parser {
!this.hooks.importSpecifier.call( !this.hooks.importSpecifier.call(
statement, statement,
source, source,
specifier.imported.name, specifier.imported.name || specifier.imported.value,
name name
) )
) { ) {
@ -1956,7 +1978,7 @@ class JavascriptParser extends Parser {
const specifier = statement.specifiers[specifierIndex]; const specifier = statement.specifiers[specifierIndex];
switch (specifier.type) { switch (specifier.type) {
case "ExportSpecifier": { case "ExportSpecifier": {
const name = specifier.exported.name; const name = specifier.exported.name || specifier.exported.value;
if (source) { if (source) {
this.hooks.exportImportSpecifier.call( this.hooks.exportImportSpecifier.call(
statement, statement,
@ -3603,6 +3625,10 @@ class JavascriptParser extends Parser {
} }
} }
evaluatedVariable(tagInfo) {
return new VariableInfo(this.scope, undefined, tagInfo);
}
parseCommentOptions(range) { parseCommentOptions(range) {
const comments = this.getComments(range); const comments = this.getComments(range);
if (comments.length === 0) { if (comments.length === 0) {

View File

@ -24,6 +24,14 @@ class JsonData {
} }
return this._data; return this._data;
} }
updateHash(hash) {
if (this._buffer === undefined && this._data !== undefined) {
this._buffer = Buffer.from(JSON.stringify(this._data));
}
if (this._buffer) return hash.update(this._buffer);
}
} }
register(JsonData, "webpack/lib/json/JsonData", null, { register(JsonData, "webpack/lib/json/JsonData", null, {

View File

@ -41,15 +41,13 @@ class JsonParser extends Parser {
typeof source === "object" typeof source === "object"
? source ? source
: parseFn(source[0] === "\ufeff" ? source.slice(1) : source); : parseFn(source[0] === "\ufeff" ? source.slice(1) : source);
const jsonData = new JsonData(data);
state.module.buildInfo.jsonData = new JsonData(data); state.module.buildInfo.jsonData = jsonData;
state.module.buildInfo.strict = true; state.module.buildInfo.strict = true;
state.module.buildMeta.exportsType = "default"; state.module.buildMeta.exportsType = "default";
state.module.buildMeta.defaultObject = state.module.buildMeta.defaultObject =
typeof data === "object" ? "redirect-warn" : false; typeof data === "object" ? "redirect-warn" : false;
state.module.addDependency( state.module.addDependency(new JsonExportsDependency(jsonData));
new JsonExportsDependency(JsonExportsDependency.getExportsFromData(data))
);
return state; return state;
} }
} }

View File

@ -21,7 +21,7 @@ const HarmonyImportDependency = require("../dependencies/HarmonyImportDependency
const JavascriptParser = require("../javascript/JavascriptParser"); const JavascriptParser = require("../javascript/JavascriptParser");
const { equals } = require("../util/ArrayHelpers"); const { equals } = require("../util/ArrayHelpers");
const LazySet = require("../util/LazySet"); const LazySet = require("../util/LazySet");
const { concatComparators, keepOriginalOrder } = require("../util/comparators"); const { concatComparators } = require("../util/comparators");
const createHash = require("../util/createHash"); const createHash = require("../util/createHash");
const { makePathsRelative } = require("../util/identifier"); const { makePathsRelative } = require("../util/identifier");
const makeSerializable = require("../util/makeSerializable"); const makeSerializable = require("../util/makeSerializable");
@ -185,23 +185,25 @@ const RESERVED_NAMES = new Set(
.split(",") .split(",")
); );
const bySourceOrder = (a, b) => { const createComparator = (property, comparator) => (a, b) =>
const aOrder = a.sourceOrder; comparator(a[property], b[property]);
const bOrder = b.sourceOrder; const compareNumbers = (a, b) => {
if (isNaN(aOrder)) { if (isNaN(a)) {
if (!isNaN(bOrder)) { if (!isNaN(b)) {
return 1; return 1;
} }
} else { } else {
if (isNaN(bOrder)) { if (isNaN(b)) {
return -1; return -1;
} }
if (aOrder !== bOrder) { if (a !== b) {
return aOrder < bOrder ? -1 : 1; return a < b ? -1 : 1;
} }
} }
return 0; return 0;
}; };
const bySourceOrder = createComparator("sourceOrder", compareNumbers);
const byRangeStart = createComparator("rangeStart", compareNumbers);
const joinIterableWithComma = iterable => { const joinIterableWithComma = iterable => {
// This is more performant than Array.from().join(", ") // This is more performant than Array.from().join(", ")
@ -885,6 +887,9 @@ class ConcatenatedModule extends Module {
for (const c of moduleGraph.getOutgoingConnections(this)) for (const c of moduleGraph.getOutgoingConnections(this))
connections.push(c); connections.push(c);
} }
/**
* @type {Array<{ connection: ModuleGraphConnection, sourceOrder: number, rangeStart: number }>}
*/
const references = connections const references = connections
.filter(connection => { .filter(connection => {
if (!(connection.dependency instanceof HarmonyImportDependency)) if (!(connection.dependency instanceof HarmonyImportDependency))
@ -896,15 +901,33 @@ class ConcatenatedModule extends Module {
connection.isTargetActive(runtime) connection.isTargetActive(runtime)
); );
}) })
.map(connection => ({ .map(connection => {
connection, const dep = /** @type {HarmonyImportDependency} */ (
sourceOrder: /** @type {HarmonyImportDependency} */ (
connection.dependency connection.dependency
).sourceOrder
}));
references.sort(
concatComparators(bySourceOrder, keepOriginalOrder(references))
); );
return {
connection,
sourceOrder: dep.sourceOrder,
rangeStart: dep.range && dep.range[0]
};
});
/**
* bySourceOrder
* @example
* import a from "a"; // sourceOrder=1
* import b from "b"; // sourceOrder=2
*
* byRangeStart
* @example
* import {a, b} from "a"; // sourceOrder=1
* a.a(); // first range
* b.b(); // second range
*
* If there is no reexport, we have the same source.
* If there is reexport, but module has side effects, this will lead to reexport module only.
* If there is side-effects-free reexport, we can get simple deterministic result with range start comparison.
*/
references.sort(concatComparators(bySourceOrder, byRangeStart));
/** @type {Map<Module, { connection: ModuleGraphConnection, runtimeCondition: RuntimeSpec | true }>} */ /** @type {Map<Module, { connection: ModuleGraphConnection, runtimeCondition: RuntimeSpec | true }>} */
const referencesMap = new Map(); const referencesMap = new Map();
for (const { connection } of references) { for (const { connection } of references) {

View File

@ -20,12 +20,13 @@ class AsyncModuleRuntimeModule extends HelperRuntimeModule {
const { runtimeTemplate } = this.compilation; const { runtimeTemplate } = this.compilation;
const fn = RuntimeGlobals.asyncModule; const fn = RuntimeGlobals.asyncModule;
return Template.asString([ return Template.asString([
'var webpackThen = typeof Symbol === "function" ? Symbol("webpack then") : "__webpack_then__";', 'var webpackQueues = typeof Symbol === "function" ? Symbol("webpack queues") : "__webpack_queues__";',
'var webpackExports = typeof Symbol === "function" ? Symbol("webpack exports") : "__webpack_exports__";', 'var webpackExports = typeof Symbol === "function" ? Symbol("webpack exports") : "__webpack_exports__";',
'var webpackError = typeof Symbol === "function" ? Symbol("webpack error") : "__webpack_error__";', 'var webpackError = typeof Symbol === "function" ? Symbol("webpack error") : "__webpack_error__";',
`var completeQueue = ${runtimeTemplate.basicFunction("queue", [ `var resolveQueue = ${runtimeTemplate.basicFunction("queue", [
"if(queue) {", "if(queue && !queue.d) {",
Template.indent([ Template.indent([
"queue.d = 1;",
`queue.forEach(${runtimeTemplate.expressionFunction( `queue.forEach(${runtimeTemplate.expressionFunction(
"fn.r--", "fn.r--",
"fn" "fn"
@ -37,35 +38,26 @@ class AsyncModuleRuntimeModule extends HelperRuntimeModule {
]), ]),
"}" "}"
])}`, ])}`,
`var completeFunction = ${runtimeTemplate.expressionFunction(
"!--fn.r && fn()",
"fn"
)};`,
`var queueFunction = ${runtimeTemplate.expressionFunction(
"queue ? queue.push(fn) : completeFunction(fn)",
"queue, fn"
)};`,
`var wrapDeps = ${runtimeTemplate.returningFunction( `var wrapDeps = ${runtimeTemplate.returningFunction(
`deps.map(${runtimeTemplate.basicFunction("dep", [ `deps.map(${runtimeTemplate.basicFunction("dep", [
'if(dep !== null && typeof dep === "object") {', 'if(dep !== null && typeof dep === "object") {',
Template.indent([ Template.indent([
"if(dep[webpackThen]) return dep;", "if(dep[webpackQueues]) return dep;",
"if(dep.then) {", "if(dep.then) {",
Template.indent([ Template.indent([
"var queue = [];", "var queue = [];",
"queue.d = 0;",
`dep.then(${runtimeTemplate.basicFunction("r", [ `dep.then(${runtimeTemplate.basicFunction("r", [
"obj[webpackExports] = r;", "obj[webpackExports] = r;",
"completeQueue(queue);", "resolveQueue(queue);"
"queue = 0;"
])}, ${runtimeTemplate.basicFunction("e", [ ])}, ${runtimeTemplate.basicFunction("e", [
"obj[webpackError] = e;", "obj[webpackError] = e;",
"completeQueue(queue);", "resolveQueue(queue);"
"queue = 0;"
])});`, ])});`,
"var obj = {};", "var obj = {};",
`obj[webpackThen] = ${runtimeTemplate.expressionFunction( `obj[webpackQueues] = ${runtimeTemplate.expressionFunction(
"queueFunction(queue, fn), dep['catch'](reject)", `fn(queue)`,
"fn, reject" "fn"
)};`, )};`,
"return obj;" "return obj;"
]), ]),
@ -73,54 +65,28 @@ class AsyncModuleRuntimeModule extends HelperRuntimeModule {
]), ]),
"}", "}",
"var ret = {};", "var ret = {};",
`ret[webpackThen] = ${runtimeTemplate.expressionFunction( `ret[webpackQueues] = ${runtimeTemplate.emptyFunction()};`,
"completeFunction(fn)",
"fn"
)};`,
"ret[webpackExports] = dep;", "ret[webpackExports] = dep;",
"return ret;" "return ret;"
])})`, ])})`,
"deps" "deps"
)};`, )};`,
`${fn} = ${runtimeTemplate.basicFunction("module, body, hasAwait", [ `${fn} = ${runtimeTemplate.basicFunction("module, body, hasAwait", [
"var queue = hasAwait && [];", "var queue;",
"hasAwait && ((queue = []).d = 1);",
"var depQueues = new Set();",
"var exports = module.exports;", "var exports = module.exports;",
"var currentDeps;", "var currentDeps;",
"var outerResolve;", "var outerResolve;",
"var reject;", "var reject;",
"var isEvaluating = true;",
"var nested = false;",
`var whenAll = ${runtimeTemplate.basicFunction(
"deps, onResolve, onReject",
[
"if (nested) return;",
"nested = true;",
"onResolve.r += deps.length;",
`deps.map(${runtimeTemplate.expressionFunction(
"dep[webpackThen](onResolve, onReject)",
"dep, i"
)});`,
"nested = false;"
]
)};`,
`var promise = new Promise(${runtimeTemplate.basicFunction( `var promise = new Promise(${runtimeTemplate.basicFunction(
"resolve, rej", "resolve, rej",
[ ["reject = rej;", "outerResolve = resolve;"]
"reject = rej;",
`outerResolve = ${runtimeTemplate.expressionFunction(
"resolve(exports), completeQueue(queue), queue = 0"
)};`
]
)});`, )});`,
"promise[webpackExports] = exports;", "promise[webpackExports] = exports;",
`promise[webpackThen] = ${runtimeTemplate.basicFunction( `promise[webpackQueues] = ${runtimeTemplate.expressionFunction(
"fn, rejectFn", `queue && fn(queue), depQueues.forEach(fn), promise["catch"](${runtimeTemplate.emptyFunction()})`,
[ "fn"
"if (isEvaluating) { return completeFunction(fn); }",
"if (currentDeps) whenAll(currentDeps, fn, rejectFn);",
"queueFunction(queue, fn);",
"promise['catch'](rejectFn);"
]
)};`, )};`,
"module.exports = promise;", "module.exports = promise;",
`body(${runtimeTemplate.basicFunction("deps", [ `body(${runtimeTemplate.basicFunction("deps", [
@ -133,21 +99,29 @@ class AsyncModuleRuntimeModule extends HelperRuntimeModule {
])})` ])})`
)}`, )}`,
`var promise = new Promise(${runtimeTemplate.basicFunction( `var promise = new Promise(${runtimeTemplate.basicFunction(
"resolve, reject", "resolve",
[ [
`fn = ${runtimeTemplate.expressionFunction( `fn = ${runtimeTemplate.expressionFunction(
"resolve(getResult)" "resolve(getResult)",
""
)};`, )};`,
"fn.r = 0;", "fn.r = 0;",
"whenAll(currentDeps, fn, reject);" `var fnQueue = ${runtimeTemplate.expressionFunction(
"q !== queue && !depQueues.has(q) && (depQueues.add(q), q && !q.d && (fn.r++, q.push(fn)))",
"q"
)};`,
`currentDeps.map(${runtimeTemplate.expressionFunction(
"dep[webpackQueues](fnQueue)",
"dep"
)});`
] ]
)});`, )});`,
"return fn.r ? promise : getResult();" "return fn.r ? promise : getResult();"
])}, ${runtimeTemplate.expressionFunction( ])}, ${runtimeTemplate.expressionFunction(
"err && reject(promise[webpackError] = err), outerResolve()", "(err ? reject(promise[webpackError] = err) : outerResolve(exports)), resolveQueue(queue)",
"err" "err"
)});`, )});`,
"isEvaluating = false;" "queue && (queue.d = 0);"
])};` ])};`
]); ]);
} }

View File

@ -87,7 +87,9 @@ class LoadScriptRuntimeModule extends HelperRuntimeModule {
: "url" : "url"
};`, };`,
crossOriginLoading crossOriginLoading
? Template.asString([ ? crossOriginLoading === "use-credentials"
? 'script.crossOrigin = "use-credentials";'
: Template.asString([
"if (script.src.indexOf(window.location.origin + '/') !== 0) {", "if (script.src.indexOf(window.location.origin + '/') !== 0) {",
Template.indent( Template.indent(
`script.crossOrigin = ${JSON.stringify(crossOriginLoading)};` `script.crossOrigin = ${JSON.stringify(crossOriginLoading)};`

View File

@ -0,0 +1,24 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Ivan Kopeykin @vankop
*/
"use strict";
const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");
class NonceRuntimeModule extends RuntimeModule {
constructor() {
super("nonce", RuntimeModule.STAGE_ATTACH);
}
/**
* @returns {string} runtime code
*/
generate() {
return `${RuntimeGlobals.scriptNonce} = undefined;`;
}
}
module.exports = NonceRuntimeModule;

View File

@ -129,8 +129,7 @@ class ProvideSharedPlugin {
details = details =
"No description file (usually package.json) found. Add description file with name and version, or manually specify version in shared config."; "No description file (usually package.json) found. Add description file with name and version, or manually specify version in shared config.";
} else if (!descriptionFileData.version) { } else if (!descriptionFileData.version) {
details = details = `No version in description file (usually package.json). Add version to description file ${resourceResolveData.descriptionFilePath}, or manually specify version in shared config.`;
"No version in description file (usually package.json). Add version to description file, or manually specify version in shared config.";
} else { } else {
version = descriptionFileData.version; version = descriptionFileData.version;
} }

View File

@ -263,7 +263,9 @@ class JsonpChunkLoadingRuntimeModule extends RuntimeModule {
'link.as = "script";', 'link.as = "script";',
`link.href = ${RuntimeGlobals.publicPath} + ${RuntimeGlobals.getChunkScriptFilename}(chunkId);`, `link.href = ${RuntimeGlobals.publicPath} + ${RuntimeGlobals.getChunkScriptFilename}(chunkId);`,
crossOriginLoading crossOriginLoading
? Template.asString([ ? crossOriginLoading === "use-credentials"
? 'link.crossOrigin = "use-credentials";'
: Template.asString([
"if (link.href.indexOf(window.location.origin + '/') !== 0) {", "if (link.href.indexOf(window.location.origin + '/') !== 0) {",
Template.indent( Template.indent(
`link.crossOrigin = ${JSON.stringify( `link.crossOrigin = ${JSON.stringify(

View File

@ -1,6 +1,6 @@
{ {
"name": "webpack", "name": "webpack",
"version": "5.72.0", "version": "5.74.0",
"author": "Tobias Koppers @sokra", "author": "Tobias Koppers @sokra",
"description": "Packs CommonJs/AMD modules for the browser. Allows to split your codebase into multiple bundles, which can be loaded on demand. Support loaders to preprocess files, i.e. json, jsx, es7, css, less, ... and your custom stuff.", "description": "Packs CommonJs/AMD modules for the browser. Allows to split your codebase into multiple bundles, which can be loaded on demand. Support loaders to preprocess files, i.e. json, jsx, es7, css, less, ... and your custom stuff.",
"license": "MIT", "license": "MIT",
@ -10,11 +10,11 @@
"@webassemblyjs/ast": "1.11.1", "@webassemblyjs/ast": "1.11.1",
"@webassemblyjs/wasm-edit": "1.11.1", "@webassemblyjs/wasm-edit": "1.11.1",
"@webassemblyjs/wasm-parser": "1.11.1", "@webassemblyjs/wasm-parser": "1.11.1",
"acorn": "^8.4.1", "acorn": "^8.7.1",
"acorn-import-assertions": "^1.7.6", "acorn-import-assertions": "^1.7.6",
"browserslist": "^4.14.5", "browserslist": "^4.14.5",
"chrome-trace-event": "^1.0.2", "chrome-trace-event": "^1.0.2",
"enhanced-resolve": "^5.9.3", "enhanced-resolve": "^5.10.0",
"es-module-lexer": "^0.9.0", "es-module-lexer": "^0.9.0",
"eslint-scope": "5.1.1", "eslint-scope": "5.1.1",
"events": "^3.2.0", "events": "^3.2.0",
@ -27,7 +27,7 @@
"schema-utils": "^3.1.0", "schema-utils": "^3.1.0",
"tapable": "^2.1.1", "tapable": "^2.1.1",
"terser-webpack-plugin": "^5.1.3", "terser-webpack-plugin": "^5.1.3",
"watchpack": "^2.3.1", "watchpack": "^2.4.0",
"webpack-sources": "^3.2.3" "webpack-sources": "^3.2.3"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
@ -121,6 +121,7 @@
"url": "https://opencollective.com/webpack" "url": "https://opencollective.com/webpack"
}, },
"homepage": "https://github.com/webpack/webpack", "homepage": "https://github.com/webpack/webpack",
"bugs": "https://github.com/webpack/webpack/issues",
"main": "lib/index.js", "main": "lib/index.js",
"bin": { "bin": {
"webpack": "bin/webpack.js" "webpack": "bin/webpack.js"

File diff suppressed because one or more lines are too long

View File

@ -897,7 +897,10 @@
}, },
"css": { "css": {
"description": "Enable css support.", "description": "Enable css support.",
"oneOf": [ "anyOf": [
{
"enum": [false]
},
{ {
"$ref": "#/definitions/CssExperimentOptions" "$ref": "#/definitions/CssExperimentOptions"
} }
@ -913,7 +916,10 @@
}, },
"lazyCompilation": { "lazyCompilation": {
"description": "Compile entrypoints and import()s only when they are accessed.", "description": "Compile entrypoints and import()s only when they are accessed.",
"oneOf": [ "anyOf": [
{
"enum": [false]
},
{ {
"$ref": "#/definitions/LazyCompilationOptions" "$ref": "#/definitions/LazyCompilationOptions"
} }
@ -1580,6 +1586,43 @@
"description": "Enable/disable parsing of magic comments in CommonJs syntax.", "description": "Enable/disable parsing of magic comments in CommonJs syntax.",
"type": "boolean" "type": "boolean"
}, },
"createRequire": {
"description": "Enable/disable parsing \"import { createRequire } from \"module\"\" and evaluating createRequire().",
"anyOf": [
{
"type": "boolean"
},
{
"type": "string"
}
]
},
"dynamicImportMode": {
"description": "Specifies global mode for dynamic import.",
"enum": ["eager", "weak", "lazy", "lazy-once"]
},
"dynamicImportPrefetch": {
"description": "Specifies global prefetch for dynamic import.",
"anyOf": [
{
"type": "number"
},
{
"type": "boolean"
}
]
},
"dynamicImportPreload": {
"description": "Specifies global preload for dynamic import.",
"anyOf": [
{
"type": "number"
},
{
"type": "boolean"
}
]
},
"exportsPresence": { "exportsPresence": {
"description": "Specifies the behavior of invalid export names in \"import ... from ...\" and \"export ... from ...\".", "description": "Specifies the behavior of invalid export names in \"import ... from ...\" and \"export ... from ...\".",
"enum": ["error", "warn", "auto", false] "enum": ["error", "warn", "auto", false]
@ -3700,6 +3743,29 @@
"type": "string" "type": "string"
} }
}, },
"extensionAlias": {
"description": "An object which maps extension to extension aliases.",
"type": "object",
"additionalProperties": {
"description": "Extension alias.",
"anyOf": [
{
"description": "Multiple extensions.",
"type": "array",
"items": {
"description": "Aliased extension.",
"type": "string",
"minLength": 1
}
},
{
"description": "Aliased extension.",
"type": "string",
"minLength": 1
}
]
}
},
"extensions": { "extensions": {
"description": "Extensions added to the request when trying to find the file.", "description": "Extensions added to the request when trying to find the file.",
"type": "array", "type": "array",

View File

@ -214,6 +214,10 @@ describe("snapshots", () => {
}, },
}, },
"javascript": Object { "javascript": Object {
"createRequire": false,
"dynamicImportMode": "lazy",
"dynamicImportPrefetch": false,
"dynamicImportPreload": false,
"exprContextCritical": true, "exprContextCritical": true,
"exprContextRecursive": true, "exprContextRecursive": true,
"exprContextRegExp": false, "exprContextRegExp": false,
@ -1266,6 +1270,9 @@ describe("snapshots", () => {
- "target": "web", - "target": "web",
+ "target": "node", + "target": "node",
@@ ... @@ @@ ... @@
- "createRequire": false,
+ "createRequire": true,
@@ ... @@
- "__dirname": "mock", - "__dirname": "mock",
- "__filename": "mock", - "__filename": "mock",
- "global": true, - "global": true,
@ -1407,6 +1414,9 @@ describe("snapshots", () => {
- "target": "web", - "target": "web",
+ "target": "electron-main", + "target": "electron-main",
@@ ... @@ @@ ... @@
- "createRequire": false,
+ "createRequire": true,
@@ ... @@
- "__dirname": "mock", - "__dirname": "mock",
- "__filename": "mock", - "__filename": "mock",
- "global": true, - "global": true,
@ -1530,6 +1540,9 @@ describe("snapshots", () => {
- "target": "web", - "target": "web",
+ "target": "electron-preload", + "target": "electron-preload",
@@ ... @@ @@ ... @@
- "createRequire": false,
+ "createRequire": true,
@@ ... @@
- "__dirname": "mock", - "__dirname": "mock",
- "__filename": "mock", - "__filename": "mock",
- "global": true, - "global": true,
@ -2208,6 +2221,84 @@ describe("snapshots", () => {
+ /^(.+?[\\\\/]node_modules[\\\\/])/, + /^(.+?[\\\\/]node_modules[\\\\/])/,
`) `)
); );
test(
"experiments.futureDefaults w/ experiments.css disabled",
{
experiments: {
css: false,
futureDefaults: true
}
},
e =>
e.toMatchInlineSnapshot(`
- Expected
+ Received
@@ ... @@
- "asyncWebAssembly": false,
- "backCompat": true,
+ "asyncWebAssembly": true,
+ "backCompat": false,
@@ ... @@
- "cacheUnaffected": false,
- "css": undefined,
- "futureDefaults": false,
+ "cacheUnaffected": true,
+ "css": false,
+ "futureDefaults": true,
@@ ... @@
- "topLevelAwait": false,
+ "topLevelAwait": true,
@@ ... @@
+ },
+ Object {
+ "rules": Array [
+ Object {
+ "descriptionData": Object {
+ "type": "module",
+ },
+ "resolve": Object {
+ "fullySpecified": true,
+ },
+ },
+ ],
+ "test": /\\.wasm$/i,
+ "type": "webassembly/async",
@@ ... @@
+ "mimetype": "application/wasm",
+ "rules": Array [
+ Object {
+ "descriptionData": Object {
+ "type": "module",
+ },
+ "resolve": Object {
+ "fullySpecified": true,
+ },
+ },
+ ],
+ "type": "webassembly/async",
+ },
+ Object {
@@ ... @@
+ "exportsPresence": "error",
@@ ... @@
- "__dirname": "mock",
- "__filename": "mock",
- "global": true,
+ "__dirname": "warn-mock",
+ "__filename": "warn-mock",
+ "global": "warn",
@@ ... @@
- "hashDigestLength": 20,
- "hashFunction": "md4",
+ "hashDigestLength": 16,
+ "hashFunction": "xxhash64",
@@ ... @@
- "<cwd>/node_modules/",
+ /^(.+?[\\\\/]node_modules[\\\\/])/,
`)
);
}); });
it("should result in the same target options for same target", () => { it("should result in the same target options for same target", () => {

View File

@ -363,4 +363,50 @@ ${details(snapshot)}`)
} }
}); });
} }
describe("stable iterables identity", () => {
const options = { timestamp: true };
/**
* @param {function((WebpackError | null)=, (Snapshot | null)=): void} callback callback function
*/
function getSnapshot(callback) {
const fs = createFs();
const fsInfo = createFsInfo(fs);
fsInfo.createSnapshot(
Date.now() + 10000,
files,
directories,
missing,
options,
callback
);
}
it("should return same iterable for getFileIterable()", done => {
getSnapshot((err, snapshot) => {
if (err) done(err);
expect(snapshot.getFileIterable()).toEqual(snapshot.getFileIterable());
done();
});
});
it("should return same iterable for getContextIterable()", done => {
getSnapshot((err, snapshot) => {
if (err) done(err);
expect(snapshot.getContextIterable()).toEqual(
snapshot.getContextIterable()
);
done();
});
});
it("should return same iterable for getMissingIterable()", done => {
getSnapshot((err, snapshot) => {
if (err) done(err);
expect(snapshot.getFileIterable()).toEqual(snapshot.getFileIterable());
done();
});
});
});
}); });

View File

@ -0,0 +1,131 @@
"use strict";
require("./helpers/warmup-webpack");
const path = require("path");
const fs = require("graceful-fs");
const rimraf = require("rimraf");
const captureStdio = require("./helpers/captureStdio");
const webpack = require("..");
const toMiB = bytes => `${Math.round(bytes / 1024 / 1024)}MiB`;
const base = path.join(__dirname, "memoryLimitCases");
const outputBase = path.join(__dirname, "js", "memoryLimit");
const tests = fs
.readdirSync(base)
.filter(
testName =>
fs.existsSync(path.join(base, testName, "index.js")) ||
fs.existsSync(path.join(base, testName, "webpack.config.js"))
)
.filter(testName => {
const testDirectory = path.join(base, testName);
const filterPath = path.join(testDirectory, "test.filter.js");
if (fs.existsSync(filterPath) && !require(filterPath)()) {
describe.skip(testName, () => it("filtered"));
return false;
}
return true;
});
describe("MemoryLimitTestCases", () => {
jest.setTimeout(40000);
let stderr;
beforeEach(() => {
stderr = captureStdio(process.stderr, true);
if (global.gc) {
global.gc();
global.gc();
}
});
afterEach(() => {
stderr.restore();
});
tests.forEach(testName => {
let testConfig = {
heapSizeLimitBytes: 250 * 1024 * 1024
};
try {
// try to load a test file
testConfig = Object.assign(
testConfig,
require(path.join(base, testName, "test.config.js"))
);
} catch (e) {
// ignored
}
it(`should build ${JSON.stringify(testName)} with heap limit of ${toMiB(
testConfig.heapSizeLimitBytes
)}`, done => {
const outputDirectory = path.join(outputBase, testName);
rimraf.sync(outputDirectory);
fs.mkdirSync(outputDirectory, { recursive: true });
let options = {
mode: "development",
entry: "./index",
output: {
filename: "bundle.js"
}
};
if (fs.existsSync(path.join(base, testName, "webpack.config.js"))) {
options = require(path.join(base, testName, "webpack.config.js"));
}
(Array.isArray(options) ? options : [options]).forEach(options => {
if (!options.context) options.context = path.join(base, testName);
if (!options.output) options.output = options.output || {};
if (!options.output.path) options.output.path = outputDirectory;
if (!options.plugins) options.plugins = [];
if (!options.optimization) options.optimization = {};
if (options.optimization.minimize === undefined)
options.optimization.minimize = false;
});
const heapSizeStart = process.memoryUsage().heapUsed;
const c = webpack(options);
const compilers = c.compilers ? c.compilers : [c];
compilers.forEach(c => {
const ifs = c.inputFileSystem;
c.inputFileSystem = Object.create(ifs);
c.inputFileSystem.readFile = function () {
const args = Array.prototype.slice.call(arguments);
const callback = args.pop();
ifs.readFile.apply(
ifs,
args.concat([
(err, result) => {
if (err) return callback(err);
if (!/\.(js|json|txt)$/.test(args[0]))
return callback(null, result);
callback(null, result.toString("utf-8").replace(/\r/g, ""));
}
])
);
};
});
c.run((err, stats) => {
if (err) return done(err);
if (/error$/.test(testName)) {
expect(stats.hasErrors()).toBe(true);
} else if (stats.hasErrors()) {
return done(
new Error(
stats.toString({
all: false,
errors: true,
errorStack: true,
errorDetails: true
})
)
);
}
const heapUsed = process.memoryUsage().heapUsed - heapSizeStart;
if (heapUsed > testConfig.heapSizeLimitBytes) {
return done(
new Error(`Out of memory limit with ${toMiB(heapUsed)} heap used`)
);
}
if (testConfig.validate) testConfig.validate(stats, stderr.toString());
done();
});
});
});
});

View File

@ -1503,6 +1503,82 @@ Object {
"multiple": false, "multiple": false,
"simpleType": "boolean", "simpleType": "boolean",
}, },
"module-parser-javascript-auto-create-require": Object {
"configs": Array [
Object {
"description": "Enable/disable parsing \\"import { createRequire } from \\"module\\"\\" and evaluating createRequire().",
"multiple": false,
"path": "module.parser.javascript/auto.createRequire",
"type": "boolean",
},
Object {
"description": "Enable/disable parsing \\"import { createRequire } from \\"module\\"\\" and evaluating createRequire().",
"multiple": false,
"path": "module.parser.javascript/auto.createRequire",
"type": "string",
},
],
"description": "Enable/disable parsing \\"import { createRequire } from \\"module\\"\\" and evaluating createRequire().",
"multiple": false,
"simpleType": "string",
},
"module-parser-javascript-auto-dynamic-import-mode": Object {
"configs": Array [
Object {
"description": "Specifies global mode for dynamic import.",
"multiple": false,
"path": "module.parser.javascript/auto.dynamicImportMode",
"type": "enum",
"values": Array [
"eager",
"weak",
"lazy",
"lazy-once",
],
},
],
"description": "Specifies global mode for dynamic import.",
"multiple": false,
"simpleType": "string",
},
"module-parser-javascript-auto-dynamic-import-prefetch": Object {
"configs": Array [
Object {
"description": "Specifies global prefetch for dynamic import.",
"multiple": false,
"path": "module.parser.javascript/auto.dynamicImportPrefetch",
"type": "number",
},
Object {
"description": "Specifies global prefetch for dynamic import.",
"multiple": false,
"path": "module.parser.javascript/auto.dynamicImportPrefetch",
"type": "boolean",
},
],
"description": "Specifies global prefetch for dynamic import.",
"multiple": false,
"simpleType": "string",
},
"module-parser-javascript-auto-dynamic-import-preload": Object {
"configs": Array [
Object {
"description": "Specifies global preload for dynamic import.",
"multiple": false,
"path": "module.parser.javascript/auto.dynamicImportPreload",
"type": "number",
},
Object {
"description": "Specifies global preload for dynamic import.",
"multiple": false,
"path": "module.parser.javascript/auto.dynamicImportPreload",
"type": "boolean",
},
],
"description": "Specifies global preload for dynamic import.",
"multiple": false,
"simpleType": "string",
},
"module-parser-javascript-auto-exports-presence": Object { "module-parser-javascript-auto-exports-presence": Object {
"configs": Array [ "configs": Array [
Object { Object {
@ -2025,6 +2101,25 @@ Object {
"multiple": false, "multiple": false,
"simpleType": "boolean", "simpleType": "boolean",
}, },
"module-parser-javascript-create-require": Object {
"configs": Array [
Object {
"description": "Enable/disable parsing \\"import { createRequire } from \\"module\\"\\" and evaluating createRequire().",
"multiple": false,
"path": "module.parser.javascript.createRequire",
"type": "boolean",
},
Object {
"description": "Enable/disable parsing \\"import { createRequire } from \\"module\\"\\" and evaluating createRequire().",
"multiple": false,
"path": "module.parser.javascript.createRequire",
"type": "string",
},
],
"description": "Enable/disable parsing \\"import { createRequire } from \\"module\\"\\" and evaluating createRequire().",
"multiple": false,
"simpleType": "string",
},
"module-parser-javascript-dynamic-amd": Object { "module-parser-javascript-dynamic-amd": Object {
"configs": Array [ "configs": Array [
Object { Object {
@ -2080,6 +2175,82 @@ Object {
"multiple": false, "multiple": false,
"simpleType": "boolean", "simpleType": "boolean",
}, },
"module-parser-javascript-dynamic-create-require": Object {
"configs": Array [
Object {
"description": "Enable/disable parsing \\"import { createRequire } from \\"module\\"\\" and evaluating createRequire().",
"multiple": false,
"path": "module.parser.javascript/dynamic.createRequire",
"type": "boolean",
},
Object {
"description": "Enable/disable parsing \\"import { createRequire } from \\"module\\"\\" and evaluating createRequire().",
"multiple": false,
"path": "module.parser.javascript/dynamic.createRequire",
"type": "string",
},
],
"description": "Enable/disable parsing \\"import { createRequire } from \\"module\\"\\" and evaluating createRequire().",
"multiple": false,
"simpleType": "string",
},
"module-parser-javascript-dynamic-dynamic-import-mode": Object {
"configs": Array [
Object {
"description": "Specifies global mode for dynamic import.",
"multiple": false,
"path": "module.parser.javascript/dynamic.dynamicImportMode",
"type": "enum",
"values": Array [
"eager",
"weak",
"lazy",
"lazy-once",
],
},
],
"description": "Specifies global mode for dynamic import.",
"multiple": false,
"simpleType": "string",
},
"module-parser-javascript-dynamic-dynamic-import-prefetch": Object {
"configs": Array [
Object {
"description": "Specifies global prefetch for dynamic import.",
"multiple": false,
"path": "module.parser.javascript/dynamic.dynamicImportPrefetch",
"type": "number",
},
Object {
"description": "Specifies global prefetch for dynamic import.",
"multiple": false,
"path": "module.parser.javascript/dynamic.dynamicImportPrefetch",
"type": "boolean",
},
],
"description": "Specifies global prefetch for dynamic import.",
"multiple": false,
"simpleType": "string",
},
"module-parser-javascript-dynamic-dynamic-import-preload": Object {
"configs": Array [
Object {
"description": "Specifies global preload for dynamic import.",
"multiple": false,
"path": "module.parser.javascript/dynamic.dynamicImportPreload",
"type": "number",
},
Object {
"description": "Specifies global preload for dynamic import.",
"multiple": false,
"path": "module.parser.javascript/dynamic.dynamicImportPreload",
"type": "boolean",
},
],
"description": "Specifies global preload for dynamic import.",
"multiple": false,
"simpleType": "string",
},
"module-parser-javascript-dynamic-exports-presence": Object { "module-parser-javascript-dynamic-exports-presence": Object {
"configs": Array [ "configs": Array [
Object { Object {
@ -2228,6 +2399,63 @@ Object {
"multiple": false, "multiple": false,
"simpleType": "boolean", "simpleType": "boolean",
}, },
"module-parser-javascript-dynamic-import-mode": Object {
"configs": Array [
Object {
"description": "Specifies global mode for dynamic import.",
"multiple": false,
"path": "module.parser.javascript.dynamicImportMode",
"type": "enum",
"values": Array [
"eager",
"weak",
"lazy",
"lazy-once",
],
},
],
"description": "Specifies global mode for dynamic import.",
"multiple": false,
"simpleType": "string",
},
"module-parser-javascript-dynamic-import-prefetch": Object {
"configs": Array [
Object {
"description": "Specifies global prefetch for dynamic import.",
"multiple": false,
"path": "module.parser.javascript.dynamicImportPrefetch",
"type": "number",
},
Object {
"description": "Specifies global prefetch for dynamic import.",
"multiple": false,
"path": "module.parser.javascript.dynamicImportPrefetch",
"type": "boolean",
},
],
"description": "Specifies global prefetch for dynamic import.",
"multiple": false,
"simpleType": "string",
},
"module-parser-javascript-dynamic-import-preload": Object {
"configs": Array [
Object {
"description": "Specifies global preload for dynamic import.",
"multiple": false,
"path": "module.parser.javascript.dynamicImportPreload",
"type": "number",
},
Object {
"description": "Specifies global preload for dynamic import.",
"multiple": false,
"path": "module.parser.javascript.dynamicImportPreload",
"type": "boolean",
},
],
"description": "Specifies global preload for dynamic import.",
"multiple": false,
"simpleType": "string",
},
"module-parser-javascript-dynamic-node": Object { "module-parser-javascript-dynamic-node": Object {
"configs": Array [ "configs": Array [
Object { Object {
@ -2618,6 +2846,82 @@ Object {
"multiple": false, "multiple": false,
"simpleType": "boolean", "simpleType": "boolean",
}, },
"module-parser-javascript-esm-create-require": Object {
"configs": Array [
Object {
"description": "Enable/disable parsing \\"import { createRequire } from \\"module\\"\\" and evaluating createRequire().",
"multiple": false,
"path": "module.parser.javascript/esm.createRequire",
"type": "boolean",
},
Object {
"description": "Enable/disable parsing \\"import { createRequire } from \\"module\\"\\" and evaluating createRequire().",
"multiple": false,
"path": "module.parser.javascript/esm.createRequire",
"type": "string",
},
],
"description": "Enable/disable parsing \\"import { createRequire } from \\"module\\"\\" and evaluating createRequire().",
"multiple": false,
"simpleType": "string",
},
"module-parser-javascript-esm-dynamic-import-mode": Object {
"configs": Array [
Object {
"description": "Specifies global mode for dynamic import.",
"multiple": false,
"path": "module.parser.javascript/esm.dynamicImportMode",
"type": "enum",
"values": Array [
"eager",
"weak",
"lazy",
"lazy-once",
],
},
],
"description": "Specifies global mode for dynamic import.",
"multiple": false,
"simpleType": "string",
},
"module-parser-javascript-esm-dynamic-import-prefetch": Object {
"configs": Array [
Object {
"description": "Specifies global prefetch for dynamic import.",
"multiple": false,
"path": "module.parser.javascript/esm.dynamicImportPrefetch",
"type": "number",
},
Object {
"description": "Specifies global prefetch for dynamic import.",
"multiple": false,
"path": "module.parser.javascript/esm.dynamicImportPrefetch",
"type": "boolean",
},
],
"description": "Specifies global prefetch for dynamic import.",
"multiple": false,
"simpleType": "string",
},
"module-parser-javascript-esm-dynamic-import-preload": Object {
"configs": Array [
Object {
"description": "Specifies global preload for dynamic import.",
"multiple": false,
"path": "module.parser.javascript/esm.dynamicImportPreload",
"type": "number",
},
Object {
"description": "Specifies global preload for dynamic import.",
"multiple": false,
"path": "module.parser.javascript/esm.dynamicImportPreload",
"type": "boolean",
},
],
"description": "Specifies global preload for dynamic import.",
"multiple": false,
"simpleType": "string",
},
"module-parser-javascript-esm-exports-presence": Object { "module-parser-javascript-esm-exports-presence": Object {
"configs": Array [ "configs": Array [
Object { Object {

View File

@ -1192,6 +1192,17 @@ cacheable modules 142 bytes
webpack x.x.x compiled successfully in X ms" webpack x.x.x compiled successfully in X ms"
`; `;
exports[`StatsTestCases should print correct stats for import-weak-parser-option 1`] = `
"asset entry.js 13 KiB [emitted] (name: entry)
asset 836.js 138 bytes [emitted]
runtime modules 7.68 KiB 10 modules
orphan modules 37 bytes [orphan] 1 module
cacheable modules 116 bytes
./entry.js 94 bytes [built] [code generated]
./modules/b.js 22 bytes [built] [code generated]
webpack x.x.x compiled successfully in X ms"
`;
exports[`StatsTestCases should print correct stats for import-with-invalid-options-comments 1`] = ` exports[`StatsTestCases should print correct stats for import-with-invalid-options-comments 1`] = `
"runtime modules 8.6 KiB 12 modules "runtime modules 8.6 KiB 12 modules
cacheable modules 559 bytes cacheable modules 559 bytes
@ -4600,8 +4611,8 @@ webpack x.x.x compiled with 1 warning in X ms"
`; `;
exports[`StatsTestCases should print correct stats for wasm-explorer-examples-sync 1`] = ` exports[`StatsTestCases should print correct stats for wasm-explorer-examples-sync 1`] = `
"assets by path *.js 22.2 KiB "assets by path *.js 21.7 KiB
asset bundle.js 16.7 KiB [emitted] (name: main) asset bundle.js 16.2 KiB [emitted] (name: main)
asset 325.bundle.js 3.9 KiB [emitted] asset 325.bundle.js 3.9 KiB [emitted]
asset 795.bundle.js 557 bytes [emitted] asset 795.bundle.js 557 bytes [emitted]
asset 526.bundle.js 366 bytes [emitted] (id hint: vendors) asset 526.bundle.js 366 bytes [emitted] (id hint: vendors)
@ -4617,8 +4628,8 @@ assets by path *.wasm 1.37 KiB
asset 0301cb3f9f4151b567f5.module.wasm 120 bytes [emitted] [immutable] asset 0301cb3f9f4151b567f5.module.wasm 120 bytes [emitted] [immutable]
chunk (runtime: main) 20.bundle.js 50 bytes (javascript) 531 bytes (webassembly) [rendered] chunk (runtime: main) 20.bundle.js 50 bytes (javascript) 531 bytes (webassembly) [rendered]
./duff.wasm 50 bytes (javascript) 531 bytes (webassembly) [built] [code generated] ./duff.wasm 50 bytes (javascript) 531 bytes (webassembly) [built] [code generated]
chunk (runtime: main) bundle.js (main) 586 bytes (javascript) 9.49 KiB (runtime) [entry] [rendered] chunk (runtime: main) bundle.js (main) 586 bytes (javascript) 9.12 KiB (runtime) [entry] [rendered]
runtime modules 9.49 KiB 11 modules runtime modules 9.12 KiB 11 modules
./index.js 586 bytes [built] [code generated] ./index.js 586 bytes [built] [code generated]
chunk (runtime: main) 189.bundle.js 50 bytes (javascript) 156 bytes (webassembly) [rendered] chunk (runtime: main) 189.bundle.js 50 bytes (javascript) 156 bytes (webassembly) [rendered]
./Q_rsqrt.wasm 50 bytes (javascript) 156 bytes (webassembly) [built] [code generated] ./Q_rsqrt.wasm 50 bytes (javascript) 156 bytes (webassembly) [built] [code generated]
@ -4632,7 +4643,7 @@ chunk (runtime: main) 526.bundle.js (id hint: vendors) 34 bytes [rendered] split
chunk (runtime: main) 795.bundle.js 110 bytes (javascript) 444 bytes (webassembly) [rendered] chunk (runtime: main) 795.bundle.js 110 bytes (javascript) 444 bytes (webassembly) [rendered]
./fact.wasm 50 bytes (javascript) 154 bytes (webassembly) [built] [code generated] ./fact.wasm 50 bytes (javascript) 154 bytes (webassembly) [built] [code generated]
./fast-math.wasm 60 bytes (javascript) 290 bytes (webassembly) [built] [code generated] ./fast-math.wasm 60 bytes (javascript) 290 bytes (webassembly) [built] [code generated]
runtime modules 9.49 KiB 11 modules runtime modules 9.12 KiB 11 modules
cacheable modules 2.31 KiB (javascript) 1.37 KiB (webassembly) cacheable modules 2.31 KiB (javascript) 1.37 KiB (webassembly)
webassembly modules 310 bytes (javascript) 1.37 KiB (webassembly) webassembly modules 310 bytes (javascript) 1.37 KiB (webassembly)
./Q_rsqrt.wasm 50 bytes (javascript) 156 bytes (webassembly) [built] [code generated] ./Q_rsqrt.wasm 50 bytes (javascript) 156 bytes (webassembly) [built] [code generated]

View File

@ -0,0 +1,2 @@
await 1;
export default 1;

View File

@ -0,0 +1,5 @@
it("should not take too long to evaluate nested async modules", async () => {
const start = Date.now();
await import(/* webpackMode: "eager" */ "./loader.js?i=40!./loader.js");
expect(Date.now() - start).toBeLessThan(100);
});

View File

@ -0,0 +1,14 @@
/** @type {import("../../../../").LoaderDefinition<{ i: string }>} */
module.exports = function () {
const options = this.getOptions();
const i = +options.i;
let src = `import n from "./async.js";\n`;
if (i > 0) {
src += `import a from "./loader.js?i=${i - 1}&a!./loader.js";\n`;
src += `import b from "./loader.js?i=${i - 1}&b!./loader.js";\n`;
src += `export default n + a + b;\n`;
} else {
src += `export default n;\n`;
}
return src;
};

View File

@ -0,0 +1,4 @@
let value = 0;
const add = () => value++;
export { value, add }

View File

@ -0,0 +1,20 @@
import { "\0 add" as add } from './reexport';
export default class Foo {
static {
new Foo(add);
}
constructor(fn) {
this.#foo = fn;
this.#add();
}
#foo = undefined;
#add() {
if (#foo in this && this.#foo) {
this.#foo();
}
}
}

View File

@ -0,0 +1,7 @@
import { value, add } from "./counter";
import Foo from "./es2022";
it("should compile and run", () => {
new Foo(add);
expect(value).toBe(2);
});

View File

@ -0,0 +1 @@
export { add as "\0 add" } from "./counter";

View File

@ -0,0 +1,11 @@
module.exports = function(config) {
// terser doesn't support static {}
if (config.mode === "production") return false;
try {
eval("class A { static {} }");
return true;
} catch {
return false;
}
};

View File

@ -79,3 +79,12 @@ it("should handle 'm in n' case", () => {
expect(m.canMangleA).toBe(true); expect(m.canMangleA).toBe(true);
} }
}); });
it("issue-15759", () => {
function foo() {
// PLEASE CONFIRM there is no space after return
// prettier-ignore
return"usedA"in m;
}
expect(foo.call()).toBe(true);
});

View File

@ -1,3 +1,5 @@
module.exports = [ module.exports = [
// each time sets different assetsInfo object instance in webpack.config.js:54
// this prevents hit in inmemory cache
/^Pack got invalid because of write to: TerserWebpackPlugin|bundle0\.js$/ /^Pack got invalid because of write to: TerserWebpackPlugin|bundle0\.js$/
]; ];

View File

@ -0,0 +1,11 @@
import { b, a, c } from "dep";
c.cc();
b.bbb();
a.aa();
import { order } from "dep/order.js";
it("should import side-effect-free modules in deterministic order (usage order)", () => {
expect(order).toEqual(["c", "b", "a"]);
});

View File

@ -0,0 +1,4 @@
import { track } from "./order.js";
track("a");
export function aa() {}
export function aaa() {}

View File

@ -0,0 +1,4 @@
import { track } from "./order.js";
track("b");
export function bb() {}
export function bbb() {}

View File

@ -0,0 +1,4 @@
import { track } from "./order.js";
track("c");
export function cc() {}
export function ccc() {}

View File

@ -0,0 +1,8 @@
import * as a from "./a.js";
import * as b from "./b.js";
import * as c from "./c.js";
export {
a,
b,
c
}

View File

@ -0,0 +1,4 @@
export let order = [];
export function track(name) {
order.push(name);
}

View File

@ -0,0 +1,6 @@
{
"name": "dep",
"version": "1.0.0",
"type": "module",
"sideEffects": false
}

View File

@ -0,0 +1,6 @@
/** @type {import("../../../../").Configuration} */
module.exports = {
optimization: {
concatenateModules: true
}
};

View File

@ -0,0 +1,2 @@
export * as c from "./b";
export * as c2 from "./harmony2";

View File

@ -0,0 +1,7 @@
export function square(x) {
return x * x;
}
export function cube(x) {
return x * x * x;
}

View File

@ -0,0 +1,2 @@
export const a = 1;
export const aUsed = __webpack_exports_info__.a.used;

View File

@ -48,6 +48,11 @@ it("should provide a module for a property request", function() {
expect(x).toBe("fff"); expect(x).toBe("fff");
}); });
it("should tree-shake unused exports", function() {
expect(aa1(2)).toBe(8);
expect(es2015_aUsed).toBe(false);
});
it("should provide ES2015 modules", function() { it("should provide ES2015 modules", function() {
expect((es2015.default)).toBe("ECMAScript 2015"); expect((es2015.default)).toBe("ECMAScript 2015");
expect((es2015.alias)).toBe("ECMAScript Harmony"); expect((es2015.alias)).toBe("ECMAScript Harmony");

View File

@ -6,6 +6,8 @@ module.exports = {
aaa: "./aaa", aaa: "./aaa",
"bbb.ccc": "./bbbccc", "bbb.ccc": "./bbbccc",
dddeeefff: ["./ddd", "eee", "3-f"], dddeeefff: ["./ddd", "eee", "3-f"],
aa1: ["./a", "c", "cube"],
es2015_aUsed: ["./harmony2", "aUsed"],
"process.env.NODE_ENV": "./env", "process.env.NODE_ENV": "./env",
es2015: "./harmony", es2015: "./harmony",
es2015_name: ["./harmony", "default"], es2015_name: ["./harmony", "default"],

View File

@ -1,3 +1,5 @@
module.exports = [ module.exports = [
// each time returns different OriginalSource in webpack.config.js:78
// this prevents hit in inmemory cache
/^Pack got invalid because of write to: RealContentHashPlugin|analyse|index\.html$/ /^Pack got invalid because of write to: RealContentHashPlugin|analyse|index\.html$/
]; ];

View File

@ -0,0 +1 @@
module.exports = 1;

View File

@ -0,0 +1 @@
module.exports = 2;

View File

@ -0,0 +1 @@
module.exports = 3;

View File

@ -0,0 +1 @@
module.exports = 4;

View File

@ -0,0 +1 @@
module.exports = 5;

View File

@ -0,0 +1,58 @@
import { createRequire as _createRequire } from "module";
import { createRequire as __createRequire, builtinModules } from "module";
it("should evaluate require/createRequire", () => {
expect(
(function() { return typeof _createRequire; }).toString()
).toBe('function() { return "function"; }');
expect(
(function() { if (typeof _createRequire); }).toString()
).toBe('function() { if (true); }');
const require = __createRequire(import.meta.url);
expect(
(function() { return typeof require; }).toString()
).toBe('function() { return "function"; }');
expect(
(function() { if (typeof require); }).toString()
).toBe('function() { if (true); }');
});
it("should create require", () => {
const require = _createRequire(import.meta.url);
expect(require("./a")).toBe(1);
expect(_createRequire(import.meta.url)("./c")).toBe(3);
});
it("should resolve using created require", () => {
const require = _createRequire(import.meta.url);
expect(require.resolve("./b")).toBe("./b.js");
expect(_createRequire(import.meta.url).resolve("./b")).toBe("./b.js");
});
it("should provide require.cache", () => {
const _require = _createRequire(import.meta.url);
expect(require.cache).toBe(_require.cache);
expect(require.cache).toBe(_createRequire(import.meta.url).cache);
});
it("should provide dependency context", () => {
const _require = _createRequire(new URL("./foo/c.js", import.meta.url));
expect(_require("./a")).toBe(4);
const _require1 = _createRequire(new URL("./foo/", import.meta.url));
expect(_require1("./c")).toBe(5);
});
it("should add warning on using as expression", () => {
let _require = _createRequire(new URL("./foo/c.js", import.meta.url));
const a = _require;
expect(typeof a).toBe("function");
});
it("should add warning on using require.main", () => {
let _require = _createRequire(new URL("./foo/c.js", import.meta.url));
expect(_require.main).toBe(undefined);
});
it("should import Node.js module", () => {
expect(Array.isArray(builtinModules)).toBe(true);
});

View File

@ -0,0 +1,4 @@
module.exports = [
/require function is used in a way in which dependencies cannot be statically extracted/,
/createRequire\(\)\.main is not supported by webpack/
];

View File

@ -0,0 +1,7 @@
/** @type {import("../../../../").Configuration} */
module.exports = {
target: "node",
optimization: {
moduleIds: "named"
}
};

View File

@ -0,0 +1,5 @@
import "./nonce";
it("should set nonce", () => {
expect(__webpack_nonce__).toBe("nonce");
});

View File

@ -0,0 +1 @@
__webpack_nonce__ = "nonce";

View File

@ -0,0 +1,7 @@
const webpack = require("../../../../");
/** @type {import("../../../../").Configuration} */
module.exports = {
target: "web",
// plugin that intercepts __webpack_require__
plugins: [new webpack.HotModuleReplacementPlugin()]
};

View File

@ -0,0 +1 @@
const ctx = require.context("./src", false, /\.json$/);

View File

@ -0,0 +1 @@
{"type":"Topology","box":[-73.9958013,45.3984821,-73.4742952,45.7047897],"transform":{"scale":[0.0005225512024048059,0.00030692144288576825],"translate":[-73.9958013,45.3984821]},"objects":{"boundary":{"type":"Polygon","arcs":[[0]],"id":"relation/8508277","properties":{"admin_level":"6","alt_name:1":"Montréal","boundary":"administrative","name":"Agglomération de Montréal","name:en":"Urban agglomeration of Montreal","name:fr":"Agglomération de Montréal","type":"boundary","wikidata":"Q2826806","wikipedia":"fr:Agglomération de Montréal","id":"relation/8508277"}}},"arcs":[[[992,804],[-2,23],[-15,31],[-3,32],[4,45],[12,24],[2,14],[5,9],[3,8],[-4,7],[-23,-3],[-4,4],[-8,-1],[-5,-2],[-22,-7],[-18,-7],[-10,-1],[-8,-25],[-5,-18],[-6,-11],[-11,-9],[-18,-14],[-29,-31],[-25,-20],[-6,-5],[-53,-44],[-17,-21],[-14,-17],[-17,-22],[-3,-9],[-6,-16],[-5,-24],[-2,-6],[-6,-22],[-13,-25],[-11,-21],[-5,-11],[-2,-3],[-12,-28],[-1,-3],[-1,-25],[-11,-22],[-2,-3],[-1,-4],[-3,-8],[0,-2],[-4,-6],[-6,-6],[-23,-7],[-7,-3],[-6,-3],[-14,-11],[-6,-11],[-11,-7],[-7,-3],[-3,-1],[-16,-17],[-11,-8],[-8,-5],[-3,-5],[-9,-22],[-11,-3],[-11,-8],[-5,-10],[-5,-5],[-4,-1],[-10,-3],[-27,3],[-20,4],[-11,9],[-8,0],[-10,7],[-15,-5],[-5,0],[-21,8],[-20,0],[-2,-2],[-3,-1],[-3,-4],[-7,-12],[-3,-3],[-1,-1],[-2,-1],[-2,1],[-6,12],[-8,4],[-3,5],[-1,5],[-7,1],[-14,1],[-7,0],[-8,3],[-11,6],[-7,5],[-7,6],[-11,-4],[-11,-9],[-6,-7],[-7,-12],[-8,-11],[-7,-9],[-21,-21],[-19,-13],[-14,-19],[-10,-19],[-5,-16],[-7,-13],[-11,-26],[-14,-17],[-15,-20],[-10,-6],[-12,-4],[-4,0],[5,-17],[0,-3],[1,-2],[1,-6],[3,-10],[2,-12],[2,-9],[2,-9],[2,-5],[2,-19],[0,-25],[10,-13],[17,-16],[14,-14],[5,-6],[6,-7],[2,-2],[1,0],[1,-1],[1,0],[11,-5],[6,-3],[2,-1],[6,0],[16,1],[21,2],[12,5],[13,3],[3,2],[6,3],[2,2],[8,7],[12,5],[5,2],[3,0],[4,0],[6,-2],[18,-9],[13,-5],[25,-6],[36,-6],[29,-3],[9,-2],[22,-5],[7,11],[4,7],[5,7],[5,4],[1,1],[3,4],[7,5],[7,5],[8,4],[9,6],[8,5],[12,8],[49,5],[14,1],[5,1],[13,2],[45,1],[12,1],[12,0],[4,0],[8,-1],[11,-2],[8,-3],[9,-3],[12,-5],[3,-2],[6,-3],[18,-10],[10,-6],[9,-3],[5,-1],[1,0],[7,-1],[2,0],[12,1],[13,1],[16,1],[6,1],[7,1],[36,4],[24,4],[15,4],[20,7],[13,8],[7,5],[4,3],[14,14],[9,15],[7,21],[2,7],[3,26],[1,14],[-1,23],[0,5],[0,5],[0,21],[-2,7],[-2,7],[-5,16],[-2,23],[-1,6],[-4,10],[7,5],[2,1],[1,3],[1,1],[2,2],[3,4],[-1,5],[2,2],[-2,10],[-3,16],[-8,45],[-2,7],[0,3],[-2,9],[0,3],[-4,29],[-2,10],[19,25],[14,32],[10,25],[14,35],[1,4],[0,17],[3,18],[-4,33],[-2,25],[3,20],[4,12],[17,40],[9,21],[4,11],[10,33]]]}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,3 @@
import("./modules/a");
import("./modules/b");
import(/* webpackMode: "lazy" */"./modules/b");

View File

@ -0,0 +1,2 @@
import("./b");
module.exports = "a";

View File

@ -0,0 +1 @@
module.exports = "b";

View File

@ -0,0 +1,14 @@
/** @type {import("../../../").Configuration} */
module.exports = {
mode: "production",
entry: {
entry: "./entry"
},
module: {
parser: {
javascript: {
dynamicImportMode: "weak"
}
}
}
};

102
types.d.ts vendored
View File

@ -2503,11 +2503,11 @@ declare interface ContextHash {
} }
type ContextMode = type ContextMode =
| "weak" | "weak"
| "sync"
| "eager" | "eager"
| "async-weak"
| "lazy" | "lazy"
| "lazy-once"; | "lazy-once"
| "sync"
| "async-weak";
declare abstract class ContextModuleFactory extends ModuleFactory { declare abstract class ContextModuleFactory extends ModuleFactory {
hooks: Readonly<{ hooks: Readonly<{
beforeResolve: AsyncSeriesWaterfallHook<[any]>; beforeResolve: AsyncSeriesWaterfallHook<[any]>;
@ -3543,12 +3543,12 @@ declare interface ExperimentsNormalizedExtra {
/** /**
* Enable css support. * Enable css support.
*/ */
css?: CssExperimentOptions; css?: false | CssExperimentOptions;
/** /**
* Compile entrypoints and import()s only when they are accessed. * Compile entrypoints and import()s only when they are accessed.
*/ */
lazyCompilation?: LazyCompilationOptions; lazyCompilation?: false | LazyCompilationOptions;
} }
declare abstract class ExportInfo { declare abstract class ExportInfo {
name: string; name: string;
@ -3847,6 +3847,13 @@ declare interface ExpressionExpressionInfo {
getMembers: () => string[]; getMembers: () => string[];
getMembersOptionals: () => boolean[]; getMembersOptionals: () => boolean[];
} }
declare interface ExtensionAliasOption {
alias: string | string[];
extension: string;
}
declare interface ExtensionAliasOptions {
[index: string]: string | string[];
}
type ExternalItem = type ExternalItem =
| string | string
| RegExp | RegExp
@ -4502,6 +4509,42 @@ declare interface HandleModuleCreationOptions {
*/ */
connectOrigin?: boolean; connectOrigin?: boolean;
} }
declare class HarmonyImportDependency extends ModuleDependency {
constructor(
request: string,
sourceOrder: number,
assertions?: Record<string, any>
);
sourceOrder: number;
getImportVar(moduleGraph: ModuleGraph): string;
getImportStatement(
update: boolean,
__1: DependencyTemplateContext
): [string, string];
getLinkingErrors(
moduleGraph: ModuleGraph,
ids: string[],
additionalMessage: string
): undefined | WebpackError[];
static Template: typeof HarmonyImportDependencyTemplate;
static ExportPresenceModes: {
NONE: 0;
WARN: 1;
AUTO: 2;
ERROR: 3;
fromUserOption(str?: any): 0 | 1 | 2 | 3;
};
static NO_EXPORTS_REFERENCED: string[][];
static EXPORTS_OBJECT_REFERENCED: string[][];
static TRANSITIVE: typeof TRANSITIVE;
}
declare class HarmonyImportDependencyTemplate extends DependencyTemplate {
constructor();
static getImportEmittedRuntime(
module: Module,
referencedModule: Module
): undefined | string | boolean | SortableSet<string>;
}
declare class Hash { declare class Hash {
constructor(); constructor();
@ -4902,6 +4945,15 @@ declare class JavascriptParser extends Parser {
undefined | null | BasicEvaluatedExpression undefined | null | BasicEvaluatedExpression
> >
>; >;
evaluateNewExpression: HookMap<
SyncBailHook<[NewExpression], undefined | null | BasicEvaluatedExpression>
>;
evaluateCallExpression: HookMap<
SyncBailHook<
[CallExpression],
undefined | null | BasicEvaluatedExpression
>
>;
evaluateCallExpressionMember: HookMap< evaluateCallExpressionMember: HookMap<
SyncBailHook< SyncBailHook<
[CallExpression, undefined | BasicEvaluatedExpression], [CallExpression, undefined | BasicEvaluatedExpression],
@ -5410,6 +5462,7 @@ declare class JavascriptParser extends Parser {
isVariableDefined(name?: any): boolean; isVariableDefined(name?: any): boolean;
getVariableInfo(name: string): ExportedVariableInfo; getVariableInfo(name: string): ExportedVariableInfo;
setVariable(name: string, variableInfo: ExportedVariableInfo): void; setVariable(name: string, variableInfo: ExportedVariableInfo): void;
evaluatedVariable(tagInfo?: any): VariableInfo;
parseCommentOptions( parseCommentOptions(
range?: any range?: any
): { options: null; errors: null } | { options: object; errors: unknown[] }; ): { options: null; errors: null } | { options: object; errors: unknown[] };
@ -5490,6 +5543,26 @@ declare interface JavascriptParserOptions {
*/ */
commonjsMagicComments?: boolean; commonjsMagicComments?: boolean;
/**
* Enable/disable parsing "import { createRequire } from "module"" and evaluating createRequire().
*/
createRequire?: string | boolean;
/**
* Specifies global mode for dynamic import.
*/
dynamicImportMode?: "weak" | "eager" | "lazy" | "lazy-once";
/**
* Specifies global prefetch for dynamic import.
*/
dynamicImportPrefetch?: number | boolean;
/**
* Specifies global preload for dynamic import.
*/
dynamicImportPreload?: number | boolean;
/** /**
* Specifies the behavior of invalid export names in "import ... from ..." and "export ... from ...". * Specifies the behavior of invalid export names in "import ... from ..." and "export ... from ...".
*/ */
@ -9544,6 +9617,7 @@ declare interface ResolveOptionsTypes {
alias: AliasOption[]; alias: AliasOption[];
fallback: AliasOption[]; fallback: AliasOption[];
aliasFields: Set<string | string[]>; aliasFields: Set<string | string[]>;
extensionAlias: ExtensionAliasOption[];
cachePredicate: (arg0: ResolveRequest) => boolean; cachePredicate: (arg0: ResolveRequest) => boolean;
cacheWithContext: boolean; cacheWithContext: boolean;
@ -9642,6 +9716,11 @@ declare interface ResolveOptionsWebpackOptions {
*/ */
exportsFields?: string[]; exportsFields?: string[];
/**
* An object which maps extension to extension aliases.
*/
extensionAlias?: { [index: string]: string | string[] };
/** /**
* Extensions added to the request when trying to find the file. * Extensions added to the request when trying to find the file.
*/ */
@ -11854,6 +11933,11 @@ declare interface UserResolveOptions {
*/ */
fallback?: AliasOption[] | AliasOptions; fallback?: AliasOption[] | AliasOptions;
/**
* An object which maps extension to extension aliases
*/
extensionAlias?: ExtensionAliasOptions;
/** /**
* A list of alias fields in description files * A list of alias fields in description files
*/ */
@ -12691,7 +12775,12 @@ declare namespace exports {
) => void; ) => void;
} }
export namespace dependencies { export namespace dependencies {
export { ModuleDependency, ConstDependency, NullDependency }; export {
ModuleDependency,
HarmonyImportDependency,
ConstDependency,
NullDependency
};
} }
export namespace ids { export namespace ids {
export { export {
@ -13063,6 +13152,7 @@ declare namespace exports {
Asset, Asset,
AssetInfo, AssetInfo,
EntryOptions, EntryOptions,
PathData,
AssetEmittedInfo, AssetEmittedInfo,
MultiStats, MultiStats,
ParserState, ParserState,

View File

@ -1230,10 +1230,10 @@ acorn@^7.1.1, acorn@^7.4.0:
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
acorn@^8.2.4, acorn@^8.4.1: acorn@^8.2.4, acorn@^8.7.1:
version "8.7.0" version "8.7.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30"
integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==
agent-base@6: agent-base@6:
version "6.0.2" version "6.0.2"
@ -2259,10 +2259,10 @@ enhanced-resolve@^4.0.0:
memory-fs "^0.5.0" memory-fs "^0.5.0"
tapable "^1.0.0" tapable "^1.0.0"
enhanced-resolve@^5.9.3: enhanced-resolve@^5.10.0:
version "5.9.3" version "5.10.0"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz#44a342c012cbc473254af5cc6ae20ebd0aae5d88" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz#0dc579c3bb2a1032e357ac45b8f3a6f3ad4fb1e6"
integrity sha512-Bq9VSor+kjvW3f9/MiiR4eE3XYgOl7/rS8lnSxbRbF3kS0B2r+Y9w5krBWxZgDxASVZbdYrn5wT4j/Wb0J9qow== integrity sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==
dependencies: dependencies:
graceful-fs "^4.2.4" graceful-fs "^4.2.4"
tapable "^2.2.0" tapable "^2.2.0"
@ -6082,10 +6082,10 @@ wast-loader@^1.11.0:
dependencies: dependencies:
wabt "1.0.0-nightly.20180421" wabt "1.0.0-nightly.20180421"
watchpack@^2.3.1: watchpack@^2.4.0:
version "2.3.1" version "2.4.0"
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.3.1.tgz#4200d9447b401156eeca7767ee610f8809bc9d25" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d"
integrity sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA== integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==
dependencies: dependencies:
glob-to-regexp "^0.4.1" glob-to-regexp "^0.4.1"
graceful-fs "^4.1.2" graceful-fs "^4.1.2"