浏览器中的 ESM

大家好,我是若川。最近组织了源码共读活动,感兴趣的可以加我微信 ruochuan12

早期的web应用非常简单,可以直接加载js的形式去实现。随着需求的越来越多,应用越做越大,需要模块化去管理项目中的js、css、图片等资源。这里有很多大家熟悉的模块化标准, CJS、AMD、CMD、UMD 等等。模块化提供了我们更好的方式来组织和维护函数以及变量。而在 npm 生态开发的背景下,CJS 模块是开发过程中接触最多也是无法避免的。但由于浏览器并不能直接执行基于 CJS 打包的模块,因此类似 webpack 等打包工具便应运而生。随着webpack 大有一统构建工具的趋势下,JavaScript 官方的标准化模块系统ESM完成了。本文主要介绍下模块化标准间差异、基本加载原理。

模块化发展

1、为何要模块化

仔细想想,用 JavaScript 编码就是管理变量。这一切都是关于为变量赋值,或为变量添加数字,或将两个变量组合在一起并将它们放入另一个变量中。

18b0dce1b5643310eeab66323cfdfaba.png

如果代码中仅有少量的变量,那么组织起来其实是很简单的。一旦有很多的变量,我们会通过函数作用域去组织变量。因为函数作用域的缘故,一个函数无法访问另一个函数中定义的变量。

如果只维护少量变量非常简单。但是如果有很多的变量,我们就需要用一种方法来帮助做到这一点,叫做作用域。由于作用域在 JavaScript 中的工作方式,函数不能访问在其他函数中定义的变量。

fcd2de9bb092853f6da23f47e3765af0.png

这种方式是很有效的。在写一个函数的时候,只需要考虑当前函数,而不必担心其它函数可能会改变当前函数的变量。如果想要函数之间共享变量要怎么办呢?一种通用的做法是全局作用域。

在 jQuery 时代这种提升做法相当普遍。在我们加载任何 jQuery 插件之前,我们必须确保 jQuery 已经存在于全局作用域。

98485ede48230781e3b88e5b1e457ac5.png

所有的 <script> 必须以正确的顺序排列,必须保证被依赖的变量先加载。如果排列错了,那么在运行过程中,应用将会抛出错误,并且停止继续运行。

代码之间的依赖是不透明的。这使得代码维护变得困难。代码变得充满不确定性。任何函数都可能依赖全局作用域中的任何变量。

其次,由于变量存在于全局作用域,所以任何代码都可以改变它。

2、模块化的作用

模块化为你提供了一种更好的方式来组织变量和函数。可以把相关的变量和函数放在一起组成一个模块。这种实现形式可以把函数和变量放在模块作用域中。模块作用域还提供一种暴露变量给其他模块使用的方式。模块可以明确地指定哪些变量、类或函数对外暴露。

对外暴露的过程称为导出。一旦导出,其他模块就可以明确地声称它们依赖这些导出的变量、类或者函数。

95a7ee95e3d9085d220da3f52fb318f9.png

因为这是一种明确的关系,所以你可以很简单地辨别哪些代码能移除,哪些不能移除。

拥有了在模块之间导出和导入变量的能力之后,你就可以把代码分割成更小的、可以独立运行地代码块了。基于这些代码块,你就可以像搭乐高积木一样,创建所有不同类型的应用。比较流程的规范有CommonJS,AMD,CMD,ES,UMD等

3、现有模块标准

CJS 是 CommonJS 的缩写。只适用于node端:

const _ = require('lodash'); module.exports = function doSomething(n) {}

AMD 代表异步模块定义。在浏览器端有效:

define(['dep1', 'dep2'], function (dep1, dep2) {return function () {};
});

UMD 代表通用模块定义(Universal Module Definition):

(function (root, factory) {if (typeof define === 'function' && define.amd) {// AMD. Register as an anonymous module.define([], factory);} else if (typeof module === 'object' && module.exports) {// Node. Does not work with strict CommonJS, but// only CommonJS-like environments that support module.exports,// like Node.module.exports = factory();} else {// Browser globals (root is window)root.returnExports = factory();}
}(typeof self !== 'undefined' ? self : this, function () {// Just return a value to define the module export.// This example returns an object, but the module// can return a function as the exported value.return {};
}));

什么是 ESM

简介

ESM是ES6提出的标准模块系统,ECMAScript modules。JS自己的模块体系

<script type="module">import { html, Component, render } from 'https://unpkg.com/htm/preact/standalone.module.js';class App extends Component {state = {count: 0}add = () => {this.setState({ count: this.state.count + 1 });}render() {return html`<div class="app"><div>count: ${this.state.count}</div><button onClick=${this.add}>Add Todo</button></div>`;}}render(html`<${App} page="All" />`, document.body);
</script>

思考:上述代码和在webpack中开发有啥区别?

2、浏览器端技术实现

回顾下Webpack执行流程

  1. 本地模块化解析(通过webpack或者babel,将import解析成cjs)

  2. 将各个库打包成一个js boundle

  1. 开启服务,托管资源

  2. 浏览器获取资源

  1. 执行代码

浏览器端ESM执行流程

  1. 开启服务,托管资源(ES源码)

  2. 加载入口文件,浏览器模块化解析

    47cf87ba58bdeb0f56e1a696a97cb838.png

  3. 构建

    1. 遍历依赖树,先解析文件,然后找出依赖,最后又定位并加载这些依赖,如此往复。(下载所有的js)

      99e825b667bb8143496cb0c585a13c70.png

    2. 模块映射

      当加载器要从一个 URL 加载文件时,它会把 URL 记录到模块映射中,并把它标记为正在下载的文件。然后它会发出这个文件请求并继续开始获取下一个文件。

      480dffbfc210687aa585d23831ca212b.png

    3. 解析模块
      所有的模块都按照严格模式来解析的。不同文件类型按照不同的解析方式称。在浏览器中,通过 type="module" 属性告诉浏览器这个文件需要被解析为一个模块。不过在 Node 中,我们并不使用 HTML 标签,所以也没办法通过 type 属性来辨别。社区提出一种解决办法是使用 .mjs 拓展名。

  1. 运行
    采用深度优先的后序遍历方式,顺着关系图到达最底端没有任何依赖的模块,然后设置它们的导出。模块映射会以 URL 为索引来缓存模块,以确保每个模块只有一个模块记录。这保证了每个模块只会运行一次。

3、为什么火起来

  • ES语法基本确定

  • http2普及

  • 新浏览器普及

  • 开发与发布代码一致

  • 启动快

  • 全新加载模式

目前浏览器支持:

86356fa04ef755e150d5a3ee6aadb9f0.png

a237c2f4774df7880994fe35b90272e0.png

5e24b6a8e4e61b45d6c24f005cd37d30.png

e92234d971bda3cdcdbb103be80a7be5.png

6374a0f2228808a415cc77d6576484d5.png

目前只有5%的浏览器不兼容es相关规范。

4、为什么还没火起来

  • 部分浏览器的兼容性

  • 历史包袱悠久

  • 生态不完善

实战

当我们在项目中使用需要考虑以下几个问题点

1. 代码开发需要基于es开发

let a = 1;
new Promise()
() => {}
...

2. 依赖库加载

  • node_modules代码服务化

  • 兼容cjs

    1. 加载包内部es目录

    2. cjstoesm

c30923406ac07add1128d1db22347c18.png

  • CDN(network for npm)

    1. https://unpkg.com/

    2. https://www.skypack.dev/

3. 兼容不支持的浏览器

  • type="module"实现

    • 如果浏览器不支持,他只识别type="text/javascript"不识别 type="module" ,故不下载js;如果支持,则会下载js

    • 如果浏览器不支持,则会忽略nomodule,下载js;如果支持,则不会下载js

<script type="module" src="app.js"></script>
<script nomodule src="app-bundle.js"></script>
  • systemjs实现https://github.com/systemjs/systemjs

<script src="system.js"></script>
<script type="systemjs-importmap">
{"imports": {"lodash": "https://unpkg.com/lodash@4.17.10/lodash.js"}
}
</script>
<script type="systemjs-module" src="/js/main.js"></script>

4. jsx支持

  • 通过其他开源库

<script type="module">import { html, Component, render } from 'https://unpkg.com/htm/preact/standalone.module.js';class App extends Component {render() {return html`<div class="app"></div>`;}}render(html`<${App} page="All" />`, document.body);
</script>
  • 本地语法糖解析

<APP {...Props}/>
=>
React.createElement(App, {...props})

现有脚手架

1. snowpack

4bb0dccb70e4f5d4d8f0ee80d4369923.png

  • 托管node_modules

  • 支持图片、css等资源

  • JSX 和 Typescript 编译

  • HMR

  • ...

2. vite

https://cn.vitejs.dev/guide/

目前snowpack的作者后续可能不再维护了,所以推荐大家使用vite

ESM 未来

2018 年 5 月 Firefox 60 发布后,所有的主流浏览器就都默认支持 ESM 了。Node 也正在添加 ESM 支持,为此还成立了工作小组来专门研究 CJS 和 ESM 之间的兼容性问题。所以,在未来你可以直接在 <script> 标签中使用 type="module",并且在代码中使用 importexport 。同时,更多的模块功能也正在研究中。比如动态导入提案已经处于 Stage 3 状态;import.meta也被提出以便 Node.js 对 ESM 的支持;模块定位提案 也致力于解决浏览器和 Node.js 之间的差异。

相信在不久的未来,跟模块一起玩耍将会变成一件更加愉快的事!

node v10以上版本全部支持ESM https://kentcdodds.com/blog/super-simple-start-to-es-modules-in-node-js

相关参考

ECMAScript modules in browsers https://jakearchibald.com/2017/es-modules-in-browsers/

JavaScript 模块现状 https://zhuanlan.zhihu.com/p/26567790

基于esm、html、unpkg的前端开发模式:https://github.com/developit/htm

How I Build JavaScript Apps In 2021:https://timdaub.github.io/2021/01/16/web-principles/

Find out how much turning on modern JS could save. https://estimator.dev/

什么是amd、commonjs、umd、esm? https://zhuanlan.zhihu.com/p/96718777

ES modules: A cartoon deep-dive:https://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive/

import.map:https://github.com/WICG/import-maps

面对 ESM 的开发模式,webpack 还有还手之力吗? https://topic.atatech.org/articles/202736


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/275287.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

标记图标_标记您的图标

标记图标Not labeling your icons is the same as assuming that we are all fluent in ancient hieroglyphics. Are you? Can you just walk up to Cleopatras needle and read it like you could read a childrens book? Even emojis, our modern hieroglyphics dont mean …

找出无序数组中最小的k个数(top k问题)

2019独角兽企业重金招聘Python工程师标准>>> 给定一个无序的整型数组arr&#xff0c;找到其中最小的k个数 该题是互联网面试中十分高频的一道题&#xff0c;如果用普通的排序算法&#xff0c;排序之后自然可以得到最小的k个数&#xff0c;但时间复杂度高达O(NlogN)&…

你应该知道的 Node 基础知识

大家好&#xff0c;我是若川。最近组织了源码共读活动&#xff0c;感兴趣的可以加我微信 ruochuan12 参与&#xff0c;已进行两个多月&#xff0c;大家一起交流学习&#xff0c;共同进步。源码共读学的多数是 Node.js &#xff0c;今天分享一篇 Node.js 基础知识的文章。一. N…

react 引入 mobx @babel/core: 7.2.2

为什么80%的码农都做不了架构师&#xff1f;>>> yarn add babel/plugin-proposal-class-propertiesyarn add babel/plugin-proposal-decorators"babel": {"plugins": [["babel/plugin-proposal-decorators", {"legacy": …

面试官问:怎么自动检测你使用的组件库有更新

大家好&#xff0c;我是若川。最近组织了源码共读活动&#xff0c;感兴趣的可以加我微信 ruochuan12本文来自V同学投稿的源码共读第六期笔记&#xff0c;写得很有趣。现在已经进行到第十期了。你或许经常看见 npm 更新的提示。npm 更新提示面试官可能也会问你&#xff0c;组件库…

使用Microsoft Web Application Stress Tool对web进行压力测试

你的Web服务器和应用到底能够支持多少并发用户访问&#xff1f;在出现大量并发请求的情况下&#xff0c;软件会出现问题吗&#xff1f;这些问题靠通常的测试手段是无法解答的。本文介绍 了Microsoft为这个目的而提供的免费工具WAS及其用法。另外&#xff0c;本文介绍了一种Web应…

2021前端高频面试题整理,附答案

大家好&#xff0c;我是若川。最近组织了源码共读活动&#xff0c;感兴趣的可以加我微信 ruochuan12若川视野原意是若川的前端视野。但太长了就留下了四个字&#xff0c;不知道的以为关注的不是技术公众号。今天分享一篇慕课网精英讲师河畔一角的好文章~废话不多说&#xff0c;…

OO第二单元作业小结

总结性博客作业 第一次作业 (1)从多线程的协同和同步控制方面&#xff0c;分析和总结自己三次作业的设计策略。 第一次作业为单电梯傻瓜调度&#xff0c;可以采用生产者——消费者模型&#xff0c;是一个有一个生产者&#xff08;标准输入电梯请求&#xff09;&#xff0c;一个…

dribbble加速vpn_关于Dribbble设计的几点思考

dribbble加速vpn重点 (Top highlight)I’d like to start with the following quote from Paul Adam’s “The Dribbbilisation of Design,” a powerful read that examines the superficiality of modern product design portfolios, often containing Dribbble posts that l…

尤雨溪推荐神器 ni ,能替代 npm/yarn/pnpm ?简单好用!源码揭秘!

1. 前言大家好&#xff0c;我是若川。最近组织了源码共读活动&#xff0c;感兴趣的可以加我微信 ruochuan12想学源码&#xff0c;极力推荐之前我写的《学习源码整体架构系列》jQuery、underscore、lodash、vuex、sentry、axios、redux、koa、vue-devtools、vuex4、koa-compose、…

如何了解自己的认知偏差_了解吸引力偏差

如何了解自己的认知偏差Let me introduce you the attractiveness bias theory known as cognitive bias.让我向您介绍称为认知偏差的吸引力偏差理论。 Think about a person with outstanding fashion. It will draw our attention, and maybe encourage us to interact with…

隐马尔可夫模型(HMM)及Viterbi算法

HMM简介 对于算法爱好者来说&#xff0c;隐马尔可夫模型的大名那是如雷贯耳。那么&#xff0c;这个模型到底长什么样&#xff1f;具体的原理又是什么呢&#xff1f;有什么具体的应用场景呢&#xff1f;本文将会解答这些疑惑。  本文将通过具体形象的例子来引入该模型&#xf…

尤大直播分享:vue3生态进展和展望

大家好&#xff0c;我是若川。最近组织了源码共读活动&#xff0c;感兴趣的可以加我微信 ruochuan12前言10月23日&#xff0c;参加了前端早早聊组织的【vue生态专场】&#xff0c;准备写一波分享方便大家学习。早上有4个话题&#xff1a;volar开发&#xff0c;搭建平台组件开发…

利用Python查看微信共同好友

思路 首先通过itchat这个微信个人号接口扫码登录个人微信网页版&#xff0c;获取可以识别好友身份的数据。这里是需要分别登录两人微信的&#xff0c;拿到两人各自的好友信息存到列表中。 这样一来&#xff0c;查共同好友就转化成了查两个列表中相同元素的问题。获取到共同好友…

女生适合学ux吗_UX设计色彩心理学,理论与可访问性

女生适合学ux吗Colour is an interesting topic, which I feel is often overlooked and sometimes under-appreciated. One of the first things I was taught was the power of colour, how it can have an impact on human emotion, and that there should be purpose behin…

初学者也能看懂的 Vue2 源码中那些实用的基础工具函数

1. 前言大家好&#xff0c;我是若川。最近组织了源码共读活动&#xff0c;感兴趣的可以加我微信 ruochuan12想学源码&#xff0c;极力推荐之前我写的《学习源码整体架构系列》jQuery、underscore、lodash、vuex、sentry、axios、redux、koa、vue-devtools、vuex4、koa-compose、…

视觉测试_视觉设计流行测验

视觉测试重点 (Top highlight)I often discuss the topic of improving visual design skills with junior and mid-level designers. While there are a number of design principles the designers should learn and practice, one important skill that is not often consid…

如何给开源项目提过 PR 呢?其实很简单

大家好&#xff0c;我是若川。最近组织了源码共读活动&#xff0c;感兴趣的可以加我微信 ruochuan12源码共读群里有小伙伴聊到如何给开源项目提PR&#xff0c;所以今天分享这篇文章。你有给开源的库或者框架提过 PR 吗&#xff1f;如果没有&#xff0c;那么今天的文章会教你怎么…

一次回母校教前端的经历

大家好&#xff0c;我是若川。最近组织了源码共读活动&#xff0c;感兴趣的可以加我微信 ruochuan12已进行了三个月&#xff0c;很多小伙伴都表示收获颇丰。分享一篇武大毕业的耀耀大佬的文章。有些时候会受限于环境影响&#xff0c;特别是在校大学生。所以要融入到积极上进的环…

设计插画工具_5个强大的设计师插画工具

设计插画工具As Product Designers, most likely, we have come across illustrative work. Visual design is one important element in enhancing the user experience. As many gravitate toward attractive looking products, designers are also adapting to the changing…