《二十四》运行 webpack 命令的启动流程

文章详细描述了运行npxwebpack命令时WebpackCLI如何初始化、检查是否安装、合并命令参数和配置文件的过程,以及在不同版本和操作系统中的文件路径。同时指出,不依赖WebpackCLI的场景和手动使用Webpack打包的示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. 运行 npx webpack 命令进行打包,会去当前项目的 node_module/.bin 目录下查找 webpack.js 文件进行执行。
  2. webpack.js 文件中:首先会去判断是否有安装 Webpack CLI,如果没有安装的话,会在命令行中给出提示并引导安装;一直判断到安装了 Webpack CLI之后,就会去导入并执行 webpack-cli/bin/cli.js 文件。
  3. webpack-cli/bin/cli.js 文件及其导入的文件中:会创建 WebpackCLI 的实例对象,并执行其 run() 方法进行编译打包。
    在 WebpackCLI 类中,做的最重要的一步就是会把打包命令中的参数和配置文件中的配置进行合并,然后把合并后的配置信息作为第一个参数传递给引入的 webpack 函数,就会生成编译器 compiler,就可以利用这个编译器去编译了。

总结来说,执行 npx webpack 时,会先去执行 Webpack CLI,目的就是为了把打包命令中的参数和配置文件中的配置进行合并;然后再真正执行 Webpoack。

不同的版本可能会略有差异,此处是 webpack5.88.2webpack-cli5.1.4
mac 和 windows 中文件的位置不同,此处是 mac 中的文件路径。

在这里插入图片描述

运行 webpack 命令的详细启动流程:

  1. 运行 npx webpack 命令进行打包,会去当前项目的 node_module/.bin 目录下查找本地安装的 webpack 进行执行。
    请添加图片描述

    // node_module/.bin/webpack.js
    #!/usr/bin/env node
    
    // 安装 webpack-cli
    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();
    			}
    		});
    	});
    };
    
    // 判断是否安装了 webpack-cli
    const isInstalled = packageName => {
    	if (process.versions.pnp) {
    		return true;
    	}
    
    	const path = require("path");
    	const fs = require("graceful-fs");
    
    	let dir = __dirname;
    
    	do {
    		try {
    			if (
    				fs.statSync(path.join(dir, "node_modules", packageName)).isDirectory()
    			) {
    				return true;
    			}
    		} catch (_error) {}
    	} while (dir !== (dir = path.dirname(dir)));
    
    	for (const internalPath of require("module").globalPaths) {
    		try {
    			if (fs.statSync(path.join(internalPath, packageName)).isDirectory()) {
    				return true;
    			}
    		} catch (_error) {}
    	}
    
    	return false;
    };
    
    // 执行 webpack-cli
    const runCli = cli => {
    	const path = require("path");
    	// 获取到 webpack-cli/package.json 文件的路径
    	const pkgPath = require.resolve(`${cli.package}/package.json`);
    	const pkg = require(pkgPath);
    
    	// 通过拼接 webpack-cli/package.json 文件路径和其中 bin[webpack-cli]的属性值,获取到 webpack-cli/bin/cli.js 文件的路径,对其进行导入并执行
    	if (pkg.type === "module" || /\.mjs/i.test(pkg.bin[cli.binName])) {
    		import(path.resolve(path.dirname(pkgPath), pkg.bin[cli.binName])).catch(
    			error => {
    				console.error(error);
    				process.exitCode = 1;
    			}
    		);
    	} else {
    		require(path.resolve(path.dirname(pkgPath), pkg.bin[cli.binName]));
    	}
    };
    
    // 1. 定义 cli 的对象
    const cli = {
    	name: "webpack-cli",
    	package: "webpack-cli",
    	binName: "webpack-cli",
    	installed: isInstalled("webpack-cli"),
    	url: "https://github.com/webpack/webpack-cli"
    };
    
    // 2. 如果没有安装 webpack-cli
    if (!cli.installed) {
    	const path = require("path");
    	const fs = require("graceful-fs");
    	const readLine = require("readline");
    
    	// 2.1 报错提示 CLI for webpack must be installed
    	const notify =
    		"CLI for webpack must be installed.\n" + `  ${cli.name} (${cli.url})\n`;
    	console.error(notify);
    
    	// 2.2 检查当前使用的是哪个包管理工具,并且报错提示使用哪个包管理工具来安装 webpack-cli
    	let packageManager;
    	if (fs.existsSync(path.resolve(process.cwd(), "yarn.lock"))) {
    		packageManager = "yarn";
    	} else if (fs.existsSync(path.resolve(process.cwd(), "pnpm-lock.yaml"))) {
    		packageManager = "pnpm";
    	} else {
    		packageManager = "npm";
    	}
    	const installOptions = [packageManager === "yarn" ? "add" : "install", "-D"];
    	console.error(
    		`We will use "${packageManager}" to install the CLI via "${packageManager} ${installOptions.join(
    			" "
    		)} ${cli.package}".`
    	);
    
    	// 2.3 提问,并且接收在命令行中的输入和输出
    	const question = `Do you want to install 'webpack-cli' (yes/no): `;
    	const questionInterface = readLine.createInterface({
    		input: process.stdin,
    		output: process.stderr
    	});
    
    	// 2.4 接收到答案
    	process.exitCode = 1;
    	questionInterface.question(question, answer => {
    		questionInterface.close();
    
    		// 2.4.1 如果回答的不是 y,那么报错提示
    		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."
    			);
    
    			return;
    		}
    
    		// 2.4.2 否则的话,安装 webpack-cli,并且在安装成功之后,运行 webpack-cli
    		process.exitCode = 0;
    		console.log(
    			`Installing '${
    				cli.package
    			}' (running '${packageManager} ${installOptions.join(" ")} ${
    				cli.package
    			}')...`
    		);
    		runCommand(packageManager, installOptions.concat(cli.package))
    			.then(() => {
    				runCli(cli);
    			})
    			.catch(error => {
    				console.error(error);
    				process.exitCode = 1;
    			});
    	});
    } else {
    	// 3. 如果安装了 webpack-cli,运行 webpack-cli
    	runCli(cli);
    }
    
  2. node_module/.bin/webpack.js 中运行了 runCli() 函数,会导入并执行 webpack-cli/bin/cli.js 文件。
    在这里插入图片描述

    // webpack-cli/bin/cli.js
    #!/usr/bin/env node
    
    "use strict";
    
    const importLocal = require("import-local");
    const runCLI = require("../lib/bootstrap");
    
    if (!process.env.WEBPACK_CLI_SKIP_IMPORT_LOCAL) {
      if (importLocal(__filename)) {
        return;
      }
    }
    
    process.title = "webpack";
    
    // 1. 运行 runCLI() 函数
    runCLI(process.argv);
    
    // webpack-cli/lib/bootstrap.js
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    const WebpackCLI = require("./webpack-cli");
    const runCLI = async (args) => {
        // 1. 创建 WebpackCLI 的实例对象
        const cli = new WebpackCLI();
        try {
            // 2. 执行 WebpackCLI 实例对象的 run 方法
            // webpack-cli/lib/webpack-cli.js 中创建并导出了 WebpackCLI  类,WebpackCLI  类的实例方法 run() 会执行引入的 webpack 函数
            await cli.run(args);
        }
        catch (error) {
            cli.logger.error(error);
            process.exit(2);
        }
    };
    module.exports = runCLI;
    
  3. webpack-cli/lib/webpack-cli.js 中中创建并导出了 WebpackCLI 类。会把打包命令中的参数和配置文件中的配置进行合并;然后把合并后的配置信息作为第一个参数传递给引入的 webpack 函数;然后就会生成编译器 compiler。

    Webpack 本质上导出的就是一个函数。
    在这里插入图片描述

    在这里插入图片描述

不使用 Webpack CLI,手动使用 Webpack 进行打包:

Webpack CLI 做的最重要的事就是把打包命令中的参数和配置文件中的配置进行合并。

如果打包命令中根本没有什么核心的东西,不需要 Webpack CLI来对其进行合并配置的话,完全可以不使用 Webpack CLI ,开发者手动利用 Webpack 进行打包。例如 Vue CLIReact CLI 都没有使用 Webpack CLI

  1. 新建 build.js 文件并编写代码,用来直接利用 Webpack 进行打包。

    // 引入 webpack。由于要使用 node 来执行这个文件,因此此处使用 CommonJS
    const webpack = require('webpack')
    // 引入 webpack 的配置文件
    const config = require('./webpack.config')
    
    // 执行 webpack 函数并传入配置参数,生成 compiler 编译器
    const compiler = webpack(config)
    // 执行 compiler 编译器的 run 方法来进行编译打包
    compiler.run((err,stats) => {
      if (err) {
        console.log(err)
      } else {
        console.log(stats)
      }
    })
    

    请添加图片描述

  2. 在命令行中运行 node build.js 来执行该文件,会发现,成功利用 Webpack 进行了编译打包。
    在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值