2020-05-23 22:08:51 +08:00
/ *
MIT License http : //www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @ sokra and Zackary Jackson @ ScriptedAlchemy
* /
"use strict" ;
2020-05-27 17:53:59 +08:00
const WebpackError = require ( "../WebpackError" ) ;
2020-05-23 22:08:51 +08:00
const { parseOptions } = require ( "../container/options" ) ;
2021-04-16 21:35:18 +08:00
const createSchemaValidation = require ( "../util/create-schema-validation" ) ;
2020-06-18 21:11:29 +08:00
const ProvideForSharedDependency = require ( "./ProvideForSharedDependency" ) ;
const ProvideSharedDependency = require ( "./ProvideSharedDependency" ) ;
const ProvideSharedModuleFactory = require ( "./ProvideSharedModuleFactory" ) ;
2020-05-23 22:08:51 +08:00
/** @typedef {import("../../declarations/plugins/sharing/ProvideSharedPlugin").ProvideSharedPluginOptions} ProvideSharedPluginOptions */
2020-06-15 22:20:34 +08:00
/** @typedef {import("../Compilation")} Compilation */
2020-05-23 22:08:51 +08:00
/** @typedef {import("../Compiler")} Compiler */
2021-04-16 21:35:18 +08:00
const validate = createSchemaValidation (
require ( "../../schemas/plugins/sharing/ProvideSharedPlugin.check.js" ) ,
( ) => require ( "../../schemas/plugins/sharing/ProvideSharedPlugin.json" ) ,
{
name : "Provide Shared Plugin" ,
baseDataPath : "options"
}
) ;
2020-05-23 22:08:51 +08:00
/ * *
* @ typedef { Object } ProvideOptions
2020-06-10 22:30:08 +08:00
* @ property { string } shareKey
2020-05-23 22:08:51 +08:00
* @ property { string } shareScope
2020-07-02 17:06:42 +08:00
* @ property { string | undefined | false } version
2020-05-26 23:11:21 +08:00
* @ property { boolean } eager
2020-05-23 22:08:51 +08:00
* /
2020-07-02 17:06:42 +08:00
/** @typedef {Map<string, { config: ProvideOptions, version: string | undefined | false }>} ResolvedProvideMap */
2020-06-15 22:20:34 +08:00
2020-05-23 22:08:51 +08:00
class ProvideSharedPlugin {
/ * *
* @ param { ProvideSharedPluginOptions } options options
* /
constructor ( options ) {
2021-04-16 21:35:18 +08:00
validate ( options ) ;
2020-05-23 22:08:51 +08:00
/** @type {[string, ProvideOptions][]} */
this . _provides = parseOptions (
options . provides ,
item => {
if ( Array . isArray ( item ) )
2020-05-26 23:26:28 +08:00
throw new Error ( "Unexpected array of provides" ) ;
2020-05-26 23:11:21 +08:00
/** @type {ProvideOptions} */
const result = {
2020-06-10 22:30:08 +08:00
shareKey : item ,
2020-05-23 22:08:51 +08:00
version : undefined ,
2020-05-26 23:11:21 +08:00
shareScope : options . shareScope || "default" ,
eager : false
2020-05-23 22:08:51 +08:00
} ;
2020-05-26 23:11:21 +08:00
return result ;
2020-05-23 22:08:51 +08:00
} ,
item => ( {
2020-06-10 22:30:08 +08:00
shareKey : item . shareKey ,
2020-07-02 17:06:42 +08:00
version : item . version ,
2020-05-26 23:11:21 +08:00
shareScope : item . shareScope || options . shareScope || "default" ,
eager : ! ! item . eager
2020-05-23 22:08:51 +08:00
} )
) ;
this . _provides . sort ( ( [ a ] , [ b ] ) => {
if ( a < b ) return - 1 ;
if ( b < a ) return 1 ;
return 0 ;
} ) ;
}
/ * *
* Apply the plugin
* @ param { Compiler } compiler the compiler instance
* @ returns { void }
* /
apply ( compiler ) {
2020-06-15 22:20:34 +08:00
/** @type {WeakMap<Compilation, ResolvedProvideMap>} */
2020-06-10 22:30:08 +08:00
const compilationData = new WeakMap ( ) ;
2020-05-23 22:08:51 +08:00
2020-06-10 22:30:08 +08:00
compiler . hooks . compilation . tap (
"ProvideSharedPlugin" ,
( compilation , { normalModuleFactory } ) => {
2020-06-15 22:20:34 +08:00
/** @type {ResolvedProvideMap} */
const resolvedProvideMap = new Map ( ) ;
2020-06-13 21:17:28 +08:00
/** @type {Map<string, ProvideOptions>} */
2020-06-15 22:20:34 +08:00
const matchProvides = new Map ( ) ;
2020-06-13 21:17:28 +08:00
/** @type {Map<string, ProvideOptions>} */
2020-06-15 22:20:34 +08:00
const prefixMatchProvides = new Map ( ) ;
for ( const [ request , config ] of this . _provides ) {
if ( /^(\/|[A-Za-z]:\\|\\\\|\.\.?(\/|$))/ . test ( request ) ) {
// relative request
resolvedProvideMap . set ( request , {
config ,
version : config . version
} ) ;
} else if ( /^(\/|[A-Za-z]:\\|\\\\)/ . test ( request ) ) {
// absolute path
resolvedProvideMap . set ( request , {
config ,
version : config . version
} ) ;
} else if ( request . endsWith ( "/" ) ) {
// module request prefix
prefixMatchProvides . set ( request , config ) ;
} else {
// module request
matchProvides . set ( request , config ) ;
2020-06-13 21:17:28 +08:00
}
2020-06-15 22:20:34 +08:00
}
compilationData . set ( compilation , resolvedProvideMap ) ;
2020-06-24 20:09:36 +08:00
const provideSharedModule = (
2020-06-18 21:11:29 +08:00
key ,
config ,
resource ,
resourceResolveData
) => {
2020-06-13 21:17:28 +08:00
let version = config . version ;
if ( version === undefined ) {
let details = "" ;
if ( ! resourceResolveData ) {
details = ` No resolve data provided from resolver. ` ;
} else {
const descriptionFileData =
resourceResolveData . descriptionFileData ;
if ( ! descriptionFileData ) {
details =
"No description file (usually package.json) found. Add description file with name and version, or manually specify version in shared config." ;
} else if ( ! descriptionFileData . version ) {
2022-05-30 19:56:08 +08:00
details = ` No version in description file (usually package.json). Add version to description file ${ resourceResolveData . descriptionFilePath } , or manually specify version in shared config. ` ;
2020-06-13 21:17:28 +08:00
} else {
2020-07-02 17:06:42 +08:00
version = descriptionFileData . version ;
2020-06-13 21:17:28 +08:00
}
}
if ( ! version ) {
const error = new WebpackError (
` No version specified and unable to automatically determine one. ${ details } `
) ;
error . file = ` shared module ${ key } -> ${ resource } ` ;
compilation . warnings . push ( error ) ;
}
}
2020-06-15 22:20:34 +08:00
resolvedProvideMap . set ( resource , {
2020-06-13 21:17:28 +08:00
config ,
version
} ) ;
} ;
2020-06-10 22:30:08 +08:00
normalModuleFactory . hooks . module . tap (
"ProvideSharedPlugin" ,
2020-06-24 20:09:10 +08:00
( module , { resource , resourceResolveData } , resolveData ) => {
2020-06-15 22:20:34 +08:00
if ( resolvedProvideMap . has ( resource ) ) {
2020-06-10 22:30:08 +08:00
return module ;
}
2020-06-24 20:09:10 +08:00
const { request } = resolveData ;
2020-06-13 21:17:28 +08:00
{
2020-06-15 22:20:34 +08:00
const config = matchProvides . get ( request ) ;
2020-06-13 21:17:28 +08:00
if ( config !== undefined ) {
2020-06-24 20:09:36 +08:00
provideSharedModule (
2020-06-18 21:11:29 +08:00
request ,
config ,
resource ,
resourceResolveData
) ;
2020-06-24 20:09:10 +08:00
resolveData . cacheable = false ;
2020-06-13 21:17:28 +08:00
}
2020-06-10 22:30:08 +08:00
}
2020-06-15 22:20:34 +08:00
for ( const [ prefix , config ] of prefixMatchProvides ) {
2020-06-13 21:17:28 +08:00
if ( request . startsWith ( prefix ) ) {
const remainder = request . slice ( prefix . length ) ;
2020-06-24 20:09:36 +08:00
provideSharedModule (
2020-06-13 21:17:28 +08:00
resource ,
{
... config ,
shareKey : config . shareKey + remainder
} ,
resource ,
resourceResolveData
2020-05-27 17:53:59 +08:00
) ;
2020-06-24 20:09:10 +08:00
resolveData . cacheable = false ;
2020-05-27 17:53:59 +08:00
}
}
2020-06-10 22:30:08 +08:00
return module ;
}
) ;
}
) ;
compiler . hooks . finishMake . tapPromise ( "ProvideSharedPlugin" , compilation => {
2020-06-15 22:20:34 +08:00
const resolvedProvideMap = compilationData . get ( compilation ) ;
if ( ! resolvedProvideMap ) return Promise . resolve ( ) ;
2020-06-10 22:30:08 +08:00
return Promise . all (
Array . from (
2020-06-15 22:20:34 +08:00
resolvedProvideMap ,
2020-06-10 22:30:08 +08:00
( [ resource , { config , version } ] ) =>
new Promise ( ( resolve , reject ) => {
compilation . addInclude (
compiler . context ,
2020-06-18 21:11:29 +08:00
new ProvideSharedDependency (
2020-06-10 22:30:08 +08:00
config . shareScope ,
config . shareKey ,
version || false ,
resource ,
config . eager
) ,
{
name : undefined
} ,
err => {
if ( err ) return reject ( err ) ;
resolve ( ) ;
}
) ;
} )
)
) . then ( ( ) => { } ) ;
} ) ;
2020-05-23 22:08:51 +08:00
compiler . hooks . compilation . tap (
"ProvideSharedPlugin" ,
( compilation , { normalModuleFactory } ) => {
compilation . dependencyFactories . set (
2020-06-18 21:11:29 +08:00
ProvideForSharedDependency ,
2020-05-23 22:08:51 +08:00
normalModuleFactory
) ;
compilation . dependencyFactories . set (
2020-06-18 21:11:29 +08:00
ProvideSharedDependency ,
new ProvideSharedModuleFactory ( )
2020-05-23 22:08:51 +08:00
) ;
}
) ;
}
}
module . exports = ProvideSharedPlugin ;