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

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》

相关推荐
weixin_382395236 小时前
为小工厂量身打造:本地部署的物料管理系统带缺料计算
前端·制造
__zRainy__6 小时前
解决pnpm v10+不自动构建
前端·pnpm·工程化
猫猫不是喵喵.7 小时前
Vue3 Props 属性
前端·javascript·vue.js
醉城夜风~8 小时前
CSS元素显示模式(display)
前端·css
AI大模型-小华9 小时前
Codex 三方充值快速入门指南
java·前端·数据库·chatgpt·ai编程·codex·chatgpt pro
做前端的娜娜子11 小时前
同一链接实现 PC Web 与移动 H5 自适应
前端·掘金·金石计划
小帅不太帅11 小时前
架构没变、规模没变,DeepSeek V4 Flash 正式版凭什么暴涨 47 分?
前端·aigc·deepseek
jarvisuni12 小时前
DeepSeekFlash前端依旧拉垮,而且变慢了很多!
前端·javascript·算法
卷福同学13 小时前
AI编程出海第二步:验证关键词能否做站
前端·人工智能·后端