From 8d66aa7bc63b2d2efa59c7b70eb0d6f526a06b45 Mon Sep 17 00:00:00 2001 From: Akhil G Krishnan Date: Mon, 7 Nov 2022 15:09:11 +0530 Subject: [PATCH 01/20] Bump the loader-utils version to 2.0.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 769674d939d..e4ccc601e14 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "less": "^4.0.0", "less-loader": "^8.0.0", "lint-staged": "^11.0.0", - "loader-utils": "^2.0.0", + "loader-utils": "^2.0.3", "lodash": "^4.17.19", "lodash-es": "^4.17.15", "memfs": "^3.2.0", From 139d1b4ff0a150ada8aa188a6a11432674865d42 Mon Sep 17 00:00:00 2001 From: Akhil G Krishnan Date: Thu, 10 Nov 2022 15:25:12 +0530 Subject: [PATCH 02/20] Yarn lock updated --- yarn.lock | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/yarn.lock b/yarn.lock index 951cf8d49d0..19e410685b4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4163,6 +4163,15 @@ loader-utils@^2.0.0: emojis-list "^3.0.0" json5 "^2.1.2" +loader-utils@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.3.tgz#d4b15b8504c63d1fc3f2ade52d41bc8459d6ede1" + integrity sha512-THWqIsn8QRnvLl0shHYVBN9syumU8pYWEHPTmkiVGd+7K5eFNVSY6AJhRvgGF70gg1Dz+l/k8WicvFCxdEs60A== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^2.1.2" + locate-path@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" From 960a025f1d219b512da2b8b7d365fa5f6148ed61 Mon Sep 17 00:00:00 2001 From: Akhil G Krishnan Date: Thu, 10 Nov 2022 15:31:00 +0530 Subject: [PATCH 03/20] Yarn lint issue fix --- yarn.lock | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/yarn.lock b/yarn.lock index 19e410685b4..14ea915aa37 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4154,16 +4154,7 @@ loader-utils@^1.1.0, loader-utils@^1.4.0: emojis-list "^3.0.0" json5 "^1.0.1" -loader-utils@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.0.tgz#e4cace5b816d425a166b5f097e10cd12b36064b0" - integrity sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ== - dependencies: - big.js "^5.2.2" - emojis-list "^3.0.0" - json5 "^2.1.2" - -loader-utils@^2.0.3: +loader-utils@^2.0.0, loader-utils@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.3.tgz#d4b15b8504c63d1fc3f2ade52d41bc8459d6ede1" integrity sha512-THWqIsn8QRnvLl0shHYVBN9syumU8pYWEHPTmkiVGd+7K5eFNVSY6AJhRvgGF70gg1Dz+l/k8WicvFCxdEs60A== From d4b1d69ef042db5ac19b0a0337924dac608cddef Mon Sep 17 00:00:00 2001 From: Yehor Lvivski Date: Fri, 18 Nov 2022 19:08:49 +0100 Subject: [PATCH 04/20] Initialize hash conditionally --- lib/optimize/RealContentHashPlugin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/optimize/RealContentHashPlugin.js b/lib/optimize/RealContentHashPlugin.js index 39493200c96..7ab9c46fb8b 100644 --- a/lib/optimize/RealContentHashPlugin.js +++ b/lib/optimize/RealContentHashPlugin.js @@ -342,7 +342,6 @@ ${referencingAssets for (const oldHash of hashesInOrder) { const assets = hashToAssets.get(oldHash); assets.sort(comparator); - const hash = createHash(this._hashFunction); await Promise.all( assets.map(asset => asset.ownHashes.has(oldHash) @@ -363,6 +362,7 @@ ${referencingAssets }); let newHash = hooks.updateHash.call(assetsContent, oldHash); if (!newHash) { + const hash = createHash(this._hashFunction); for (const content of assetsContent) { hash.update(content); } From 7e8260a86cc3b8183dd76572981f7aa5f1b485ee Mon Sep 17 00:00:00 2001 From: Piotr Wysocki <86244209+piwysocki@users.noreply.github.com> Date: Sun, 20 Nov 2022 14:41:35 +0100 Subject: [PATCH 05/20] ci: test workflow - bump actions/cache --- .github/workflows/test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 11a4dbe2a81..9dfebc27c2a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,7 +27,7 @@ jobs: node-version: 17.x cache: "yarn" - run: yarn --frozen-lockfile - - uses: actions/cache@v1 + - uses: actions/cache@v3 with: path: .eslintcache key: lint-${{ env.GITHUB_SHA }} @@ -62,7 +62,7 @@ jobs: - run: yarn --frozen-lockfile - run: yarn link --frozen-lockfile || true - run: yarn link webpack --frozen-lockfile - - uses: actions/cache@v1 + - uses: actions/cache@v3 with: path: .jest-cache key: jest-unit-${{ env.GITHUB_SHA }} @@ -101,7 +101,7 @@ jobs: - run: yarn --frozen-lockfile - run: yarn link --frozen-lockfile || true - run: yarn link webpack --frozen-lockfile - - uses: actions/cache@v2 + - uses: actions/cache@v3 with: path: .jest-cache key: jest-integration-${{ env.GITHUB_SHA }} From 18c59c600d6d6149011f3c0a3b6d0e85b31329f3 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Tue, 22 Nov 2022 11:37:16 +0800 Subject: [PATCH 06/20] fix: avoid cross-realm objects --- lib/dependencies/CommonJsImportsParserPlugin.js | 3 +-- lib/dependencies/ImportParserPlugin.js | 11 +++++------ lib/dependencies/WorkerPlugin.js | 7 ++++--- lib/javascript/JavascriptParser.js | 15 +++++++++++---- 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/lib/dependencies/CommonJsImportsParserPlugin.js b/lib/dependencies/CommonJsImportsParserPlugin.js index e74e5c9743b..5a6e5faa4cd 100644 --- a/lib/dependencies/CommonJsImportsParserPlugin.js +++ b/lib/dependencies/CommonJsImportsParserPlugin.js @@ -236,8 +236,7 @@ class CommonJsImportsParserPlugin { parser.parseCommentOptions(expr.range); if (commentErrors) { - for (const e of commentErrors) { - const { comment } = e; + for (const { cause: e, comment } of commentErrors) { parser.state.module.addWarning( new CommentCompilationWarning( `Compilation error while processing magic comment(-s): /*${comment.value}*/: ${e.message}`, diff --git a/lib/dependencies/ImportParserPlugin.js b/lib/dependencies/ImportParserPlugin.js index 151ff89adcc..3dc84bd83af 100644 --- a/lib/dependencies/ImportParserPlugin.js +++ b/lib/dependencies/ImportParserPlugin.js @@ -55,8 +55,7 @@ class ImportParserPlugin { parser.parseCommentOptions(expr.range); if (commentErrors) { - for (const e of commentErrors) { - const { comment } = e; + for (const { cause: e, comment } of commentErrors) { parser.state.module.addWarning( new CommentCompilationWarning( `Compilation error while processing magic comment(-s): /*${comment.value}*/: ${e.message}`, @@ -137,7 +136,7 @@ class ImportParserPlugin { if (importOptions.webpackInclude !== undefined) { if ( !importOptions.webpackInclude || - importOptions.webpackInclude.constructor.name !== "RegExp" + !(importOptions.webpackInclude instanceof RegExp) ) { parser.state.module.addWarning( new UnsupportedFeatureWarning( @@ -146,13 +145,13 @@ class ImportParserPlugin { ) ); } else { - include = new RegExp(importOptions.webpackInclude); + include = importOptions.webpackInclude; } } if (importOptions.webpackExclude !== undefined) { if ( !importOptions.webpackExclude || - importOptions.webpackExclude.constructor.name !== "RegExp" + !(importOptions.webpackExclude instanceof RegExp) ) { parser.state.module.addWarning( new UnsupportedFeatureWarning( @@ -161,7 +160,7 @@ class ImportParserPlugin { ) ); } else { - exclude = new RegExp(importOptions.webpackExclude); + exclude = importOptions.webpackExclude; } } if (importOptions.webpackExports !== undefined) { diff --git a/lib/dependencies/WorkerPlugin.js b/lib/dependencies/WorkerPlugin.js index 5b68d84c06a..4dd193d44d7 100644 --- a/lib/dependencies/WorkerPlugin.js +++ b/lib/dependencies/WorkerPlugin.js @@ -203,8 +203,7 @@ class WorkerPlugin { parser.parseCommentOptions(expr.range); if (commentErrors) { - for (const e of commentErrors) { - const { comment } = e; + for (const { cause: e, comment } of commentErrors) { parser.state.module.addWarning( new CommentCompilationWarning( `Compilation error while processing magic comment(-s): /*${comment.value}*/: ${e.message}`, @@ -246,7 +245,9 @@ class WorkerPlugin { } else { Object.assign( entryOptions, - importOptions.webpackEntryOptions + JSON.parse( + JSON.stringify(importOptions.webpackEntryOptions) + ) ); } } diff --git a/lib/javascript/JavascriptParser.js b/lib/javascript/JavascriptParser.js index c10c7b16eaf..c1e0d34dc3b 100644 --- a/lib/javascript/JavascriptParser.js +++ b/lib/javascript/JavascriptParser.js @@ -3641,11 +3641,18 @@ class JavascriptParser extends Parser { if (value && webpackCommentRegExp.test(value)) { // try compile only if webpack options comment is present try { - const val = vm.runInNewContext(`(function(){return {${value}};})()`); - Object.assign(options, val); + let val = vm.runInNewContext(`(function(){return {${value}};})()`); + const key = Object.getOwnPropertyNames(val)[0]; + if (!key) continue; + val = val[key]; + + if (typeof val === "object" && val !== null) { + if (val.constructor.name === "RegExp") val = new RegExp(val); + else val = JSON.parse(JSON.stringify(val)); + } + options[key] = val; } catch (e) { - e.comment = comment; - errors.push(e); + errors.push({ comment, cause: e }); } } } From 4e643be0d78f2f6b010d71fd1583c5e4a0f92258 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Tue, 22 Nov 2022 11:42:29 +0800 Subject: [PATCH 07/20] fix: remove extra change --- lib/dependencies/WorkerPlugin.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/dependencies/WorkerPlugin.js b/lib/dependencies/WorkerPlugin.js index 4dd193d44d7..a5a51a48154 100644 --- a/lib/dependencies/WorkerPlugin.js +++ b/lib/dependencies/WorkerPlugin.js @@ -245,9 +245,7 @@ class WorkerPlugin { } else { Object.assign( entryOptions, - JSON.parse( - JSON.stringify(importOptions.webpackEntryOptions) - ) + importOptions.webpackEntryOptions ); } } From 1d86c181a8342860676579ce8abc4d2e705b37f6 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Tue, 22 Nov 2022 11:52:04 +0800 Subject: [PATCH 08/20] fix: test fail --- lib/javascript/JavascriptParser.js | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/lib/javascript/JavascriptParser.js b/lib/javascript/JavascriptParser.js index c1e0d34dc3b..780c2de03a7 100644 --- a/lib/javascript/JavascriptParser.js +++ b/lib/javascript/JavascriptParser.js @@ -3641,16 +3641,15 @@ class JavascriptParser extends Parser { if (value && webpackCommentRegExp.test(value)) { // try compile only if webpack options comment is present try { - let val = vm.runInNewContext(`(function(){return {${value}};})()`); - const key = Object.getOwnPropertyNames(val)[0]; - if (!key) continue; - val = val[key]; - - if (typeof val === "object" && val !== null) { - if (val.constructor.name === "RegExp") val = new RegExp(val); - else val = JSON.parse(JSON.stringify(val)); + for (let [key, val] of Object.entries( + vm.runInNewContext(`(function(){return {${value}};})()`) + )) { + if (typeof val === "object" && val !== null) { + if (val.constructor.name === "RegExp") val = new RegExp(val); + else val = JSON.parse(JSON.stringify(val)); + } + options[key] = val; } - options[key] = val; } catch (e) { errors.push({ comment, cause: e }); } From e7e2aecd1c3e5fc893664f85a1da3bf1083533bc Mon Sep 17 00:00:00 2001 From: Jack Works Date: Tue, 22 Nov 2022 11:57:02 +0800 Subject: [PATCH 09/20] update dts --- types.d.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/types.d.ts b/types.d.ts index 251d0adfd3d..10e2a474b77 100644 --- a/types.d.ts +++ b/types.d.ts @@ -5476,7 +5476,9 @@ declare class JavascriptParser extends Parser { evaluatedVariable(tagInfo?: any): VariableInfo; parseCommentOptions( range?: any - ): { options: null; errors: null } | { options: object; errors: unknown[] }; + ): + | { options: null; errors: null } + | { options: object; errors: { comment: any; cause: unknown }[] }; extractMemberExpressionChain(expression: MemberExpression): { members: string[]; object: From c922ee15690941ba54a4b47c11c77003c2815a7c Mon Sep 17 00:00:00 2001 From: Jack Works Date: Tue, 22 Nov 2022 12:03:27 +0800 Subject: [PATCH 10/20] chore: revert breaking change --- lib/dependencies/CommonJsImportsParserPlugin.js | 3 ++- lib/dependencies/ImportParserPlugin.js | 3 ++- lib/dependencies/WorkerPlugin.js | 3 ++- lib/javascript/JavascriptParser.js | 6 +++++- types.d.ts | 4 +--- 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/lib/dependencies/CommonJsImportsParserPlugin.js b/lib/dependencies/CommonJsImportsParserPlugin.js index 5a6e5faa4cd..e74e5c9743b 100644 --- a/lib/dependencies/CommonJsImportsParserPlugin.js +++ b/lib/dependencies/CommonJsImportsParserPlugin.js @@ -236,7 +236,8 @@ class CommonJsImportsParserPlugin { parser.parseCommentOptions(expr.range); if (commentErrors) { - for (const { cause: e, comment } of commentErrors) { + for (const e of commentErrors) { + const { comment } = e; parser.state.module.addWarning( new CommentCompilationWarning( `Compilation error while processing magic comment(-s): /*${comment.value}*/: ${e.message}`, diff --git a/lib/dependencies/ImportParserPlugin.js b/lib/dependencies/ImportParserPlugin.js index 3dc84bd83af..718b0482828 100644 --- a/lib/dependencies/ImportParserPlugin.js +++ b/lib/dependencies/ImportParserPlugin.js @@ -55,7 +55,8 @@ class ImportParserPlugin { parser.parseCommentOptions(expr.range); if (commentErrors) { - for (const { cause: e, comment } of commentErrors) { + for (const e of commentErrors) { + const { comment } = e; parser.state.module.addWarning( new CommentCompilationWarning( `Compilation error while processing magic comment(-s): /*${comment.value}*/: ${e.message}`, diff --git a/lib/dependencies/WorkerPlugin.js b/lib/dependencies/WorkerPlugin.js index a5a51a48154..5b68d84c06a 100644 --- a/lib/dependencies/WorkerPlugin.js +++ b/lib/dependencies/WorkerPlugin.js @@ -203,7 +203,8 @@ class WorkerPlugin { parser.parseCommentOptions(expr.range); if (commentErrors) { - for (const { cause: e, comment } of commentErrors) { + for (const e of commentErrors) { + const { comment } = e; parser.state.module.addWarning( new CommentCompilationWarning( `Compilation error while processing magic comment(-s): /*${comment.value}*/: ${e.message}`, diff --git a/lib/javascript/JavascriptParser.js b/lib/javascript/JavascriptParser.js index 780c2de03a7..61d3eafe470 100644 --- a/lib/javascript/JavascriptParser.js +++ b/lib/javascript/JavascriptParser.js @@ -3635,6 +3635,7 @@ class JavascriptParser extends Parser { return EMPTY_COMMENT_OPTIONS; } let options = {}; + /** @type {unknown[]} */ let errors = []; for (const comment of comments) { const { value } = comment; @@ -3651,7 +3652,10 @@ class JavascriptParser extends Parser { options[key] = val; } } catch (e) { - errors.push({ comment, cause: e }); + const newErr = new Error(String(e.message)); + newErr.stack = String(e.stack); + newErr.comment = comment; + errors.push(newErr); } } } diff --git a/types.d.ts b/types.d.ts index 10e2a474b77..251d0adfd3d 100644 --- a/types.d.ts +++ b/types.d.ts @@ -5476,9 +5476,7 @@ declare class JavascriptParser extends Parser { evaluatedVariable(tagInfo?: any): VariableInfo; parseCommentOptions( range?: any - ): - | { options: null; errors: null } - | { options: object; errors: { comment: any; cause: unknown }[] }; + ): { options: null; errors: null } | { options: object; errors: unknown[] }; extractMemberExpressionChain(expression: MemberExpression): { members: string[]; object: From 4f39c9f65878ef0f5db5754d73157f5f13d56352 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Tue, 22 Nov 2022 12:09:17 +0800 Subject: [PATCH 11/20] fix: type error --- lib/javascript/JavascriptParser.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/javascript/JavascriptParser.js b/lib/javascript/JavascriptParser.js index 61d3eafe470..58bcc4a64b3 100644 --- a/lib/javascript/JavascriptParser.js +++ b/lib/javascript/JavascriptParser.js @@ -3654,7 +3654,7 @@ class JavascriptParser extends Parser { } catch (e) { const newErr = new Error(String(e.message)); newErr.stack = String(e.stack); - newErr.comment = comment; + Object.assign(newErr, { comment }); errors.push(newErr); } } From 2112f9bc7d7659607f8dda22b31ed85f3adc3bb6 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Thu, 5 Jan 2023 10:50:51 -0800 Subject: [PATCH 12/20] Replace TypeScript logo in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c712d27fd7a..23c8a88f40a 100644 --- a/README.md +++ b/README.md @@ -161,7 +161,7 @@ or are automatically applied via regex from your webpack configuration. | Name | Status | Install Size | Description | | :--------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------: | :------------: | :------------------------------------------------------------------------------------------------ | | | ![babel-npm] | ![babel-size] | Loads ES2015+ code and transpiles to ES5 using Babel | -| | ![type-npm] | ![type-size] | Loads TypeScript like JavaScript | +| | ![type-npm] | ![type-size] | Loads TypeScript like JavaScript | | | ![coffee-npm] | ![coffee-size] | Loads CoffeeScript like JavaScript | [babel-npm]: https://img.shields.io/npm/v/babel-loader.svg From ea5e86459ecda94846804f7159d485a55dac9ca6 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Thu, 5 Jan 2023 10:59:27 -0800 Subject: [PATCH 13/20] Fix HTML5 logo in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c712d27fd7a..8dd012864ef 100644 --- a/README.md +++ b/README.md @@ -175,7 +175,7 @@ or are automatically applied via regex from your webpack configuration. | Name | Status | Install Size | Description | | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------: | :--------------: | :-------------------------------------------------------------------------------------- | -| | ![html-npm] | ![html-size] | Exports HTML as string, requires references to static resources | +| | ![html-npm] | ![html-size] | Exports HTML as string, requires references to static resources | | | ![pug-npm] | ![pug-size] | Loads Pug templates and returns a function | | | ![pug3-npm] | ![pug3-size] | Compiles Pug to a function or HTML string, useful for use with Vue, React, Angular | | | ![md-npm] | ![md-size] | Compiles Markdown to HTML | From 6011163450ae85c1d2d27ebb49aac211c75d7f01 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Thu, 5 Jan 2023 11:01:28 -0800 Subject: [PATCH 14/20] Fix formatting --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 23c8a88f40a..0d372c369af 100644 --- a/README.md +++ b/README.md @@ -158,11 +158,11 @@ or are automatically applied via regex from your webpack configuration. #### Transpiling -| Name | Status | Install Size | Description | -| :--------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------: | :------------: | :------------------------------------------------------------------------------------------------ | -| | ![babel-npm] | ![babel-size] | Loads ES2015+ code and transpiles to ES5 using Babel | -| | ![type-npm] | ![type-size] | Loads TypeScript like JavaScript | -| | ![coffee-npm] | ![coffee-size] | Loads CoffeeScript like JavaScript | +| Name | Status | Install Size | Description | +| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------: | :------------: | :------------------------------------------------------------------------------------------------ | +| | ![babel-npm] | ![babel-size] | Loads ES2015+ code and transpiles to ES5 using Babel | +| | ![type-npm] | ![type-size] | Loads TypeScript like JavaScript | +| | ![coffee-npm] | ![coffee-size] | Loads CoffeeScript like JavaScript | [babel-npm]: https://img.shields.io/npm/v/babel-loader.svg [babel-size]: https://packagephobia.com/badge?p=babel-loader From d957cdf918213857b71755c902621a4345ab3e90 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Thu, 5 Jan 2023 11:01:52 -0800 Subject: [PATCH 15/20] Fix formatting --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8dd012864ef..652a3898c00 100644 --- a/README.md +++ b/README.md @@ -175,7 +175,7 @@ or are automatically applied via regex from your webpack configuration. | Name | Status | Install Size | Description | | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------: | :--------------: | :-------------------------------------------------------------------------------------- | -| | ![html-npm] | ![html-size] | Exports HTML as string, requires references to static resources | +| | ![html-npm] | ![html-size] | Exports HTML as string, requires references to static resources | | | ![pug-npm] | ![pug-size] | Loads Pug templates and returns a function | | | ![pug3-npm] | ![pug3-size] | Compiles Pug to a function or HTML string, useful for use with Vue, React, Angular | | | ![md-npm] | ![md-size] | Compiles Markdown to HTML | From dcc3e7164eb8757effec79928181b88d79a9e7bf Mon Sep 17 00:00:00 2001 From: Ryan Wilson-Perkin Date: Tue, 7 Feb 2023 17:54:09 -0500 Subject: [PATCH 16/20] Serialize code generator data to support generated assets AssetGenerator calls out in a TODO-comment that the filename, assetInfo, and fullContentHash values must be captured in the 'data' object that's populated during code generation in order to be accessible in the AssetModulesPlugin. It notes that it must store them in the code generation results because it will be cached, but that appears to be incorrect as data is a simple Map that's instantiated within the NormalModule and not captured anywhere that would be cached. As a result, configurations that use the asset/resource type and make changes to assets between cached builds will result in a runtime error as Webpack is able to access the file from cache but isn't able to access the expected values from the data object. This solution captures the data object as a property of the NormalModule and hooks in to the existing serialize/deserialize functionality in order to make this value available across cached builds. --- lib/NormalModule.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/NormalModule.js b/lib/NormalModule.js index 4d1264f9b3c..3afa2336a61 100644 --- a/lib/NormalModule.js +++ b/lib/NormalModule.js @@ -330,6 +330,8 @@ class NormalModule extends Module { this._isEvaluatingSideEffects = false; /** @type {WeakSet | undefined} */ this._addedSideEffectsBailout = undefined; + /** @type {Map} */ + this._codeGeneratorData = new Map(); } /** @@ -1188,11 +1190,9 @@ class NormalModule extends Module { runtimeRequirements.add(RuntimeGlobals.thisAsExports); } - /** @type {Map} */ - let data; + /** @type {function(): Map} */ const getData = () => { - if (data === undefined) data = new Map(); - return data; + return this._codeGeneratorData; }; const sources = new Map(); @@ -1223,7 +1223,7 @@ class NormalModule extends Module { const resultEntry = { sources, runtimeRequirements, - data + data: this._codeGeneratorData, }; return resultEntry; } @@ -1371,6 +1371,7 @@ class NormalModule extends Module { write(this.error); write(this._lastSuccessfulBuildMeta); write(this._forceBuild); + write(this._codeGeneratorData); super.serialize(context); } @@ -1403,6 +1404,7 @@ class NormalModule extends Module { this.error = read(); this._lastSuccessfulBuildMeta = read(); this._forceBuild = read(); + this._codeGeneratorData = read(); super.deserialize(context); } } From dfaa3b401e2730d719c66fdd9652c0c3feda043b Mon Sep 17 00:00:00 2001 From: Ryan Wilson-Perkin Date: Tue, 7 Feb 2023 18:11:50 -0500 Subject: [PATCH 17/20] lint: remove trailing comma --- lib/NormalModule.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/NormalModule.js b/lib/NormalModule.js index 3afa2336a61..b3fababd63f 100644 --- a/lib/NormalModule.js +++ b/lib/NormalModule.js @@ -1223,7 +1223,7 @@ class NormalModule extends Module { const resultEntry = { sources, runtimeRequirements, - data: this._codeGeneratorData, + data: this._codeGeneratorData }; return resultEntry; } From 4d561a658020778d412367bb9744e5ca3007105b Mon Sep 17 00:00:00 2001 From: Ryan Wilson-Perkin Date: Thu, 16 Feb 2023 01:11:36 -0500 Subject: [PATCH 18/20] Add test for behaviour of filesystem-cached assets with loaders --- test/Compiler-filesystem-caching.test.js | 152 +++++++++++++++++++++++ test/fixtures/empty-svg-loader.js | 1 + test/fixtures/file.svg | 1 + test/fixtures/uses-asset.js | 1 + 4 files changed, 155 insertions(+) create mode 100644 test/Compiler-filesystem-caching.test.js create mode 100644 test/fixtures/empty-svg-loader.js create mode 100644 test/fixtures/file.svg create mode 100644 test/fixtures/uses-asset.js diff --git a/test/Compiler-filesystem-caching.test.js b/test/Compiler-filesystem-caching.test.js new file mode 100644 index 00000000000..cad5f679208 --- /dev/null +++ b/test/Compiler-filesystem-caching.test.js @@ -0,0 +1,152 @@ +"use strict"; + +require("./helpers/warmup-webpack"); + +const path = require("path"); +const fs = require("graceful-fs"); +const rimraf = require("rimraf"); + +let fixtureCount = 0; + +describe("Compiler (filesystem caching)", () => { + jest.setTimeout(5000); + + const tempFixturePath = path.join( + __dirname, + "fixtures", + "temp-filesystem-cache-fixture" + ); + + function compile(entry, onSuccess, onError) { + const webpack = require(".."); + const options = webpack.config.getNormalizedWebpackOptions({}); + options.cache = { + type: "filesystem", + cacheDirectory: path.join(tempFixturePath, "cache") + }; + options.entry = entry; + options.context = path.join(__dirname, "fixtures"); + options.output.path = path.join(tempFixturePath, "dist"); + options.output.filename = "bundle.js"; + options.output.pathinfo = true; + options.module = { + rules: [ + { + test: /\.svg$/, + type: "asset/resource", + use: { + loader: require.resolve("./fixtures/empty-svg-loader") + } + } + ] + }; + + function runCompiler(onSuccess, onError) { + const c = webpack(options); + c.hooks.compilation.tap( + "CompilerCachingTest", + compilation => (compilation.bail = true) + ); + c.run((err, stats) => { + if (err) throw err; + expect(typeof stats).toBe("object"); + stats = stats.toJson({ + modules: true, + reasons: true + }); + expect(typeof stats).toBe("object"); + expect(stats).toHaveProperty("errors"); + expect(Array.isArray(stats.errors)).toBe(true); + if (stats.errors.length > 0) { + onError(new Error(JSON.stringify(stats.errors, null, 4))); + } + c.close(() => { + onSuccess(stats); + }); + }); + } + + runCompiler(onSuccess, onError); + + return { + runAgain: runCompiler + }; + } + + function cleanup() { + rimraf.sync(`${tempFixturePath}*`); + } + + beforeAll(cleanup); + afterAll(cleanup); + + function createTempFixture() { + const fixturePath = `${tempFixturePath}-${fixtureCount}`; + const usesAssetFilepath = path.join(fixturePath, "uses-asset.js"); + const svgFilepath = path.join(fixturePath, "file.svg"); + + // Remove previous copy if present + rimraf.sync(fixturePath); + + // Copy over file since we"ll be modifying some of them + fs.mkdirSync(fixturePath); + fs.copyFileSync( + path.join(__dirname, "fixtures", "uses-asset.js"), + usesAssetFilepath + ); + fs.copyFileSync(path.join(__dirname, "fixtures", "file.svg"), svgFilepath); + + fixtureCount++; + return { + rootPath: fixturePath, + usesAssetFilepath: usesAssetFilepath, + svgFilepath: svgFilepath + }; + } + + it("should compile again when cached asset has changed but loader output remains the same", done => { + const tempFixture = createTempFixture(); + + const onError = error => done(error); + + const helper = compile( + tempFixture.usesAssetFilepath, + stats => { + // Not cached the first time + expect(stats.assets[0].name).toBe("bundle.js"); + expect(stats.assets[0].emitted).toBe(true); + + expect(stats.assets[1].name).toMatch(/\w+\.svg$/); + expect(stats.assets[0].emitted).toBe(true); + + helper.runAgain(stats => { + // Cached the second run + expect(stats.assets[0].name).toBe("bundle.js"); + expect(stats.assets[0].emitted).toBe(false); + + expect(stats.assets[1].name).toMatch(/\w+\.svg$/); + expect(stats.assets[0].emitted).toBe(false); + + const svgContent = fs + .readFileSync(tempFixture.svgFilepath) + .toString() + .replace("icon-square-small", "icon-square-smaller"); + + fs.writeFileSync(tempFixture.svgFilepath, svgContent); + + helper.runAgain(stats => { + // Still cached after file modification because loader always returns empty + expect(stats.assets[0].name).toBe("bundle.js"); + expect(stats.assets[0].emitted).toBe(false); + + expect(stats.assets[1].name).toMatch(/\w+\.svg$/); + expect(stats.assets[0].emitted).toBe(false); + + done(); + }, onError); + }, onError); + }, + onError + ); + }); +}); diff --git a/test/fixtures/empty-svg-loader.js b/test/fixtures/empty-svg-loader.js new file mode 100644 index 00000000000..0a599e7d5d6 --- /dev/null +++ b/test/fixtures/empty-svg-loader.js @@ -0,0 +1 @@ +module.exports = () => ""; diff --git a/test/fixtures/file.svg b/test/fixtures/file.svg new file mode 100644 index 00000000000..d7b7e40b4f8 --- /dev/null +++ b/test/fixtures/file.svg @@ -0,0 +1 @@ +icon-square-small diff --git a/test/fixtures/uses-asset.js b/test/fixtures/uses-asset.js new file mode 100644 index 00000000000..b3532c8b7fc --- /dev/null +++ b/test/fixtures/uses-asset.js @@ -0,0 +1 @@ +import SVG from './file.svg'; From cfdb1dfe59b33bf7441b8a8e4fc58d75e4f54cee Mon Sep 17 00:00:00 2001 From: Ryan Wilson-Perkin Date: Fri, 24 Feb 2023 16:17:15 -0500 Subject: [PATCH 19/20] Improve performance of hashRegExp lookup For applications with a very large number of assets, the cost of invoking a single regular expression with many many values in a group becomes very high. By changing to a list of regular expressions (with helper methods for maintaining the original design) we can get a large performance improvement. --- lib/optimize/RealContentHashPlugin.js | 58 ++++++++++++++++++++------- 1 file changed, 44 insertions(+), 14 deletions(-) diff --git a/lib/optimize/RealContentHashPlugin.js b/lib/optimize/RealContentHashPlugin.js index 7ab9c46fb8b..ba058b753a2 100644 --- a/lib/optimize/RealContentHashPlugin.js +++ b/lib/optimize/RealContentHashPlugin.js @@ -178,10 +178,43 @@ class RealContentHashPlugin { } } if (hashToAssets.size === 0) return; - const hashRegExp = new RegExp( - Array.from(hashToAssets.keys(), quoteMeta).join("|"), - "g" + const hashRegExps = Array.from(hashToAssets.keys(), quoteMeta).map( + hash => new RegExp(hash, "g") ); + + /** + * @param {string} str string to be matched against all hashRegExps + * @returns {string[] | null} matches found + */ + const hashMatch = str => { + /** @type {string[]} */ + const results = []; + for (const hashRegExp of hashRegExps) { + const matches = str.match(hashRegExp); + if (matches) { + matches.forEach(match => results.push(match)); + } + } + if (results.length) { + return results; + } else { + return null; + } + }; + + /** + * @param {string} str string to be replaced with all hashRegExps + * @param {function(string): string} fn replacement function to use when a hash is found + * @returns {string} replaced content + */ + const hashReplace = (str, fn) => { + let result = str; + for (const hashRegExp of hashRegExps) { + result = result.replace(hashRegExp, fn); + } + return result; + }; + await Promise.all( assetsWithInfo.map(async asset => { const { name, source, content, hashes } = asset; @@ -198,7 +231,7 @@ class RealContentHashPlugin { await cacheAnalyse.providePromise(name, etag, () => { const referencedHashes = new Set(); let ownHashes = new Set(); - const inContent = content.match(hashRegExp); + const inContent = hashMatch(content); if (inContent) { for (const hash of inContent) { if (hashes.has(hash)) { @@ -298,7 +331,7 @@ ${referencingAssets identifier, etag, () => { - const newContent = asset.content.replace(hashRegExp, hash => + const newContent = hashReplace(asset.content, hash => hashToNewHash.get(hash) ); return new RawSource(newContent); @@ -323,15 +356,12 @@ ${referencingAssets identifier, etag, () => { - const newContent = asset.content.replace( - hashRegExp, - hash => { - if (asset.ownHashes.has(hash)) { - return ""; - } - return hashToNewHash.get(hash); + const newContent = hashReplace(asset.content, hash => { + if (asset.ownHashes.has(hash)) { + return ""; } - ); + return hashToNewHash.get(hash); + }); return new RawSource(newContent); } ); @@ -374,7 +404,7 @@ ${referencingAssets await Promise.all( assetsWithInfo.map(async asset => { await computeNewContent(asset); - const newName = asset.name.replace(hashRegExp, hash => + const newName = hashReplace(asset.name, hash => hashToNewHash.get(hash) ); From 5f34acfbc074da6cc09f48944d7f2b4273ffb3f8 Mon Sep 17 00:00:00 2001 From: Adam Skoufis Date: Tue, 7 Mar 2023 09:39:54 +1100 Subject: [PATCH 20/20] feat: Add `target` to `LoaderContext` type --- declarations/LoaderContext.d.ts | 6 ++++++ types.d.ts | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/declarations/LoaderContext.d.ts b/declarations/LoaderContext.d.ts index 3e9341423a7..f93a0890d2d 100644 --- a/declarations/LoaderContext.d.ts +++ b/declarations/LoaderContext.d.ts @@ -212,6 +212,12 @@ export interface LoaderRunnerLoaderContext { * Example: "/abc/resource.js?query#frag" */ resource: string; + + /** + * Target of compilation. + * Example: "web" + */ + target: string; } type AdditionalData = { diff --git a/types.d.ts b/types.d.ts index 251d0adfd3d..78da415cff2 100644 --- a/types.d.ts +++ b/types.d.ts @@ -6595,6 +6595,12 @@ declare interface LoaderRunnerLoaderContext { * Example: "/abc/resource.js?query#frag" */ resource: string; + + /** + * Target of compilation. + * Example: "web" + */ + target: string; } declare class LoaderTargetPlugin { constructor(target: string);