关于模块化
不同功能划分成不同的模块
模块化 是 一种思想
能够学到什么?
- 模块化演变过程
- 模块化规范
- 常用的模块化打包工具
- 基于模块化工具构建现代Web应用
- 打包工具的优化技巧
模块化演变过程
- stage 1: 文件划分方式
缺点:污染全局作用域;命名冲突;无法管理模块依赖关系 - stage 2: 命名空间方式
将每个模块包括成为一个全局对象的方式,解决了命名冲突的问题,但是仍然没有私有空间,模块成员仍然可以在外部被修改,模块之间的依赖关系也没有得到解决 - stage 3: IIFE
将模块中的每一个成员都放在函数提供的私有域中,对于需要暴露在外部的成员,将其挂载在全局对象(浏览器的全局对象为window)的方式实现
NodeJS的模块化规范-CommonJS规范 - 一个文件就是一个模块
- 每个模块都有单独的作用域
- 通过module.exports导出成员
- 通过require函数载入模块
CommonJS是以同步的方式加载模块,Node的执行机制是在启动时加载模块,执行过程中不需要加载,只会使用模块
如果浏览器端使用CommonJS规范会导致效率低下,因为在加载页面时,会同步加载大量的模块,所以浏览器端不适合使用CommonJS规范
针对浏览器端的特性,设计了AMD( Asynchronous Module Definition:异步模块定义 )规范,同时出现一款强大的模块加载起(Require.js)
AMD缺点:AMD使用起来相对复杂;模块JS文件请求频繁
CMD( Common Module Definition )规范,类似CommonJS,后期被Require.js兼容
ES Modules
- 自动采用严格模式,忽略‘use strict’(严格模式特点之一:不能在全局范围直接使用this,非严格模式下全局this指向的是全局对象)
- 每个ES Module都是运行在单独的私有作用域中
- ES Module是通过CORS的方式请求外部JS模块
- ES Module的script标签会延迟执行脚本
在ES Module中如何动态的加载模块?
import('./module.js').then(function(module){ console.log(module) })
ES Module的浏览器兼容性问题
部分浏览器不支持ES Module,需要添加插件作为转化
<script src="https://unpkg.com/browse/promise-polyfill@8.1.3/dist/polyfill.min.js"></script>
<script src="https://unpkg.com/browser-es-module-loader@0.4.1/dist/browser-es-module-loader.js"></script>
<script src="https://unpkg.com/browse/browser-es-module-loader@0.4.1/dist/babel-browser-build.js"></script>
<sript type="module" src="./module.js"></sript>
注意:上图代码是针对不支持ES Module的浏览器进行的处理,如果在支持ES Module的浏览器中,假如代码,则会使代码执行两遍解决方案如下,在scripr标签上添加“nomodule”属性,然而此种解决方案只适用于开发阶段,正式环境编译转化过程会造成性能问题
<script nomodule src="https://unpkg.com/browse/promise-polyfill@8.1.3/dist/polyfill.min.js"></script>
<script nomodule src="https://unpkg.com/browser-es-module-loader@0.4.1/dist/browser-es-module-loader.js"></script>
<script nomodule src="https://unpkg.com/browse/browser-es-module-loader@0.4.1/dist/babel-browser-build.js"></script>
<sript type="module" src="./module.js"></sript>
ES Module in Node
注:ES Module在Node中是使用,在过渡阶段,Node版本8.5版本之后支持
要在node中使用ES Module,首先要将文件后缀.js改为.mjs,其次在启动的时候,要在node 后面添加 --experimental-modules
index.mjs
import { foo, bar } from './module.js'
console.log(foo, bar)
module.mjs
export const foo = 'foo'
export const bar = 'bar'
控制台执行
node --experimental-modules index.mjs
ES Module 与 CommonJS
1. ES Modules中可以导入CommonJS模块
2. CommonJS中不可以导入ES Modules模块
3. CommonJS始终只会导出一个默认成员
4. 注意import不是解构对象
新版本的Node对ES Module的支持
可以在package.json文件下,添加type: 'module'属性,然后将之前针对ES Module进行
的.mjs后缀名重新改为.js
然而在这种情况下,还需要在项目中加入CommonJS模块的js,就会出现问
题,具体解决方法为将CommonJS模块的文件后缀名改为.cjs即可
低版本的Node对ES Module的兼容
安装babel插件 babel-node