1. 程式人生 > >webpack原始碼分析(2)---- webpack\bin\webpack.js

webpack原始碼分析(2)---- webpack\bin\webpack.js

前言

上文講到呼叫webpack指令實際執行的是node webpack\bin\webpack.js這段程式碼,我們今天的目的就是分析webpack\bin\路徑下的webpack.js檔案

原始碼

// 將 webpack.js 中的原始碼主體扣出來並添加註釋

process.exitCode = 0;

// 定義命令執行函式
const runCommand = (command, args) => {
	// ...
}

// 定義判斷包是否安裝函式
const isInstalled = packageName  => {
	// ...
}

// 定義cli陣列
const CLIs = [
	{
		name: "webpack-cli",
		package: "webpack-cli",
		binName: "webpack-cli",
		alias: "cli",
		installed: isInstalled("webpack-cli"),
		recommended: true,
		url: "https://github.com/webpack/webpack-cli",
		description: "The original webpack full-featured CLI."
	},
	{
		name: "webpack-command",
		package: "webpack-command",
		binName: "webpack-command",
		alias: "command",
		installed: isInstalled("webpack-command"),
		recommended: false,
		url: "https://github.com/webpack-contrib/webpack-command",
		description: "A lightweight, opinionated webpack CLI."
	}
];

// 執行cli陣列中每一項的installed方法

const installedClis = CLIs.filter(cli => cli.installed);

// 根據返回值installedClis長度執行對應邏輯
if (installedClis.length === 0) {
	// ...
}else if (installedClis.length === 1) {
	// ...
}else {
	// ...
}

分析

程式碼簡化之後更方便我們理解他的作用,現在我們來逐步分析這塊程式碼的執行過程:

第一步

const installedClis = CLIs.filter(cli => cli.installed);

第二步

isInstalled("webpack-cli")
isInstalled("webpack-command")

const isInstalled = packageName => {
	try {
		require.resolve(packageName);

		return true;
	} catch (err) {
		return false;
	}
};

// require.resolve函式會查詢模組的帶有完整路徑的檔名,但並不會載入該模組。
// 由於我們專案中只安裝了webpack-cli,所以installedClis的值為[ true ]。

第三步

// 當installedClis的length為0時,則會提示使用者必須安裝一個webpack的cli模組並引導使用者安裝webpack-cli

// 以下為簡化程式碼
if (installedClis.length === 0) {

	let notify =
		"One CLI for webpack must be installed. These are recommended choices, delivered as separate packages:";

	for (const item of CLIs) {
		if (item.recommended) {
			notify += `\n - ${item.name} (${item.url})\n   ${item.description}`;
		}
	}

	console.error(notify);

	console.error(
		`We will use "${packageManager}" to install the CLI via "${packageManager} ${installOptions.join(
			" "
		)}".`
	);
	
	let question = `Do you want to install 'webpack-cli' (yes/no): `;
} else if (installedClis.length === 1) {
	// ...
} else {
	// ...
}

// 當installedClis的length為2時,會提示使用者只能安裝一個webpack的cli庫,使用者需要解除安裝其中之一。
if (installedClis.length === 0) {
	// ...
} else if (installedClis.length === 1) {
	// ...
} else {
	console.warn(
		`You have installed ${installedClis
			.map(item => item.name)
			.join(
				" and "
			)} together. To work with the "webpack" command you need only one CLI package, please remove one of them or use 		them directly via their binary.`
	);
}

// 當installedClis的length為1時

if (installedClis.length === 0) {
	// ...
} else if (installedClis.length === 1) {

	// 獲取webpack-cli/package.json檔案完整路徑
	const pkgPath = require.resolve(`${installedClis[0].package}/package.json`);
	
	// 引入webpack-cli/package.json 包檔案
	const pkg = require(pkgPath);
	
	// 引入webpack-cli/bin/cli.js 模組
	require(path.resolve(
		path.dirname(pkgPath),
		pkg.bin[installedClis[0].binName]
	));
} else {
	// ...
}

總結

通過上面的分析,webpack.js檔案最終的目的就是引入 ==webpack-cli/bin/cli.js== 模組。

o