js模块化的总结

从前端打包的历史谈起javascript

  在很长的一段前端历史里,是不存在打包这个说法的。那个时候页面基本是纯静态的或者服务端输出的, 没有 AJAX,也没有 jQuery。Google 推出 Gmail 的时候(2004 年),XMLHttpRequest, 也就是咱们俗称的 AJAX被拾起的时候,前端开发者开始往页面里插入各类库和插件,咱们的 js 文件程指数倍的开始增长了。JSMinYUI CompressorClosure CompilerUglifyJS 等 js 文件压缩合并工具陆陆续续诞生了。压缩工具是有了,但咱们得要执行它,最简单的办法呢,就是 windows 上搞个 bat 脚本,mac / linux 上搞个 bash 脚本,哪几个文件要合并在一块的,哪几个要压缩的,发布的时候运行一下脚本,生成压缩后的文件。css

  这时候commonJS出现了,若是想在a.js引入b.js和c.js,大概语法是html

var b = require(./b.js);
var c = require(./c.js);

  b.js和c.js导出方式是大概这样的前端

exports.add = function(a, b) {
  return a+b;        
}

  而后再a.js中可使用b模块的add方法java

var n = b.add(5, 8);

 

// b.js
module.exports = {
  add(a, b){
    return a+b;
  }    
}

// or
exports.add = function(a,b) {
   return a+b; 
}

// a.js
var b = require('./b.js');
var n = b.add(5,8);

  上述代码中, module.exports 和 exports 很容易混淆,下面看下大体的内部实现node

 

var module = require('./b.js');
module.add 
// 包装了一层当即执行函数,防止全局变量污染,重要的是module,module是node独有的一个变量
module.exports = {
  add: function(a,b) {
    return a+b;      
  }    
}

// 基本实现
var module = {
  exports: {}  // exports是个空对象  
}
var exports = module.exports
var load = function(module) {
  // 须要导出的东西
  var add = function(a, b) {
    return a+b;  
  }    
  module.exports = add;
  return module.exports;    
}

  module.exports和exports用法如出一辙,可是不能对exports直接赋值,没有任何效果。linux

 

  可是commonJS是node独有的规范,浏览器中并不适用,由于require()的返回是同步的,服务器加载资源的时候并不能异步的读取。在浏览器中若是使用这种方式就会堵塞js脚本的执行,因此浏览器中只能使用Browserify解析。Browserify和webpack几乎同时出现,简单介绍下Browserify: 其目的是让前端也能使用commonJS的语法来加载js,它会从入口js开始,把全部的require()调用文件打包并合并到一个文件,这样就解决了异步加载的问题。可是对比webpack,他的缺点也是明显的: webpack

  1.不支持按需加载,Browserify不支持把代码打包成多个文件。git

  2.对非js文件的加载不够完善,好比html中的img标签,只能转成Data URI的形式,并不能替换为打包后的路径。在配合gulp或者grunt使用时增长了难度。github

  3.只支持commonJS规范,不支持后续介绍的AMD和ES6 Module。

  因此webpack一统了天下。

  因而,在commonJS的基础上,2011又出现了 Asynchronous Module Definition,也是就是AMD规范,AMD规范使用异步回调的语法来并行下载多个依赖项,基本语法以下

require(['./b.js', './c.js'], function(b,c){
   var n = b.add(5,8);  
  console.log(c) })

  同时,导出的时候也须要使用异步回调的方式,好比,c模块又依赖了d.js

defined(['./d'], function(d){
   return d.PI
})

  总结下AMD: 定义模块使用defined()函数,引入使用reqire()函数,二者的区别是,前者必需要在回调函数中返回一个值做为导出的东西,后者确不须要任何导出,同时也没法做为被依赖项被其余文件导入,所以通常用于入口文件。

  AMD是由RequireJS提出的。若是想了解能够查看其文档。可是如今基本已经被淘汰了。

  js的模块化问题解决后,css模块化也被各类各样的css预处理器所处理: less、sass、stylus、scss等等。

  后来有了ES6规范,提出了模块化的概念,配合babel能够直接使用 ES6模块化

  

// b.js 
export function a() {}
export function b() {}

// c.js
export default function() {}

// a.js
import {a, b} from './b.js'
import ModuleC from './c.js'

  对于commonJS和ES6 module 的区别简单总结以下:

  1. 前者支持动态导入,也就是能够这样写 require(`${path}/b.js`), 后者目前不支持,可是已有提案。

  2. 前者是同步导入,由于用于服务器,文件都在本地,同步导入即便卡主主线程也影响不大;后者是异步导入,由于用于浏览器,须要从服务器下载文件,若是使用同步导入会影响页面渲染。

  3. 前者在导出时是值拷贝,就算导出的值发生变化了,导入的值也不会改变。因此若是导入结束后想更新值,必须从新导入一次;后者才用的是实时绑定的方式, 导入导出的值都指向同一个内存地址,因此导入值会跟随导出值变化。

  4. ES6 module 会编译成为 require/exports 来执行。

原文出处:https://www.cnblogs.com/jasonwang2y60/p/10795103.html

相关文章
相关标签/搜索