模块化开发

143 阅读4分钟

1. 模块化的演进过程

stage1 文件划分

污染全局作用域

命名冲突问题

无法管理模块依赖关系

早期模块化完成靠约定

stage2 命名空间方式

每个模块包裹成为全局对象

减小命名冲突的可能

没有私有空间,仍然可以在外部进行访问或修改

无法管理模块依赖关系

stage3 IIFE(立即执行函数)

每个成员放在一个函数提供的私有作用域当中

对于需要暴露给外部的成员,通过挂载到全局对象来实现,实现私有变量

私有成员通过闭包去访问,外部无法使用

利用自执行函数的参数作为依赖声明去使用,使得每个模块的依赖关系更加明显

以上是早期在没有工具和规范的情况下对模块化的落地方式

2.模块化规范的出现

模块化标准+模块加载器

CommonJS规范:一个文件就是一个模块

每个模块都有单独的作用于
通过module.exports导出成员

通过require函数载入模块

CommonJS是以同步模式加载模块

\

早期使用AMD(异步模块定义规范),Require.js实现了AMD规范

AMD使用起来相对复杂,模块JS文件请求频繁

3.模块化标准规范

image.png

CommonJS in Node.js

ES Modules in Browers(新规范)

\

4.ES Modules基本特性

1.ESM 自动采用严格模式,忽略'use strict'

 2.每个ES Module都是运行在单独有的私有作用域中

 3.ESM是通过CORS的方式请求外部JS模块的,注意请求的地址要支持CORS

 4.ESM的 script标签会延迟执行脚本(类似defer)

\

5.     ES Modules 导入与导出

导出:

通过as进行导出成员的重命名

 var name = 'foo11 module'

 function hello(){
    console.log('hello')
}


class Person {}


export { name,hello,Person } 

export {
    name as fooName
}
export default name//默认成员

将成员重命名为default,则该成员为默认成员。

导入:

import{fooName} from './module.js'
import foo from './module.js'//接收默认导出的成员,名称可以随便取

console.log(fooName)

6.导入导出中的注意事项

(1)export不是导出字面量对象,import也不是对对象的解构。都是一种固定的用法

(2)导出成员,导出的是对对象的引用。(指向被引用的地址)

(3)导入的成员是一个只读成员,不能修改(可用于定义常量模块)

import {} from 或者(直接import '')导入不需要控制的子功能模块image.png

import * as mod from './module.js' 导出所有的成员到一个对象中

import只能出现在最顶层。

动态导入模块:import('./module.js').then(function(){
})

\

import title,{name,age} from *//title为默认成员

\

7.ES Modules in Broswer Polyfill兼容方案

将浏览器中不识别的ES module通过babel去转换,需要import的文件通过ajax去请求,请求回来的代码通过babel转换从而能够支持ES Module。

对于支持ES Module的浏览器,需要添加nomodule属性来阻止ES module的二次加载

具体操作:(只在开发阶段使用)

image.png

8.NodeJS中使用ES Module

node 8.5+就可以使用

1.将文件扩展名由js改为mjs

2.启动:node --experimental-modules index.mjs

9.ES Modules 与CommonJS交互

ES Modules中可以导入CommonJS模块

CommonJS模块始终只会导出一个默认成员

不能在CommonJS模块通过require载入 ES Modules模块

10. ES Modules 与CommonJS的差异

ESM中没有CommonJS中的那些模块全局成员

image.png

require、module和exports可以使用ES Modules中的import和export代替

__filename和__dirname需要转换,具体操作如下图

image.png

11.Nodejs新版本的进一步支持

node 12.10+可以通过项目的package.json中添加type字段("type":"module"),这样就不需要将文件扩展名改为mjs了,但想要正常执行CommonJS,需要把文件扩展名改为.cjs。

\

12.Babel兼容方案

babel是最主流的一款JS编译器,它可以将一些使用新特性的代码,编译成当前环境支持的代码。

babel是基于插件机制去实现的,通过插件去转换代码的特性。perset-env是一个插件的集合。

安装:yarn add @babel/node @babel/core @babel/perset-env --dev

使用:yarn babel-node index.js --persets=@babel/preset-env

也可以添加一个.babelrc的文件将presets添加到文件里

image.png

这样就可以这样使用了:yarn babel-node index.js

也可以单独安装preset中的一些插件来使用。