Skip to content

Commit

Permalink
fix: when using integrity occurs ERROR in RealContentHashPlugin in se…
Browse files Browse the repository at this point in the history
…rv/watch mode after changes by using dynamic import
  • Loading branch information
webdiscus committed Aug 13, 2024
1 parent 1aca813 commit d245481
Show file tree
Hide file tree
Showing 13 changed files with 173 additions and 32 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Change log

## 4.0.0-beta.1 (2024-08-13)

- fix: when using integrity occurs ERROR in RealContentHashPlugin in serv/watch mode after changes by using dynamic import

## 4.0.0-beta.0 (2024-08-10)

### BREAKING CHANGES
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
</h1>
</div>

[![npm](https://img.shields.io/npm/v/html-bundler-webpack-plugin?logo=npm&color=brightgreen 'npm package')](https://www.npmjs.com/package/html-bundler-webpack-plugin 'download npm package')
[![npm](https://img.shields.io/npm/v/html-bundler-webpack-plugin?logo=npm&color=brightgreen 'npm package')](https://www.npmjs.com/package/html-bundler-webpack-plugin/v/4.0.0-beta.1 'download npm package')
[![node](https://img.shields.io/node/v/html-bundler-webpack-plugin)](https://nodejs.org)
[![node](https://img.shields.io/github/package-json/dependency-version/webdiscus/html-bundler-webpack-plugin/peer/webpack)](https://webpack.js.org/)
[![Test](https://github.com/webdiscus/html-bundler-webpack-plugin/actions/workflows/test.yml/badge.svg)](https://github.com/webdiscus/html-bundler-webpack-plugin/actions/workflows/test.yml)
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "html-bundler-webpack-plugin",
"version": "4.0.0-beta.0",
"version": "4.0.0-beta.1",
"description": "HTML bundler plugin for webpack handles a template as an entry point, extracts CSS and JS from their sources referenced in HTML, supports template engines like Eta, EJS, Handlebars, Nunjucks.",
"keywords": [
"html",
Expand Down
63 changes: 36 additions & 27 deletions src/Plugin/Extras/Integrity.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ class Integrity {

this.options = options;
this.chunkChildChunksMap = new WeakMap();
this.referencePlaceholders = new Map();
this.placeholderByChunkId = new Map();
this.chunkByChunkId = new Map();
this.templateByChunkId = new Map();
this.placeholderByChunkId = new Map();
}

apply(compiler) {
Expand Down Expand Up @@ -69,12 +69,12 @@ class Integrity {
this.isRealContentHash = this.options.isRealContentHash();

// dynamically import a JS file
mainTemplate.hooks.jsonpScript.tap(pluginName, (source) => this.addReference('script', source));
mainTemplate.hooks.linkPreload.tap(pluginName, (source) => this.addReference('link', source));
mainTemplate.hooks.localVars.tap(pluginName, this.setReferencePlaceholder.bind(this));
mainTemplate.hooks.jsonpScript.tap(pluginName, (source) => this.getTemplateByTag('script', source));
mainTemplate.hooks.linkPreload.tap(pluginName, (source) => this.getTemplateByTag('link', source));
mainTemplate.hooks.localVars.tap(pluginName, this.getTemplateByChunk.bind(this));

compilation.hooks.beforeRuntimeRequirements.tap(pluginName, () => {
this.placeholderByChunkId.clear();
// note: don't clear the cached placeholderByChunkId
});

compilation.hooks.processAssets.tap(
Expand Down Expand Up @@ -134,6 +134,7 @@ class Integrity {
}

// TODO: find the use case when childChunk.files.size > 1
// the size of childChunk.files is always 1
const childChunkFile = [...childChunk.files][0];
const placeholder = this.placeholderByChunkId.get(childChunk.id);

Expand All @@ -143,16 +144,22 @@ class Integrity {
childChunkFile,
(source) => source,
(assetInfo) => {
return assetInfo
? {
...assetInfo,
contenthash: Array.isArray(assetInfo.contenthash)
? [...new Set([...assetInfo.contenthash, placeholder])]
: assetInfo.contenthash
? [...new Set([assetInfo.contenthash, placeholder])]
: placeholder,
}
: undefined;
if (!assetInfo) {
return undefined;
}

let contenthash = placeholder;

if (Array.isArray(assetInfo.contenthash)) {
contenthash = [...new Set([...assetInfo.contenthash, placeholder])];
} else if (assetInfo.contenthash) {
contenthash = [...new Set([assetInfo.contenthash, placeholder])];
}

return {
...assetInfo,
contenthash,
};
}
);
} else {
Expand All @@ -172,13 +179,13 @@ class Integrity {
}

/**
* Add the reference of integrity hashes into a tag object.
* Create the integrity template by the tag.
*
* @param {string} tagName
* @param {string} source
* @return {string}
*/
addReference = (tagName, source) => {
getTemplateByTag = (tagName, source) => {
const { compilation, pluginName } = this;
const { Template } = compilation.compiler.webpack;
const { crossOriginLoading } = compilation.outputOptions;
Expand All @@ -191,19 +198,21 @@ class Integrity {
};

/**
* Set the placeholder in the hash reference using the hash of a chunk file.
* Create the integrity template by the chunk.
*
* Saves the placeholder in the hash reference using the hash of a chunk file.
* When the asset is processed, the placeholder will be replaced
* with real integrity hash of the processed asset.
*
* @param {string} source
* @param {Chunk} chunk
* @return {string}
*/
setReferencePlaceholder(source, chunk) {
getTemplateByChunk(source, chunk) {
const { Template } = this.compilation.compiler.webpack;

if (this.referencePlaceholders.has(chunk.id)) {
return this.referencePlaceholders.get(chunk.id);
if (this.templateByChunkId.has(chunk.id)) {
return this.templateByChunkId.get(chunk.id);
}

const childChunks = chunk.getAllAsyncChunks();
Expand All @@ -218,10 +227,10 @@ class Integrity {
}

if (Object.keys(placeholders).length > 0) {
const refTemplate = Template.asString([source, `${hashesReference} = ${JSON.stringify(placeholders)};`]);
this.referencePlaceholders.set(chunk.id, refTemplate);
const template = Template.asString([source, `${hashesReference} = ${JSON.stringify(placeholders)};`]);
this.templateByChunkId.set(chunk.id, template);

return refTemplate;
return template;
}

return source;
Expand Down Expand Up @@ -320,10 +329,10 @@ class Integrity {
*/
const getPlaceholder = (chunkId) => {
// the prefix must be exact 7 chars, the same length as a hash function name, e.g. 'sha256-'
const placeholderPrefix = '___TMP-';
const prefix = 'xxxxxx-';
const hash = Integrity.computeIntegrity(chunkId);

return placeholderPrefix + hash.slice(placeholderPrefix.length);
return prefix + hash.slice(prefix.length);
};

module.exports = Integrity;
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<title>Dev</title>
<!-- load source script -->
<link href="main.css" rel="stylesheet" integrity="sha384-P3uRZYJvNVccCqk2iQVGvwDZOYfrwSq1FHv6Ahsf4lBoPPD3ODc0xdEdeom27+CM" crossorigin="anonymous">
<script src="main.6180b06e.js" defer="defer" integrity="sha384-Z4FhgIhPOjwFF+fQqBxQN+0fSOAaqGSti1rzQNtVlipdTz8Ruwa+NFI68hsRe75h" crossorigin="anonymous"></script>
<script src="main.b2802b44.js" defer="defer" integrity="sha384-0oaEWvg3ko+CNViLGy2MgqEQe65Jbi+2m0/2Q0Mmx5UOsruQcchdOezxnn1odKxD" crossorigin="anonymous"></script>
</head>
<body>
<h1>Hello World!</h1>
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit d245481

Please sign in to comment.