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" ) ;
function getFinalName ( info , exportName , moduleToInfoMap , requestShortener ) {
const directExport = info . exportMap . get ( exportName ) ;
if ( directExport ) {
if ( exportName === true )
info . needNamespaceObject = true ;
2017-06-20 22:13:32 +08:00
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 ;
2017-05-10 19:15:14 +08:00
}
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 ) ;
} else {
const dep = reexport . dependency ;
const importedModule = reexport . module ;
const exportName = reexport . exportName ;
2017-05-21 12:56:24 +08:00
const isHarmonyModule = importedModule && ( ! importedModule . meta || importedModule . meta . harmonyModule ) ;
2017-05-10 19:15:14 +08:00
const importedVar = dep . importedVar ;
const used = importedModule . isUsed ( exportName ) ;
if ( ! used ) return "/* unused reexport */undefined" ;
2017-05-21 12:56:24 +08:00
if ( ! isHarmonyModule && exportName === "default" ) {
2017-05-10 19:15:14 +08:00
return ` ${ importedVar } _default.a ` ;
}
return ` ${ importedVar } [ ${ JSON . stringify ( used ) } ] ` ;
}
}
throw new Error ( ` Cannot get final name for export " ${ exportName } " in " ${ info . module . readableIdentifier ( requestShortener ) } " ` +
` (known exports: ${ Array . from ( info . exportMap . keys ( ) ) . join ( " " ) } , ` +
` known reexports: ${ Array . from ( info . reexportMap . keys ( ) ) . join ( " " ) } ) ` ) ;
}
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 . modules = modules ;
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 ) ;
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-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-06-18 20:46:06 +08:00
for ( const m of modules ) {
// 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 ) ) ;
2017-06-22 22:30:28 +08:00
// 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 ) ) ;
2017-06-18 20:46:06 +08:00
// populate warnings
m . warnings . forEach ( warning => this . warnings . push ( warning ) ) ;
// populate errors
m . errors . forEach ( error => this . errors . push ( error ) ) ;
2017-06-22 11:32:59 +08:00
Object . assign ( this . assets , m . assets ) ;
2017-06-18 20:46:06 +08:00
}
2017-05-10 19:15:14 +08:00
}
identifier ( ) {
return this . modules . map ( m => m . identifier ( ) ) . join ( " " ) ;
}
readableIdentifier ( requestShortener ) {
return this . rootModule . readableIdentifier ( requestShortener ) + ` + ${ this . modules . length - 1 } modules ` ;
}
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
return this . modules . reduce ( ( sum , m ) => sum + m . size ( ) , 0 ) ;
}
source ( dependencyTemplates , outputOptions , requestShortener ) {
const modulesSet = new Set ( ) ;
this . modules . forEach ( m => modulesSet . add ( m ) ) ;
// Metainfo for each module
const modulesWithInfo = this . modules . map ( ( m , idx ) => {
const exportMap = new Map ( ) ;
const reexportMap = new Map ( ) ;
m . 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 ${ m . readableIdentifier ( requestShortener ) } ` ) ;
}
}
} ) ;
return {
module : m ,
index : idx ,
2017-06-13 19:38:12 +08:00
ast : undefined ,
2017-05-10 19:15:14 +08:00
source : undefined ,
globalScope : undefined ,
moduleScope : undefined ,
internalNames : new Map ( ) ,
exportMap : exportMap ,
reexportMap : reexportMap ,
needCompatibilityFlag : false ,
2017-06-07 18:56:53 +08:00
needNamespaceObject : false ,
namespaceObjectSource : null
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 => {
const m = info . module ;
const source = m . source ( innerDependencyTemplates , outputOptions , requestShortener ) ;
const code = source . source ( ) ;
const ast = acorn . parse ( code , {
ranges : true ,
locations : true ,
2017-05-21 12:56:24 +08:00
ecmaVersion : Parser . ECMA _VERSION ,
2017-05-10 19:15:14 +08:00
sourceType : "module"
} ) ;
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 ] ;
2017-06-06 17:18:34 +08:00
const resultSource = new ReplaceSource ( source ) ;
2017-06-13 19:38:12 +08:00
info . ast = ast ;
2017-05-10 19:15:14 +08:00
info . source = resultSource ;
info . globalScope = globalScope ;
info . moduleScope = moduleScope ;
} ) ;
// 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-05-31 22:46:25 +08:00
info . globalScope . through . forEach ( reference => {
const name = reference . identifier . name ;
if ( /^__WEBPACK_MODULE_REFERENCE__\d+_(\d+|ns)__$/ . test ( name ) ) {
for ( const s of getSymbolsFromScope ( reference . from , info . moduleScope ) ) {
allUsedNames . add ( s ) ;
}
} else {
2017-05-10 19:15:14 +08:00
allUsedNames . add ( name ) ;
2017-05-31 22:46:25 +08:00
}
2017-05-10 19:15:14 +08:00
} ) ;
} ) ;
modulesWithInfo . forEach ( info => {
2017-05-31 22:46:25 +08:00
const namespaceObjectName = this . findNewName ( "namespaceObject" , allUsedNames , null , info . module . readableIdentifier ( requestShortener ) ) ;
2017-06-07 18:56:53 +08:00
allUsedNames . add ( namespaceObjectName ) ;
2017-05-10 19:15:14 +08:00
info . internalNames . set ( namespaceObjectName , namespaceObjectName ) ;
info . exportMap . set ( true , namespaceObjectName ) ;
info . moduleScope . variables . forEach ( variable => {
2017-05-21 12:56:24 +08:00
const name = variable . name ;
2017-05-10 19:15:14 +08:00
if ( allUsedNames . has ( name ) ) {
2017-06-06 17:18:34 +08:00
const references = getAllReferences ( variable ) ;
const symbolsInReferences = references . map ( ref => getSymbolsFromScope ( ref . from , info . moduleScope ) ) . reduce ( reduceSet , new Set ( ) ) ;
2017-05-31 22:46:25 +08:00
const newName = this . findNewName ( name , allUsedNames , symbolsInReferences , info . module . readableIdentifier ( requestShortener ) ) ;
2017-05-10 19:15:14 +08:00
allUsedNames . add ( newName ) ;
info . internalNames . set ( name , newName ) ;
const source = info . source ;
2017-06-06 17:18:34 +08:00
const allIdentifiers = new Set ( references . map ( r => r . identifier ) . concat ( variable . identifiers ) ) ;
2017-05-10 19:15:14 +08:00
for ( const identifier of allIdentifiers ) {
const r = identifier . range ;
2017-06-13 19:38:12 +08:00
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 ) ;
}
2017-05-10 19:15:14 +08:00
}
} else {
allUsedNames . add ( name ) ;
info . internalNames . set ( name , name ) ;
}
} ) ;
} ) ;
modulesWithInfo . forEach ( info => {
info . globalScope . through . forEach ( reference => {
const name = reference . identifier . name ;
const match = /^__WEBPACK_MODULE_REFERENCE__(\d+)_(\d+|ns)__$/ . exec ( name ) ;
if ( match ) {
const referencedModule = modulesWithInfo [ + match [ 1 ] ] ;
let exportName ;
if ( match [ 2 ] === "ns" ) {
exportName = true ;
} else {
const exportIdx = + match [ 2 ] ;
exportName = referencedModule . module . providedExports [ exportIdx ] ;
}
const finalName = getFinalName ( referencedModule , exportName , moduleToInfoMap , requestShortener ) ;
const r = reference . identifier . range ;
const source = info . source ;
source . replace ( r [ 0 ] , r [ 1 ] - 1 , finalName ) ;
}
} ) ;
} ) ;
const result = new ConcatSource ( ) ;
if ( moduleToInfoMap . get ( this . rootModule ) . needCompatibilityFlag ) {
2017-05-23 02:04:23 +08:00
result . add ( ` Object.defineProperty( ${ this . rootModule . exportsArgument || "exports" } , "__esModule", { value: true }); \n ` ) ;
2017-05-10 19:15:14 +08:00
}
2017-06-07 19:12:37 +08:00
let generated = true ;
const ensureNsObjSource = info => {
if ( info . needNamespaceObject && ! info . namespaceObjectSource ) {
const name = info . exportMap . get ( true ) ;
const nsObj = [ ` var ${ name } = {}; ` ] ;
for ( const exportName of info . module . providedExports ) {
const finalName = getFinalName ( info , exportName , moduleToInfoMap , requestShortener ) ;
nsObj . push ( ` __webpack_require__.d( ${ name } , ${ JSON . stringify ( exportName ) } , function() { return ${ finalName } ; }); ` ) ;
2017-06-07 18:56:53 +08:00
}
2017-06-07 19:12:37 +08:00
info . namespaceObjectSource = nsObj . join ( "\n" ) + "\n" ;
generated = true ;
}
} ;
while ( generated ) {
generated = false ;
modulesWithInfo . forEach ( ensureNsObjSource ) ;
}
2017-05-10 19:15:14 +08:00
modulesWithInfo . forEach ( info => {
2017-05-21 12:56:24 +08:00
result . add ( ` \n // CONCATENATED MODULE: ${ info . module . readableIdentifier ( requestShortener ) } \n ` ) ;
2017-06-07 18:56:53 +08:00
if ( info . namespaceObjectSource ) {
result . add ( info . namespaceObjectSource ) ;
2017-05-10 19:15:14 +08:00
}
result . add ( info . source ) ;
} ) ;
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 ) {
for ( const m of this . modules ) {
m . updateHash ( hash ) ;
}
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 ;
}
if ( ! Array . isArray ( module . providedExports ) )
throw new Error ( ` Module ${ module . resource } has no static exports ${ module . providedExports } ` ) ;
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 {
const exportIdx = ( module . providedExports ) . indexOf ( dep . id ) ;
content = exportIdx === - 1 ? "undefined" : ` __WEBPACK_MODULE_REFERENCE__ ${ info . index } _ ${ exportIdx } __ ` ;
}
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 ) {
if ( dep . originModule === this . rootModule ) {
this . originalTemplate . apply ( dep , source , outputOptions , requestShortener , dependencyTemplates ) ;
} else {
const content = "/* harmony default export */ var __WEBPACK_MODULE_DEFAULT_EXPORT__ = " ;
if ( dep . range ) {
source . replace ( dep . rangeStatement [ 0 ] , dep . range [ 0 ] - 1 , content + "(" ) ;
source . replace ( dep . range [ 1 ] , dep . rangeStatement [ 1 ] - 1 , ");" ) ;
return ;
}
source . replace ( dep . rangeStatement [ 0 ] , dep . rangeStatement [ 1 ] - 1 , content ) ;
}
}
}
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 {
const exportIdx = def . module . providedExports . indexOf ( def . id ) ;
finalName = exportIdx < 0 ? "undefined" : ` __WEBPACK_MODULE_REFERENCE__ ${ info . index } _ ${ exportIdx } __ ` ;
}
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 ;