说明

玩转 webpack 学习笔记

开始:从 webpack 命令行说起

通过 npm scripts 运行 webpack

  • 开发环境:npm run dev
  • 生产环境:npm run build

通过 webpack 直接运行

  • ​webpack entry.js bundle.js​

查找 webpack 入口文件

在命令行运行以上命令后,npm会让命令行工具进入 ​​node_modules\.bin​​​ 目录查找是否存在 ​​webpack.sh​​​ 或者 ​​webpack.cmd​​ 文件,如果存在,就执行,不存在,就抛出错误。

webpack原理篇(五十一):webpack启动过程分析_webpack

实际的入口文件是:​​node_modules\webpack\bin\webpack.js​

webpack原理篇(五十一):webpack启动过程分析_webpack_02

分析 webpack 的入口文件:webpack.js

webpack原理篇(五十一):webpack启动过程分析_github_03

源代码如下:

#!/usr/bin/env node

// @ts-ignore
// 1# 正常执行返回
process.exitCode = 0;

/**
* @param {string} command process to run
* @param {string[]} args commandline arguments
* @returns {Promise<void>} promise
*/
// 2# 运行某个命令
const runCommand = (command,) => {
const cp = require("child_process");
return new Promise((resolve,) => {
const executedCommand = cp.spawn(command, args, {
stdio: "inherit",
shell: true
});

executedCommand.on("error", error => {
reject(error);
});

executedCommand.on("exit", code => {
if (code === 0) {
resolve();
} else {
reject();
}
});
});
};

/**
* @param {string} packageName name of the package
* @returns {boolean} is the package installed?
*/
// 3# 判断某个包是否安装
const isInstalled = packageName => {
try {
require.resolve(packageName);

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

/**
* @typedef {Object} CliOption
* @property {string} name display name
* @property {string} package npm package name
* @property {string} binName name of the executable file
* @property {string} alias shortcut for choice
* @property {boolean} installed currently installed?
* @property {boolean} recommended is recommended
* @property {string} url homepage
* @property {string} description description
*/

/** @type {CliOption[]} */
// 4# webpack 可用 cli webpack-cli(功能丰富一点) 跟 webpack-command
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."
}
];
// 5# 判断两个是否都安装了
const installedClis = CLIs.filter(cli => cli.installed);
// 6# 根据安装的数量进行处理
if (installedClis.length === 0) {
const path = require("path");
const fs = require("fs");
const readLine = require("readline");

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);

const isYarn = fs.existsSync(path.resolve(process.cwd(), "yarn.lock"));

const packageManager = isYarn ? "yarn" : "npm";
const installOptions = [isYarn ? "add" : "install", "-D"];

console.error(
`We will use "${packageManager}" to install the CLI via "${packageManager} ${installOptions.join(
" "
)}".`
);

const question = `Do you want to install 'webpack-cli' (yes/no): `;

const questionInterface = readLine.createInterface({
input: process.stdin,
output: process.stderr
});
questionInterface.question(question, answer => {
questionInterface.close();

const normalizedAnswer = answer.toLowerCase().startsWith("y");

if (!normalizedAnswer) {
console.error(
"You need to install 'webpack-cli' to use webpack via CLI.\n" +
"You can also install the CLI manually."
);
process.exitCode = 1;

return;
}

const packageName = "webpack-cli";

console.log(
`Installing '${packageName}' (running '${packageManager} ${installOptions.join(
" "
)} ${packageName}')...`
);

runCommand(packageManager, installOptions.concat(packageName))
.then(() => {
require(packageName); //eslint-disable-line
})
.catch(error => {
console.error(error);
process.exitCode = 1;
});
});
} else if (installedClis.length === 1) {
const path = require("path");
const pkgPath = require.resolve(`${installedClis[0].package}/package.json`);
// eslint-disable-next-line node/no-missing-require
const pkg = require(pkgPath);
// eslint-disable-next-line node/no-missing-require
require(path.resolve(
path.dirname(pkgPath),
pkg.bin[installedClis[0].binName]
));
} 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.`
);

// @ts-ignore
process.exitCode = 1;
}

启动后的结果

webpack 最终找到 webpack-cli (webpack-command) 这个 npm 包,并且执行 CLI。