我們先看一下 compilation是什麼?
是一個很大的物件
列印key值
[ `_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定義的屬性
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編譯的過程
裡面有一些方法
1.對模組的處理,建立搜尋新增構建/模組依賴處理,新增模組依賴,分類模組等
addModule/getModule/ findModule/buildModule/sortModules
2.對Chunk的處理,建立Chunk
3.雜湊值
Compilation.prototype.applyPlugins
在原型上新增了applyPlugins方法
Compilation.js也是對Tapable 的擴充
主要處理Chunk、Module等
我們學習一下
webpack術語表定義
模組:離散的功能塊,提供比完整程式更小的表面積。編寫良好的模組提供了可靠的抽象和封裝邊界,構成了一致的設計和明確的目的。
塊:此Webpack特定術語在內部用於管理捆綁過程。捆綁包由塊組成,其中有幾種型別(例如入口和子)。通常,塊直接與輸出束相對應,但是,有些配置不會產生一對一的關係。
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編譯的過程
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)
);
}
}
}
modules
[ {
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 = {
doubleLine: function doubleLine(arr) {
if (arr && !Array.isArray(arr)) {
console.error(`the first params type must be Array`);
return;
}
return {
credits: {
enabled: false // 禁用版權資訊
},
chart: {
width: `400`,
height: `400`,
type: `area`,
backgroundColor: {
linearGradient: [0, 0, 500, 500],
stops: [[0, `rgba(14, 8, 55,1)`], [1, `rgba(14, 8, 55,1)`]]
}
},
title: {
text: ``,
style: {
color: `#a6aed2`,
font: `bold 16px "Trebuchet MS", Verdana, sans-serif`
}
},
xAxis: {
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`],
labels: {
format: `{value} `,
style: {
color: `#746f95`,
fontSize: `12px`,
fontFamily: `微軟雅黑`
}
},
maxPadding: 0.05,
showLastLabel: true,
// tickmarkPlacement:`on`,
tickColor: `#746f95`,
lineWidth: 1,
lineColor: `#746f95`,
tickLength: 5,
minRange: 5,
tickInterval: 1 // 座標軸刻度間隔為一星期
},
yAxis: {
gridLineWidth: `0px`,
startOnTick: true,
endOnTick: false,
maxPadding: 0.35,
title: {
text: null
},
labels: {
// format: `{value} m`,
style: {
color: `#746f95`,
fontSize: `12px`,
fontFamily: `微軟雅黑`
}
},
lineWidth: 1,
lineColor: `#746f95`
},
legend: {
itemStyle: {
font: `9pt Trebuchet MS, Verdana, sans-serif`,
color: `#a6aed2`
},
itemHoverStyle: {
color: `#fff`
}
},
tooltip: {
pointFormat: `{series.name}: <b>{point.y:,.0f}</b>人`
},
plotOptions: {
area: {
// pointStart: 1920,
marker: {
enabled: false,
symbol: `circle`,
radius: 2,
states: {
hover: {
enabled: true
}
}
}
}
},
series: arr && arr[0] === `pink` ? [{
// data: [ 110, 235, 369, 640,
// 1005, 1436, 2063, 3057, 4618, 6444, 9822, 15468, 20434, 24126,
// 27387, 29459, 31056, 31982, 32040, 31233, 29224, 27342, 26662,
// 26956, 27912, 28999, 28965, 27826, 25579, 25722, 24826, 24605,
// 24304, 23464, 23708, 24099, 24357, 24237, 24401, 24344, 23586,
// 22380, 21004, 17287, 14747, 13076, 12555, 12144, 11009, 10950,
// 10871, 10824, 10577, 10527, 10475, 10421, 10358, 10295, 10104],
lineColor: `#e88eb3`,
color: {
linearGradient: {
x1: 0,
x2: 0,
y1: 0,
y2: 1
},
stops: [[0, `rgba(231,142,179,0.8)`], [1, `rgba(135,56,89,0.5)`]]
},
fillOpacity: 0.5,
name: `進`,
marker: {
enabled: false
} // threshold: null // 是否顯示負數
}, {
// data: ,
lineColor: `#b946ff`,
color: {
linearGradient: {
x1: 0,
x2: 0,
y1: 0,
y2: 1
},
stops: [[0, `rgba(152,60,210,0.8)`], [1, `rgba(65,25,90,0.35)`]]
},
fillOpacity: 0.5,
name: `出`,
marker: {
enabled: false
},
threshold: null
}] : [{
// data: [ 110, 235, 369, 640,
// 1005, 1436, 2063, 3057, 4618, 6444, 9822, 15468, 20434, 24126,
// 27387, 29459, 31056, 31982, 32040, 31233, 29224, 27342, 26662,
// 26956, 27912, 28999, 28965, 27826, 25579, 25722, 24826, 24605,
// 24304, 23464, 23708, 24099, 24357, 24237, 24401, 24344, 23586,
// 22380, 21004, 17287, 14747, 13076, 12555, 12144, 11009, 10950,
// 10871, 10824, 10577, 10527, 10475, 10421, 10358, 10295, 10104],
lineColor: `#b946ff`,
color: {
linearGradient: {
x1: 0,
x2: 0,
y1: 0,
y2: 1
},
stops: [[0, `rgba(152,60,210,0.8)`], [1, `rgba(65,25,90,0.35)`]]
},
fillOpacity: 0.5,
name: `進`,
marker: {
enabled: false
} // threshold: null // 是否顯示負數
}, {
// data: ,
lineColor: `#68d5ee`,
color: {
linearGradient: {
x1: 0,
x2: 0,
y1: 0,
y2: 1
},
stops: [[0, `rgba(104,213,238,0.8)`], [1, `rgba(7,44,96,0.5)`]]
},
fillOpacity: 0.5,
name: `出`,
marker: {
enabled: false
},
threshold: null
}]
};
},
columns: function columns() {
return {
credits: {
enabled: false
},
chart: {
type: `column`,
backgroundColor: {
linearGradient: [0, 0, 500, 500],
stops: [[0, `rgb(14, 8, 55)`], [1, `rgb(14, 8, 55)`]]
}
},
title: {
text: `月平均降雨量`,
style: {
color: `#a6aed2`,
font: `bold 16px "Trebuchet MS", Verdana, sans-serif`
}
},
xAxis: {
gridLineWidth: `0px`,
startOnTick: true,
endOnTick: false,
maxPadding: 0.35,
categories: [`一月`, `二月`, `三月`, `四月`, `五月`, `六月`, `七月`, `八月`, `九月`, `十月`, `十一月`, `十二月`],
labels: {
format: `{value} `,
style: {
color: `#746f95`,
fontSize: `12px`,
fontFamily: `微軟雅黑`
}
},
crosshair: true,
lineWidth: 1,
lineColor: `#746f95`,
tickLength: 5,
tickColor: `#746f95`
},
yAxis: {
gridLineWidth: `0px`,
startOnTick: true,
endOnTick: false,
maxPadding: 0.35,
min: 0,
labels: {
format: `{value} `,
style: {
color: `#746f95`,
fontSize: `12px`,
fontFamily: `微軟雅黑`
}
},
title: {
// 平均時長 (min)
text: ``,
style: {
color: `#746f95`,
fontSize: `12px`,
fontFamily: `微軟雅黑`
}
},
lineWidth: 1,
lineColor: `#746f95`
},
tooltip: {
// head + 每個 point + footer 拼接成完整的 table
headerFormat: `<span style="font-size:10px">{point.key}</span><table>`,
pointFormat: `<tr><td style="color:{series.color};padding:0">{series.name}: </td>` + `<td style="padding:0"><b>{point.y} </b></td></tr>`,
footerFormat: `</table>`,
shared: true,
useHTML: true
},
plotOptions: {
column: {
borderWidth: 0
}
},
legend: {
itemStyle: {
font: `9pt Trebuchet MS, Verdana, sans-serif`,
color: `#a6aed2`
},
itemHoverStyle: {
color: `#fff`
}
},
series: [{
color: `#3453d4`,
name: `>120s`,
data: [1, 2, 3, 4, 5, 6, 7]
}, {
color: `#ff2674`,
name: `60~120s`,
data: [3, 4, 3, 1, 3, 2, 2]
}, {
color: `#66c3e3`,
// color:`#66c3e3`,
name: `<60s`,
data: [7, 4, 3, 4, 2, 6, 8]
}]
};
}
};`,
_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
裡面值得分析的還有很多,關於怎麼壓縮,壓縮演算法是怎麼處理的,二次讀原始碼再詳解
週六快樂,剛剛抓娃娃機一個都沒抓上,哈哈哈哈,但是我抓的激動開心啊?