为了账号安全,请及时绑定邮箱和手机立即绑定

【九月打卡】第17天 vite从入门到精通 4-2章

标签:
征文 活动

课程名称: Vite 从入门到精通,玩转新时代前端构建法则

课程章节: 4-2 【知识拓展】ES Module详解

课程讲师: Jokcy

课程内容:

ES Module详解

讲解以下几个词:

  • ESM
  • ES Module
  • type等于module
定义

ES Module是随着ES6语法推出的正式的JavaScript模块语法。在JavaScript的发展初期,因为脚本量往往都非常小,所以可能一个或者几个独立运行的JS脚本文件就足够一个网站使用了。而随着前端框架的流行,前端应用愈发复杂,单纯的独立运行JS文件显然已经跟不上应用规模的发展速度,在这个过程中,前端社区发展出了一些非标准的模块管理方案:

  • CommonJs规范
  • AMD规范
  • UMD规范

但是这些模块管理方法本质上都是通过JS脚本的执行来进行管理,并不是原生的Native模块管理能力。

而ES Module则是原生的JS语法,ES Module增加了importexport两个主要的关键字,并且使用特殊的语句来完成模块的功能:

import React, { useEffect } from 'react'

这是模块导入的语句,从react中引入默认的对象,以及单独导入useEffect函数。

export defualt SomeObject

export const fun = () => {}

这是模块导出的语句,第一个作为默认导出,第二个则为具名导出。

因为这两个是关键字而不像require是一个函数,所以他们的使用具有一定的限制,这两者都只能在模块的顶级作用域中使用:

// worked
import xxx from 'xxx'
export const a = 1

// not work
if (x = 1){
  import xxx from 'xxx'
  export const a = 1
}

语法:

一、import

import是模块导入的关键字,在ES Module中模块引入具有两种主要的方式:

  • 默认导入
  • 具名导入

在上述的例子中,引入的React就是默认导入的结果,其对应的是在react模块中的export default

useEffect的引入就属于具名导入,其对应的则是在react模块中进行export const useEffect或者export { useEffect }

在具名导入时,我们还可以同时进行重命名,比如import { useEffect as myUseEffect } from 'react',就可以在引入时给变量进行一个新的命名。

注意在模块导入时还有一种不太常用的语法:

import * as React from 'react'

这里的*对应的其实就是react模块中的所有具名导出,比如上述的useEffect在这里就可以通过React.useEffect进行使用。需要注意的是这种方式引入的Reactimport React from 'react'中的React是不一样的,举个例子:

export const a = 1
export const b = 2

export default { a }

那么这里通过import *的方式引入的会具有ab两个属性,而默认import则只有a

二、export

export的使用方式则相对更丰富一些:

export default xxx // 默认导出
export const name = 'Jokcy' // 具名导出
const age = 18
export { age } // 集合形式的具名导出
export { age as JokcyAge } // 导出并重命名
export * from 'another-module' // re- export 重新导出
export { someValue } from 'another-module' // 具名重新导出

我们可以简单地在导出语句中是否看到具体的变量名的方式来归纳其导出方式是否属于具名导出,事实上我们可以认为除了默认导出方式外其他的都属于具名导出。

在网页上使用ES Module

在现在主流的现代浏览器上基本都已经支持了ES Module的JS模块管理功能。我们可以通过:

<script type="module" src="/path/to/file.js"></script>

来加载并执行ES Module的JS脚本。需要注意的是这里的type="module"是不能省略的,浏览的只会对加了这个属性的JS脚本采用ES Module的形式进行解析,不然可能会出现报错,比如在火狐浏览器中就会提示SyntaxError: import declarations may only appear at top level of a module

对于ES Module的JS脚本,在浏览器解析并执行之后,对文件内的import语句,浏览器则会根据其路径继续请求其依赖的模块,也就是说只有真正被依赖的JS模块才会被真正的加载。

动态加载模块

那么如果我们需要在一些条件判断中来决定是否进行一些模块的加载,是否就做不到了呢?毕竟我们之前已经说过importexport必须在顶层作用域中使用。

如果是通过importexport关键字,那么确实是无法实现的。不过在ES Module的规范中,也为我们提供了动态导入模块的工具函数:import()

import()函数接收一个字符串作为需要引入的模块路径,比如import('./my-route2.js')就表示现在我需要加载my-route2这个模块。该函数返回一个Promise,当模块加载成功之后会调用then,反之则进入catch。在then中我们会拿到对应模块的所有导出:

import('./a.js').then(m => {
  m.sayHello()
})

因为其是一个函数,所以自然可以在任何地方被调用,不会受到语法的限制。

mjs 和 js

在ES Module宣布时,也同时宣布了mjs后缀名。统一的认知是以mjs结尾的文件被视为ES Module的文件,而js文件则为非ES Module文件。在nodejs 14之后已经正式支持了ES Module,如果你没有在package.json中声明module: true,那么你只能在mjs结尾的文件中使用ES Module。

但业界并没有局限于该规范,毕竟后缀名更多仍然是便于阅读,主流的模块管理工具比如webpack、rollup他们都有自己独有的配置或者识别方式来判断某个文件是否是ES Module的模块,所以也并不需要局限于后缀名带来的限制。

require的区别

一个大部分人会关心的问题就是ES Module和我们用的最多的Common JS模块的区别。

Common JS模块通过require函数和module对象来进行模块管理,而这两个函数则是在JS脚本执行前,有JS引擎通过VM进行注入的全局对象,本质上他们就是JS的函数或者对象,可以在任意地方被引用和使用,他们的运行的同时也是JS运行的同时。

而ES Module的importexport则不同,他们是关键字,在脚本被语法解析还没有执行时,就已经可以知道该模块导入或者导出了什么内容,本质上这两个模块管理方式的执行时机就是不同的。

一个典型的区别就是import导入的内容是静态的不允许修改的,而require引入的对象本身就是原始对象的引用,可以直接进行修改。

课程收获:
理解除了 ES Module 之外,都是非标准的模块管理方案。
对 ES Module 的语法有了深入的了解。
明白对如何 动态加载模块,还有在网页上使用 ES Module。
明白 mjs 和 js 的区别,还有 ES Module 和 require 的区别。

图片描述

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
Web前端工程师
手记
粉丝
10
获赞与收藏
5

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消