classModuleNode{/**
* Public served url path, starts with /
*/url: string/**
* Resolved file system path + query
*/id: string|null=nullfile: string|null=nulltype:'js'|'css'info?: ModuleInfometa?: Record<string,any>importers=newSet<ModuleNode>()importedModules=newSet<ModuleNode>()acceptedHmrDeps=newSet<ModuleNode>()isSelfAccepting?: booleantransformResult: TransformResult|null=nullssrTransformResult: TransformResult|null=nullssrModule: Record<string,any>|null=nullssrError: Error|null=nulllastHMRTimestamp=0lastInvalidationTimestamp=0constructor(url: string){this.url=urlthis.type=isDirectCSSRequest(url)?'css':'js'// #7870
// The `isSelfAccepting` value is set by importAnalysis, but some
// assets don't go through importAnalysis.
if(isHTMLRequest(url)||canSkipImportAnalysis(url)){this.isSelfAccepting=false}}}
ModuleGraph 🔗
模块依赖容器类
容器类有4个属性,分别用来记录url、id、文件和模块之间的对应关系
1
2
3
4
5
urlToModuleMap=newMap<string,ModuleNode>()idToModuleMap=newMap<string,ModuleNode>()// a single file may corresponds to multiple modules with different queries
fileToModulesMap=newMap<string,Set<ModuleNode>>()safeModulesPath=newSet<string>()
// for incoming urls, it is important to:
// 1. remove the HMR timestamp query (?t=xxxx)
// 2. resolve its extension so that urls with or without extension all map to
// the same module
asyncresolveUrl(url:string,ssr?:boolean):Promise<ResolvedUrl>{url=removeImportQuery(removeTimestampQuery(url))constresolved=awaitthis.resolveId(url,!!ssr)constresolvedId=resolved?.id||urlconstext=extname(cleanUrl(resolvedId))const{pathname,search,hash}=parseUrl(url)if(ext&&!pathname!.endsWith(ext)){url=pathname+ext+(search||'')+(hash||'')}return[url,resolvedId,resolved?.meta]}
/**
* Update the module graph based on a module's updated imports information
* If there are dependencies that no longer have any importers, they are
* returned as a Set.
*/asyncupdateModuleInfo(mod:ModuleNode,importedModules:Set<string|ModuleNode>,acceptedModules:Set<string|ModuleNode>,isSelfAccepting:boolean,ssr?:boolean):Promise<Set<ModuleNode>|undefined>{mod.isSelfAccepting=isSelfAccepting// 之前的引入的依赖
constprevImports=mod.importedModules// 重置依赖为一个set
constnextImports=(mod.importedModules=newSet())// 这个变量用于保存那些不再有任何依赖的模块
letnoLongerImported:Set<ModuleNode>|undefined// update import graph
for(constimportedofimportedModules){constdep=typeofimported==='string'// 依赖是个字符串的时候,都会再去走一下获取文件的逻辑
?awaitthis.ensureEntryFromUrl(imported,ssr):imported// 加入到模块的importers中去
dep.importers.add(mod)nextImports.add(dep)}// remove the importer from deps that were imported but no longer are.
prevImports.forEach((dep)=>{// 比对,新模块中没有就删除掉
if(!nextImports.has(dep)){dep.importers.delete(mod)if(!dep.importers.size){// 加入到0依赖的set中
// dependency no longer imported
;(noLongerImported||(noLongerImported=newSet())).add(dep)}}})// update accepted hmr deps
// 遍历加入到模块acceptedHmrDeps队列中
constdeps=(mod.acceptedHmrDeps=newSet())for(constacceptedofacceptedModules){constdep=typeofaccepted==='string'?awaitthis.ensureEntryFromUrl(accepted,ssr):accepteddeps.add(dep)}returnnoLongerImported}