一文带你了解,前端模块化那些事儿( 二 )

  • 缓存
  • cjs在引用文件的时候,会将文件执行一遍,然后将结果通过浅拷贝的方式写入全局缓存中
  • 后续再次require同一个文件时,直接从缓存中读取,不会重新执行模块文件
  • // a.jsvar name = 'morrain'var age = 18exports.name = nameexports.getAge = function(){return age}// b.jsvar a = require('a.js')console.log(a.name) // 'morrain'a.name = 'rename'var b = require('a.js')console.log(b.name) // 'rename'
    • 模块输出的结果是值的拷贝,一但输出,模块内部变化后,无法影响之前的引用,而ESModule是引用拷贝
    // a.jsvar name = 'morrain'var age = 18exports.name = nameexports.age = ageexports.setAge = function(a){age = a}// b.jsvar a = require('a.js')console.log(a.age) // 18a.setAge(19)console.log(a.age) // 18
    • cjs在运行时加载,ESM是编译时加载
    • 缺点:不支持异步
    • cjs更偏向于服务端,因为服务端I/O能力强,所以CMJ是同步的方法
    • ESM时机遇编译时的,所以支持异步能力
    4.AMDAMD(Asynchronous module definition)异步的模块定义 解决了Commonjs不支持异步的缺点,可以在浏览器端运行
    经典代表:require.js
    使用方法:
    // define来定义模块define(id, [depends], callback);// require进行加载require([module], callback);示例:
    //提前加载执行顺序// RequireJSdefine('a', function () {console.log('a load')return {run: function () { console.log('a run') }}})define('b', function () {console.log('b load')return {run: function () { console.log('b run') }}})require(['a', 'b'], function (a, b) {console.log('main run') //a.run()b.run()})// a load// b load// main run// a run// b run缺点:
    • 在代码运行时,会先递归的找出所有的依赖,然后将依赖放到前面加载
    • 如果依赖过多,项目可能会变慢,引入成本升高
    引出的问题:
    • 如果现在AMD中兼容CJS的代码怎么办?
    define('amdModule', [], require => {const dep1 = require('./dep1');const dep2 = require('./dep2');// 业务逻辑……})5.CMDCMD(Common Module Definition-通用模块定义)推崇依赖后置,也就是按需执行 CMD解决了AMD依赖前置导致的引入成本过高的问题 整合了CJS和AMD的特点,浏览器端运行
    经典代表:Sea.js
    // 引入requirevar fs = require('fs'); //同步require.async('./module3', function (m3) {}) //异步// sea.js,按需引入define('a', function (require, exports, module) {console.log('a load')exports.run = function () { console.log('a run') }})define('b', function (require, exports, module) {console.log('b load')exports.run = function () { console.log('b run') }})define('main', function (require, exports, module) {console.log('main run')var a = require('a')a.run()var b = require('b')b.run()})seajs.use('main')// main run// a load// a run// b load// b run缺点:
    • 依赖打包,加载逻辑存在于每个模块中
    • 扩大了模块体积,同时功能上依赖编译
    6.UMDUMD (Universal Module Definition)就是一种通用模块定义规范,让你的模块能在所有运行环境中使用,如CommonJS, AMD, CMD
    (function(root, factory) {if (typeof module === 'object' && typeof module.exports === 'object') {console.log('是commonjs模块规范,nodejs环境')module.exports = factory();} else if (typeof define === 'function' && define.amd) {console.log('是AMD模块规范,如require.js')define(factory)} else if (typeof define === 'function' && define.cmd) {console.log('是CMD模块规范,如sea.js')define(function(require, exports, module) {module.exports = factory()})} else {console.log('没有模块环境,直接挂载在全局对象上')root.umdModule = factory();}}(this, function() {return {name: '我是一个umd模块'}}))7.ESMESModule是伴随着ES6推出的原生模块化解决方案 import输入、export输出
    • 支持异步加载
    • 编译时加载,支持静态分析
    • 更好的支持chunk和tree shaking
    • 支持动态导入(按需加载)import().then()
    • 支持import.meta获取模块元数据




    推荐阅读