js module bundle 模块捆绑

什么是模块捆绑

模块捆绑就是把所有的模块依赖捆绑到一个文件里面,使各种模块依赖可以按照顺序的执行,webpack, rollup 做的都是这个东西.

译者注(此文所有链接需墙)

为什么需要模块捆绑

如果项目中使用的模块过多,那么你就需要一个一个的使用script 标签引入到html中去,然后html运行的时候会一个一个的去加载你引入的模块,这会导致延迟过久,用户体验不好.

模块捆绑的方式

如果你使用标准的模块定义方式定义,那么使用串联和压缩你的文件 可以很好的解决这个问题,如果你使用了不标准的模块定义方式,那么你就需要使用一些工具来让他们绑定在一起, 这就是 browserify requirejs, webpack, 所做的事情.

下面我们来看一些模块捆绑在一起的方法.

commonjs 的绑定方式

使用过nodejs 的应该对commonjs 不陌生了

因为commonjs 是同步的 所以对浏览器不怎么友好 (页面卡顿)

看个例子, 计算一个数字类型数组的平均数

var myDependency = require(‘myDependency’);

var myGrades = [93, 95, 88, 0, 91];

var myAverageGrade = myDependency.average(myGrades);
复制代码

browserify 是捆绑commonjs模块的一个工具,当你使用

browserify main.js -o bundle.js

时,browserify 会通过 ast(抽象语法树), 把你的所有依赖找出来并且组织成一张图(一种数据结构)然后把他们都捆绑进一个js文件中,然后把这个js 引入到html中,从而实现捆绑功能.

就算你有很多个文件,有很多个依赖,你只需要告诉browserify 你的入口文件就可以了.

AMD 的捆绑模式

requirejs 就是一个绑定 AMD 模块的出色的工具.

AMD 跟 browserify 最大的一个区别就是, AMD 是异步的.

严格来说 AMD 的模块捆绑的时候不需要 build 的步骤, 因为AMD 加载模块是异步的. 也就是说 用户第一次访问你的页面的时候, 他只会加载必须的模块,其他不需要的,并不会去加载.但是为了缩小文件体积的性能优化,还是有一些工具具备 build 的功能.

webpack 的捆绑模式

webpack 允许你使用任何一种模块化的标准来定义模块,commonjs AMD es6 都可以,你可能奇怪为什么已经有了其他的工具,为什么还需要webapack 来捆绑模块呢,webpack 的功能不止捆绑模块 他还提供了其他很多有用的工具, 比如 code splitting

如果你有一些代码,是在特定条件下才需要的,你可以使用 code splitting 来提取那部分代码,让他需要的时候再执行,避免代码体积过大.

es6 模块捆绑

es6模块跟AMD COMMONJS 最大的不同就是 es6 是设置于内部的静态语法,也就是说 当你导入一个模块的时候, 这个导入是在 编译时解析的, 并不是动态的,意味着,我们在程序运行之前,可以删除那些没有被其他模块依赖的模块,这能节省空间,和减轻浏览器的压力.

那么问题来了,这样跟消除那些死代码(没有执行到的代码)有什么不同?

答案是 看情况

注意,死代码消除是一个移除没用的代码和变量的优化手段,想象一下你带了过重的行李,而你不需要用到他们.

有时候死代码消除可以和 es6 模块的 移除没有被依赖的模块是一样的,有时又是不一样的,这里有一个很酷的例子

使es6 模块不同的是 消除死代码的不同途径, 叫 tree shaking . 这个东西实质上是反过来的死代码去除,死代码去除是找到没使用的代码不要, tree shaking 是只打包会执行到的代码,因为不一定依赖了的代码都用得上,所以后者的性能会比前者更好.

来看一个例子

export function each(collection, iterator) {
  if (Array.isArray(collection)) {
    for (var i = 0; i < collection.length; i++) {
      iterator(collection[i], i, collection);
    }
  } else {
    for (var key in collection) {
      iterator(collection[key], key, collection);
    }
  }
 }

export function filter(collection, test) {
  var filtered = [];
  each(collection, function(item) {
    if (test(item)) {
      filtered.push(item);
    }
  });
  return filtered;
}

export function map(collection, iterator) {
  var mapped = [];
  each(collection, function(value, key, collection) {
    mapped.push(iterator(value));
  });
  return mapped;
}

export function reduce(collection, iterator, accumulator) {
    var startingValueMissing = accumulator === undefined;

    each(collection, function(item) {
      if(startingValueMissing) {
        accumulator = item;
        startingValueMissing = false;
      } else {
        accumulator = iterator(accumulator, item);
      }
    });

	return accumulator;
}
复制代码

导入所有的

import * as Utils from ‘./utils.js’;
复制代码

然后我们只掉用一个方法

Utils.each([1, 2, 3], function(x) { console.log(x) });
复制代码

tree shaking 过后 你们应该知道剩下什么了吧

// 剩下一个函数打包进来了 因为只是用了一个函数 就算我导入了所有的函数 他也不会打包进来,但是如果是寻找死代码,也就是没有被依赖的代码,那是不会删除的,因为他们所有的代码都被依赖了
function each(collection, iterator) {
  if (Array.isArray(collection)) {
    for (var i = 0; i < collection.length; i++) {
      iterator(collection[i], i, collection);
    }
  } else {
    for (var key in collection) {
      iterator(collection[key], key, collection);
    }
  }
 };

each([1, 2, 3], function(x) { console.log(x) });
复制代码

构建 es6 模块

不幸的是,es6 模块还需要做一些额外的工作才可以被构建,因为浏览器还没有很好的实现es6 的模块加载. (个人感觉很难做到,国内的浏览器乱象就不说了,感觉我们任重而道远啊)

这里有两个方法让模块加载可以再浏览器使用

  1. 使用babel 去转译es6 的代码到es5 的 commonjs 格式 或者 AMD 格式, 或者 UMD模式,然后把他们放进webpack 仲去构建
  2. 使用rollup.js 这是一个类似于 webpack 的构建工具, (但是已经有了 webpack 了为什么后还要rollup呢? 有兴趣的可以区了解一下,提示一下,vue react 也已经使用了rollup 而放弃了webpack 了解一下?)

好咯,大概介绍到这里,下回见.

转载于:https://juejin.im/post/5ba30f275188255c652d396b

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值