从前端打包的历史谈起

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

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

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方法

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 很容易混淆,下面看下大致的内部实现

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直接赋值,没有任何效果。

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

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

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

  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 来执行。

js模块化的总结的更多相关文章

  1. JS模块化开发:使用SeaJs高效构建页面

    一.扯淡部分 很久很久以前,也就是刚开始接触前端的那会儿,脑袋里压根没有什么架构.重构.性能这些概念,天真地以为前端===好看的页面,甚至把js都划分到除了用来写一些美美的特效别无它用的阴暗角落里,就 ...

  2. 从273二手车的M站点初探js模块化编程

    前言 这几天在看273M站点时被他们的页面交互方式所吸引,他们的首页是采用三次加载+分页的方式.也就说分为大分页和小分页两种交互.大分页就是通过分页按钮来操作,小分页是通过下拉(向下滑动)时异步加载数 ...

  3. ReactJS webpack实现JS模块化使用的坑

    从一个原生HTML/CSS/JS模式的网页改造到ReactJS模块化的结构,需要以下步骤: (1)引用ReactJS框架 ->(2)使用webpack 工具 -> (3)配置webpack ...

  4. JS 模块化和打包方案收集

    1.这里想讨论的是拆分规则,不是在问哪个工具怎么使用.2.这里没有在想找正确答案,因为感觉这个问题要结合具体业务场景. 随着项目开发越来越大,一开始代码全打包到一个文件的方式,让文件越来越大,接下来要 ...

  5. 闲聊——浅谈前端js模块化演变

    function时代 前端这几年发展太快了,我学习的速度都跟不上演变的速度了(门派太多了,后台都是大牛公司支撑类似于facebook的react.google的angular,angular的1.0还 ...

  6. js模块化历程

    这是一篇关于js模块化历程的长长的流水账,记录js模块化思想的诞生与变迁,展望ES6模块化标准的未来.经历过这段历史的人或许会感到沧桑,没经历过的人也应该知道这段历史. 无模块时代 在ajax还未提出 ...

  7. js 模块化的一些理解和es6模块化学习

    模块化 1 IIFE 2 commonjs 3 浏览器中js的模块化 4 简单理解模块加载器的原理  5 es6 之前在参加百度前端技术学院做的小题目的时候,自己写模块的时候 都是写成立即调用表达式( ...

  8. 探索javascript----浅析js模块化

    引言: 鸭子类型: 面向对象的编程思想里,有一个有趣的概念,叫鸭子类型:“一只鸟走起来像鸭子.游起泳来像鸭子.叫起来也像鸭子,那它就可以被当做鸭子.也就是说,它不关注对象的类型,而是关注对象具有的行为 ...

  9. js 模块化历程

    作者:吕大豹 网址:http://www.cnblogs.com/lvdabao/p/js-modules-develop.html 这是一篇关于js模块化历程的长长的流水账,记录js模块化思想的诞生 ...

  10. Ampersand.js - 模块化的 JS 应用程序开发框架

    Ampersand.js 是一个高度模块化,松耦合,用于构建先进的 JavaScript 应用程序的框架.通过良好定义的方法,结合了一系列微小的 CommonJS 模块.条理清晰,没有多余的冗余代码. ...

随机推荐

  1. 推荐一个娱乐化学习python的网站

    https://py.checkio.org/ 这个网站通过解决一些小任务引导初学者了解和使用python来处理一些实际需求.在coding的过程中还可以通过查看提示,帮助完成任务. 不过需要一点英文 ...

  2. LINUX系统下跑分测试脚本:unixbench.sh

    linux 系统跑分测试脚本:     一.下载脚本:        wget http://teddysun.com/wp-content/uploads/unixbench.sh 二.更改权限:  ...

  3. 关于Unity中OnGUI()的简单使用

    有时候想要输出一些数据到屏幕上方便查看,新建一个UI对象又挺麻烦,用OnGUI()在屏幕上直接绘制UI比较方便. GUI.Label(, , , ), “aaa", style); 这条语句 ...

  4. uptime命令详解

    基础命令学习目录首页 users个数和窗口数一致 原文链接:https://www.cnblogs.com/ultranms/p/9253217.html uptime 另外还有一个参数 -V(大写) ...

  5. Python入门学习系列——Python文件和异常

    从文件中读取数据 首先准备一个文本文件,文件中存储着普通文本数据.读取文件需要调用open()和read()函数. 读取整个文件 代码示例: with open('pi_digits.txt') as ...

  6. jenkins展示report测试报告的配置

    HTML报告展示 1. 需要HTML Publisher plugin插件 2. 在workspace下的工程(构建)中的目录中存储测试报告 在Jenkins中新建一个job,进入配置项. 首先通过p ...

  7. C++ Style Languages: C++, Objective-C, Java, C#

    Hyperpolyglot.org From Hyperpolyglot.org C++ Style Languages: C++, Objective-C, Java, C# a side-by-s ...

  8. Daily Scrumming* 2015.11.1(Day 13)

    一.今明两天任务表 Member Today’s Task Tomorrow’s Task 江昊 实现API小的更改 实现前后端整合 杨墨犁 实现首页 修改首页 付帅 实现创建编辑登录登出 测试修改 ...

  9. CS小分队第二阶段冲刺站立会议(6月3日)

    昨日成果:完成了主界面按钮移动交换位置 遇到问题:最后的时候发现仅交换了按钮在数据库中的信息,对于按钮的链接忘记交换了 今日计划:解决这个问题,对这个冲刺阶段的成果进行整理

  10. linux下创建virtualenv时指定python版本

    virtualenv是python开发中一个重要的工具,它可以帮助我们创建一个干净的python解释环境,创建虚拟环境时,这个虚拟环境的python版本往往是系统默认的2.x版本.别急,我们只需要一条 ...