野生模块化规范

前端是一个野蛮生长的领域,有非常多的模块化规范,在ES6模块化规范前就已经有很多,例如

  • Commonjs,用于Nodejs

    1
    2
    3
    4
    5
    6
    // 导入
    require('xxx')
    require('./xxx.js')
    // 导出
    exports.xxx = function() {}
    module.exports = xxxxx
  • AMD,用于Requirejs

    1
    2
    3
    4
    // 定义模块
    define('module', ['dep1', 'dep2'], function(d1, d2) {...})
    // 加载模块
    require(['module', '../app'], function(module, app) {...})
  • CMD,用于Seajs

    1
    2
    3
    4
    5
    6
    7
    define(function(require, exports, module) {
    let a = require('./a')
    a.foo()

    let b = require('./b')
    b.bar()
    })
  • UMD,是AMD和Commonjs的结合

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    (function (window, factory) {
    // 检测是否为Nodejs环境
    if(typeof module === 'object' && typeof module.exports = 'objects') {
    module.exports = factory()
    }
    // 检测是否为AMD规范
    else if(typeof define === 'function' && define.amd) {
    define(factory)
    }
    // 检测是否为浏览器环境
    else {
    window.eventUtil = factory()
    }
    })(this, function() {
    // module...
    })

ESM

自从ES6模块化规范横空出世,上面的模块化规范就不常见了

服务器和浏览器环境都支持ESM

默认导出/导入

一个文件只能有一个默认导出,可以导出任意类型

引入时的模块名任意

1
2
3
4
// 导出
export default {
yajue: 11451
}
1
2
// 引入
import yjsp from './yjsp'

分别导出

除了默认导出外,其他导出需要有名字

1
2
3
4
5
6
7
8
9
10
// 导出
export default {
yajue: 11451
}

export function foo {
return 'bar'
}

export const omg = 12321
1
2
3
// 引入
import yjsp, {foo, omg} from './yjsp'
console.log(foo(), omg)

也可以一次性导入该文件所有的导出,一次性导入后会获得一个对象

1
2
3
4
// 导入
import * as api from './yjsp'
console.log(api.omg) // ->12321
console.log(api.default) // -> {yajue:11451}

解构导出

一次性导出所有需要的变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 导出
function foo {
return 'bar'
}

const arr = [1,2,3]

let yajue = 11451

export {
foo,
arr,
yajue
}
1
2
3
// 导入
import {foo, arr, yajue} from './yjsp'
console.log(foo(), arr, yajue)

如果导入时发现与现有模块的变量重名,也可以为导入的模块起别名

1
2
3
4
5
6
7
// 导入
import {foo as qux, arr, yajue} from './yjsp'
console.log(qux(), arr, yajue)

const foo = ()=>{
return 'baz'
}

动态引入

通常import只能在文件的最上层使用,但有时确实有按需引入的需求,可以使用动态引入异步地引入模块

1
2
3
4
5
6
7
if(true) {
// 这样不行
// import yjsp, {foo, omg} from './yjsp'
import('./yjsp').then(res=> {
console.log(res)
})
}