2017-05-10 19:15:14 +08:00
/ *
MIT License http : //www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @ sokra
* /
"use strict" ;
const Module = require ( "../Module" ) ;
const Template = require ( "../Template" ) ;
2017-05-21 12:56:24 +08:00
const Parser = require ( "../Parser" ) ;
2017-05-10 19:15:14 +08:00
const acorn = require ( "acorn" ) ;
const escope = require ( "escope" ) ;
const ReplaceSource = require ( "webpack-sources/lib/ReplaceSource" ) ;
const ConcatSource = require ( "webpack-sources/lib/ConcatSource" ) ;
const HarmonyImportDependency = require ( "../dependencies/HarmonyImportDependency" ) ;
const HarmonyImportSpecifierDependency = require ( "../dependencies/HarmonyImportSpecifierDependency" ) ;
const HarmonyExportSpecifierDependency = require ( "../dependencies/HarmonyExportSpecifierDependency" ) ;
const HarmonyExportExpressionDependency = require ( "../dependencies/HarmonyExportExpressionDependency" ) ;
const HarmonyExportImportedSpecifierDependency = require ( "../dependencies/HarmonyExportImportedSpecifierDependency" ) ;
const HarmonyCompatibilityDependency = require ( "../dependencies/HarmonyCompatibilityDependency" ) ;
const HarmonyModulesHelpers = require ( "../dependencies/HarmonyModulesHelpers" ) ;
2017-08-07 17:53:07 +08:00
function ensureNsObjSource ( info , moduleToInfoMap , requestShortener ) {
if ( ! info . hasNamespaceObject ) {
info . hasNamespaceObject = true ;
const name = info . exportMap . get ( true ) ;
const nsObj = [ ` var ${ name } = {}; ` ] ;
for ( const exportName of info . module . providedExports ) {
2017-08-07 19:19:24 +08:00
const finalName = getFinalName ( info , exportName , moduleToInfoMap , requestShortener , false ) ;
2017-08-07 17:53:07 +08:00
nsObj . push ( ` __webpack_require__.d( ${ name } , ${ JSON . stringify ( exportName ) } , function() { return ${ finalName } ; }); ` ) ;
}
info . namespaceObjectSource = nsObj . join ( "\n" ) + "\n" ;
}
}
2017-08-07 19:19:24 +08:00
function getExternalImport ( importedModule , importedVar , exportName , asCall ) {
const isHarmonyModule = importedModule && ( ! importedModule . meta || importedModule . meta . harmonyModule ) ;
if ( exportName === true ) return importedVar ;
const used = importedModule . isUsed ( exportName ) ;
if ( ! used ) return "/* unused reexport */undefined" ;
if ( ! isHarmonyModule && exportName === "default" ) {
return asCall ? ` ${ importedVar } _default() ` : ` ${ importedVar } _default.a ` ;
2017-05-10 19:15:14 +08:00
}
2017-08-07 19:19:24 +08:00
if ( asCall )
return ` Object( ${ importedVar } [ ${ JSON . stringify ( used ) } ]) ` ;
return ` ${ importedVar } [ ${ JSON . stringify ( used ) } ] ` ;
}
function getFinalName ( info , exportName , moduleToInfoMap , requestShortener , asCall ) {
switch ( info . type ) {
case "concatenated" :
{
const directExport = info . exportMap . get ( exportName ) ;
if ( directExport ) {
if ( exportName === true )
ensureNsObjSource ( info , moduleToInfoMap , requestShortener ) ;
const name = info . internalNames . get ( directExport ) ;
if ( ! name )
throw new Error ( ` The export " ${ directExport } " in " ${ info . module . readableIdentifier ( requestShortener ) } " has no internal name ` ) ;
return name ;
}
const reexport = info . reexportMap . get ( exportName ) ;
if ( reexport ) {
const refInfo = moduleToInfoMap . get ( reexport . module ) ;
if ( refInfo ) {
// module is in the concatenation
return getFinalName ( refInfo , reexport . exportName , moduleToInfoMap , requestShortener , asCall ) ;
} else {
const dep = reexport . dependency ;
const importedModule = reexport . module ;
const exportName = reexport . exportName ;
const importedVar = dep . importedVar ;
return getExternalImport ( importedModule , importedVar , exportName , asCall ) ;
}
}
2017-08-07 19:56:50 +08:00
const problem = ` Cannot get final name for export " ${ exportName } " in " ${ info . module . readableIdentifier ( requestShortener ) } " ` +
` (known exports: ${ Array . from ( info . exportMap . keys ( ) ) . filter ( name => name !== true ) . join ( " " ) } , ` +
` known reexports: ${ Array . from ( info . reexportMap . keys ( ) ) . join ( " " ) } ) ` ;
// TODO use Template.toNormalComment when merging with pure-module
return ` /* ${ problem } */ undefined ` ;
2017-08-07 19:19:24 +08:00
}
case "external" :
{
const importedModule = info . module ;
return getExternalImport ( importedModule , info . name , exportName , asCall ) ;
2017-05-10 19:15:14 +08:00
}
}
}
2017-05-31 22:46:25 +08:00
function getSymbolsFromScope ( s , untilScope ) {
const allUsedNames = new Set ( ) ;
let scope = s ;
while ( scope ) {
if ( untilScope === scope ) break ;
scope . variables . forEach ( variable => allUsedNames . add ( variable . name ) ) ;
scope = scope . upper ;
}
return allUsedNames ;
}
2017-06-06 17:18:34 +08:00
function getAllReferences ( variable ) {
let set = variable . references ;
// Look for inner scope variables too (like in class Foo { t() { Foo } })
const identifiers = new Set ( variable . identifiers ) ;
for ( const scope of variable . scope . childScopes ) {
for ( const innerVar of scope . variables ) {
if ( innerVar . identifiers . some ( id => identifiers . has ( id ) ) ) {
set = set . concat ( innerVar . references ) ;
break ;
}
}
}
return set ;
}
2017-05-31 22:46:25 +08:00
function reduceSet ( a , b ) {
for ( const item of b )
a . add ( item ) ;
return a ;
}
2017-06-13 19:38:12 +08:00
function getPathInAst ( ast , node ) {
if ( ast === node ) {
return [ ] ;
}
const nr = node . range ;
var i ;
if ( Array . isArray ( ast ) ) {
for ( i = 0 ; i < ast . length ; i ++ ) {
const enterResult = enterNode ( ast [ i ] ) ;
if ( typeof enterResult !== "undefined" )
return enterResult ;
}
} else if ( ast && typeof ast === "object" ) {
const keys = Object . keys ( ast ) ;
for ( i = 0 ; i < keys . length ; i ++ ) {
const value = ast [ keys [ i ] ] ;
if ( Array . isArray ( value ) ) {
const pathResult = getPathInAst ( value , node ) ;
if ( typeof pathResult !== "undefined" )
return pathResult ;
} else if ( value && typeof value === "object" ) {
const enterResult = enterNode ( value ) ;
if ( typeof enterResult !== "undefined" )
return enterResult ;
}
}
}
function enterNode ( n ) {
const r = n . range ;
if ( r ) {
if ( r [ 0 ] <= nr [ 0 ] && r [ 1 ] >= nr [ 1 ] ) {
const path = getPathInAst ( n , node ) ;
if ( path ) {
path . push ( n ) ;
return path ;
}
}
}
return undefined ;
}
}
2017-05-10 19:15:14 +08:00
class ConcatenatedModule extends Module {
constructor ( rootModule , modules ) {
super ( ) ;
2017-06-20 20:47:38 +08:00
super . setChunks ( rootModule . _chunks ) ;
2017-05-10 19:15:14 +08:00
this . rootModule = rootModule ;
this . usedExports = rootModule . usedExports ;
this . providedExports = rootModule . providedExports ;
2017-05-28 21:25:07 +08:00
this . optimizationBailout = rootModule . optimizationBailout ;
2017-05-16 17:14:59 +08:00
this . used = rootModule . used ;
2017-05-10 19:15:14 +08:00
this . index = rootModule . index ;
this . index2 = rootModule . index2 ;
this . depth = rootModule . depth ;
this . built = modules . some ( m => m . built ) ;
this . cacheable = modules . every ( m => m . cacheable ) ;
const modulesSet = new Set ( modules ) ;
2017-08-07 17:53:07 +08:00
this . _modulesSet = modulesSet ;
2017-05-10 19:15:14 +08:00
this . reasons = rootModule . reasons . filter ( reason => ! modulesSet . has ( reason . module ) ) ;
this . meta = rootModule . meta ;
this . moduleArgument = rootModule . moduleArgument ;
this . exportsArgument = rootModule . exportsArgument ;
this . strict = true ;
2017-08-07 17:53:07 +08:00
this . _numberOfConcatenatedModules = modules . length ;
2017-06-18 20:46:06 +08:00
this . dependencies = [ ] ;
this . dependenciesWarnings = [ ] ;
this . dependenciesErrors = [ ] ;
2017-06-22 22:30:28 +08:00
this . fileDependencies = [ ] ;
this . contextDependencies = [ ] ;
2017-06-18 20:46:06 +08:00
this . warnings = [ ] ;
this . errors = [ ] ;
2017-06-22 11:32:59 +08:00
this . assets = { } ;
2017-08-07 17:53:07 +08:00
this . _orderedConcatenationList = this . _createOrderedConcatenationList ( rootModule , modulesSet ) ;
for ( const info of this . _orderedConcatenationList ) {
if ( info . type === "concatenated" ) {
const m = info . module ;
// populate dependencies
m . dependencies . filter ( dep => ! modulesSet . has ( dep . module ) )
. forEach ( d => this . dependencies . push ( d ) ) ;
// populate dep warning
m . dependenciesWarnings . forEach ( depWarning => this . dependenciesWarnings . push ( depWarning ) ) ;
// populate dep errors
m . dependenciesErrors . forEach ( depError => this . dependenciesErrors . push ( depError ) ) ;
// populate file dependencies
if ( m . fileDependencies ) m . fileDependencies . forEach ( file => this . fileDependencies . push ( file ) ) ;
// populate context dependencies
if ( m . contextDependencies ) m . contextDependencies . forEach ( context => this . contextDependencies . push ( context ) ) ;
// populate warnings
m . warnings . forEach ( warning => this . warnings . push ( warning ) ) ;
// populate errors
m . errors . forEach ( error => this . errors . push ( error ) ) ;
Object . assign ( this . assets , m . assets ) ;
}
2017-06-18 20:46:06 +08:00
}
2017-05-10 19:15:14 +08:00
}
identifier ( ) {
2017-08-07 17:53:07 +08:00
return this . _orderedConcatenationList . map ( info => info . module . identifier ( ) ) . join ( " " ) ;
2017-05-10 19:15:14 +08:00
}
readableIdentifier ( requestShortener ) {
2017-08-07 17:53:07 +08:00
return this . rootModule . readableIdentifier ( requestShortener ) + ` + ${ this . _numberOfConcatenatedModules - 1 } modules ` ;
2017-05-10 19:15:14 +08:00
}
libIdent ( options ) {
2017-06-05 20:01:19 +08:00
return this . rootModule . libIdent ( options ) ;
2017-05-10 19:15:14 +08:00
}
nameForCondition ( ) {
return this . rootModule . nameForCondition ( ) ;
}
build ( options , compilation , resolver , fs , callback ) {
throw new Error ( "Cannot build this module. It should be already built." ) ;
}
size ( ) {
// Guess size from embedded modules
2017-08-07 17:53:07 +08:00
return this . _orderedConcatenationList . reduce ( ( sum , info ) => {
switch ( info . type ) {
case "concatenated" :
return sum + info . module . size ( ) ;
case "external" :
return sum + 5 ;
}
return sum ;
} , 0 ) ;
}
_createOrderedConcatenationList ( rootModule , modulesSet ) {
const list = [ ] ;
2017-08-07 19:19:24 +08:00
const set = new Set ( ) ;
2017-08-07 17:53:07 +08:00
function getConcatenatedImports ( module ) {
// TODO need changes when merging with the pure-module branch
const allDeps = module . dependencies
. filter ( dep => dep instanceof HarmonyImportDependency && dep . module ) ;
2017-08-07 19:56:50 +08:00
return allDeps . map ( dep => ( ) => dep . module ) ;
2017-08-07 17:53:07 +08:00
}
2017-08-07 19:56:50 +08:00
function enterModule ( getModule ) {
const module = getModule ( ) ;
2017-08-07 19:19:24 +08:00
if ( set . has ( module ) ) return ;
set . add ( module ) ;
2017-08-07 17:53:07 +08:00
if ( modulesSet . has ( module ) ) {
const imports = getConcatenatedImports ( module ) ;
imports . forEach ( enterModule ) ;
list . push ( {
type : "concatenated" ,
module
} ) ;
} else {
list . push ( {
type : "external" ,
2017-08-07 19:56:50 +08:00
get module ( ) {
// We need to use a getter here, because the module in the dependency
// could be replaced by some other process (i. e. also replaced with a
// concatenated module)
return getModule ( ) ;
}
2017-08-07 17:53:07 +08:00
} ) ;
}
}
2017-08-07 19:56:50 +08:00
enterModule ( ( ) => rootModule ) ;
2017-08-07 17:53:07 +08:00
return list ;
2017-05-10 19:15:14 +08:00
}
source ( dependencyTemplates , outputOptions , requestShortener ) {
2017-08-07 17:53:07 +08:00
const modulesSet = this . _modulesSet ;
2017-05-10 19:15:14 +08:00
// Metainfo for each module
2017-08-07 19:19:24 +08:00
const modulesWithInfo = this . _orderedConcatenationList . map ( ( info , idx ) => {
switch ( info . type ) {
case "concatenated" :
{
const exportMap = new Map ( ) ;
const reexportMap = new Map ( ) ;
info . module . dependencies . forEach ( dep => {
if ( dep instanceof HarmonyExportSpecifierDependency ) {
exportMap . set ( dep . name , dep . id ) ;
} else if ( dep instanceof HarmonyExportExpressionDependency ) {
exportMap . set ( "default" , "__WEBPACK_MODULE_DEFAULT_EXPORT__" ) ;
} else if ( dep instanceof HarmonyExportImportedSpecifierDependency ) {
const exportName = dep . name ;
const importName = dep . id ;
const importModule = dep . importDependency . module ;
const innerReexport = modulesSet . has ( importModule ) ;
if ( exportName && importName ) {
reexportMap . set ( exportName , {
module : importModule ,
exportName : importName ,
dependency : dep
} ) ;
} else if ( exportName ) {
reexportMap . set ( exportName , {
module : importModule ,
exportName : true ,
dependency : dep
} ) ;
} else if ( Array . isArray ( importModule . providedExports ) ) {
var activeExports = new Set ( HarmonyModulesHelpers . getActiveExports ( dep . originModule , dep ) ) ;
importModule . providedExports . forEach ( name => {
if ( activeExports . has ( name ) || name === "default" )
return ;
reexportMap . set ( name , {
module : importModule ,
exportName : name ,
dependency : dep
} ) ;
} ) ;
} else if ( innerReexport ) {
throw new Error ( ` Module " ${ importModule . readableIdentifier ( requestShortener ) } " doesn't provide static exports for "export *" in ${ info . module . readableIdentifier ( requestShortener ) } ` ) ;
}
}
2017-05-10 19:15:14 +08:00
} ) ;
2017-08-07 19:19:24 +08:00
return {
type : "concatenated" ,
module : info . module ,
index : idx ,
ast : undefined ,
source : undefined ,
globalScope : undefined ,
moduleScope : undefined ,
internalNames : new Map ( ) ,
exportMap : exportMap ,
reexportMap : reexportMap ,
needCompatibilityFlag : false ,
hasNamespaceObject : false ,
namespaceObjectSource : null
} ;
2017-05-10 19:15:14 +08:00
}
2017-08-07 19:19:24 +08:00
case "external" :
return {
type : "external" ,
module : info . module ,
index : idx ,
name : undefined
} ;
default :
throw new Error ( ` Unsupported concatenation entry type ${ info . type } ` ) ;
}
2017-05-10 19:15:14 +08:00
} ) ;
// Create mapping from module to info
const moduleToInfoMap = new Map ( ) ;
modulesWithInfo . forEach ( m => moduleToInfoMap . set ( m . module , m ) ) ;
// Configure template decorators for dependencies
const innerDependencyTemplates = new Map ( dependencyTemplates ) ;
innerDependencyTemplates . set ( HarmonyImportSpecifierDependency , new HarmonyImportSpecifierDependencyConcatenatedTemplate (
dependencyTemplates . get ( HarmonyImportSpecifierDependency ) ,
moduleToInfoMap
) ) ;
innerDependencyTemplates . set ( HarmonyImportDependency , new HarmonyImportDependencyConcatenatedTemplate (
dependencyTemplates . get ( HarmonyImportDependency ) ,
moduleToInfoMap
) ) ;
innerDependencyTemplates . set ( HarmonyExportSpecifierDependency , new HarmonyExportSpecifierDependencyConcatenatedTemplate (
dependencyTemplates . get ( HarmonyExportSpecifierDependency ) ,
this . rootModule
) ) ;
innerDependencyTemplates . set ( HarmonyExportExpressionDependency , new HarmonyExportExpressionDependencyConcatenatedTemplate (
dependencyTemplates . get ( HarmonyExportExpressionDependency ) ,
this . rootModule ,
moduleToInfoMap
) ) ;
innerDependencyTemplates . set ( HarmonyExportImportedSpecifierDependency , new HarmonyExportImportedSpecifierDependencyConcatenatedTemplate (
dependencyTemplates . get ( HarmonyExportImportedSpecifierDependency ) ,
this . rootModule ,
moduleToInfoMap
) ) ;
innerDependencyTemplates . set ( HarmonyCompatibilityDependency , new HarmonyCompatibilityDependencyConcatenatedTemplate (
dependencyTemplates . get ( HarmonyCompatibilityDependency ) ,
this . rootModule ,
moduleToInfoMap
) ) ;
2017-07-14 18:50:39 +08:00
innerDependencyTemplates . set ( "hash" , innerDependencyTemplates . get ( "hash" ) + this . rootModule . identifier ( ) ) ;
2017-05-10 19:15:14 +08:00
// Generate source code and analyse scopes
// Prepare a ReplaceSource for the final source
modulesWithInfo . forEach ( info => {
2017-08-07 19:19:24 +08:00
if ( info . type === "concatenated" ) {
const m = info . module ;
const source = m . source ( innerDependencyTemplates , outputOptions , requestShortener ) ;
const code = source . source ( ) ;
let ast ;
try {
ast = acorn . parse ( code , {
ranges : true ,
locations : true ,
ecmaVersion : Parser . ECMA _VERSION ,
sourceType : "module"
} ) ;
} catch ( err ) {
if ( err . loc && typeof err . loc === "object" && typeof err . loc . line === "number" ) {
const lineNumber = err . loc . line ;
const lines = code . split ( "\n" ) ;
err . message += "\n| " + lines . slice ( Math . max ( 0 , lineNumber - 3 ) , lineNumber + 2 ) . join ( "\n| " ) ;
}
throw err ;
2017-07-22 05:32:31 +08:00
}
2017-08-07 19:19:24 +08:00
const scopeManager = escope . analyze ( ast , {
ecmaVersion : 6 ,
sourceType : "module" ,
optimistic : true ,
ignoreEval : true ,
impliedStrict : true
} ) ;
const globalScope = scopeManager . acquire ( ast ) ;
const moduleScope = globalScope . childScopes [ 0 ] ;
const resultSource = new ReplaceSource ( source ) ;
info . ast = ast ;
info . source = resultSource ;
info . globalScope = globalScope ;
info . moduleScope = moduleScope ;
2017-07-22 05:32:31 +08:00
}
2017-05-10 19:15:14 +08:00
} ) ;
// List of all used names to avoid conflicts
const allUsedNames = new Set ( [ "__WEBPACK_MODULE_DEFAULT_EXPORT__" , "defaultExport" , "Object" ] ) ;
// get all global names
modulesWithInfo . forEach ( info => {
2017-08-07 19:19:24 +08:00
if ( info . globalScope ) {
info . globalScope . through . forEach ( reference => {
const name = reference . identifier . name ;
2017-08-07 19:56:50 +08:00
if ( /^__WEBPACK_MODULE_REFERENCE__\d+_([\da-f]+|ns)(_call)?__$/ . test ( name ) ) {
2017-08-07 19:19:24 +08:00
for ( const s of getSymbolsFromScope ( reference . from , info . moduleScope ) ) {
allUsedNames . add ( s ) ;
}
} else {
allUsedNames . add ( name ) ;
2017-05-31 22:46:25 +08:00
}
2017-08-07 19:19:24 +08:00
} ) ;
}
2017-05-10 19:15:14 +08:00
} ) ;
2017-08-07 19:19:24 +08:00
// generate names for symbols
2017-05-10 19:15:14 +08:00
modulesWithInfo . forEach ( info => {
2017-08-07 19:19:24 +08:00
switch ( info . type ) {
case "concatenated" :
{
const namespaceObjectName = this . findNewName ( "namespaceObject" , allUsedNames , null , info . module . readableIdentifier ( requestShortener ) ) ;
allUsedNames . add ( namespaceObjectName ) ;
info . internalNames . set ( namespaceObjectName , namespaceObjectName ) ;
info . exportMap . set ( true , namespaceObjectName ) ;
info . moduleScope . variables . forEach ( variable => {
const name = variable . name ;
if ( allUsedNames . has ( name ) ) {
const references = getAllReferences ( variable ) ;
const symbolsInReferences = references . map ( ref => getSymbolsFromScope ( ref . from , info . moduleScope ) ) . reduce ( reduceSet , new Set ( ) ) ;
const newName = this . findNewName ( name , allUsedNames , symbolsInReferences , info . module . readableIdentifier ( requestShortener ) ) ;
allUsedNames . add ( newName ) ;
info . internalNames . set ( name , newName ) ;
const source = info . source ;
const allIdentifiers = new Set ( references . map ( r => r . identifier ) . concat ( variable . identifiers ) ) ;
for ( const identifier of allIdentifiers ) {
const r = identifier . range ;
const path = getPathInAst ( info . ast , identifier ) ;
if ( path && path . length > 1 && path [ 1 ] . type === "Property" && path [ 1 ] . shorthand ) {
source . insert ( r [ 1 ] , ` : ${ newName } ` ) ;
} else {
source . replace ( r [ 0 ] , r [ 1 ] - 1 , newName ) ;
}
}
} else {
allUsedNames . add ( name ) ;
info . internalNames . set ( name , name ) ;
}
} ) ;
break ;
2017-05-10 19:15:14 +08:00
}
2017-08-07 19:19:24 +08:00
case "external" :
{
const externalName = this . findNewName ( "externalModule" , allUsedNames , null , info . module . readableIdentifier ( requestShortener ) ) ;
allUsedNames . add ( externalName ) ;
info . name = externalName ;
break ;
}
}
2017-05-10 19:15:14 +08:00
} ) ;
2017-08-07 19:19:24 +08:00
// Find and replace referenced to modules
2017-05-10 19:15:14 +08:00
modulesWithInfo . forEach ( info => {
2017-08-07 19:19:24 +08:00
if ( info . type === "concatenated" ) {
info . globalScope . through . forEach ( reference => {
const name = reference . identifier . name ;
2017-08-07 19:56:50 +08:00
const match = /^__WEBPACK_MODULE_REFERENCE__(\d+)_([\da-f]+|ns)(_call)?__$/ . exec ( name ) ;
2017-08-07 19:19:24 +08:00
if ( match ) {
const referencedModule = modulesWithInfo [ + match [ 1 ] ] ;
let exportName ;
if ( match [ 2 ] === "ns" ) {
exportName = true ;
} else {
2017-08-07 19:56:50 +08:00
const exportData = match [ 2 ] ;
exportName = Buffer . from ( exportData , "hex" ) . toString ( "utf-8" ) ;
2017-08-07 19:19:24 +08:00
}
const asCall = ! ! match [ 3 ] ;
const finalName = getFinalName ( referencedModule , exportName , moduleToInfoMap , requestShortener , asCall ) ;
const r = reference . identifier . range ;
const source = info . source ;
source . replace ( r [ 0 ] , r [ 1 ] - 1 , finalName ) ;
2017-05-10 19:15:14 +08:00
}
2017-08-07 19:19:24 +08:00
} ) ;
}
2017-05-10 19:15:14 +08:00
} ) ;
const result = new ConcatSource ( ) ;
2017-08-07 20:12:31 +08:00
// add harmony compatibility flag (must be first because of possible circular dependencies)
2017-05-10 19:15:14 +08:00
if ( moduleToInfoMap . get ( this . rootModule ) . needCompatibilityFlag ) {
2017-08-07 17:53:07 +08:00
result . add ( ` Object.defineProperty( ${ this . exportsArgument || "exports" } , "__esModule", { value: true }); \n ` ) ;
2017-05-10 19:15:14 +08:00
}
2017-08-07 20:12:31 +08:00
// define required namespace objects (must be before evaluation modules)
modulesWithInfo . forEach ( info => {
if ( info . namespaceObjectSource ) {
result . add ( info . namespaceObjectSource ) ;
}
} ) ;
// evaluate modules in order
2017-08-07 19:19:24 +08:00
modulesWithInfo . forEach ( info => {
switch ( info . type ) {
2017-08-07 17:53:07 +08:00
case "concatenated" :
2017-08-07 19:19:24 +08:00
result . add ( ` \n // CONCATENATED MODULE: ${ info . module . readableIdentifier ( requestShortener ) } \n ` ) ;
result . add ( info . source ) ;
break ;
2017-08-07 17:53:07 +08:00
case "external" :
2017-08-07 19:19:24 +08:00
result . add ( ` \n // EXTERNAL MODULE: ${ info . module . readableIdentifier ( requestShortener ) } \n ` ) ;
result . add ( ` var ${ info . name } = __webpack_require__( ${ info . module . id } ); \n ` ) ;
if ( info . module . meta && ! info . module . meta . harmonyModule ) {
result . add ( ` var ${ info . name } _default = /*#__PURE__*/__webpack_require__.n( ${ info . name } ); \n ` ) ;
}
2017-08-07 17:53:07 +08:00
break ;
default :
2017-08-07 19:19:24 +08:00
throw new Error ( ` Unsupported concatenation entry type ${ info . type } ` ) ;
2017-05-10 19:15:14 +08:00
}
} ) ;
return result ;
}
2017-05-31 22:46:25 +08:00
findNewName ( oldName , usedNamed1 , usedNamed2 , extraInfo ) {
2017-05-10 19:15:14 +08:00
let name = oldName ;
if ( name === "__WEBPACK_MODULE_DEFAULT_EXPORT__" )
name = "defaultExport" ;
2017-06-07 18:57:15 +08:00
// Remove uncool stuff
extraInfo = extraInfo . replace ( /(\/index)?\.([a-zA-Z0-9]{1,4})$/ , "" ) ;
2017-05-10 19:15:14 +08:00
const splittedInfo = extraInfo . split ( "/" ) ;
while ( splittedInfo . length ) {
name = splittedInfo . pop ( ) + "_" + name ;
2017-05-31 22:46:25 +08:00
const nameIdent = Template . toIdentifier ( name ) ;
if ( ! usedNamed1 . has ( nameIdent ) && ( ! usedNamed2 || ! usedNamed2 . has ( nameIdent ) ) ) return nameIdent ;
2017-05-10 19:15:14 +08:00
}
2017-05-31 22:46:25 +08:00
while ( usedNamed1 . has ( name = name + "_" ) || ( usedNamed2 && usedNamed2 . has ( name ) ) ) { /* do nothing */ }
2017-05-10 19:15:14 +08:00
return name ;
}
2017-07-07 17:48:52 +08:00
updateHash ( hash ) {
2017-08-07 17:53:07 +08:00
for ( const info of this . _orderedConcatenationList ) {
switch ( info . type ) {
case "concatenated" :
info . module . updateHash ( hash ) ;
break ;
case "external" :
hash . update ( ` ${ info . module . id } ` ) ;
break ;
}
2017-07-07 17:48:52 +08:00
}
super . updateHash ( hash ) ;
}
2017-05-10 19:15:14 +08:00
}
class HarmonyImportSpecifierDependencyConcatenatedTemplate {
constructor ( originalTemplate , modulesMap ) {
this . originalTemplate = originalTemplate ;
this . modulesMap = modulesMap ;
}
apply ( dep , source , outputOptions , requestShortener , dependencyTemplates ) {
const module = dep . importDependency . module ;
const info = this . modulesMap . get ( module ) ;
if ( ! info ) {
this . originalTemplate . apply ( dep , source , outputOptions , requestShortener , dependencyTemplates ) ;
return ;
}
let content ;
if ( dep . id === null ) {
content = ` __WEBPACK_MODULE_REFERENCE__ ${ info . index } _ns__ ` ;
2017-07-12 01:08:23 +08:00
} else if ( dep . namespaceObjectAsContext ) {
content = ` __WEBPACK_MODULE_REFERENCE__ ${ info . index } _ns__[ ${ JSON . stringify ( dep . id ) } ] ` ;
2017-05-10 19:15:14 +08:00
} else {
2017-08-07 19:56:50 +08:00
const exportData = Buffer . from ( dep . id , "utf-8" ) . toString ( "hex" ) ;
content = ` __WEBPACK_MODULE_REFERENCE__ ${ info . index } _ ${ exportData } ${ dep . call ? "_call" : "" } __ ` ;
2017-05-10 19:15:14 +08:00
}
if ( dep . shorthand ) {
content = dep . name + ": " + content ;
}
source . replace ( dep . range [ 0 ] , dep . range [ 1 ] - 1 , content ) ;
}
}
class HarmonyImportDependencyConcatenatedTemplate {
constructor ( originalTemplate , modulesMap ) {
this . originalTemplate = originalTemplate ;
this . modulesMap = modulesMap ;
}
apply ( dep , source , outputOptions , requestShortener , dependencyTemplates ) {
const module = dep . module ;
const info = this . modulesMap . get ( module ) ;
if ( ! info ) {
this . originalTemplate . apply ( dep , source , outputOptions , requestShortener , dependencyTemplates ) ;
return ;
}
source . replace ( dep . range [ 0 ] , dep . range [ 1 ] - 1 , "" ) ;
}
}
class HarmonyExportSpecifierDependencyConcatenatedTemplate {
constructor ( originalTemplate , rootModule ) {
this . originalTemplate = originalTemplate ;
this . rootModule = rootModule ;
}
apply ( dep , source , outputOptions , requestShortener , dependencyTemplates ) {
if ( dep . originModule === this . rootModule ) {
this . originalTemplate . apply ( dep , source , outputOptions , requestShortener , dependencyTemplates ) ;
}
}
}
class HarmonyExportExpressionDependencyConcatenatedTemplate {
constructor ( originalTemplate , rootModule ) {
this . originalTemplate = originalTemplate ;
this . rootModule = rootModule ;
}
apply ( dep , source , outputOptions , requestShortener , dependencyTemplates ) {
2017-07-22 05:32:31 +08:00
let content = "/* harmony default export */ var __WEBPACK_MODULE_DEFAULT_EXPORT__ = " ;
2017-05-10 19:15:14 +08:00
if ( dep . originModule === this . rootModule ) {
2017-07-22 05:32:31 +08:00
const used = dep . originModule . isUsed ( "default" ) ;
const exportsName = dep . originModule . exportsArgument || "exports" ;
if ( used ) content += ` ${ exportsName } [ ${ JSON . stringify ( used ) } ] = ` ;
}
2017-05-10 19:15:14 +08:00
2017-07-22 05:32:31 +08:00
if ( dep . range ) {
source . replace ( dep . rangeStatement [ 0 ] , dep . range [ 0 ] - 1 , content + "(" ) ;
source . replace ( dep . range [ 1 ] , dep . rangeStatement [ 1 ] - 1 , ");" ) ;
return ;
2017-05-10 19:15:14 +08:00
}
2017-07-22 05:32:31 +08:00
source . replace ( dep . rangeStatement [ 0 ] , dep . rangeStatement [ 1 ] - 1 , content ) ;
2017-05-10 19:15:14 +08:00
}
}
class HarmonyExportImportedSpecifierDependencyConcatenatedTemplate {
constructor ( originalTemplate , rootModule , modulesMap ) {
this . originalTemplate = originalTemplate ;
this . rootModule = rootModule ;
this . modulesMap = modulesMap ;
}
getExports ( dep ) {
const active = HarmonyModulesHelpers . isActive ( dep . originModule , dep ) ;
if ( ! active ) return [ ] ;
const importModule = dep . importDependency . module ;
if ( dep . id ) {
// export { named } from "module"
return [ {
name : dep . name ,
id : dep . id ,
module : importModule
} ] ;
}
if ( dep . name ) {
// export * as abc from "module"
return [ {
name : dep . name ,
id : true ,
module : importModule
} ] ;
}
// export * from "module"
const activeExports = new Set ( HarmonyModulesHelpers . getActiveExports ( dep . originModule , dep ) ) ;
return importModule . providedExports . filter ( exp => exp !== "default" && ! activeExports . has ( exp ) ) . map ( exp => {
return {
name : exp ,
id : exp ,
module : importModule
} ;
} ) ;
}
apply ( dep , source , outputOptions , requestShortener , dependencyTemplates ) {
if ( dep . originModule === this . rootModule ) {
if ( this . modulesMap . get ( dep . importDependency . module ) ) {
const exportDefs = this . getExports ( dep ) ;
exportDefs . forEach ( def => {
const info = this . modulesMap . get ( def . module ) ;
const used = dep . originModule . isUsed ( def . name ) ;
if ( ! used ) {
source . insert ( - 1 , ` /* unused concated harmony import ${ dep . name } */ \n ` ) ;
}
let finalName ;
if ( def . id === true ) {
finalName = ` __WEBPACK_MODULE_REFERENCE__ ${ info . index } _ns__ ` ;
} else {
2017-08-07 19:56:50 +08:00
const exportData = Buffer . from ( def . id , "utf-8" ) . toString ( "hex" ) ;
finalName = ` __WEBPACK_MODULE_REFERENCE__ ${ info . index } _ ${ exportData } __ ` ;
2017-05-10 19:15:14 +08:00
}
const exportsName = this . rootModule . exportsArgument || "exports" ;
2017-05-16 17:14:59 +08:00
const content = ` /* concated harmony reexport */__webpack_require__.d( ${ exportsName } , ${ JSON . stringify ( used ) } , function() { return ${ finalName } ; }); \n ` ;
2017-05-10 19:15:14 +08:00
source . insert ( - 1 , content ) ;
} ) ;
} else {
this . originalTemplate . apply ( dep , source , outputOptions , requestShortener , dependencyTemplates ) ;
}
}
}
}
class HarmonyCompatibilityDependencyConcatenatedTemplate {
constructor ( originalTemplate , rootModule , modulesMap ) {
this . originalTemplate = originalTemplate ;
this . rootModule = rootModule ;
this . modulesMap = modulesMap ;
}
apply ( dep , source , outputOptions , requestShortener , dependencyTemplates ) {
if ( dep . originModule === this . rootModule ) {
this . modulesMap . get ( this . rootModule ) . needCompatibilityFlag = true ;
}
}
}
module . exports = ConcatenatedModule ;