const webpack = (options, callback) => { //... if (callback) { if (typeof callback !== "function") { throw new Error("Invalid argument: callback"); } if ( options.watch === true || (Array.isArray(options) && options.some(o => o.watch)) ) { const watchOptions = Array.isArray(options) ? options.map(o => o.watchOptions || {}) : options.watchOptions || {}; return compiler.watch(watchOptions, callback); } compiler.run(callback); } return compiler; }
最終返回了compilerreact
exports.version = version; // ...屬性掛載,把引入的函數模塊所有暴露出來 webpack.WebpackOptionsDefaulter = WebpackOptionsDefaulter; webpack.WebpackOptionsApply = WebpackOptionsApply; webpack.Compiler = Compiler; webpack.MultiCompiler = MultiCompiler; webpack.NodeEnvironmentPlugin = NodeEnvironmentPlugin; // @ts-ignore Global @this directive is not supported webpack.validate = validateSchema.bind(this, webpackOptionsSchema); webpack.validateSchema = validateSchema; webpack.WebpackOptionsValidationError = WebpackOptionsValidationError;
下面暴露了一些插件webpack
const exportPlugins = (obj, mappings) => { for (const name of Object.keys(mappings)) { Object.defineProperty(obj, name, { configurable: false, enumerable: true, get: mappings[name] }); } }; exportPlugins(exports, { AutomaticPrefetchPlugin: () => require("./AutomaticPrefetchPlugin"), BannerPlugin: () => require("./BannerPlugin"), CachePlugin: () => require("./CachePlugin")} )
再通俗一點的解釋:
好比當你api.AutomaticPrefetchPlugin你能
調用AutomaticPrefetchPlugin文件下的方法
這個和上面的不一樣在於上面的是掛在webpack函數對象上的git
要想理解Compiler.js
必需要理解tapable
再寫一遍 git地址 github
咱們先簡單的理解它爲一個經過tap 註冊插件
call是run插件的事件流,裏面還有一些異步的操做web
Compiler整理以下api
class Compiler extends Tapable { constructor(context) { super(); this.hooks = { //羅列一些出現頻率比較高的 shouldEmit: new SyncBailHook(["compilation"]), done: new AsyncSeriesHook(["stats"]), beforeRun: new AsyncSeriesHook(["compiler"]), run: new AsyncSeriesHook(["compiler"]), emit: new AsyncSeriesHook(["compilation"]), afterEmit: new AsyncSeriesHook(["compilation"]), thisCompilation: new SyncHook(["compilation", "params"]), compilation: new SyncHook(["compilation", "params"]), beforeCompile: new AsyncSeriesHook(["params"]), compile: new SyncHook(["params"]), make: new AsyncParallelHook(["compilation"]), afterCompile: new AsyncSeriesHook(["compilation"]), watchRun: new AsyncSeriesHook(["compiler"]), //... } // 添加事件流 this._pluginCompat.tap("Compiler", options => { switch (options.name) { case "additional-pass": case "before-run": case "run": case "emit": case "after-emit": case "before-compile": case "make": case "after-compile": case "watch-run": options.async = true; break; } }); } watch(){ //... } run(callback) { //... } // 清除輸入文件系統 purgeInputFileSystem() { if (this.inputFileSystem && this.inputFileSystem.purge) { this.inputFileSystem.purge(); } } emitAssets(compilation, callback) { //... } createChildCompiler( compilation, compilerName, compilerIndex, outputOptions, plugins ) { //... } //... compile(callback){ //... } }
和tapable用法一個模子裏刻出來的,咱們仔細的研究run函數promise
compiler.js是webpack 的核心app
run(callback) { //若是正在running,返回報錯處理 if (this.running) return callback(new ConcurrentCompilationError()); //running調用finalCallback const finalCallback = (err, stats) => { this.running = false; if (callback !== undefined) return callback(err, stats); }; //記錄初始化running時間 const startTime = Date.now(); //設置running標誌,防止屢次running this.running = true; //正在編譯 const onCompiled = (err, compilation) => { //若是報錯,編譯結束 if (err) return finalCallback(err); //若是沒有編譯完成 if (this.hooks.shouldEmit.call(compilation) === false) { // Stats模塊有1400行, // compiler.js是webpack 的核心,new Stats(compilation)是compiler.js的核心 const stats = new Stats(compilation); // stats對象掛載startTime,endTime stats.startTime = startTime; stats.endTime = Date.now(); // 異步調用完成事件流,running結束 this.hooks.done.callAsync(stats, err => { if (err) return finalCallback(err); return finalCallback(null, stats); }); return; } // 調用emitAsset方法,emitAsset主要負責寫入文件輸出文件,不影響咱們先看編譯 this.emitAssets(compilation, err => { // 相似同上, 若是報錯,編譯結束 if (err) return finalCallback(err); // 若是須要額外的編譯,上次的沒編譯完成嗎😰 if (compilation.hooks.needAdditionalPass.call()) { compilation.needAdditionalPass = true; //再來一遍new Stats const stats = new Stats(compilation); stats.startTime = startTime; stats.endTime = Date.now(); //繼續異步調用時間流 this.hooks.done.callAsync(stats, err => { if (err) return finalCallback(err); // 此次多了一個時間流,調用額外編譯,告知編譯終於編完了 this.hooks.additionalPass.callAsync(err => { if (err) return finalCallback(err); //調用compile,把onCompiled的返回值傳入compile函數,onCompiled的返回值也就是new Stats的對象 this.compile(onCompiled); }); }); return; } // 若是都不走上面的分支,即編譯完成,不須要額外的編譯 // 調用emitRecords方法,主要用來記錄輸出的 this.emitRecords(err => { if (err) return finalCallback(err); // 一樣new Stats const stats = new Stats(compilation); stats.startTime = startTime; stats.endTime = Date.now(); // 異步調用完成事件 this.hooks.done.callAsync(stats, err => { if (err) return finalCallback(err); return finalCallback(null, stats); }); }); //最終總結,不管走那個分支都是 new Stats(compilation) 返回stats的回調函數,按照目前的流程走的是最後一個分支,調用 this.emitRecords }); }; // 調用beforeRun鉤子 this.hooks.beforeRun.callAsync(this, err => { if (err) return finalCallback(err); // 調用run鉤子 this.hooks.run.callAsync(this, err => { if (err) return finalCallback(err); //讀文件記錄 this.readRecords(err => { if (err) return finalCallback(err); //把onCompiled函數傳入,調用compile this.compile(onCompiled); }); }); }); }
compilation和Stats分別對應兩個模塊
compilation.js 2500行,Stats.js 1400行異步
接下來咱們看一下compile函數async
newCompilationParams() { const params = { // 普通模塊工廠 normalModuleFactory: this.createNormalModuleFactory(), // 上下文模塊工廠 contextModuleFactory: this.createContextModuleFactory(), // 編譯依賴 compilationDependencies: new Set() }; return params; } compile(callback) { // params值以下 const params = this.newCompilationParams(); // 異步調用beforeCompile鉤子 this.hooks.beforeCompile.callAsync(params, err => { if (err) return callback(err); // 調用compile鉤子 this.hooks.compile.call(params); // 終於出現了compilation,以前一直沒有講了compilation是什麼,newCompilation咱們看以下函數 const compilation = this.newCompilation(params); this.hooks.make.callAsync(compilation, err => { if (err) return callback(err); compilation.finish(); compilation.seal(err => { if (err) return callback(err); // 異步調用afterCompile,返回回調函數 this.hooks.afterCompile.callAsync(compilation, err => { if (err) return callback(err); return callback(null, compilation); }); }); }); }); } newCompilation(params) { // compilation 是 this.createCompilation(),繼續往下 const compilation = this.createCompilation(); //給compilation對象掛載屬性 compilation.fileTimestamps = this.fileTimestamps; compilation.contextTimestamps = this.contextTimestamps; compilation.name = this.name; compilation.records = this.records; compilation.compilationDependencies = params.compilationDependencies; //告知鉤子調用完畢 this.hooks.thisCompilation.call(compilation, params); this.hooks.compilation.call(compilation, params); return compilation; } createCompilation() { // 原來compilation 是 newCompilation而來,Compilation一共2500行,堪稱整個compiler.js的核心 return new Compilation(this); }
params以下
{ normalModuleFactory: NormalModuleFactory { _pluginCompat: SyncBailHook { // key是tapable 方法名 _args: [Array], taps: [Array], interceptors: [], call: [Function: lazyCompileHook], promise: [Function: lazyCompileHook], callAsync: [Function: lazyCompileHook], _x: undefined }, hooks: { resolver: [SyncWaterfallHook], factory: [SyncWaterfallHook], beforeResolve: [AsyncSeriesWaterfallHook], afterResolve: [AsyncSeriesWaterfallHook], createModule: [SyncBailHook], module: [SyncWaterfallHook], createParser: [HookMap], parser: [HookMap], createGenerator: [HookMap], generator: [HookMap] }, resolverFactory: ResolverFactory { _pluginCompat: [SyncBailHook], hooks: [Object], cache1: [WeakMap], cache2: Map {} }, ruleSet: RuleSet { references: {}, rules: [Array] }, cachePredicate: [Function: bound Boolean], //文件路徑 context: '/Users/orion/Desktop/react-beauty-highcharts', parserCache: {}, generatorCache: {} }, contextModuleFactory: ContextModuleFactory { _pluginCompat: SyncBailHook { _args: [Array], taps: [Array], interceptors: [], call: [Function: lazyCompileHook], promise: [Function: lazyCompileHook], callAsync: [Function: lazyCompileHook], _x: undefined }, hooks: { beforeResolve: [AsyncSeriesWaterfallHook], afterResolve: [AsyncSeriesWaterfallHook], contextModuleFiles: [SyncWaterfallHook], alternatives: [AsyncSeriesWaterfallHook] }, resolverFactory: ResolverFactory { _pluginCompat: [SyncBailHook], hooks: [Object], cache1: [WeakMap], cache2: Map {} } }, compilationDependencies: Set {} }
this.compile(onCompiled) 是個高階函數,能夠簡單的理解爲參數是函數,而且返回一個函數
撒花🌹 🎉🍀我要買瓶skii犒賞本身