Skip to content

Commit 82d0ee8

Browse files
sibiraj-sjantimon
authored andcommitted
fix: remove loader-utils from plugin core
1 parent 6f39192 commit 82d0ee8

File tree

4 files changed

+74
-51
lines changed

4 files changed

+74
-51
lines changed

README.md

+3-9
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,7 @@ which will inject the element `<base href="http://example.com/some/page.html" ta
464464

465465
### Long Term Caching
466466

467-
For long term caching add `contenthash/templatehash` to the filename.
467+
For long term caching add `contenthash` to the filename.
468468

469469
**Example:**
470470

@@ -476,15 +476,9 @@ plugins: [
476476
]
477477
```
478478

479-
`contenthash/templatehash` is the hash of the content of the output file.
479+
`contenthash` is the hash of the content of the output file.
480480

481-
Optionally, You can configure like `[<hashType>:contenthash:<digestType>:<length>]`
482-
483-
* `hashType` - one of `sha1`, `md5`, `sha256`, `sha512` or any other node.js supported hash type
484-
* `digestType` - one of `hex`, `base26`, `base32`, `base36`, `base49`, `base52`, `base58`, `base62`, `base64`
485-
* `maxlength` - maximum length of the generated hash in chars
486-
487-
**Defaults:** `[md5:contenthash:hex:9999]`
481+
Refer webpack's [Template Strings](https://webpack.js.org/configuration/output/#template-strings) for more details
488482

489483
### Events
490484

index.js

+47-34
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ const vm = require('vm');
1414
const fs = require('fs');
1515
const _ = require('lodash');
1616
const path = require('path');
17-
const loaderUtils = require('loader-utils');
1817
const { CachedChildCompilation } = require('./lib/cached-child-compiler');
1918

2019
const { createHtmlTagObject, htmlTagObjectToString, HtmlTagArray } = require('./lib/html-tags');
@@ -132,8 +131,7 @@ class HtmlWebpackPlugin {
132131
...global,
133132
HTML_WEBPACK_PLUGIN: true,
134133
require: require,
135-
htmlWebpackPluginPublicPath:
136-
publicPath,
134+
htmlWebpackPluginPublicPath: publicPath,
137135
URL: require('url').URL,
138136
__filename: templateWithoutLoaders
139137
});
@@ -189,13 +187,6 @@ function hookIntoCompiler (compiler, options, plugin) {
189187
options.filename = path.relative(outputPath, filename);
190188
}
191189

192-
// `contenthash` is introduced in webpack v4.3
193-
// which conflicts with the plugin's existing `contenthash` method,
194-
// hence it is renamed to `templatehash` to avoid conflicts
195-
options.filename = options.filename.replace(/\[(?:(\w+):)?contenthash(?::([a-z]+\d*))?(?::(\d+))?\]/ig, (match) => {
196-
return match.replace('contenthash', 'templatehash');
197-
});
198-
199190
// Check if webpack is running in production mode
200191
// @see https://github.com/webpack/webpack/blob/3366421f1784c449f415cda5930a8e445086f688/lib/WebpackOptionsDefaulter.js#L12-L14
201192
const isProductionLikeMode = compiler.options.mode === 'production' || !compiler.options.mode;
@@ -249,21 +240,12 @@ function hookIntoCompiler (compiler, options, plugin) {
249240
compilation.errors.push(prettyError(templateResult.error, compiler.context).toString());
250241
}
251242

252-
const compiledEntries = 'compiledEntry' in templateResult ? {
253-
hash: templateResult.compiledEntry.hash,
254-
chunk: templateResult.compiledEntry.entry
255-
} : {
256-
hash: templateResult.mainCompilationHash
257-
};
258-
259-
const childCompilationOutputName = compilation.getAssetPath(options.filename, compiledEntries);
260-
261243
// If the child compilation was not executed during a previous main compile run
262244
// it is a cached result
263245
const isCompilationCached = templateResult.mainCompilationHash !== compilation.hash;
264246

265247
/** The public path used inside the html file */
266-
const htmlPublicPath = getPublicPath(compilation, childCompilationOutputName, options.publicPath);
248+
const htmlPublicPath = getPublicPath(compilation, options.filename, options.publicPath);
267249

268250
/** Generated file paths from the entry point names */
269251
const assets = htmlWebpackPluginAssets(compilation, sortedEntryNames, htmlPublicPath);
@@ -288,7 +270,7 @@ function hookIntoCompiler (compiler, options, plugin) {
288270
assets.favicon = faviconPath;
289271
return getHtmlWebpackPluginHooks(compilation).beforeAssetTagGeneration.promise({
290272
assets: assets,
291-
outputName: childCompilationOutputName,
273+
outputName: options.filename,
292274
plugin: plugin
293275
});
294276
});
@@ -306,7 +288,7 @@ function hookIntoCompiler (compiler, options, plugin) {
306288
...generateFaviconTags(assets.favicon)
307289
]
308290
},
309-
outputName: childCompilationOutputName,
291+
outputName: options.filename,
310292
publicPath: htmlPublicPath,
311293
plugin: plugin
312294
}))
@@ -320,7 +302,7 @@ function hookIntoCompiler (compiler, options, plugin) {
320302
return getHtmlWebpackPluginHooks(compilation).alterAssetTagGroups.promise({
321303
headTags: assetGroups.headTags,
322304
bodyTags: assetGroups.bodyTags,
323-
outputName: childCompilationOutputName,
305+
outputName: options.filename,
324306
publicPath: htmlPublicPath,
325307
plugin: plugin
326308
});
@@ -351,7 +333,7 @@ function hookIntoCompiler (compiler, options, plugin) {
351333
const injectedHtmlPromise = Promise.all([assetTagGroupsPromise, templateExectutionPromise])
352334
// Allow plugins to change the html before assets are injected
353335
.then(([assetTags, html]) => {
354-
const pluginArgs = { html, headTags: assetTags.headTags, bodyTags: assetTags.bodyTags, plugin: plugin, outputName: childCompilationOutputName };
336+
const pluginArgs = { html, headTags: assetTags.headTags, bodyTags: assetTags.bodyTags, plugin: plugin, outputName: options.filename };
355337
return getHtmlWebpackPluginHooks(compilation).afterTemplateExecution.promise(pluginArgs);
356338
})
357339
.then(({ html, headTags, bodyTags }) => {
@@ -361,7 +343,7 @@ function hookIntoCompiler (compiler, options, plugin) {
361343
const emitHtmlPromise = injectedHtmlPromise
362344
// Allow plugins to change the html after assets are injected
363345
.then((html) => {
364-
const pluginArgs = { html, plugin: plugin, outputName: childCompilationOutputName };
346+
const pluginArgs = { html, plugin: plugin, outputName: options.filename };
365347
return getHtmlWebpackPluginHooks(compilation).beforeEmit.promise(pluginArgs)
366348
.then(result => result.html);
367349
})
@@ -372,16 +354,15 @@ function hookIntoCompiler (compiler, options, plugin) {
372354
return options.showErrors ? prettyError(err, compiler.context).toHtml() : 'ERROR';
373355
})
374356
.then(html => {
375-
// Allow to use [templatehash] as placeholder for the html-webpack-plugin name
376-
// See also https://survivejs.com/webpack/optimizing/adding-hashes-to-filenames/
377-
// From https://github.com/webpack-contrib/extract-text-webpack-plugin/blob/8de6558e33487e7606e7cd7cb2adc2cccafef272/src/index.js#L212-L214
378-
const finalOutputName = childCompilationOutputName.replace(/\[(?:(\w+):)?templatehash(?::([a-z]+\d*))?(?::(\d+))?\]/ig, (_, hashType, digestType, maxLength) => {
379-
return loaderUtils.getHashDigest(Buffer.from(html, 'utf8'), hashType, digestType, parseInt(maxLength, 10));
380-
});
357+
const filename = options.filename.replace(/\[templatehash([^\]]*)\]/g, require('util').deprecate(
358+
(match, options) => `[contenthash${options}]`,
359+
'[templatehash] is now [contenthash]')
360+
);
361+
const replacedFilename = replacePlaceholdersInFilename(filename, html, compilation);
381362
// Add the evaluated html code to the webpack assets
382-
compilation.emitAsset(finalOutputName, new webpack.sources.RawSource(html, false));
383-
previousEmittedAssets.push({ name: finalOutputName, html });
384-
return finalOutputName;
363+
compilation.emitAsset(replacedFilename.path, new webpack.sources.RawSource(html, false), replacedFilename.info);
364+
previousEmittedAssets.push({ name: replacedFilename.path, html });
365+
return replacedFilename.path;
385366
})
386367
.then((finalOutputName) => getHtmlWebpackPluginHooks(compilation).afterEmit.promise({
387368
outputName: finalOutputName,
@@ -519,6 +500,38 @@ function hookIntoCompiler (compiler, options, plugin) {
519500
});
520501
}
521502

503+
/**
504+
* Replace [contenthash] in filename
505+
*
506+
* @see https://survivejs.com/webpack/optimizing/adding-hashes-to-filenames/
507+
*
508+
* @param {string} filename
509+
* @param {string|Buffer} fileContent
510+
* @param {WebpackCompilation} compilation
511+
* @returns {{ path: string, info: {} }}
512+
*/
513+
function replacePlaceholdersInFilename (filename, fileContent, compilation) {
514+
if (/\[\\*([\w:]+)\\*\]/i.test(filename) === false) {
515+
return { path: filename, info: {} };
516+
}
517+
const hash = compiler.webpack.util.createHash(compilation.outputOptions.hashFunction);
518+
hash.update(fileContent);
519+
if (compilation.outputOptions.hashSalt) {
520+
hash.update(compilation.outputOptions.hashSalt);
521+
}
522+
const contentHash = hash.digest(compilation.outputOptions.hashDigest).slice(0, compilation.outputOptions.hashDigestLength);
523+
return compilation.getPathWithInfo(
524+
filename,
525+
{
526+
contentHash,
527+
chunk: {
528+
hash: contentHash,
529+
contentHash
530+
}
531+
}
532+
);
533+
}
534+
522535
/**
523536
* Helper to sort chunks
524537
* @param {string[]} entryNames

package.json

+2-3
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
]
2929
},
3030
"devDependencies": {
31-
"@types/loader-utils": "2.0.1",
3231
"@types/node": "11.13.9",
3332
"commitizen": "4.2.1",
3433
"css-loader": "5.0.1",
@@ -45,9 +44,9 @@
4544
"standard-version": "9.1.0",
4645
"style-loader": "2.0.0",
4746
"typescript": "4.1.3",
48-
"webpack": "5.23.0",
47+
"webpack": "5.24.3",
4948
"webpack-recompilation-simulator": "3.2.0",
50-
"webpack-cli": "4.2.0"
49+
"webpack-cli": "4.5.0"
5150
},
5251
"dependencies": {
5352
"@types/html-minifier-terser": "^5.0.0",

spec/basic.spec.js

+22-5
Original file line numberDiff line numberDiff line change
@@ -951,7 +951,24 @@ describe('HtmlWebpackPlugin', () => {
951951
}, ['<script defer="defer" src="index_bundle.js"'], /test-\S+\.html$/, done);
952952
});
953953

954-
it('should allow filename in the format of [<hashType>:contenthash:<digestType>:<length>]', done => {
954+
it('should work with hash options provided in output options', done => {
955+
testHtmlPlugin({
956+
mode: 'production',
957+
entry: {
958+
index: path.join(__dirname, 'fixtures/index.js')
959+
},
960+
output: {
961+
path: OUTPUT_DIR,
962+
filename: '[name]_bundle.js',
963+
hashDigestLength: 16
964+
},
965+
plugins: [
966+
new HtmlWebpackPlugin({ filename: 'index.[contenthash].html' })
967+
]
968+
}, [], /index\.[a-z0-9]{16}\.html/, done);
969+
});
970+
971+
it('should allow filename in the format of [contenthash:<length>]', done => {
955972
testHtmlPlugin({
956973
mode: 'production',
957974
entry: {
@@ -962,9 +979,9 @@ describe('HtmlWebpackPlugin', () => {
962979
filename: '[name]_bundle.js'
963980
},
964981
plugins: [
965-
new HtmlWebpackPlugin({ filename: 'index.[sha256:contenthash:base32:32].html' })
982+
new HtmlWebpackPlugin({ filename: 'index.[contenthash:4].html' })
966983
]
967-
}, [], /index\.[a-z0-9]{32}\.html/, done);
984+
}, [], /index\.[a-z0-9]{4}\.html/, done);
968985
});
969986

970987
it('will replace [contenthash] in the filename with a content hash of 32 hex characters', done => {
@@ -980,7 +997,7 @@ describe('HtmlWebpackPlugin', () => {
980997
plugins: [
981998
new HtmlWebpackPlugin({ filename: 'index.[contenthash].html' })
982999
]
983-
}, [], /index\.[a-f0-9]{32}\.html/, done);
1000+
}, [], /index\.[a-f0-9]{20}\.html/, done);
9841001
});
9851002

9861003
it('will replace [templatehash] in the filename with a content hash of 32 hex characters', done => {
@@ -996,7 +1013,7 @@ describe('HtmlWebpackPlugin', () => {
9961013
plugins: [
9971014
new HtmlWebpackPlugin({ filename: 'index.[templatehash].html' })
9981015
]
999-
}, [], /index\.[a-f0-9]{32}\.html/, done);
1016+
}, [], /index\.[a-f0-9]{20}\.html/, done);
10001017
});
10011018

10021019
it('allows you to use an absolute output filename', done => {

0 commit comments

Comments
 (0)