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

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

说明

玩转 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 文件,如果存在,就执行,不存在,就抛出错误。

310697cd5b7640079dce5871ab9b2241.png


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

466bd3933dbe47ddabadf4017bcfcc9c.png


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


b9d03a30d7b04c4782fe0415198fbc8c.png


源代码如下:

#!/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。



目录
相关文章
|
3月前
|
缓存 前端开发 数据可视化
Webpack Bundle Analyzer:深入分析与优化你的包
Webpack Bundle Analyzer是一款可视化工具,帮助分析Webpack构建结果,找出占用空间较大的模块以便优化。首先需安装Webpack和Webpack Bundle Analyzer,接着在`webpack.config.js`中配置插件。运行Webpack后,会在`dist`目录生成`report.html`,展示交互式图表分析包大小分布。为优化可采用代码分割、Tree Shaking、压缩插件、加载器优化、模块懒加载、代码预热、提取公共库、使用CDN、图片优化、利用缓存、避免重复模块、使用Source Maps、优化字体和图标、避免全局样式污染以及优化HTML输出等策略。
132 3
|
18天前
|
监控 前端开发 JavaScript
Webpack 中 HMR 插件的工作原理
【10月更文挑战第23天】可以进一步深入探讨 HMR 工作原理的具体细节、不同场景下的应用案例,以及与其他相关技术的结合应用等方面的内容。通过全面、系统地了解 HMR 插件的工作原理,能够更好地利用这一功能,为项目的成功开发提供有力保障。同时,要不断关注技术的发展动态,以便及时掌握最新的 HMR 技术和最佳实践。
|
18天前
|
缓存 前端开发 JavaScript
Webpack 动态加载的原理
【10月更文挑战第23天】Webpack 动态加载通过巧妙的机制和策略,实现了模块的按需加载和高效运行,提升了应用程序的性能和用户体验。同时,它也为前端开发提供了更大的灵活性和可扩展性,适应了不断变化的业务需求和技术发展。
|
18天前
|
缓存 前端开发 JavaScript
webpack 原理
【10月更文挑战第23天】Webpack 原理是一个复杂但又非常重要的体系。它通过模块解析、依赖管理、加载器和插件的协作,实现了对各种模块的高效打包和处理,为现代前端项目的开发和部署提供了强大的支持。同时,通过代码分割、按需加载、热模块替换等功能,提升了应用程序的性能和用户体验。随着前端技术的不断发展,Webpack 也在不断演进和完善,以适应不断变化的需求和挑战。
|
1月前
|
缓存 前端开发 JavaScript
Webpack 打包的基本原理
【10月更文挑战第5天】
|
3月前
webpack——通过webpack-bundle-analyzer分析项目包占比情况
webpack——通过webpack-bundle-analyzer分析项目包占比情况
35 2
webpack——通过webpack-bundle-analyzer分析项目包占比情况
|
2月前
|
JavaScript 前端开发
手写一个简易bundler打包工具带你了解Webpack原理
该文章通过手写一个简易的打包工具bundler,帮助读者理解Webpack的工作原理,包括模块解析、依赖关系构建、转换源代码以及生成最终输出文件的整个流程。
|
3月前
|
缓存 前端开发 JavaScript
Webpack 模块解析:打包原理、构造形式、扣代码补参数和全局导出
Webpack 模块解析:打包原理、构造形式、扣代码补参数和全局导出
133 1
|
6月前
|
API 开发工具 开发者
webpack热更新原理
Webpack的Hot Module Replacement(HMR)提升开发效率,无需刷新页面即可更新模块。开启HMR需在配置中设`devServer.hot: true`。Webpack构建时插入HMR Runtime,通过WebSocket监听并处理文件变化。当模块改变,Webpack发送更新到浏览器,HMR Runtime找到对应模块进行热替换,保持应用状态。开发者可利用`module.hot` API处理热替换逻辑。
|
6月前
|
前端开发 测试技术 开发者
深入理解 Webpack 热更新原理:提升开发效率的关键
深入理解 Webpack 热更新原理:提升开发效率的关键