webpack运行过程(2)

222 阅读2分钟

这是我参与11月更文挑战的第5天

webpack运行过程(1)中讲到 宏任务执行AsyncQueue的_ensureProcessing()方法,该方法内会遍历前面加入到AsyncAueue中的所有entry

遍历AsyncQueue中存储的所有entry,执行_startProcessing(entry)

function _startProcessing(entry){
  this.hooks.beforestart.callAsync(entry.item, err => {
      if(err) {}
      this._processor(entry.item)
  })
}

执行AsyncQueue的_processor()方法

_processor方法时前面实例化new AsyncQueue时传入的函数

这个函数是:

this.factorizeQueue = new AsyncQueue({
    name: 'factorize',
    parent: this.addModuleQueue,
    processor: this._factorizeModule.bind(this)
})

function _factorizeModule(){
    factory.create()
}


//webpack/lib/NormalModuleFactory.js 
function create(data, callback){
    const dependencies = data.dependencies
    const request = dependencies.request // './src/app.js'
    this.hooks.beforeResolved.callAsync(resolveData, (err, result) => {
        this.hooks.factorize.callAsync(resolveDate, (err, module) => {
        
        
        })
    })
}

//插件ExternalModuleFactoryPlugin注册了normalModuleFactory.hooks.factorize.tapAsync


normalModuleFactory.hooks.factorize.tapAsync(
"ExternalModuleFactoryPlugin", 
(data, callback) => {
    handleExternals()
}
)


// NormalModuleFactory自己也注册了 this.hooks.factorize.tapAsync


this.hooks.factorize.tapAsync({
    name : 'NormalModuleFactory',
    stage: 400
}, (resolveData, callback) => {
    // 运行NormalModuleFactory的resolve钩子
    this.hooks.resolve.callAsync()
    
})

this.hooks.resolve.tapAsync({}, ()=>{
    defaultResolve(context) // context = 'D:\\code\\web_learn\\webpack\\demo'
})

function defaultResolve(){
    this.resolveResource()
}

function resolveResource(){
    resolver.resolve()
}

//enhanced-resolve/lib/Resolver.js
function resolve(){
    this.doResolve()
}

function doResolve(){
    request = {
        context: {}
        path : 'D:\\code\\web_learn\\webpack\\demo'
        request: './src/app.js'
    }
    hook.callAsync(request)
}

// webpack/li/cache/ResolverCachePlugin.js
// ResolverCachePlugin注册了hook.tapAsync
resolver.hooks.resolve.tapAsync({},()=>{
    itemCache.get(processCacheResult)
})

// webpack/lib/CacheFacade.js
get(){
    // this._name = 'ResolverCachePlugin|normal|dependencyType=|esm|path=|D:\\code\\web_learn\\webpack\\demo|request=|./src/app.js'
    this._cache.get(this._name)
}

// Cache.js
get(identifier){
    const gotHandler = []
    this.hooks.get.callAsync(identifier, gotHandler, (err, result)=>{
        if(gotHandlers.length === 1){
            // 先执行回调函数callback
            gotHandler[0](result, ()=> callback(null, result))
        }
    })
}

// 上面的回调函数是processCacheResult
// webpack/li/cache/ResolverCachePlugin.js
function processCacheResult(err, cacheEntry){
    if(cacheEntry){
    
    }else{
        doRealResolve(itemCache)
    }
}

function doRealResolve(){
    resolver.doResolve()
}

//enhanced-resolve/lib/Resolver.js
function doResolve(){
}

处理入口文件之前,先下载描述文件package.json

DescriptionFilePlugin插件注册了resolver.getHook(this.source).tapAsync

class DescriptionFilePlugin {
     apply(resolver){
         const target = resolver.ensureHook(this.target);
		resolver
			.getHook(this.source)
			.tapAsync(
				"DescriptionFilePlugin",
				(request, resolveContext, callback) => {
                                //'D:\\code\\web_learn\\webpack\\demo'
                                 const path = request.path;
                                 DescriptionFileUtils.loadDescriptionFile()
                }
     }
}
loadDescriptionFile(){
    (findDescripttionFile(){
        forEachBail(filenames,  (filename, callback) => {
            // directory = 'D:\\code\\web_learn\\webpack\\demo'
            // filename = 'package.json'
            const descriptionFilePath = resolver.join(directory, filename);
            resolver.fileSystem.readJson(descriptionFilePath, (err, context) => {
            
            })
            
        
        })
    })()
}



使用node的fs.readFile(path)读取package.json文件,并将文件内容缓存



_readFileTimestamp(path)  //webpack/lib/FileSystemInfo.js
provide(path) //enhanced-resolve/lib/CachedInputFileSystem.js

function provide(path){
    // 首先检查缓存中是否有该路径文件
    let cacheEntry = this._data.get(path)
    let result = this.readFile(path)
    this.storeResult(path, result)
    // 获取到文件以后再执行回调函数
}

//graceful-fs/graceful-fs.js
function readFile(path){
    go$readFile(path)
    fs$readFile(path)
    fs$readFile = fs.readfile(path)
    // 通过node的fs.readFile(path)读取文件
}

//读取文件内容后,缓存起来
function _storeResult(path,result){
    if(this._data.has(path)) return;
    const level = this._levels[this._currentLevel]
    this._data.set(path, {err, result, level})
    level.add(path)
}

将读取到的package.json文件内容Buffer转换为utf-8


let cacheEntry = this._data.get(path)
if(!cacheEntry){
    fs.readFile(path, (err, result){
        this.date.set(path, result)
        // buffer转化为utf-8
        let data = JSON.parse(result.toString('utf-8'))
    })
}

resolveContext.fileDependencies中添加path

//descriptionFilePath  = 'D:\\code\\web_learn\\webpack\\demo\\package.json'
resolveContext.fileDependencies.add(descriptionFilePath);

//enhanced-resolve/lib/DescriptionFileUtil.js
function onJson(){
 callback()
}

// 执行前面传入的回调函数
// result.directory = 'D:\\code\\web_learn\\webpack\\demo'
// path = 'D:\\code\\web_learn\\webpack\\demo'
const relativePath = "." + path.substr(result.directory.length).replace(/\\/g, "/")
// relativePath = "."
resolver.doResolve()

//enhanced-resolve/lib/Resolver.js
function doResolve(){
    const stackEntry = "describedResolve: (D:\\code\\web_learn\\webpack\\demo) ./src/app.js"
    let newStack;
    newStack.add(stackEntry)
    newStack = {
        0 : "resolve: (D:\\code\\web_learn\\webpack\\demo) ./src/app.js",
        1 : "parseResolve (D:\\code\\web_learn\\webpack\\demo) ./src/app.js",
        2 : "describedResolve: (D:\\code\\web_learn\\webpack\\demo) ./src/app.js"
    }
}

ConditionalPlugin插件

FileExistsPlugin插件判断文件是否存在

//enhanced-relove/lib/FileExistsPlugin.js
apply(resolver) {
		const target = resolver.ensureHook(this.target);
		const fs = resolver.fileSystem;
resolver.getHook(this.source).tapAsync("FileExistsPlugin", (request, resolveContext, callback) => {
	const file = request.path;
	if (!file) return callback();
         // 使用node的fs.stat(file)判断文件是否存在
	fs.stat(file, (err, stat) => {
            if(!stat.isFile()){
            
            }
            resolveContext.fileDependencies.add(file);
            resolver.doResolve()
        }
     }

SymlinkPlugin插件

// path = 'D:\\code\\web_learn\\webpack\\demo\\src\\app.js'
fs.readlink(path)

未完待续 webpack运行过程(3)