文章目录
作用 涉及 webpack API 获取chunkGraph 获取当前编译过程中被使用过的 module id:compilation.usedModuleIds 获取当前编译过程中所有的模块对象:compilation.modules 判断 module 是否需要生成 id:module.needId 获取指定module 的 module id:chunkGraph.getModuleId 获取 module 属于多少个chunk:chunkGraph.getNumberOfModuleChunks 获取 module 标识符:module.identifier 设置 module id:chunkGraph.setModuleId
实现 constructor apply getUsedModuleIdsAndModules
作用
将模块打包生成后的 id 变成 hash 值,用于生成稳定的模块 id
new webpack. ids. HashedModuleIdsPlugin ( ) ,
涉及 webpack API
const chunkGraph = compilation. chunkGraph;
获取当前编译过程中被使用过的 module id:compilation.usedModuleIds
compilation. usedModuleIds;
获取当前编译过程中所有的模块对象:compilation.modules
for ( const module of compilation. modules) {
}
判断 module 是否需要生成 id:module.needId
表示该模块是否需要一个模块 id, 在 webpack 的编译过程中,有些模块可能不需要一个独立的模块 id,例如一些内置模块或者一些被动态加载的模块
for ( const module of compilation. modules) {
if ( ! module. needId) continue ;
const moduleId = chunkGraph. getModuleId ( module) ;
}
获取指定module 的 module id:chunkGraph.getModuleId
for ( const module of compilation. modules) {
if ( ! module. needId) continue ;
const moduleId = chunkGraph. getModuleId ( module) ;
}
获取 module 属于多少个chunk:chunkGraph.getNumberOfModuleChunks
if ( chunkGraph. getNumberOfModuleChunks ( module) !== 0 ) {
}
获取 module 标识符:module.identifier
根据 module 的 type、request、layer创建
for ( const module of compilation. modules) {
module. identifier ( )
}
identifier ( ) {
if ( this . layer === null ) {
if ( this . type === "javascript/auto" ) {
return this . request;
} else {
return ` ${ this . type} | ${ this . request} ` ;
}
} else {
return ` ${ this . type} | ${ this . request} | ${ this . layer} ` ;
}
}
设置 module id:chunkGraph.setModuleId
for ( const module of compilation. modules) {
const moduleId= 'xxx'
chunkGraph. setModuleId ( module, moduleId) ;
}
实现
constructor
class HashedModuleIdsPlugin {
constructor ( options = { } ) {
validate ( options) ;
this . options = {
context : null ,
hashFunction : "md4" ,
hashDigest : "base64" ,
hashDigestLength : 4 ,
... options
} ;
}
}
apply
apply ( compiler ) {
const options = this . options;
compiler. hooks. compilation. tap ( "HashedModuleIdsPlugin" , compilation => {
compilation. hooks. moduleIds. tap ( "HashedModuleIdsPlugin" , ( ) => {
const chunkGraph = compilation. chunkGraph;
const context = this . options. context
? this . options. context
: compiler. context;
const [ usedIds, modules] = getUsedModuleIdsAndModules ( compilation) ;
const modulesInNaturalOrder = modules. sort (
compareModulesByPreOrderIndexOrIdentifier ( compilation. moduleGraph)
) ;
for ( const module of modulesInNaturalOrder) {
const ident = getFullModuleName ( module, context, compiler. root) ;
const hash = createHash ( options. hashFunction) ;
hash. update ( ident || "" ) ;
const hashId = (
hash. digest ( options. hashDigest)
) ;
let len = options. hashDigestLength;
while ( usedIds. has ( hashId. slice ( 0 , len) ) ) len++ ;
const moduleId = hashId. slice ( 0 , len) ;
chunkGraph. setModuleId ( module, moduleId) ;
usedIds. add ( moduleId) ;
}
} ) ;
} ) ;
}
getUsedModuleIdsAndModules
获取所有效的 modules 和已经编译使用过的 module id 只有需要生成 module id 的 module 且之前没有创建过且 module 在某个 chunk 中才有效
const getUsedModuleIdsAndModules = ( compilation, filter ) => {
const chunkGraph = compilation. chunkGraph;
const modules = [ ] ;
const usedIds = new Set ( ) ;
if ( compilation. usedModuleIds) {
for ( const id of compilation. usedModuleIds) {
usedIds. add ( id + "" ) ;
}
}
for ( const module of compilation. modules) {
if ( ! module. needId) continue ;
const moduleId = chunkGraph. getModuleId ( module) ;
if ( moduleId !== null ) {
usedIds. add ( moduleId + "" ) ;
} else {
if (
( ! filter || filter ( module) ) &&
chunkGraph. getNumberOfModuleChunks ( module) !== 0
) {
modules. push ( module) ;
}
}
}
return [ usedIds, modules] ;
} ;