JS 模块化开发


CommonJS规范

  • 一个文件就是一个模块
  • 每个模块都有单独的作用域
  • 通过 module.exports 导出成员
  • 通过 require 函数载入模块
  • CommonJS 是以同步模式加载模块
  • node端: node的执行机制是在启动时加载模块。执行过程中不需要加载,只会使用到模块,因此node环境下使用commonjs没有问题
  • 浏览器端: 必然导致效率低下,每次页面加载都会导致大量同步模式请求出现,因此早期前端模块化中并没有使用commonjs规范,而是根据浏览器特点设计了专门用于浏览器端的规范AMD(Asynchronous Module Definition),和库Require.js(实现了AMD规范),Require也是个非常强大的模块加载器
  • 目前绝大多数第三方库都支持AMD规范,但使用起来相对复杂,另外如果项目模块划分过细,那么同一个页面对js文件的请求次数就会特别多,从而导致页面效率低下
  • 同期出现了淘宝Sea.js库+CMD规范,当然后来也被Require.js兼容了

ES Modules 的特性

<!-- 通过给 script 添加 type = module 的属性, 就可以 以 ES Module 的标准执行其中的 JS 代码 -->
<script type="module">
    console.log('this is es module')
</script>

相比于普通script标签,esm的特点。自动采用严格模式,忽略 ‘use strict’

<script type="module">
	console.log(this); //undefined
</script>

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

<script type="module">
	var foo = 100;
	console.log(foo);
</script>

<script type="module">
	console.log(foo); //报错
</script>

ESM 的script标签会延迟执行脚本 等同于defer属性
默认按执行顺序,script立即执行,页面的渲染会等待脚本执行后再继续渲染

添加type后,执行顺序并不等于引入顺序

<script type="module">
 	alert("Hello")
</script>
<p>需要显示的内容</p>

ESM 导入和导出

每个模块拥有私有作用域,因此外部无法访问
通过 export, import 进行模块暴露和载入

  • export: 模块内对外暴露接口
  • import: 导入其他模块提供的接口
// 在两个文件中的基本使用

export var name = 'foo module'

import { name } from './module.js'
console.log(name);
export {
	name as fooHellow  // as的作用为修改名称
}
export default name 
// default 修饰符为默认导出
  • export可以导出变量,函数,类
export var foo = {}
export var fn = function(){}
export class Person{}
  • 单独使用export,更直观描述导出成员
var foo = {}
var fn = function(){}

export {foo,fn}
  • 默认导出写法
export default {foo, fn} //接收对象成员 import mod from '' | mod.fn使用

导出注意事项
export {}不是字面量对象,import引入的也不是解构,都是固定语法,因此 export foo 也是不被允许的,要使用export var foo,而export default {} 默认导出,导出的是字面量对象

# a.js
var foo = {}
var fn = function(){}

export {foo,fn}

...

# b.js
import {foo,fn} from ''

通过export导出的不是值,而是值的地址,外部取值会受到内部值修改的影响

# a.js
export {foo,fn}
setTimeout(function(){foo="ben"},1000)

...
# b.js
import {foo,fn} from ''
console.log(foo)
setTimeout(function(){
console.log(foo)
},1500)

外部导入的成员属于只读成员(常量),无法修改

#b.js
import {foo,fn} from ''
console.log(foo)
foo = "bau" //报错

导入注意事项

  • import xx from ‘./module.js’ 路径名称必须完整不能省略,省略会报错
  • import xx from ‘/xx/module.js’ 导入内部文件使用相对路径或者绝对路径,’./'不能省略,否则会认为是加载模块
  • import xx from ‘http://localhost:3000/xx/module.js’ 可以使用完整的url访问
    import {} from ‘./module.js’ 只会执行模块,不会提取成员
  • import ‘./module.js’ 上面可以简写成 import ‘模块路径’,导入一些不需要控制的子功能模块非常好用
  • import * as mod from ‘./module.js’ 当导出内容很多,用* as mod 提取出来,通过mod.xx使用成员
    import() 动态导入模块

导入导出成员
export {name, age} from ‘’ 所有导入成员作为当前模块的导出成员,那么导入的成员无法访问

# index.js 临时文件
import { Button } from './xxx'
import { Avatar } from './xxx1'
export { Button,Avatar }
//改写成
export { Button } from './xxx'
export { Avatar } from './xxx1'

import { Button, Avatar } from 'xxxxxx'

ESM in Node.js

nodejs中使用ESM需要修改文件名从 .js => .mjs
node启动文件使用 node --experimental-modules xxx.mjs

// module.mjs
export const foo = 'hello'
export const bar = 'world'
// index.mjs
import { foo, bar } from './module.mjs'
console.log(foo, bar);

在这里插入图片描述

ESM 与 CommonJS交互

在这里插入图片描述

在这里插入图片描述
总结

  • ES Modules 中可以导入 CommonJS 模块
  • CommonJS 中不能导入 ES Mdoule 模块
  • CommonJS 始终只会导出一个默认成员
  • 注意 import 不是解构导出对象

ESM 与 CommonJS差异

运行环境nodemon --experimental-modules xxx.mjs
在commonjs中的对象在ESM中会报错,解决办法是用其他方法代替,报错方法有

在这里插入图片描述
在这里插入图片描述

ESM in Nodejs 进一步支持

将package.json中添加type = ‘module’,这样不用修改.js为.mjs了

# package.json

{
 	"type":"module"
}
// 运行命令`nodemon --experimental-modules xxx.js`

如果添加了type的项目中还想使用CommonJS

# common.js

const path = require('path')
console.log(path.join(__dirname,'foo'))
// 会报错,解决办法将commonjs文件修改为 common.cjs

ESM in Nodejs Babel兼容方案

早期node版本8.0.0,通过babel来让node运行esm
安装babel-mode yarn add @babel/node @babel/core @babel/preset-env --dev
babel是基于插件机制去实现的,核心core和preset-env并不会转换代码,具体转换特性通过插件
在这里插入图片描述
在这里插入图片描述

一个插件转化一个特性,preset-env是插件集合,这个集合包含了js标准中所有新特性
实际帮我们转换的是集合里的插件
可以通过yarn babel-node index.js --presets=@babel/preset-env
或者放入配置文件.babelrc json格式文件

{
  "presets":["@babel/preset-env"]
}

执行yarn babel-node index.js
或者移除集合使用插件
通过 yarn remove @babel/preset-env
yarn add @babel/plugin-transform-modules-commonjs --dev

{
  "plugins":[
    "@babel/plugin-tranform-modules-commonjs"
  ]
}

猜你喜欢

转载自blog.csdn.net/weixin_46261261/article/details/119961058