總體過了一下後面的流程,發現Compiler模塊確實不適合單獨講解,這裡繼續講解後面的代碼: 這行代碼與之前設置options預設值非常相似,但是複雜程度根本不是一個次元的。 這一節只能簡單的看一眼內部到底有多少東西,整理後源碼如下: 這個模塊除去父類引入,其餘插件光頂部引入就有34個,簡直就是插件 ...
總體過了一下後面的流程,發現Compiler模塊確實不適合單獨講解,這裡繼續講解後面的代碼:
compiler.options = new WebpackOptionsApply().process(options, compiler);
這行代碼與之前設置options預設值非常相似,但是複雜程度根本不是一個次元的。
這一節只能簡單的看一眼內部到底有多少東西,整理後源碼如下:
"use strict"; const OptionsApply = require("./OptionsApply"); // ...巨量插件引入 class WebpackOptionsApply extends OptionsApply { constructor() { super(); } process(options, compiler) { let ExternalsPlugin; compiler.outputPath = options.output.path; compiler.recordsInputPath = options.recordsInputPath || options.recordsPath; compiler.recordsOutputPath = options.recordsOutputPath || options.recordsPath; compiler.name = options.name; compiler.dependencies = options.dependencies; // 在預設參數配置中被設置為web if (typeof options.target === "string") { let JsonpTemplatePlugin; let NodeSourcePlugin; let NodeTargetPlugin; let NodeTemplatePlugin; switch (options.target) { case "web": JsonpTemplatePlugin = require("./JsonpTemplatePlugin"); NodeSourcePlugin = require("./node/NodeSourcePlugin"); compiler.apply( new JsonpTemplatePlugin(options.output), new FunctionModulePlugin(options.output), new NodeSourcePlugin(options.node), new LoaderTargetPlugin(options.target) ); break; // other case... default: throw new Error("Unsupported target '" + options.target + "'."); } } else if (options.target !== false) { options.target(compiler); } else { throw new Error("Unsupported target '" + options.target + "'."); } // options.output.library參數處理 if (options.output.library || options.output.libraryTarget !== "var") { /**/ } // options.output.externals參數處理 if (options.externals) { /**/ } let noSources; let legacy; let modern; let comment; // options.devtool => sourcemap || source-map if (options.devtool && (options.devtool.indexOf("sourcemap") >= 0 || options.devtool.indexOf("source-map") >= 0)) { /**/ } // options.devtool => eval else if (options.devtool && options.devtool.indexOf("eval") >= 0) { /**/ } // 載入模塊並觸發entry-option事件流 compiler.apply(new EntryOptionPlugin()); compiler.applyPluginsBailResult("entry-option", options.context, options.entry); // 瘋狂載入插件 compiler.apply( /**/ ); // options.performance參數處理 if (options.performance) { /**/ } // 繼續載入插件 compiler.apply(new TemplatedPathPlugin()); compiler.apply(new RecordIdsPlugin()); compiler.apply(new WarnCaseSensitiveModulesPlugin()); // options.performance參數處理 if (options.cache) { /**/ } // 觸發after-plugins compiler.applyPlugins("after-plugins", compiler); if (!compiler.inputFileSystem) throw new Error("No input filesystem provided"); // 給compiler.resolvers設置值 compiler.resolvers.normal = ResolverFactory.createResolver(Object.assign({ fileSystem: compiler.inputFileSystem }, options.resolve)); compiler.resolvers.context = ResolverFactory.createResolver(Object.assign({ fileSystem: compiler.inputFileSystem, resolveToContext: true }, options.resolve)); compiler.resolvers.loader = ResolverFactory.createResolver(Object.assign({ fileSystem: compiler.inputFileSystem }, options.resolveLoader)); // 觸發after-resolvers事件流 compiler.applyPlugins("after-resolvers", compiler); return options; } } module.exports = WebpackOptionsApply;
這個模塊除去父類引入,其餘插件光頂部引入就有34個,簡直就是插件之王。
略去具體插件內容,先看流程,父類其實是個介面,啥都沒有:
"use strict";
class OptionsApply {
process(options, compiler) {}
}
module.exports = OptionsApply;
接下來是一個唯一的主方法process,總結下流程依次為:
1、根據options.target載入對應的插件,如果配置文件沒有配置該參數,則在WebpackOptionsDefaulter模塊會被自動初始化為web。
2、處理options.output.library、options.output.externals參數
3、處理options.devtool參數
4、載入EntryOptionPlugin插件並觸發entry-option的事件流
5、載入大量插件
6、處理options.performance參數
7、載入TemplatePathPlugin、RecordIdPlugin、WarnCaseSensitiveModulesPlugin插件
8、觸發after-plugins事件流
9、設置compiler.resolvers的值
10、觸發after-resolvers事件流
如果按類型分,其實只有兩種:載入插件,觸發事件流。
事件流的觸發類似於vue源碼里的鉤子函數,到特定的階段觸發對應的方法,這個思想在Java的數據結構源碼中也被普通應用。
模塊中的參數處理如果該參數比較常用,那麼就進行分析,其餘不太常用的就先跳過,按順序依次講解。
這裡的options經過預設參數模塊的加工,豐富後如下:
{ "entry": "./input.js", "output": { "filename": "output.js", "chunkFilename": "[id].output.js", "library": "", "hotUpdateFunction": "webpackHotUpdate", "jsonpFunction": "webpackJsonp", "libraryTarget": "var", "path": "D:\\workspace\\doc", "sourceMapFilename": "[file].map[query]", "hotUpdateChunkFilename": "[id].[hash].hot-update.js", "hotUpdateMainFilename": "[hash].hot-update.json", "crossOriginLoading": false, "chunkLoadTimeout": 120000, "hashFunction": "md5", "hashDigest": "hex", "hashDigestLength": 20, "devtoolLineToLine": false, "strictModuleExceptionHandling": false }, "context": "D:\\workspace\\doc", "devtool": false, "cache": true, "target": "web", "module": { "unknownContextRequest": ".", "unknownContextRegExp": false, "unknownContextRecursive": true, "unknownContextCritical": true, "exprContextRequest": ".", "exprContextRegExp": false, "exprContextRecursive": true, "exprContextCritical": true, "wrappedContextRegExp": {}, "wrappedContextRecursive": true, "wrappedContextCritical": false, "strictExportPresence": false, "strictThisContextOnImports": false, "unsafeCache": true }, "node": { "console": false, "process": true, "global": true, "Buffer": true, "setImmediate": true, "__filename": "mock", "__dirname": "mock" }, "performance": { "maxAssetSize": 250000, "maxEntrypointSize": 250000, "hints": false }, "resolve": { "unsafeCache": true, "modules": ["node_modules"], "extensions": [".js", ".json"], "mainFiles": ["index"], "aliasFields": ["browser"], "mainFields": ["browser", "module", "main"], "cacheWithContext": false }, "resolveLoader": { "unsafeCache": true, "mainFields": ["loader", "main"], "extensions": [".js", ".json"], "mainFiles": ["index"], "cacheWithContext": false } }
除去entry與output.filename,其餘的參數全部是填充上去的,因為後面的流程會檢測參數,所以這裡先列出來。
這一節先這樣,具體內容後面進行詳細講解。