原文地址: https://github.com/HolyZheng/...
模块化主要体现的是一种分而治之的思想。分而治之是软件工程的重要思想,是复杂系统开发和维护的基石。模块化则是前端最流行的分治手段。javascript
分而治之:将一个大问题分解成多个较为独立的与原问题性质相同的小问题,将全部的小问题的解答组合起来便可获得大问题的答案。
模块化的工程意义首先在于分治的思想,对功能进行分治,有利于咱们的维护;其次是复用,有利于咱们的开发。css
最先的时期,前端的模块化方案很简单,就是经过命名空间,或module模式模拟类提供私有和共有方法来实现模块化,可是这些模块都不是以文件为单位,而是以对象为单位。前端
var namespace = { methodOne: function () { /* ...*/ }, methodTwo: function () { /* ...*/ } } namespace.methodOne()
var module = (function() { var _private = 'something', var getData = function () { console.log(_private) } return { getData: getData } })()
未解决问题: 原始的script tag,难以维护,依赖模糊,请求过多。
如 LABjs ,经过LAB.js来加载js文件代替丑陋的script tag,一种基于文件的依赖管理。java
如YUI,一个基于模块的依赖管理库。node
随后出现了CommonJS,AMD/CMD,ES6 Module等方案,以及Browserify/Webpack等模块打包工具。webpack
好比咱们的node.js,使用的即是CommomJS规范。经过require,module.exports,exports来进行导入和导出,这里exports是module.exports的一个引用。git
var http = require('http'); var server = http.createServer(); module.exports = { myserver: server }
同步模块化的应用场景:对于服务器而言,全部的模块都是存在本地硬盘中的,读取速度快,因此能够采用同步的方式读取模块。
采用异步方式加载模块,经过define来定义一个模块,经过require来引入模块,模块的加载不影响后面语句的执行,全部依赖于这些模块的语句都写在一个回调函数中,加载完毕后,这个回调函数才运行。如:es6
// 定义一个模块,name为定义的模块名称,foo为该模块依赖的其余模块 define( 'name', [ 'foo' ], function(foo) { function outPutFoo () { console.log(foo.data) } return { outPutFoo: outPutFoo } })
// 导入模块 require(['name'], function (name) { name.outPutFoo(); })
异步模块化的产生主要是由于同步加载方式没法应用到浏览器等受网速等限制加载速度较慢且不稳定的场景,因此经过异步加载的方式防止代码执行受阻,页面中止渲染等问题。
CMD规范是国内SeaJS的推广过程当中产生的,CMD规范中一个模块是一个文件。github
// 定义一个模块,可经过return, exports, mudule.exports决定要导出的内容 define(function (require, exports, module) { var one = require('./one') one.do() // 就近依赖,按需加载 var two = require('./two') two.do() })
AMD规范的require.js与CMD规范的sea.jsweb
require.js主要解决的问题:
- 管理文件之间的依赖性
- 避免浏览器由于加载依赖而中止页面渲染,失去响应。
定义模块
define(function () { // ... }) // 依赖moduleB define(['moduleB'], function (moduleB) { // ... }) // 定义命名模块moduleA define('moduleA', ['moduleB'], function { // ... })
引入模块
require(['moduleA'], function (moduleA) { // ... })
若是不在统一目录,能够经过config来自定义。
require.config({ baseUrl: "...", path: { "moduleA": "....", "moduleB": "..." } })
cmd规范的sea.js由于已经废弃了,因此就再也不详细说了。
es6带来了语言原生的模块化方案。
const methodOne = params => { console.log(params) } const methodTwo = params => { console.log(params) } // 导出方式 1 export default { methodOne, methodTwo } // 导出方式 2 export { methodOne, methodTwo }
// 引入方式 1 对应导出方式 1 import module from './module' module.methodOne(); // 引入方式2 对应导出方式 2 import { methodOne } from './module' methodOne();
使得CommonJS In Brower成为可能,它经过将require()函数解析为ast(抽象化语法树)来遍历咱们的整个关系依赖图。咱们能够在前端代码中使用CommonJS规范来模块化的开发咱们的应用,而后经过Browerify进行打包。
本质上webpack是一个现代JavaScript应用程序的静态模块打包器。它递归的构建一个依赖关系图,其中包含应用程序的每一个模块,而后将这些模块打包成一个或多个bundle.js。
webpack 支持 CommonJS,AMD,ES6等规范,因此咱们在代码中可使用多种模块加载规范,并且经过loader,它不只能够处理JavaScript,还能够处理像css,图片等等的静态资源。
前端做为一种GUI软件——图形用户界面(Graphical User Interface),在复杂的项目种,除了js/css的模块化,咱们还须要对UI进行分治,也就是组件化开发。
组件化的理念:
组件化的工程意义首先就是分治,其次就是复用。合理的模块化和组件化可使系统功能分治到独立的更小的工程中去,颗粒度越细,组织形式越松散,开发人员之间的开发就不会产生过多的依赖,提升开发效率,同时整个项目的维护也变得简单可行。
参考
---前端工程基础
---javascript模块化7日谈