咱們先看一下 compilation是什麼?
是一個很大的對象
打印key值javascript
[ '_pluginCompat', 'hooks', 'name', 'compiler', 'resolverFactory', 'inputFileSystem', 'requestShortener', 'options', 'outputOptions', 'bail', 'profile', 'performance', 'mainTemplate', 'chunkTemplate', 'hotUpdateChunkTemplate', 'runtimeTemplate', 'moduleTemplates', 'semaphore', 'entries', '_preparedEntrypoints', 'entrypoints', 'chunks', 'chunkGroups', 'namedChunkGroups', 'namedChunks', 'modules', '_modules', 'cache', 'records', 'additionalChunkAssets', 'assets', 'errors', 'warnings', 'children', 'dependencyFactories', 'dependencyTemplates', 'childrenCounters', 'usedChunkIds', 'usedModuleIds', 'fileTimestamps', 'contextTimestamps', 'compilationDependencies', '_buildingModules', '_rebuildingModules'
咱們看有熟悉的chunks,entries,options,
這些是Compilation定義的屬性java
const EntryModuleNotFoundError = require("./EntryModuleNotFoundError"); const ModuleNotFoundError = require("./ModuleNotFoundError"); const ModuleDependencyWarning = require("./ModuleDependencyWarning"); const ModuleDependencyError = require("./ModuleDependencyError"); const ChunkGroup = require("./ChunkGroup"); const Chunk = require("./Chunk"); const Entrypoint = require("./Entrypoint"); const MainTemplate = require("./MainTemplate"); const ChunkTemplate = require("./ChunkTemplate"); const HotUpdateChunkTemplate = require("./HotUpdateChunkTemplate"); const ModuleTemplate = require("./ModuleTemplate"); const RuntimeTemplate = require("./RuntimeTemplate"); const ChunkRenderError = require("./ChunkRenderError"); const AsyncDependencyToInitialChunkError = require("./AsyncDependencyToInitialChunkError"); const Stats = require("./Stats"); const Semaphore = require("./util/Semaphore"); const createHash = require("./util/createHash"); const Queue = require("./util/Queue"); const SortableSet = require("./util/SortableSet"); const GraphHelpers = require("./GraphHelpers"); const ModuleDependency = require("./dependencies/ModuleDependency"); const compareLocations = require("./compareLocations");
從這一堆的模塊引入裏,也能夠猜出Compilation主要作了Modules變成Chunks編譯的過程node
裏面有一些方法react
1.對模塊的處理,建立搜索添加構建/模塊依賴處理,添加模塊依賴,分類模塊等
addModule/getModule/ findModule/buildModule/sortModules
2.對Chunk的處理,建立Chunk
3.哈希值webpack
Compilation.prototype.applyPlugins
在原型上添加了applyPlugins方法web
Compilation.js也是對Tapable 的拓展
主要處理Chunk、Module等算法
咱們學習一下數組
模塊:離散的功能塊,提供比完整程序更小的表面積。編寫良好的模塊提供了可靠的抽象和封裝邊界,構成了一致的設計和明確的目的。緩存
塊:此Webpack特定術語在內部用於管理捆綁過程。捆綁包由塊組成,其中有幾種類型(例如入口和子)。一般,塊直接與輸出束相對應,可是,有些配置不會產生一對一的關係。babel
Bundle:由許多不一樣的模塊生成,bundle包含已通過加載和編譯過程的源文件的最終版本。
總結
a chunk is a group of modules within the webpack process, a bundle is an emitted chunk or set of chunks.
一個塊是webpack進程中的一組模塊,一個bundle是一個發出的塊或一組塊。
{ entry: { foo: ["webpack/hot/only-dev-server.js","./src/foo.js"], bar: ["./src/bar.js"] }, output: { path: "./dist", filename: "[name].js" } } Modules: "webpack/hot/only-dev-server.js", "./src/foo.js", "./src/bar.js" ( + any other modules that are dependencies of these entry points!) Chunks: foo, bar Bundles: foo, bar
通俗的解釋一下,Modules是引入的模塊,Chunks就是編譯的模塊,Bundles是提交的Chunks ,Chunks和Bundles是1:1的關係,配置map會有例外
Compilation主要作了Modules變成Chunks編譯的過程
不細看邏輯,好像太虛了,咱們看一下this.chunks
它是一個數組,目前Chunk的長度是1,由於只是引入了一個模塊
[ Chunk { id: 'main', ids: [ 'main' ], debugId: 1000, name: 'main', preventIntegration: false, entryModule: NormalModule { dependencies: [], blocks: [], variables: [], type: 'javascript/auto', context: '/Users/orion/Desktop/react-beauty-highcharts/src', debugId: 1000, hash: 'a6388d29fa15bd58c6cffb10246992a5', renderedHash: 'a6388d29fa15bd58c6cf', resolveOptions: {}, factoryMeta: {}, warnings: [], errors: [], buildMeta: [Object], buildInfo: [Object], reasons: [Array], _chunks: [SortableSet], id: './src/index.js', index: 0, index2: 0, depth: 0, issuer: null, profile: undefined, prefetched: false, built: true, used: null, usedExports: null, optimizationBailout: [], _rewriteChunkInReasons: undefined, useSourceMap: true, _source: [SourceMapSource], request: '/Users/orion/Desktop/react-beauty-highcharts/node_modules/babel-loader/lib/index.js!/Users/orion/Desktop/react-beauty-highcharts/src/index.js', userRequest: '/Users/orion/Desktop/react-beauty-highcharts/src/index.js', rawRequest: './src/index.js', binary: false, parser: [Parser], generator: JavascriptGenerator {}, resource: '/Users/orion/Desktop/react-beauty-highcharts/src/index.js', matchResource: undefined, loaders: [Array], error: null, _buildHash: '488efbd43aa05371d3f44d94c89abd57', buildTimestamp: 1547884969828, _cachedSources: Map {}, lineToLine: false, _lastSuccessfulBuildMeta: [Object], _ast: null }, _modules: SortableSet [Set] { [NormalModule], _sortFn: [Function: sortByIdentifier], _lastActiveSortFn: null, _cache: undefined, _cacheOrderIndependent: undefined }, filenameTemplate: undefined, _groups: SortableSet [Set] { [Entrypoint], _sortFn: [Function: sortChunkGroupById], _lastActiveSortFn: null, _cache: undefined, _cacheOrderIndependent: undefined }, files: [], rendered: false, hash: '0988e8454f1915ec05fee482db8d0a6f', contentHash: { javascript: '4b8695ca3c1d42e76c52' }, renderedHash: '0988e8454f1915ec05fe', chunkReason: undefined, extraAsync: false, removedModules: undefined } ]
咱們看到在entryModule下,記錄了入口的絕對地址,相對地址,編譯的hash,文件類型等信息
//文件寫入,文件輸出,文件緩存,裏面具體的template.getRenderManifest,chunk.hasRuntime(),CachedSource具體的邏輯不可以一一的去研究詳解,可是從名字能知道這個函數是作什麼的 createChunkAssets() { const outputOptions = this.outputOptions; const cachedSourceMap = new Map(); /** @type {Map<string, {hash: string, source: Source, chunk: Chunk}>} */ const alreadyWrittenFiles = new Map(); for (let i = 0; i < this.chunks.length; i++) { const chunk = this.chunks[i]; chunk.files = []; let source; let file; let filenameTemplate; try { const template = chunk.hasRuntime() ? this.mainTemplate : this.chunkTemplate; const manifest = template.getRenderManifest({ chunk, hash: this.hash, fullHash: this.fullHash, outputOptions, moduleTemplates: this.moduleTemplates, dependencyTemplates: this.dependencyTemplates }); // [{ render(), filenameTemplate, pathOptions, identifier, hash }] for (const fileManifest of manifest) { const cacheName = fileManifest.identifier; const usedHash = fileManifest.hash; filenameTemplate = fileManifest.filenameTemplate; file = this.getPath(filenameTemplate, fileManifest.pathOptions); // check if the same filename was already written by another chunk const alreadyWritten = alreadyWrittenFiles.get(file); if (alreadyWritten !== undefined) { if (alreadyWritten.hash === usedHash) { if (this.cache) { this.cache[cacheName] = { hash: usedHash, source: alreadyWritten.source }; } chunk.files.push(file); this.hooks.chunkAsset.call(chunk, file); continue; } else { throw new Error( `Conflict: Multiple chunks emit assets to the same filename ${file}` + ` (chunks ${alreadyWritten.chunk.id} and ${chunk.id})` ); } } if ( this.cache && this.cache[cacheName] && this.cache[cacheName].hash === usedHash ) { source = this.cache[cacheName].source; } else { source = fileManifest.render(); // Ensure that source is a cached source to avoid additional cost because of repeated access if (!(source instanceof CachedSource)) { const cacheEntry = cachedSourceMap.get(source); if (cacheEntry) { source = cacheEntry; } else { const cachedSource = new CachedSource(source); cachedSourceMap.set(source, cachedSource); source = cachedSource; } } if (this.cache) { this.cache[cacheName] = { hash: usedHash, source }; } } if (this.assets[file] && this.assets[file] !== source) { throw new Error( `Conflict: Multiple assets emit to the same filename ${file}` ); } this.assets[file] = source; chunk.files.push(file); this.hooks.chunkAsset.call(chunk, file); alreadyWrittenFiles.set(file, { hash: usedHash, source, chunk }); } } catch (err) { this.errors.push( new ChunkRenderError(chunk, file || filenameTemplate, err) ); } } }
[ { dependencies: [], blocks: [], variables: [], type: 'javascript/auto', context: '/Users/orion/Desktop/react-beauty-highcharts/src', debugId: 1000, hash: 'a6388d29fa15bd58c6cffb10246992a5', renderedHash: 'a6388d29fa15bd58c6cf', resolveOptions: {}, factoryMeta: {}, warnings: [], errors: [], buildMeta: { providedExports: true }, buildInfo: { cacheable: true, fileDependencies: [Set], contextDependencies: Set {}, temporaryProvidedExports: false }, reasons: [ [ModuleReason] ], _chunks:{ [Chunk], _sortFn: [Function: sortById], _lastActiveSortFn: null, _cache: undefined, _cacheOrderIndependent: undefined }, id: './src/index.js', index: 0, index2: 0, depth: 0, issuer: null, profile: undefined, prefetched: false, built: true, used: null, usedExports: null, optimizationBailout: [], _rewriteChunkInReasons: undefined, useSourceMap: true, _source:{ _value: 'module.exports = {\n doubleLine: function doubleLine(arr) {\n if (arr && !Array.isArray(arr)) {\n console.error(\'the first params type must be Array\');\n return;\n }\n\n return {\n credits: {\n enabled: false // 禁用版權信息\n\n },\n chart: {\n width: \'400\',\n height: \'400\',\n type: \'area\',\n backgroundColor: {\n linearGradient: [0, 0, 500, 500],\n stops: [[0, \'rgba(14, 8, 55,1)\'], [1, \'rgba(14, 8, 55,1)\']]\n }\n },\n title: {\n text: \'\',\n style: {\n color: \'#a6aed2\',\n font: \'bold 16px "Trebuchet MS", Verdana, sans-serif\'\n }\n },\n xAxis: {\n categories: [\'10:00\', \'10:30\', \'11:00\', \'11:30\', \'12:00\', \'12:30\', \'13:00\', \'13:30\', \'14:00\', \'14:30\', \'15:00\', \'15:30\', \'16:00\', \'16:30\', \'16:30\', \'17:00\', \'17:30\', \'18:00\', \'18:30\', \'19:00\'],\n labels: {\n format: \'{value} \',\n style: {\n color: \'#746f95\',\n fontSize: \'12px\',\n fontFamily: \'微軟雅黑\'\n }\n },\n maxPadding: 0.05,\n showLastLabel: true,\n // tickmarkPlacement:\'on\',\n tickColor: \'#746f95\',\n lineWidth: 1,\n lineColor: \'#746f95\',\n tickLength: 5,\n minRange: 5,\n tickInterval: 1 // 座標軸刻度間隔爲一星期\n\n },\n yAxis: {\n gridLineWidth: \'0px\',\n startOnTick: true,\n endOnTick: false,\n maxPadding: 0.35,\n title: {\n text: null\n },\n labels: {\n // format: \'{value} m\',\n style: {\n color: \'#746f95\',\n fontSize: \'12px\',\n fontFamily: \'微軟雅黑\'\n }\n },\n lineWidth: 1,\n lineColor: \'#746f95\'\n },\n legend: {\n itemStyle: {\n font: \'9pt Trebuchet MS, Verdana, sans-serif\',\n color: \'#a6aed2\'\n },\n itemHoverStyle: {\n color: \'#fff\'\n }\n },\n tooltip: {\n pointFormat: \'{series.name}: <b>{point.y:,.0f}</b>人\'\n },\n plotOptions: {\n area: {\n // pointStart: 1920,\n marker: {\n enabled: false,\n symbol: \'circle\',\n radius: 2,\n states: {\n hover: {\n enabled: true\n }\n }\n }\n }\n },\n series: arr && arr[0] === \'pink\' ? [{\n // data: [ 110, 235, 369, 640,\n // 1005, 1436, 2063, 3057, 4618, 6444, 9822, 15468, 20434, 24126,\n // 27387, 29459, 31056, 31982, 32040, 31233, 29224, 27342, 26662,\n // 26956, 27912, 28999, 28965, 27826, 25579, 25722, 24826, 24605,\n // 24304, 23464, 23708, 24099, 24357, 24237, 24401, 24344, 23586,\n // 22380, 21004, 17287, 14747, 13076, 12555, 12144, 11009, 10950,\n // 10871, 10824, 10577, 10527, 10475, 10421, 10358, 10295, 10104],\n lineColor: \'#e88eb3\',\n color: {\n linearGradient: {\n x1: 0,\n x2: 0,\n y1: 0,\n y2: 1\n },\n stops: [[0, \'rgba(231,142,179,0.8)\'], [1, \'rgba(135,56,89,0.5)\']]\n },\n fillOpacity: 0.5,\n name: \'進\',\n marker: {\n enabled: false\n } // threshold: null // 是否顯示負數\n\n }, {\n // data: ,\n lineColor: \'#b946ff\',\n color: {\n linearGradient: {\n x1: 0,\n x2: 0,\n y1: 0,\n y2: 1\n },\n stops: [[0, \'rgba(152,60,210,0.8)\'], [1, \'rgba(65,25,90,0.35)\']]\n },\n fillOpacity: 0.5,\n name: \'出\',\n marker: {\n enabled: false\n },\n threshold: null\n }] : [{\n // data: [ 110, 235, 369, 640,\n // 1005, 1436, 2063, 3057, 4618, 6444, 9822, 15468, 20434, 24126,\n // 27387, 29459, 31056, 31982, 32040, 31233, 29224, 27342, 26662,\n // 26956, 27912, 28999, 28965, 27826, 25579, 25722, 24826, 24605,\n // 24304, 23464, 23708, 24099, 24357, 24237, 24401, 24344, 23586,\n // 22380, 21004, 17287, 14747, 13076, 12555, 12144, 11009, 10950,\n // 10871, 10824, 10577, 10527, 10475, 10421, 10358, 10295, 10104],\n lineColor: \'#b946ff\',\n color: {\n linearGradient: {\n x1: 0,\n x2: 0,\n y1: 0,\n y2: 1\n },\n stops: [[0, \'rgba(152,60,210,0.8)\'], [1, \'rgba(65,25,90,0.35)\']]\n },\n fillOpacity: 0.5,\n name: \'進\',\n marker: {\n enabled: false\n } // threshold: null // 是否顯示負數\n\n }, {\n // data: ,\n lineColor: \'#68d5ee\',\n color: {\n linearGradient: {\n x1: 0,\n x2: 0,\n y1: 0,\n y2: 1\n },\n stops: [[0, \'rgba(104,213,238,0.8)\'], [1, \'rgba(7,44,96,0.5)\']]\n },\n fillOpacity: 0.5,\n name: \'出\',\n marker: {\n enabled: false\n },\n threshold: null\n }]\n };\n },\n columns: function columns() {\n return {\n credits: {\n enabled: false\n },\n chart: {\n type: \'column\',\n backgroundColor: {\n linearGradient: [0, 0, 500, 500],\n stops: [[0, \'rgb(14, 8, 55)\'], [1, \'rgb(14, 8, 55)\']]\n }\n },\n title: {\n text: \'月平均降雨量\',\n style: {\n color: \'#a6aed2\',\n font: \'bold 16px "Trebuchet MS", Verdana, sans-serif\'\n }\n },\n xAxis: {\n gridLineWidth: \'0px\',\n startOnTick: true,\n endOnTick: false,\n maxPadding: 0.35,\n categories: [\'一月\', \'二月\', \'三月\', \'四月\', \'五月\', \'六月\', \'七月\', \'八月\', \'九月\', \'十月\', \'十一月\', \'十二月\'],\n labels: {\n format: \'{value} \',\n style: {\n color: \'#746f95\',\n fontSize: \'12px\',\n fontFamily: \'微軟雅黑\'\n }\n },\n crosshair: true,\n lineWidth: 1,\n lineColor: \'#746f95\',\n tickLength: 5,\n tickColor: \'#746f95\'\n },\n yAxis: {\n gridLineWidth: \'0px\',\n startOnTick: true,\n endOnTick: false,\n maxPadding: 0.35,\n min: 0,\n labels: {\n format: \'{value} \',\n style: {\n color: \'#746f95\',\n fontSize: \'12px\',\n fontFamily: \'微軟雅黑\'\n }\n },\n title: {\n // 平均時長 (min)\n text: \'\',\n style: {\n color: \'#746f95\',\n fontSize: \'12px\',\n fontFamily: \'微軟雅黑\'\n }\n },\n lineWidth: 1,\n lineColor: \'#746f95\'\n },\n tooltip: {\n // head + 每一個 point + footer 拼接成完整的 table\n headerFormat: \'<span style="font-size:10px">{point.key}</span><table>\',\n pointFormat: \'<tr><td style="color:{series.color};padding:0">{series.name}: </td>\' + \'<td style="padding:0"><b>{point.y} </b></td></tr>\',\n footerFormat: \'</table>\',\n shared: true,\n useHTML: true\n },\n plotOptions: {\n column: {\n borderWidth: 0\n }\n },\n legend: {\n itemStyle: {\n font: \'9pt Trebuchet MS, Verdana, sans-serif\',\n color: \'#a6aed2\'\n },\n itemHoverStyle: {\n color: \'#fff\'\n }\n },\n series: [{\n color: \'#3453d4\',\n name: \'>120s\',\n data: [1, 2, 3, 4, 5, 6, 7]\n }, {\n color: \'#ff2674\',\n name: \'60~120s\',\n data: [3, 4, 3, 1, 3, 2, 2]\n }, {\n color: \'#66c3e3\',\n // color:\'#66c3e3\',\n name: \'<60s\',\n data: [7, 4, 3, 4, 2, 6, 8]\n }]\n };\n }\n};', _name: '/Users/orion/Desktop/react-beauty-highcharts/node_modules/babel-loader/lib/index.js!/Users/orion/Desktop/react-beauty-highcharts/src/index.js', _sourceMap: [Object], _originalSource: undefined, _innerSourceMap: undefined }, request: '/Users/orion/Desktop/react-beauty-highcharts/node_modules/babel-loader/lib/index.js!/Users/orion/Desktop/react-beauty-highcharts/src/index.js', userRequest: '/Users/orion/Desktop/react-beauty-highcharts/src/index.js', rawRequest: './src/index.js', binary: false, parser:{ _pluginCompat: [SyncBailHook], hooks: [Object], options: {}, sourceType: 'auto', scope: undefined, state: undefined, comments: undefined }, generator: JavascriptGenerator {}, resource: '/Users/orion/Desktop/react-beauty-highcharts/src/index.js', matchResource: undefined, loaders: [ [Object] ], error: null, _buildHash: '488efbd43aa05371d3f44d94c89abd57', buildTimestamp: 1547885885262, _cachedSources: Map {}, lineToLine: false, _lastSuccessfulBuildMeta: { providedExports: true }, _ast: null } ]
咱們看到module的長度也是一個,同樣有類型,路徑,hash
其中
_source的_value下的module.exports,已是略微壓縮版的了,裏面還有n
裏面值得分析的還有不少,關於怎麼壓縮,壓縮算法是怎麼處理的,二次讀源碼再詳解
週六快樂,剛剛抓娃娃機一個都沒抓上,哈哈哈哈,可是我抓的激動開心啊😄