Skip to content

webpack手写 准备工作

从这节开始,来手写一个webpack。

本节的内容

  1. 先看一下webpack的打包结果,看是如何把commonjs的node写法的代码,打包之后能在浏览器运行的
  2. 新建基础项目,本地连接一个自建库,npm link
  3. 自建库模拟 npx webpack 打包,先尝试把命令运行出来

准备空项目

空项目目录为 webpack-dev-3

新建a.js

js
// webpack\webpack-dev-3\src\a.js
let b = require('./base/b.js')
module.exports = 'aaa' + b // aaabbb

新建b.js

js
// webpack\webpack-dev-3\src\base\b.js
module.exports = 'bbb'

新建index.js

js
// webpack\webpack-dev-3\src\index.js
let str = require('./a.js')
console.log(str); // aaabbb

初始化package.json

shell
yarn init -y

安装webpack的包

shell
yarn add webpack@^4.32.2 webpack-cli@^3.3.2 -D

添加配置文件 webpack.config.js

js
// webpack\webpack-dev-3\webpack.config.js
let path = require('path')
module.exports = {
    mode: 'development',

    entry: './src/index.js',

    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist')
    }
}

打包,看一下打包结果 npx webpack,把多余的代码删除掉,只留一下核心的代码,一会写webpack的时候作为模板,往里填充内容就可以了。

js
(function (modules) { // webpackBootstrap
  // The module cache
  var installedModules = {};

  // The require function
  function __webpack_require__(moduleId) {

    // Check if module is in cache
    if (installedModules[moduleId]) {
      return installedModules[moduleId].exports;
    }
    // Create a new module (and put it into the cache)
    var module = installedModules[moduleId] = {
      i: moduleId,
      l: false,
      exports: {}
    };

    // Execute the module function
    modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);

    // Flag the module as loaded
    module.l = true;

    // Return the exports of the module
    return module.exports;
  }

  // Load entry module and return exports
  return __webpack_require__(__webpack_require__.s = "./src/index.js");
})
  ({

    "./src/a.js":
      (function (module, exports, __webpack_require__) {
        eval("// webpack\\webpack-dev-3\\src\\a.js\r\nlet b = __webpack_require__(/*! ./base/b.js */ \"./src/base/b.js\")\r\nmodule.exports = 'aaa' + b // aaabbb\n\n//# sourceURL=webpack:///./src/a.js?");
      }),

    "./src/base/b.js":
      (function (module, exports) {
        eval("// webpack\\webpack-dev-3\\src\\base\\b.js\r\nmodule.exports = 'bbb'\n\n//# sourceURL=webpack:///./src/base/b.js?");
      }),

    "./src/index.js":
      (function (module, exports, __webpack_require__) {
        eval("// webpack\\webpack-dev-3\\src\\index.js\r\nlet str = __webpack_require__(/*! ./a.js */ \"./src/a.js\")\r\nconsole.log(str); // aaabbb\n\n//# sourceURL=webpack:///./src/index.js?");
      })
  });

这个打包的文件,我们在之前已经看过了,参考 webpack打包出的文件解析

实际上就是自己写了一个webpack_require方法,根据入口文件,依次加载每个模块的代码,最终的结果都挂载到了module.exports上。

每当加载一个模块的时候,都会调用这个方法,然后遇见一个调用一个,当没有再继续调用模块时,再往上返回结果 module.exports。

我们运行结果,发现正常输出了 aaabbb。

image-20220203100145681

在外部新建自己的打包库,模拟 npx webpack 指令打包

新建打包库,链接到全局

打包库命名为 cheny-pack,所以模拟出的指令就是 npx cheny-pack

初始化package.json

shell
yarn init -y

在node的package.json文件配置bin,可以运行自定义的文件

修改package.json

json
// webpack\cheny-pack\package.json
{
  "name": "cheny-pack",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "bin": {
    "cheny-pack": "./bin/cheny-pack.js"
  }
}

新建cheny-pack.js

js
#! /usr/bin/env node

// webpack\cheny-pack\bin\cheny-pack.js
// 最顶部的注释表示,这个文件的使用node运行
console.log('start');

然后将这个包链接到全局上

shell
npm link

这个指令,会在全局下生成 bin中配置的命令,然后执行这个文件

image-20220203101029232

在需要打包的项目下,链接刚才link的指令

在webpack-dev-3项目中,链接刚才的指令,模拟打包,相当于把这个指令链接到了本地上

shell
npm link cheny-pack

image-20220203101344879

然后就可以使用 npx cheny-pack 指令来运行我们自定义的打包模块了

运行一下试试

shell
# webpack\webpack-dev-3
npx cheny-pack

image-20220203101507415

自定义指令已经生效,我们尝试修改一个打包库的代码,指令输出结果也随之改变

修改

js
#! /usr/bin/env node

// webpack\cheny-pack\bin\cheny-pack.js
// 最顶部的注释表示,这个文件的使用node运行
console.log('start 1111');

重新运行 npx cheny-pack

image-20220203101709892

总结

本节模拟了 npx webpack 指令,本地自定义打包库。

  1. 自定义打包库,在package.json中配置

    json
    {
      "name": "cheny-pack",
      "version": "1.0.0",
      "main": "index.js",
      "license": "MIT",
      "bin": {
        "cheny-pack": "./bin/cheny-pack.js"
      }
    }
  2. 指定运行文件使用node执行

    js
    #! /usr/bin/env node
    
    // webpack\cheny-pack\bin\cheny-pack.js
    // 最顶部的注释表示,这个文件的使用node运行
    console.log('start');
  3. 将打包库链接到全局,建立了一个映射关系

    shell
    npm link
  4. 在需要打包的项目中,将全局打包库再链接到本项目中

    shell
    npm link cheny-pack
  5. 然后就可以使用 npx xxx,来运行打包库了

    shell
    npm cheny-pack

参考

https://www.bilibili.com/video/BV1a4411e7Bz?p=33&spm_id_from=pageDriver