forthealllight / blog

📖我的博客,记录学习的一些笔记,如有喜欢,欢迎star
2.3k stars 225 forks source link

深入浅出浏览器中的ES modules #66

Open forthealllight opened 4 years ago

forthealllight commented 4 years ago

    主流浏览器陆续都已经开始支持es modules,此外一些Bundless的工具,比如snowpack、vite等。此外给予浏览器的ESM也可以实现一些前端微服务,本文主要介绍一下什么是浏览器中的ESM

  • import & export
  • import.map
  • import.meta
  • 浏览器中esm的兼容问题

一、import & export

    首先我们来看主流浏览器对于ES modules的支持情况:

Lark20201119-151747

    从上图可以看出来,主流的Edge, Chrome, Safari, and Firefox (+60)等浏览器都已经开始支持es modules。

    对于es modules,我们并不陌生,什么是es modules也不是本文的重点,一些流行的打包构建工具比如babel、webpack等早就支持es modules。

    我们来看一个最简单的es modules的写法:

//main.js
import a from 'a.js'
console.log(a)

//a.js
export let  a = 1

    上述的es modules就是我们经常在项目中使用的es modules,这种es modules,在支持es6的浏览器中是可以直接使用的。

    我们来举一个例子,直接在浏览器中使用es modules

<html  lang="en">
    <body>
        <div id="container">my name is {name}</div>
        <script type="module">
           import Vue from 'https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.esm.browser.js'
           new Vue({
             el: '#container',
             data:{
                name: 'Bob'
             }
           })
        </script>
    </body>
</html>

上述的代码中我们直接可以运行,我们根据script的type="module"可以判断浏览器支不支持es modules,如果不支持,该script里面的内容就不会运行。

    我们再来看一种调用方式,我们也可以通过script标签来直接引入相对路径或者绝对路径的模块。

//html
<script type="module" src="/index.js"></script>

//index.js
 import Vue from 'https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.esm.browser.js'
 new Vue({
    el: '#container',
    data:{
    name: 'Bob'
    }
 })

二、import.map

    上述的调用中我们通过绝对路径或者相对路径的形式来import,这种方式跟我们在之前的代码中有点区别,我们希望的是通过:

import Vue from 'vue'   

这种简单的方式来引入一个npm包,就像我们在之前bundle时书写格式一致,那么浏览器中如何支持这种写法呢,答案就是使哟过import.map。import.map的提案可以参考:https://github.com/WICG/import-maps

    我们直接来看例子:

//html
<script type="importmap">
  {
    "imports":{
      "vue":"https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.esm.browser.js"
    }
  }
</script>
<script type="module" src="/index.js"></script>

//index.js
 import Vue from 'vue'
 new Vue({
    el: '#container',
    data:{
    name: 'Bob'
    }
 })

通过importmap,我们可以直接在业务代码中使用:

import Vue from  'vue'

三、import.meta

    在浏览器中我们有全局上下文window,在node中我们有全局上下文global,同理可以引入一个对象作为某一个module的上下文元数据。该对象就是import.meta对象,这个对象在模块中用于存取上下文数据,可读也可以写。

(1)import.meta.url

import.meta.url返回当前模块的 URL 路径。


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

 //index.js

 console.log(import.meta.url) //输出http://localhost:8080/index.js

(2) import.meta.scriptElement

    import.meta.scriptElement返回是浏览器特有的元属性,返回加载模块的那个 Githubissues.

  • Githubissues is a development platform for aggregating issues.