常用的前端模块化标准梳理

1、模块化标准出现以前使用的模块化方案:

1)文件划分: 将不同的模块定义在不同的文件中,然后使用时通过script标签引入这些文件

缺点:

  • 模块变量相当于是定义在全局的,容易造成变量名冲突(即不同模块存在相同名称的变量);
  • 模块之间的依赖关系和加载顺序不好管理;如果模块之间存在依赖关系,则在引入文件时需要手动调整,否则会出现运行错误
  • 如果引入了多个模块,则无法清楚知道某个变量来自哪个模块,需要逐个模块进行排查;

2)命名空间:

javascript 复制代码
// module.a.js文件
window.moduleA = {
 data: 'A',
 ...
}
// module.b.js文件
window.moduleB = {
 data: 'B',
 ...
}
// html中访问模块变量
...
console.log(moduleA.data)
console.log(moduleB.data)

优点:

  • 解决了文件划分造成的全局变量命名冲突的问题;
  • 使用时能清楚知道某个变量来自哪个模块,方便开发调试

3)IIFE-立即执行函数,使变量私有化,只对外界暴露变量的访问入口

javascript 复制代码
// module.a.js文件
(
  function () {
    // 模块A的私有成员,只能在当前模块内部访问,其他模块无法访问
    const data = 'moduleA'

    function method () {
      console.log(data + ' execute');
    }
    window.moduleA = {
      method
    }
  }
)()

// module.b.js文件
(
  function () {
    const data = 'moduleB'
    function method () {
      console.log(data + ' execute');
    }
    window.moduleB = {
      method
    }
  }
)()

// index.html文件
...
<body>
  <script src="./js/module.a.js"></script>
  <script src="./js/module.b.js"></script>
  <script>
    // moduleA的私有成员,外界无法访问
    console.log(moduleA.data);  // undefined
    moduleB.method()  // moduleB execute
  </script>
</body>

优点:

  • 解决了全局变量命名冲突的问题
  • 能清楚知道使用的变量来自哪个模块,(即变量作用域清晰了)

总结:命令空间和IIFE均没有解决模块存在依赖关系时,模块加载顺序的问题、

2、主流的前端模块规范

1)CommonJs规范:

  • 使用module.exports导出模块;require()导入模块;
javascript 复制代码
// module.a.js文件
const data = 'hello CommonJs'
function getData () {
  return data
}
// 导出模块
module.exports = {
  getData
}

// main.js文件
const { getData } = require('./module.a')
console.log(getData())

特点

  • 同步加载模块;即模块加载是阻塞式的,需等待模块加载完才能执行后续操作;
  • 适用于服务器端;因为模块是在服务器本地无需进行网络IO,另外在服务启动时才会进行模块加载,而通常服务启动后就会一直运行,所以同步加载对服务的性能影响不大;但是在浏览器环境中,同步模块加载会造成浏览器JS解析过程的阻塞,导致页面加载速度缓慢;
  • 模块缓存,避免重复加载和执行

2)AMD模块规范(Asynchronous Module Definition)

javascript 复制代码
// js/main.js文件

// 使用define()加载依赖模块print.js,并定义一个新模块;也可使用require()加载依赖模块
define(['./js/print.js'], function (module) {
  // module:依赖项的导出内容
  module.print('AMD')  // print AMD
})

// js/print.js文件
// 定义一个模块并导出
// define(array, callback): array-依赖项数组;callback-回调函数,接收依赖项的导出内容
define([], function () {
  return {
    print: function (msg) {
      console.log('print ' + msg);
    }
  }
})

// index.html文件
...
<body>
  <!-- 由于AMD没有得到浏览器的原生支持,所以使用AMD规范时,需要引入第三方库,requireJS -->
  <!-- data-main="./js/main":指定主模块路径,标识main.js文件位于js目录下 -->
  <script src="./lib/require.js" data-main="./js/main"></script>
  ...
</body>

特点:

  • 异步加载模块,即模块加载时不会阻塞页面渲染
  • 未得到浏览器的原生支持,需要借助第三方库requireJS来实现
  • 代码书写和阅读稍显复杂,增加了开发人员的心智负担

同期出现的其他规范: CMD,UMD

  • CMD: 由淘宝出品的SeaJs实现,解决的问题与AMD类似;延迟执行和按需加载,即模块是在代码需要使用时才会加载执行,不会预先加载;
  • UMD:通用模块定义,兼容AMD和CommonJs的模块化方案,可以同时运行在浏览器和Node.js环境

3)ES模块(ES Module)

  • 由ECMAScript官方提出的模块化规范,已经得到现代浏览器的内置支持
  • 如果在html的script标签中加上type="module"属性,那么浏览器将按照ES的模块化规范加载和解析该脚本
  • 能够同时运行在浏览器端和Node.js环境中,拥有天然的跨平台能力
  • 使用 export 导出模块;import 导入模块;
javascript 复制代码
// ES模块在浏览器环境中运行
// module.a.js文件
// 使用export导出模块
const method = () => {
  console.log('Hello ES Module')
}
export {
  method
}

// module.b.js文件
// 使用export default导出模块
const method = () => {
  console.log('Hello ES Module')
}
export default {
  method
}

// main.js文件,引用模块
// 1、export语法导出时引入方式,可通过 as xx 给导入的方法起别名
import { method as methodA } from './module.a.js'
methodA()

// 2、export default语法导出时引入方式
import B from './module.b.js'
B.method()

// index.html文件
...
<body>
  <!-- type="module" 在html中标识这个脚本文件是一个ES模块; -->
  <script type="module" src="./js/main.js"></script>
</body>
javascript 复制代码
// ES模块在Node.js环境中运行

// package.json文件,添加type: "module"属性,使Node.js以ES规范解析模块
{
  "type": "module"
   ...
}

优点:

  • 导入,导出语法简洁明了,代码可读性强
  • 静态分析和优化;模块的依赖关系在编译时就可以确定,这使得编译器可以进行更好的静态分析,并进行代码优化,打包和压缩等操作;
  • 模块的按需加载;
  • 可以同时运行在浏览器和Node.js环境

全文参考:

《深入浅出 Vite》

相关推荐
AlienZHOU2 小时前
AI Coding 时代下,我的技术面试实践分享
前端·后端·面试
Captaincc5 小时前
AI用量v0.1.11更新发布 新增 jusage doctor 诊断指令 托盘展示token 和余额 新增 AutoClaw 支持
前端·后端·vibecoding
计算机魔术师6 小时前
德国Wiki被黑后两周,OpenAI终于把模型失控的账本摊开了
前端
kyriewen7 小时前
我让 AI 当面试官面了我一轮:第 3 个追问我就卡住了(附 10 道追问清单)
前端·面试·ai编程
IT_陈寒7 小时前
Python的GIL把我坑惨了,多线程跑得比单线程还慢
前端·人工智能·后端
前端snow8 小时前
ai agent --- 多agent框架之图编排引擎-langgraph
前端
竹林8188 小时前
OmniPic Studio v3.2.1 核心技术架构与全平台发版解析文档
前端·浏览器
JamesZhang800788 小时前
页面内存只涨不跌? 一次泄漏排查, 牵出 WeakMap 的诞生
前端
Z小明8 小时前
第 6 章 组件进阶
前端·vue.js
江华森8 小时前
HTTP请求的完整过程详解:从DNS解析到TCP挥手的微秒级实战分析
前端