目录

前端构建工具进化史之browserify

背景

上一篇文章里面,我们简单介绍了浏览器端 AMD 模块化方案。这里我们再来看看当时存在的另外一种方案 CommonJs。CommonJs 最开始是用于 node 服务端的模块化方案,browserify 为了使 node 端的代码可以在浏览器运行,对 CommonJs 的 require 语法进行了打包处理。

browserify 简介

browserify 从名字就能看出来,这是由 browser 加后缀 ify 组成的单词,字面意思就是"使浏览器化"。把什么"使浏览器化"呢?其实就是node 代码。官网中有这么一句话

Browserify lets you require('modules') in the browser by bundling up all of your dependencies.

意思是,我们可以在浏览器端使用 node 的 require 方式编写代码,browserify 会将代码中的依赖进行打包,生成的代码就可以在浏览器运行了。

browserify 总体上来说,包括两个方面的作用:

1、使 node 特定的 api 能够通过 polyfills 的方式在浏览器运行,比如说 process.nextTick() 。

2、就是通过打包,使运用了 CommonJs 规范的代码能在浏览器端运行。

这里,我们主要看一下第二点,看看它是怎么做的?

打包

首先通过 pnpm add browserify -D 的方式安装依赖,然后在 scrpits 添加

json 复制代码
"build": "browserify index.js -o bundle.js"

新建几个测试文件

csharp 复制代码
add.js
subtract.js
calc.js
index.js

文件内容如下

js 复制代码
// add.js
module.exports = function add(a, b) {
    return a + b;
}

// subtract.js
module.exports = function sub(a, b) {
    return a - b;
}

// calc.js
const add = require('./add');
const sub = require('./subtract');

module.exports = (a, b) => {
    return add(a, b) * sub(a, b);
}

// index.js
const calc = require('./calc');

console.log(calc(1, 2));

内容比较简单,index.js 中会引入 calc.js,clac.js 中会引入 add.js 和 subtract.js。 运行 pnpm build 以后,生成了 bundle.js。

js 复制代码
// bundle.js
(function () {
  // 省略加载函数
})()(
  {
    1: [
      function (require, module, exports) {
        module.exports = function add(a, b) {
          return a + b;
        };
      },
      {},
    ],
    2: [
      function (require, module, exports) {
        const add = require("./add");
        const sub = require("./subtract");

        module.exports = (a, b) => {
          return add(a, b) * sub(a, b);
        };
      },
      { "./add": 1, "./subtract": 4 },
    ],
    3: [
      function (require, module, exports) {
        const calc = require("./calc");

        console.log(calc(1, 2));
      },
      { "./calc": 2 },
    ],
    4: [
      function (require, module, exports) {
        module.exports = function sub(a, b) {
          return a - b;
        };
      },
      {},
    ],
  },
  {},
  [3]
);

简单看一下,可以看出 browserify 将每一个模块使用函数进行了包裹,并变成了一个大对象的 value,通过这种方式将之前的 4 个文件打包变成了一个文件。

我们再来看一下早期的 webpack 怎么打包的,下面是 webpack version 1 的打包结果。

javascript 复制代码
(function (modules) {
  // 省略加载函数
})([
  /* 0 */
  function (module, exports, __webpack_require__) {
    const calc = __webpack_require__(1);

    console.log(calc(1, 2));
  },
  /* 1 */
  function (module, exports, __webpack_require__) {
    const add = __webpack_require__(2);
    const sub = __webpack_require__(3);

    module.exports = (a, b) => {
      return add(a, b) * sub(a, b);
    };
  },
  /* 2 */
  function (module, exports) {
    module.exports = function add(a, b) {
      return a + b;
    };
  },
  /* 3 */
  function (module, exports) {
    module.exports = function sub(a, b) {
      return a - b;
    };
  },
]);

可以看出 browserify 和早期的 webpack 的结果是比较类似的,webpack 将 browserify 中的大对象换成了数组。如果看文章比较多的话,会发现目前网上一些关于 webpack 的文章,依然是这种数组的形式。

番外

上面这两种打包结果都有一个不太被人关注的缺陷,就是会为每一个 module 模块包裹一个函数。这会造成两个问题。

1、性能问题。每一个 module 模块都会被函数包裹,意味着 javascript 代码运行的时候,需要为每一个模块创建一个新的函数作用域。这就意味着有更多的性能消耗。The cost of small modules 这篇文章专门探讨了这个问题,当模块数量在1000 个以上的时候,性能下降非常明显。

2、打包结果变大。这个就比较容易理解了,由于会为每一个模块包裹一个函数,那么如果将项目代码拆分的越细,模块就会越多,包裹的函数就会越多,导致最后的打包结果就会越大。

这两个问题其实就是 rich harris 在这篇采访中提到的问题,也是 rollup 诞生的背景。

所以,当有人问 webpack 和 rollup 有什么区别的时候,很多人会说 rollup 用来打包库,webpack 用来打包前端代码。但是为什么呢?原因就在这里。

后来随着打包工具的进化,webpack 在新版的时候借鉴了rollup 的功能,解决了这个问题。同时 rollup 也添加了代码分割这种前端项目需要的功能。

关于 webpack 和 rollup 的详细内容,我们后面再说吧。

总结

这里我们首先简单介绍了 browserify,然后使用 browserify 进行打包,分析了打包结果。最后对比了 browserify 和 早期 webpack 的打包结果,并揭露了这种方式的弊端。

本文是转载文章,点击查看原文
如有侵权,请联系 xyy@jishuzhan.net 删除
相关推荐
吴永琦(桂林电子科技大学)24 分钟前
HTML5
前端·html·html5
爱因斯坦乐27 分钟前
【HTML】纯前端网页小游戏-戳破彩泡
前端·javascript·html
恋猫de小郭33 分钟前
注意,暂时不要升级 MacOS ,Flutter/RN 等构建 ipa 可能会因 「ITMS-90048」This bundle is invalid 被拒绝
android·前端·flutter
还是鼠鼠1 小时前
Node.js自定义中间件
javascript·vscode·中间件·node.js·json·express
大莲芒4 小时前
react 15-16-17-18各版本的核心区别、底层原理及演进逻辑的深度解析--react17
前端·react.js·前端框架
木木黄木木6 小时前
html5炫酷3D文字效果项目开发实践
前端·3d·html5
Li_Ning217 小时前
【接口重复请求】axios通过AbortController解决页面切换过快,接口重复请求问题
前端
胡八一8 小时前
Window调试 ios 的 Safari 浏览器
前端·ios·safari
Dontla8 小时前
前端页面鼠标移动监控(鼠标运动、鼠标监控)鼠标节流处理、throttle、限制触发频率(setTimeout、clearInterval)
前端·javascript
再学一点就睡8 小时前
深拷贝与浅拷贝:代码世界里的永恒与瞬间
前端·javascript