0%

esmodule 在浏览器和node端使用

esmodule 在我 2016 年刚开始学 react 时候就开始用了,虽然用的理所当然,但是其实在 js 发展的历史中,早期好多项目其实是不支持的,包括浏览器, 这个淘汰过程需要很长的时间.最近感觉在 ie 逐步历史舞台的时期,去了解一下 node 浏览器里如何直接用 esmodule 还是很需要的.
翻了一些资料,总结一下如何使用.

NODE 里用 ESModules

主流的 node js 现在都支持 ESmodules

到 2021 年 4 月 20 号, Node v10 版本将停止维护 (更多参考 Node Releases ).这很令人振奋因为这意味着每个在维护的 node 版本都官方支持 EcmaScript Modules! 可能有些人还是挺喜欢以前的 CommonJS 但是 EcmaScript Modules 是大势所趋.

First, we need the JavaScript we want to run:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// get-files.js

import path from 'path'

import fs from 'fs/promises'



const isDir \= async d \=> (await fs.lstat(d)).isDirectory()



async function getFiles(dir) {

const list \= await fs.readdir(dir)

const filePromises \= list.map(async filename \=> {

const filepath \= path.join(dir, filename)

if (await isDir(filepath)) {

return {type: 'dir', filepath}

} else {

const content \= String(await fs.readFile(filepath))

return {type: 'file', filepath, content}

}

})

return Promise.all(filePromises)

}



export {getFiles}

Next, let's make a JavaScript file that imports this and runs it:


// index.js

import {getFiles} from './get-files.js'


console.log(await getFiles('.'))

运行一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
node .

(node:5369) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.

(Use \`node --trace-warnings ...\` to show where the warning was created)

/Users/kentcdodds/Desktop/super-simple-start-to-esm-in-node/index.js:1

import {getFiles} from './get-files.js'

^^^^^^



SyntaxError: Cannot use import statement outside a module

at wrapSafe (internal/modules/cjs/loader.js:979:16)

at Module.\_compile (internal/modules/cjs/loader.js:1027:27)

at Object.Module.\_extensions..js (internal/modules/cjs/loader.js:1092:10)

at Module.load (internal/modules/cjs/loader.js:928:32)

at Function.Module.\_load (internal/modules/cjs/loader.js:769:14)

at Function.executeUserEntryPoint \[as runMain\] (internal/modules/run\_main.js:72:12)

at internal/main/run\_main\_module.js:17:47

nodejs 运行 esmodule 不是默认项. 你有两个选择:

  • .js 改成 to .mjs
  • 修改package.json,添加 "type": "module".

以下是修改 package.json 后 再次运行 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

node .

\[

{

type: 'file',

filepath: 'get-files.js',

content: "import path from 'path'\\n" +

// clipped for brevity

'export {getFiles}\\n'

},

{

type: 'file',

filepath: 'index.js',

content: "import {getFiles} from './get-files.js'\\n" +

'\\n' +

"console.log(await getFiles('.'))\\n"

},

{

type: 'file',

filepath: 'package.json',

content: '{\\n "type": "module"\\n}\\n'

}

\]

参考:

在浏览器里用 ESModules

_所有的主流浏览器现在都支持 ESModuels!!!!,demo 如下:

  • 先写一个想要运行的 js module:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

// append-div.js

function appendDiv(message) {

const div \= document.createElement('div')

div.textContent \= message

document.body.appendChild(div)

}



export {appendDiv}

Next, let's make an HTML file to load that file:

<!-- index.html -->

<script type\="module"\>

import {appendDiv} from './append-div.js'

appendDiv('Hello from inline script')

</script\>

注意 type="module" 属性. 这是所有我们需要修改的地方 ,用”module” 代替 “script”, 你可以参考several differences 看看浏览器运行模块化 js 的原理.

我们需要 启动一个静态服务器来测试 ,推荐用npx server . 这个 npm 包 来做这个事情, 默认启动的是 localhost:5000 这个地址. 🎉

从另一个 js 文件来引用 module js 文件

1
2
3
4
5
6
7
8

// script-src.js

import {appendDiv} from './append-div.js'



appendDiv('Hello from external script')

修改 html 文件:

1
2
3
4
5
6
7
8
9
10
11
12

<!-- index.html -->

<script type\="module"\>

import {appendDiv} from './append-div.js'

appendDiv('Hello from inline script')

</script\>

<script type\="module" src\="./script-src.js"\></script\>

下一个知识点,动态引用module js 文件::

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

// async-script.js

import {appendDiv} from './append-div.js'



function go() {

appendDiv('Hello from async script')

}



export {go}

Then we can load that using a dynamic import statement:

// script-src.js

import {appendDiv} from './append-div.js'



appendDiv('Hello from external script')



import('./async-script.js').then(

moduleExports \=> {

moduleExports.go()

},

error \=> {

console.error('there was an error loading the script')

throw error

},

)

你甚至可以这样来引用这个

1
2

`import \* as d3 from 'https://unpkg.com/d3?module'`

The point is, the thing you put in the quotes in your import statements has to point to a JavaScript resource on some server somewhere. Learn more about unpkg.com.

资料