• webapck打包原理--启动过程分析


    一、运行命令

     (1)npm script

    1. //开发环境
    2. npm run dev
    3. //生产环境
    4. npm run build

    (2)webpack直接执行

    webpack entry.js bundle.js

    二、查找Webpack入口文件

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

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

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

    1. #!/usr/bin/env node
    2. // @ts-ignore
    3. //正常执行返回(exitCode为0,error为null),报错会修改exitCode同时throw error
    4. process.exitCode = 0;
    5. /**
    6. * @param {string} command process to run
    7. * @param {string[]} args commandline arguments
    8. * @returns {Promise<void>} promise
    9. */
    10. //运行某个命令
    11. //command:npm
    12. //arg: install xxx -d
    13. //提供一个方案快速的去执行一个命令,而不需要再命令行里手动地去输入命令
    14. const runCommand = (command, args) => {
    15. const cp = require("child_process");
    16. return new Promise((resolve, reject) => {
    17. const executedCommand = cp.spawn(command, args, {
    18. stdio: "inherit",
    19. shell: true
    20. });
    21. executedCommand.on("error", error => {
    22. reject(error);
    23. });
    24. executedCommand.on("exit", code => {
    25. if (code === 0) {
    26. resolve();
    27. } else {
    28. reject();
    29. }
    30. });
    31. });
    32. };
    33. /**
    34. * @param {string} packageName name of the package
    35. * @returns {boolean} is the package installed?
    36. */
    37. //判断某个包是否安装
    38. const isInstalled = packageName => {
    39. try {
    40. require.resolve(packageName);
    41. return true;
    42. } catch (err) {
    43. return false;
    44. }
    45. };
    46. /**
    47. * @typedef {Object} CliOption
    48. * @property {string} name display name
    49. * @property {string} package npm package name
    50. * @property {string} binName name of the executable file
    51. * @property {string} alias shortcut for choice
    52. * @property {boolean} installed currently installed?
    53. * @property {boolean} recommended is recommended
    54. * @property {string} url homepage
    55. * @property {string} description description
    56. */
    57. //webpack 可用的CLI:webpack-cli和webpack-command
    58. /** @type {CliOption[]} */
    59. const CLIs = [
    60. //具有比较丰富的特性
    61. {
    62. name: "webpack-cli",
    63. package: "webpack-cli",
    64. binName: "webpack-cli",
    65. alias: "cli",
    66. installed: isInstalled("webpack-cli"),
    67. recommended: true,
    68. url: "https://github.com/webpack/webpack-cli",
    69. description: "The original webpack full-featured CLI."
    70. },
    71. //相对来说更加轻量
    72. {
    73. name: "webpack-command",
    74. package: "webpack-command",
    75. binName: "webpack-command",
    76. alias: "command",
    77. installed: isInstalled("webpack-command"),
    78. recommended: false,
    79. url: "https://github.com/webpack-contrib/webpack-command",
    80. description: "A lightweight, opinionated webpack CLI."
    81. }
    82. ];
    83. //判断两个CLI是否安装了
    84. const installedClis = CLIs.filter(cli => cli.installed);
    85. //一个没有安装
    86. if (installedClis.length === 0) {
    87. const path = require("path");
    88. const fs = require("fs");
    89. const readLine = require("readline");
    90. //错误提示
    91. let notify =
    92. "One CLI for webpack must be installed. These are recommended choices, delivered as separate packages:";
    93. for (const item of CLIs) {
    94. if (item.recommended) {
    95. notify += `\n - ${item.name} (${item.url})\n ${item.description}`;
    96. }
    97. }
    98. console.error(notify);
    99. //提供帮助自动安装
    100. const isYarn = fs.existsSync(path.resolve(process.cwd(), "yarn.lock"));
    101. const packageManager = isYarn ? "yarn" : "npm";
    102. const installOptions = [isYarn ? "add" : "install", "-D"];
    103. console.error(
    104. `We will use "${packageManager}" to install the CLI via "${packageManager} ${installOptions.join(
    105. " "
    106. )}".`
    107. );
    108. //询问是否安装
    109. const question = `Do you want to install 'webpack-cli' (yes/no): `;
    110. const questionInterface = readLine.createInterface({
    111. input: process.stdin,
    112. output: process.stderr
    113. });
    114. questionInterface.question(question, answer => {
    115. questionInterface.close();
    116. //是否输入yes
    117. const normalizedAnswer = answer.toLowerCase().startsWith("y");
    118. if (!normalizedAnswer) {
    119. console.error(
    120. "You need to install 'webpack-cli' to use webpack via CLI.\n" +
    121. "You can also install the CLI manually."
    122. );
    123. process.exitCode = 1;
    124. return;
    125. }
    126. //开始安装
    127. const packageName = "webpack-cli";
    128. console.log(
    129. `Installing '${packageName}' (running '${packageManager} ${installOptions.join(
    130. " "
    131. )} ${packageName}')...`
    132. );
    133. //执行安装命令
    134. runCommand(packageManager, installOptions.concat(packageName))
    135. .then(() => {
    136. require(packageName); //eslint-disable-line
    137. })
    138. .catch(error => {
    139. console.error(error);
    140. process.exitCode = 1;
    141. });
    142. });
    143. //安装了一个,直接使用
    144. } else if (installedClis.length === 1) {
    145. const path = require("path");
    146. const pkgPath = require.resolve(`${installedClis[0].package}/package.json`);
    147. // eslint-disable-next-line node/no-missing-require
    148. const pkg = require(pkgPath);
    149. // eslint-disable-next-line node/no-missing-require
    150. require(path.resolve(
    151. path.dirname(pkgPath),
    152. pkg.bin[installedClis[0].binName]
    153. ));
    154. } else {
    155. //安装了两个,提示要删掉一个才可以运行
    156. console.warn(
    157. `You have installed ${installedClis
    158. .map(item => item.name)
    159. .join(
    160. " and "
    161. )} 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.`
    162. );
    163. // @ts-ignore
    164. process.exitCode = 1;
    165. }

     四、启动后的结果

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

  • 相关阅读:
    docker --network host,仍然无法使用127.0.0.1连接数据库,改用宿主机ip后可以连接
    mysql5.7的安装
    猿创征文 第二季|业务总结 #「笔耕不辍」--生命不息,写作不止#
    知物由学 | 告别挑花眼,AI算法如何筛选低质量图片?
    Docker(13)-- Docker 网络
    十年新起点,九号公司“三路出击”:顶流代言、博士后上任、全球化布局
    juc之常用4大并发工具类 (四)
    ATF(TF-A) fvp_r 平台威胁模型-安全检测与评估
    Mybatis如何批量插入数据?
    SpringBoot静态资源路径问题、拦截器基础配置
  • 原文地址:https://blog.csdn.net/qq_40542728/article/details/125459672