diff --git a/lib/plugins/manifest.js b/lib/plugins/manifest.js index 3cc70cbe..38fb025f 100644 --- a/lib/plugins/manifest.js +++ b/lib/plugins/manifest.js @@ -10,7 +10,7 @@ 'use strict'; const WebpackConfig = require('../WebpackConfig'); //eslint-disable-line no-unused-vars -const { WebpackManifestPlugin } = require('../webpack-manifest-plugin'); +const { WebpackManifestPlugin } = require('webpack-manifest-plugin'); const PluginPriorities = require('./plugin-priorities'); const applyOptionsCallback = require('../utils/apply-options-callback'); const copyEntryTmpName = require('../utils/copyEntryTmpName'); @@ -33,7 +33,15 @@ module.exports = function(plugins, webpackConfig) { const isJsOrJsMapFile = /\.js(\.map)?$/.test(file.name); return !isCopyEntry && !(isStyleEntry && isJsOrJsMapFile); - } + }, + map: (file) => { + if (webpackConfig.useVersioning) { + // Remove hash in manifest key + file.name = file.name.replace(/(\.[a-f0-9]{8})(\..*)$/, '$2'); + } + + return file; + }, }; manifestPluginOptions = applyOptionsCallback( diff --git a/lib/webpack-manifest-plugin/LICENSE b/lib/webpack-manifest-plugin/LICENSE deleted file mode 100644 index e540a67b..00000000 --- a/lib/webpack-manifest-plugin/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) Dane Thurber - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/lib/webpack-manifest-plugin/README.md b/lib/webpack-manifest-plugin/README.md deleted file mode 100644 index ea088324..00000000 --- a/lib/webpack-manifest-plugin/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# webpack-manifest-plugin - -This is a copy of https://github.com/shellscape/webpack-manifest-plugin -at sha: 9f408f609d9b1af255491036b6fc127777ee6f9a. - -It has been modified to fix this bug: https://github.com/shellscape/webpack-manifest-plugin/pull/249 diff --git a/lib/webpack-manifest-plugin/helpers.js b/lib/webpack-manifest-plugin/helpers.js deleted file mode 100644 index 0d53a854..00000000 --- a/lib/webpack-manifest-plugin/helpers.js +++ /dev/null @@ -1,115 +0,0 @@ -const { dirname, join, basename } = require('path'); - -const generateManifest = (compilation, files, { generate, seed = {} }) => { - let result; - if (generate) { - const entrypointsArray = Array.from(compilation.entrypoints.entries()); - const entrypoints = entrypointsArray.reduce( - (e, [name, entrypoint]) => Object.assign(e, { [name]: entrypoint.getFiles() }), - {} - ); - result = generate(seed, files, entrypoints); - } else { - result = files.reduce( - (manifest, file) => Object.assign(manifest, { [file.name]: file.path }), - seed - ); - } - - return result; -}; - -const getFileType = (fileName, { transformExtensions }) => { - const replaced = fileName.replace(/\?.*/, ''); - const split = replaced.split('.'); - const extension = split.pop(); - return transformExtensions.test(extension) ? `${split.pop()}.${extension}` : extension; -}; - -const reduceAssets = (files, asset, moduleAssets) => { - let name; - if (moduleAssets[asset.name]) { - name = moduleAssets[asset.name]; - } else if (asset.info.sourceFilename) { - name = join(dirname(asset.name), basename(asset.info.sourceFilename)); - } - - if (name) { - return files.concat({ - path: asset.name, - name, - isInitial: false, - isChunk: false, - isAsset: true, - isModuleAsset: true - }); - } - - const isEntryAsset = asset.chunks && asset.chunks.length > 0; - if (isEntryAsset) { - return files; - } - - return files.concat({ - path: asset.name, - name: asset.name, - isInitial: false, - isChunk: false, - isAsset: true, - isModuleAsset: false - }); -}; - -const reduceChunk = (files, chunk, options, auxiliaryFiles) => { - // auxiliary files contain things like images, fonts AND, most - // importantly, other files like .map sourcemap files - // we modify the auxiliaryFiles so that we can add any of these - // to the manifest that was not added by another method - // (sourcemaps files are not added via any other method) - Array.from(chunk.auxiliaryFiles || []).forEach((auxiliaryFile) => { - auxiliaryFiles[auxiliaryFile] = { - path: auxiliaryFile, - name: basename(auxiliaryFile), - isInitial: false, - isChunk: false, - isAsset: true, - isModuleAsset: true - }; - }); - - return Array.from(chunk.files).reduce((prev, path) => { - let name = chunk.name ? chunk.name : null; - // chunk name, or for nameless chunks, just map the files directly. - name = name - ? options.useEntryKeys && !path.endsWith('.map') - ? name - : `${name}.${getFileType(path, options)}` - : path; - - return prev.concat({ - path, - chunk, - name, - isInitial: chunk.isOnlyInitial(), - isChunk: true, - isAsset: false, - isModuleAsset: false - }); - }, files); -}; - -const standardizeFilePaths = (file) => { - const result = Object.assign({}, file); - result.name = file.name.replace(/\\/g, '/'); - result.path = file.path.replace(/\\/g, '/'); - return result; -}; - -const transformFiles = (files, options) => - ['filter', 'map', 'sort'] - .filter((fname) => !!options[fname]) - // TODO: deprecate these - .reduce((prev, fname) => prev[fname](options[fname]), files) - .map(standardizeFilePaths); - -module.exports = { generateManifest, reduceAssets, reduceChunk, transformFiles }; diff --git a/lib/webpack-manifest-plugin/hooks.js b/lib/webpack-manifest-plugin/hooks.js deleted file mode 100644 index c257856a..00000000 --- a/lib/webpack-manifest-plugin/hooks.js +++ /dev/null @@ -1,145 +0,0 @@ -const { mkdirSync, writeFileSync } = require('fs'); -const { basename, dirname, join } = require('path'); - -const { SyncWaterfallHook } = require('tapable'); -const webpack = require('webpack'); -// eslint-disable-next-line global-require -const { RawSource } = webpack.sources || require('webpack-sources'); - -const { generateManifest, reduceAssets, reduceChunk, transformFiles } = require('./helpers'); - -const compilerHookMap = new WeakMap(); - -const getCompilerHooks = (compiler) => { - let hooks = compilerHookMap.get(compiler); - if (typeof hooks === 'undefined') { - hooks = { - afterEmit: new SyncWaterfallHook(['manifest']), - beforeEmit: new SyncWaterfallHook(['manifest']) - }; - compilerHookMap.set(compiler, hooks); - } - return hooks; -}; - -const beforeRunHook = ({ emitCountMap, manifestFileName }, compiler, callback) => { - const emitCount = emitCountMap.get(manifestFileName) || 0; - emitCountMap.set(manifestFileName, emitCount + 1); - - /* istanbul ignore next */ - if (callback) { - callback(); - } -}; - -const emitHook = function emit( - { compiler, emitCountMap, manifestAssetId, manifestFileName, moduleAssets, options }, - compilation -) { - const emitCount = emitCountMap.get(manifestFileName) - 1; - // Disable everything we don't use, add asset info, show cached assets - const stats = compilation.getStats().toJson({ - all: false, - assets: true, - cachedAssets: true, - ids: true, - publicPath: true - }); - - const publicPath = options.publicPath !== null ? options.publicPath : stats.publicPath; - const { basePath, removeKeyHash } = options; - - emitCountMap.set(manifestFileName, emitCount); - - const auxiliaryFiles = {}; - let files = Array.from(compilation.chunks).reduce( - (prev, chunk) => reduceChunk(prev, chunk, options, auxiliaryFiles), - [] - ); - - // module assets don't show up in assetsByChunkName, we're getting them this way - files = stats.assets.reduce((prev, asset) => reduceAssets(prev, asset, moduleAssets), files); - - // don't add hot updates and don't add manifests from other instances - files = files.filter( - ({ name, path }) => - !path.includes('hot-update') && - typeof emitCountMap.get(join(compiler.options.output.path, name)) === 'undefined' - ); - - // auxiliary files are "extra" files that are probably already included - // in other ways. Loop over files and remove any from auxiliaryFiles - files.forEach((file) => { - delete auxiliaryFiles[file.path]; - }); - // if there are any auxiliaryFiles left, add them to the files - // this handles, specifically, sourcemaps - Object.keys(auxiliaryFiles).forEach((auxiliaryFile) => { - files = files.concat(auxiliaryFiles[auxiliaryFile]); - }); - - files = files.map((file) => { - const changes = { - // Append optional basepath onto all references. This allows output path to be reflected in the manifest. - name: basePath ? basePath + file.name : file.name, - // Similar to basePath but only affects the value (e.g. how output.publicPath turns - // require('foo/bar') into '/public/foo/bar', see https://github.com/webpack/docs/wiki/configuration#outputpublicpath - path: publicPath ? publicPath + file.path : file.path - }; - - // Fixes #210 - changes.name = removeKeyHash ? changes.name.replace(removeKeyHash, '') : changes.name; - - return Object.assign(file, changes); - }); - - files = transformFiles(files, options); - - let manifest = generateManifest(compilation, files, options); - const isLastEmit = emitCount === 0; - - manifest = getCompilerHooks(compiler).beforeEmit.call(manifest); - - if (isLastEmit) { - const output = options.serialize(manifest); - // - // Object.assign(compilation.assets, { - // [manifestAssetId]: { - // source() { - // return output; - // }, - // size() { - // return output.length; - // } - // } - // }); - // - compilation.emitAsset(manifestAssetId, new RawSource(output)); - - if (options.writeToFileEmit) { - mkdirSync(dirname(manifestFileName), { recursive: true }); - writeFileSync(manifestFileName, output); - } - } - - getCompilerHooks(compiler).afterEmit.call(manifest); -}; - -const normalModuleLoaderHook = ({ moduleAssets }, loaderContext, module) => { - const { emitFile } = loaderContext; - - // eslint-disable-next-line no-param-reassign - loaderContext.emitFile = (file, content, sourceMap, assetInfo) => { - const info = Object.assign({}, assetInfo); - - if (module.userRequest && !moduleAssets[file]) { - info.sourceFilename = join(dirname(file), basename(module.userRequest)); - - Object.assign(moduleAssets, { [file]: info.sourceFilename }); - } - - return emitFile.call(module, file, content, sourceMap, info); - }; -}; - -module.exports = { beforeRunHook, emitHook, getCompilerHooks, normalModuleLoaderHook }; diff --git a/lib/webpack-manifest-plugin/index.js b/lib/webpack-manifest-plugin/index.js deleted file mode 100644 index 189266b1..00000000 --- a/lib/webpack-manifest-plugin/index.js +++ /dev/null @@ -1,73 +0,0 @@ -const { relative, resolve } = require('path'); - -const webpack = require('webpack'); -const NormalModule = require('webpack/lib/NormalModule'); - -const { beforeRunHook, emitHook, getCompilerHooks, normalModuleLoaderHook } = require('./hooks'); - -const emitCountMap = new Map(); - -const defaults = { - basePath: '', - fileName: 'manifest.json', - filter: null, - generate: void 0, - map: null, - publicPath: null, - removeKeyHash: /([a-f0-9]{32}\.?)/gi, - // seed must be reset for each compilation. let the code initialize it to {} - seed: void 0, - serialize(manifest) { - return JSON.stringify(manifest, null, 2); - }, - sort: null, - transformExtensions: /^(gz|map)$/i, - useEntryKeys: false, - writeToFileEmit: false -}; - -class WebpackManifestPlugin { - constructor(opts) { - this.options = Object.assign({}, defaults, opts); - } - - apply(compiler) { - const moduleAssets = {}; - const manifestFileName = resolve(compiler.options.output.path, this.options.fileName); - const manifestAssetId = relative(compiler.options.output.path, manifestFileName); - const beforeRun = beforeRunHook.bind(this, { emitCountMap, manifestFileName }); - const emit = emitHook.bind(this, { - compiler, - emitCountMap, - manifestAssetId, - manifestFileName, - moduleAssets, - options: this.options - }); - const normalModuleLoader = normalModuleLoaderHook.bind(this, { moduleAssets }); - const hookOptions = { - name: 'WebpackManifestPlugin', - stage: Infinity - }; - - compiler.hooks.compilation.tap(hookOptions, (compilation) => { - const hook = !NormalModule.getCompilationHooks - ? compilation.hooks.normalModuleLoader - : NormalModule.getCompilationHooks(compilation).loader; - hook.tap(hookOptions, normalModuleLoader); - }); - - if (webpack.version.startsWith('4')) { - compiler.hooks.emit.tap(hookOptions, emit); - } else { - compiler.hooks.thisCompilation.tap(hookOptions, (compilation) => { - compilation.hooks.processAssets.tap(hookOptions, () => emit(compilation)); - }); - } - - compiler.hooks.run.tap(hookOptions, beforeRun); - compiler.hooks.watchRun.tap(hookOptions, beforeRun); - } -} - -module.exports = { getCompilerHooks, WebpackManifestPlugin }; diff --git a/package.json b/package.json index 2f674704..b09dc2d1 100755 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "webpack": "^5.35", "webpack-cli": "^4.9.1", "webpack-dev-server": "^4.0.0", + "webpack-manifest-plugin": "^4.1.1", "yargs-parser": "^20.2.4" }, "devDependencies": { diff --git a/test/config-generator.js b/test/config-generator.js index 15a85218..a99b27a6 100644 --- a/test/config-generator.js +++ b/test/config-generator.js @@ -14,7 +14,7 @@ const WebpackConfig = require('../lib/WebpackConfig'); const RuntimeConfig = require('../lib/config/RuntimeConfig'); const configGenerator = require('../lib/config-generator'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); -const { WebpackManifestPlugin } = require('../lib/webpack-manifest-plugin'); +const { WebpackManifestPlugin } = require('webpack-manifest-plugin'); const { CleanWebpackPlugin } = require('clean-webpack-plugin'); const ESLintWebpackPlugin = require('eslint-webpack-plugin'); const webpack = require('webpack'); diff --git a/test/plugins/manifest.js b/test/plugins/manifest.js index 89a3405e..b172966a 100644 --- a/test/plugins/manifest.js +++ b/test/plugins/manifest.js @@ -10,7 +10,7 @@ 'use strict'; const expect = require('chai').expect; -const { WebpackManifestPlugin } = require('../../lib/webpack-manifest-plugin'); +const { WebpackManifestPlugin } = require('webpack-manifest-plugin'); const WebpackConfig = require('../../lib/WebpackConfig'); const RuntimeConfig = require('../../lib/config/RuntimeConfig'); const manifestPluginUtil = require('../../lib/plugins/manifest'); diff --git a/yarn.lock b/yarn.lock index eed6de14..fb06010e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6360,7 +6360,7 @@ sockjs@^0.3.21: uuid "^3.4.0" websocket-driver "^0.7.4" -source-list-map@^2.0.0: +source-list-map@^2.0.0, source-list-map@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== @@ -6685,7 +6685,7 @@ tapable@^1.0.0: resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== -tapable@^2.1.1, tapable@^2.2.0: +tapable@^2.0.0, tapable@^2.1.1, tapable@^2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== @@ -7100,6 +7100,14 @@ webpack-dev-server@^4.0.0: webpack-dev-middleware "^5.2.1" ws "^8.1.0" +webpack-manifest-plugin@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/webpack-manifest-plugin/-/webpack-manifest-plugin-4.1.1.tgz#10f8dbf4714ff93a215d5a45bcc416d80506f94f" + integrity sha512-YXUAwxtfKIJIKkhg03MKuiFAD72PlrqCiwdwO4VEXdRO5V0ORCNwaOwAZawPZalCbmH9kBDmXnNeQOw+BIEiow== + dependencies: + tapable "^2.0.0" + webpack-sources "^2.2.0" + webpack-merge@^5.7.3: version "5.8.0" resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.8.0.tgz#2b39dbf22af87776ad744c390223731d30a68f61" @@ -7124,6 +7132,14 @@ webpack-sources@^1.1.0: source-list-map "^2.0.0" source-map "~0.6.1" +webpack-sources@^2.2.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-2.3.1.tgz#570de0af163949fe272233c2cefe1b56f74511fd" + integrity sha512-y9EI9AO42JjEcrTJFOYmVywVZdKVUfOvDUPsJea5GIr1JOEGFVqwlY2K098fFoIjOkDzHn2AjRvM8dsBZu+gCA== + dependencies: + source-list-map "^2.0.1" + source-map "^0.6.1" + webpack-sources@^3.2.2: version "3.2.2" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.2.tgz#d88e3741833efec57c4c789b6010db9977545260"