草庐IT

JS 模块化- 05 ES Module & 4 大规范总结

程序员优雅哥 (youyacoder) 2023-03-28 原文

1 ES Module 规范

ES Module 是目前使用较多的模块化规范,在 Vue、React 中大量使用,大家应该非常熟悉。TypeScript 中的模块化与 ES 类似。

1.1 导出模块

导出模块有两种方式:按需导出默认导出

按需导出是使用 export 关键字,将需要导出的成员(变量、函数、对象等)依次导出:

export const xxx = ''
export const xxx = () => {}

一个模块中可以有多个按需导出,但只能有一个默认导出。假设默认导出 A 模块,当 B 模块直接导入模块 A 时,其导入的值就是模块 A 默认导出的值。

export default {}

1.2 导入模块

导入按需导出的模块:

import { xxx } from 'xxx'

上面语法中,花括号 {} 中的内容必须与导出的名称一致。

如果按需导出的成员较多,可以使用 as 一次性导入:

import * as xxx from 'xxx'

导入默认导出的模块:

import xxx from 'xxx'

也可以直接导入一个模块,并直接执行该模块的代码:

import 'xxxxx'

2 使用 Webpack 编译 ES Module

2.1 初始化项目

创建 modules 目录,里面存放两个模块 module1.jsmodule2.js。入口文件与 modules 目录同级,名为 index.js。文件和目录结构如下:

05_ESM/
  |- modules/
    |- module1.js
    |- module2.js
  |- index.js
  |- index.html

2.2 实现两个模块

module1.js 使用按需导出变量 str1 和函数 fun1,默认导出 user 对象:

console.log('in module1')

export const str1 = 'hello module1'

export const fun1 = (msg) => {
  return `module1:${msg}`
}


const user = {
  name: 'zhangsan',
  age: 30
}

export default user

module2.js 使用默认导出,导出一个对象,这个对象包括属性 str2 和方法 fun2

console.log('in module2')

const str2 = 'hello module2'

const fun2 = (msg) => {
  return `module2:${msg}`
}

export default {
  str2,
  fun2
}

2.3 实现入口文件

在入口文件 index.js 中导入两个模块。由于 module1.js 是按需导出,故导入时需要使用 {}module2.js 是默认导出,故此处可以直接导入:

import { str1, fun1 } from './modules/module1'
import m2 from './modules/module2'

console.log(str1)
console.log(fun1('程序员优雅哥'))
console.log(m2.str2)
console.log(m2.fun2('youyacoder'))

2.4 入口 HTML

创建 index.html 文件,使用 script 标签导入 index.js

<script src="./index.js"></script>

在浏览器中访问 index.html 文件,控制台会提示如下错误:

Uncaught SyntaxError: Cannot use import statement outside a module (at index.js:1:1)

这是由于浏览器不认识 ESM 语法。可以使用 babel 将 ES6 语法编译为 ES5 的语法,然后使用 browserify 进行打包;也可以使用 webpack 打包。此处我使用 webpack 5

2.5 使用 Webpack 打包

使用 npmyarn 初始化项目:

yarn init -y

安装 webpackwebpack-cli 为开发依赖:

yarn add webpack webpack-cli -D 

使用 webpack 打包:

npx webpack ./index.js -o ./dist/ --mode development

上面的打包命令直接在命令中配置参数,省略了额外的配置的文件。该命令指定了打包的入口文件为:index.js;输出的目录为 dist 目录,打包模式为 development。关于 webpack 5 的使用,有兴趣的可以看优雅哥的 webpack 5 系列文章。

执行完打包命令后,会生成 dist 目录,并且在该目录中有个 main.js 文件。

index.html 中删除之前引入的 index.js,替换为 dist/main.js

<script src="./dist/main.js"></script>

重新在浏览器中访问 index.html, 控制台输出如下:

3 ES Module 总结

导出模块:

  • 默认导出:export default xxx
  • 按需导出 export const xxx

导入模块:

  • 默认导入: import xxx from 'xxx'

  • 按需导入 import { xxx } from 'xxx'

4 JS 模块化 4 大规范总结

前面优雅哥依次写了模块化的发展史,模块化的规范(可进主页查看每个规范详细版本),现进行一个大汇总方便大家查阅和总结:

01- 模块化前传

02 - Common JS 规范

03 - AMD 规范(Require JS 实现)

04 - CMD 规范 (Sea JS 实现)

05 - ESM 规范

模块化相关 demo 源码可以 github 搜索关键词 js-module-demo 或联系 程序员优雅哥 获取。

源码目录如下:

js-module-demo/
|- 01_Histry/			模块化发展史
|- 02_CommonJS/		CommonJS 规范
|- 03_AMD/				ADM 规范
|- 04_CMD/				CMD 规范
|- 05_ESM/				ESM 规范

各个模块化规范有相似之处,也有差异,模块定义与模块加载的语法如下:

4.1 Common JS 规范

定义模块的语法:

// 暴露函数
module.exports = function () {}

// 暴露对象
module.exports = {
  xxx: () => {}
}

exports.xxx = {}

exports.xxx = function() {}

加载模块的语法:

const xxx = require('xxxx')

4.2 AMD 规范

定义模块的语法:

define(id?, dependencies?, factory)

加载模块的语法:

require([module], callback)

4.3 CMD 规范

定义模块的语法:

// 定义模块
define(function(require, exports, module) {
	
	// 使用 exports 导出模块
	exports.xxx = xxx
	
	//也可以使用 return 导出模块
	// return xxx
})

加载模块的语法:

// 同步加载模块
const m1 = require('../xxx')

// 异步加载模块
require.async('../xxx', function (m2) {
})

4.4 ESM 规范

导出模块:

// 按需导出
export const xxx = ''
export const xxx = () => {}

// 默认导出
export default xxx

导入模块:

import { xxx, yyy } from 'xxx'
import * as xxx from 'xxx'
import xxx from 'xxx'
import 'xxx'

感谢你阅读本文,如果本文给了你一点点帮助或者启发,还请三连支持一下,点赞、关注、收藏,作者会持续与大家分享更多干货

有关JS 模块化- 05 ES Module & 4 大规范总结的更多相关文章

  1. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  2. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  3. ruby-on-rails - rails : "missing partial" when calling 'render' in RSpec test - 2

    我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou

  4. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

    我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

  5. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  6. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

  7. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

    为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

  8. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

  9. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  10. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

随机推荐