说明
玩转 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
文件,如果存在,就执行,不存在,就抛出错误。
实际的入口文件是:node_modules\webpack\bin\webpack.js
分析 webpack 的入口文件:webpack.js
源代码如下:
#!/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, args) => { const cp = require("child_process"); return new Promise((resolve, reject) => { 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。