From c695c3bf03b60442a3cc52ee80b927acabc0244d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ismael=20Mart=C3=ADn=20Alabarce?= Date: Mon, 19 Jul 2021 11:00:52 +0200 Subject: [PATCH] Fix dependency extraction webpack v5 deprecation (#33090) * Get rid of webpack v5 deprecation supporting also v4 Resolve deprecations using conditionals checks to implement solutions for both versions * Little nitpick Access webpack compilation property trough compiler instead * Fix code indentation and format * Shorthand version of runtime files push/add --- .../lib/index.js | 229 ++++++++++-------- 1 file changed, 128 insertions(+), 101 deletions(-) diff --git a/packages/dependency-extraction-webpack-plugin/lib/index.js b/packages/dependency-extraction-webpack-plugin/lib/index.js index 0cc84b99a2384..6676caf42693a 100644 --- a/packages/dependency-extraction-webpack-plugin/lib/index.js +++ b/packages/dependency-extraction-webpack-plugin/lib/index.js @@ -7,6 +7,7 @@ const webpack = require( 'webpack' ); // In webpack 5 there is a `webpack.sources` field but for webpack 4 we have to fallback to the `webpack-sources` package. const { RawSource } = webpack.sources || require( 'webpack-sources' ); const json2php = require( 'json2php' ); +const isWebpack4 = webpack.version.startsWith( '4.' ); /** * Internal dependencies @@ -41,7 +42,9 @@ class DependencyExtractionWebpackPlugin { // Offload externalization work to the ExternalsPlugin. this.externalsPlugin = new webpack.ExternalsPlugin( 'window', - this.externalizeWpDeps.bind( this ) + isWebpack4 + ? this.externalizeWpDeps.bind( this ) + : this.externalizeWpDepsV5.bind( this ) ); } @@ -70,6 +73,10 @@ class DependencyExtractionWebpackPlugin { return callback(); } + externalizeWpDepsV5( { context, request }, callback ) { + return this.externalizeWpDeps( context, request, callback ); + } + mapRequestToDependency( request ) { // Handle via options.requestToHandle first if ( typeof this.options.requestToHandle === 'function' ) { @@ -104,116 +111,136 @@ class DependencyExtractionWebpackPlugin { apply( compiler ) { this.externalsPlugin.apply( compiler ); - compiler.hooks.emit.tap( this.constructor.name, ( compilation ) => { - const { - combineAssets, - combinedOutputFile, - injectPolyfill, - outputFormat, - } = this.options; - - const combinedAssetsData = {}; - - // Process each entry point independently. - for ( const [ - entrypointName, - entrypoint, - ] of compilation.entrypoints.entries() ) { - const entrypointExternalizedWpDeps = new Set(); - if ( injectPolyfill ) { - entrypointExternalizedWpDeps.add( 'wp-polyfill' ); + if ( isWebpack4 ) { + compiler.hooks.emit.tap( this.constructor.name, ( compilation ) => + this.addAssets( compilation, compiler ) + ); + } else { + compiler.hooks.thisCompilation.tap( + this.constructor.name, + ( compilation ) => { + compilation.hooks.processAssets.tap( + { + name: this.constructor.name, + stage: + compiler.webpack.Compilation + .PROCESS_ASSETS_STAGE_ADDITIONAL, + }, + () => this.addAssets( compilation, compiler ) + ); } + ); + } + } - const processModule = ( { userRequest } ) => { - if ( this.externalizedDeps.has( userRequest ) ) { - const scriptDependency = this.mapRequestToDependency( - userRequest - ); - entrypointExternalizedWpDeps.add( scriptDependency ); - } - }; - - // Search for externalized modules in all chunks. - for ( const chunk of entrypoint.chunks ) { - for ( const chunkModule of chunk.modulesIterable ) { - processModule( chunkModule ); - // loop through submodules of ConcatenatedModule - if ( chunkModule.modules ) { - for ( const concatModule of chunkModule.modules ) { - processModule( concatModule ); - } + addAssets( compilation, compiler ) { + const { + combineAssets, + combinedOutputFile, + injectPolyfill, + outputFormat, + } = this.options; + + const combinedAssetsData = {}; + + // Process each entry point independently. + for ( const [ + entrypointName, + entrypoint, + ] of compilation.entrypoints.entries() ) { + const entrypointExternalizedWpDeps = new Set(); + if ( injectPolyfill ) { + entrypointExternalizedWpDeps.add( 'wp-polyfill' ); + } + + const processModule = ( { userRequest } ) => { + if ( this.externalizedDeps.has( userRequest ) ) { + const scriptDependency = this.mapRequestToDependency( + userRequest + ); + entrypointExternalizedWpDeps.add( scriptDependency ); + } + }; + + // Search for externalized modules in all chunks. + for ( const chunk of entrypoint.chunks ) { + const modulesIterable = isWebpack4 + ? chunk.modulesIterable + : compilation.chunkGraph.getChunkModules( chunk ); + for ( const chunkModule of modulesIterable ) { + processModule( chunkModule ); + // loop through submodules of ConcatenatedModule + if ( chunkModule.modules ) { + for ( const concatModule of chunkModule.modules ) { + processModule( concatModule ); } } } + } - const runtimeChunk = entrypoint.getRuntimeChunk(); - - const assetData = { - // Get a sorted array so we can produce a stable, stringified representation. - dependencies: Array.from( - entrypointExternalizedWpDeps - ).sort(), - version: runtimeChunk.hash, - }; - - const assetString = this.stringify( assetData ); - - // Determine a filename for the asset file. - const [ filename, query ] = entrypointName.split( '?', 2 ); - const buildFilename = compilation.getPath( - compiler.options.output.filename, - { - chunk: runtimeChunk, - filename, - query, - basename: basename( filename ), - contentHash: createHash( 'md4' ) - .update( assetString ) - .digest( 'hex' ), - } - ); - - if ( combineAssets ) { - combinedAssetsData[ buildFilename ] = assetData; - continue; + const runtimeChunk = entrypoint.getRuntimeChunk(); + + const assetData = { + // Get a sorted array so we can produce a stable, stringified representation. + dependencies: Array.from( entrypointExternalizedWpDeps ).sort(), + version: runtimeChunk.hash, + }; + + const assetString = this.stringify( assetData ); + + // Determine a filename for the asset file. + const [ filename, query ] = entrypointName.split( '?', 2 ); + const buildFilename = compilation.getPath( + compiler.options.output.filename, + { + chunk: runtimeChunk, + filename, + query, + basename: basename( filename ), + contentHash: createHash( 'md4' ) + .update( assetString ) + .digest( 'hex' ), } - - const assetFilename = buildFilename.replace( - /\.js$/i, - '.asset.' + ( outputFormat === 'php' ? 'php' : 'json' ) - ); - - // Add source and file into compilation for webpack to output. - compilation.assets[ assetFilename ] = new RawSource( - assetString - ); - runtimeChunk.files.push( assetFilename ); - } + ); if ( combineAssets ) { - // Assert the `string` type for output path. - // The type indicates the option may be `undefined`. - // However, at this point in compilation, webpack has filled the options in if - // they were not provided. - const outputFolder = /** @type {{path:string}} */ ( compiler - .options.output ).path; - - const assetsFilePath = path.resolve( - outputFolder, - combinedOutputFile || - 'assets.' + ( outputFormat === 'php' ? 'php' : 'json' ) - ); - const assetsFilename = path.relative( - outputFolder, - assetsFilePath - ); - - // Add source into compilation for webpack to output. - compilation.assets[ assetsFilename ] = new RawSource( - this.stringify( combinedAssetsData ) - ); + combinedAssetsData[ buildFilename ] = assetData; + continue; } - } ); + + const assetFilename = buildFilename.replace( + /\.js$/i, + '.asset.' + ( outputFormat === 'php' ? 'php' : 'json' ) + ); + + // Add source and file into compilation for webpack to output. + compilation.assets[ assetFilename ] = new RawSource( assetString ); + runtimeChunk.files[ isWebpack4 ? 'push' : 'add' ]( assetFilename ); + } + + if ( combineAssets ) { + // Assert the `string` type for output path. + // The type indicates the option may be `undefined`. + // However, at this point in compilation, webpack has filled the options in if + // they were not provided. + const outputFolder = /** @type {{path:string}} */ ( compiler.options + .output ).path; + + const assetsFilePath = path.resolve( + outputFolder, + combinedOutputFile || + 'assets.' + ( outputFormat === 'php' ? 'php' : 'json' ) + ); + const assetsFilename = path.relative( + outputFolder, + assetsFilePath + ); + + // Add source into compilation for webpack to output. + compilation.assets[ assetsFilename ] = new RawSource( + this.stringify( combinedAssetsData ) + ); + } } }