ES6 Module学习

一直对ES6都是知识了解其大致的feature,却从来没有用过,也不知道怎么用…
一直对前端的组织、打包不了解,类似Babel、Webpack、Browsify这些看着都是避而远之…
一直对React、Vue这些框架的使用都是套scaffold,根本不知道其中是怎样运作的,脱离了脚手架完全不会写…

可是,这样终归是不行的,终于下定决心去了解,去使用这些东西,真正接触现代的JavaScript!


浏览器script标签

好吧,我以前只知道script标签是把src中指的文件复制过来,现在发现自己已经火星了,去年chrome就支持了引入module,好吧,这样看来,如果就自己用新版的Chrome的话,一切变得简单起来~

写一个最简单的demo,虽然很直白,但毕竟纪念一下自己第一次使用module:

index.html:

1
2
3
4
5
6
7
8
9
10
11
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test</title>
</head>
<body>
hello world
<script type="module" src="./index.js"></script>
</body>
</html>

index.js:

1
2
import * as a from './a.js'
console.log(a.aaa)

a.js:

1
export const aaa = 3

console:

1
3

可以看出,如果浏览器支持的话,只要加个type='module'就可以,不用什么编译工具呀,打包工具呀之类的。

Module怎么用???

其实目前自己对module的理解就是很不具体,可能就是能分成好多个文件写,避免一个文件写的太长;把一些公用的东西提出来,比如config、常数之类的供复用;隔离作用域之类的…

这些应该都是没有错的,可是真正让自己用的时候,就觉得,没那么简单,它到底是干什么用的?什么时候该用?什么时候不该用?有什么范式嘛?有什么best practice吗?

这些可能需要长期使用后才有体会吧,目前自己可以先学习一点..

这里,我觉得讲了一点比较具体的东西,感觉应该值得一看,这本书好像都挺不错的样子:
http://exploringjs.com/es6/ch_modules.html#sec_modules-in-javascript
http://exploringjs.com/es6/ch_modules.html#sec_design-goals-es6-modules

具体的,就不再说了,毕竟没有什么使用经验,以后可以补上…

编译与打包

前边提到的是直接浏览器标签type='module'来让js引入module。

  1. 如果要给用户用呢?用户的浏览器可是无法预知的..
  2. 标签引入是不是不怎么好呀,如果不是http/2的话,是不是还是打包下比较好?

自己虽然不懂第二点,但是目前这前端形势,第一条就决定了你除非是自己写着玩玩,否则必须使用编译到ES5以及打包的工具..

于是,自己要接触自己之前恐惧的名词了:Babel,Browsify,Rollup,Webpack…

这里自己看了一篇文风非常impressive的文章..感觉对新手来说还是很友好的:
https://blessing.studio/how-could-i-use-es6-modules-in-production/

其中这张图片比较好的说明了问题:

Babel转译工具

如果单纯的来说的话,Babel就是一个转译工具,把原来用ES6+的语法变成ES5的或者其它的,可是自己不解的地方在于,ES6支持的module,Babel是怎么变的?转译之后,又该如何使用呢??

了解了一下,发现它好像是把module转换成CommonJS的规范,所以也不能直接script标签引入完事,而是要用一定的库,比如RequireJS,这个自己之后有时间再看吧,毕竟有了现成的打包工具把它变成一个bundle.js,我为何还要煞费苦心的处理这心转译之后的文件呢?还是看看一些打包工具吧。

Webpack打包工具

如果用一句话解释,就是官网上的slogan:

bundle your scripts
bundle your styles
bundle your assets
bundle your images

或者官网这张图:

-w1131

把有依赖的各种资源编程静态的assets,让我们不用考虑依赖之类的。

具体的如何整理依赖,tree-shaking什么的就先不管了,反正,最后给我一个bundle.js直接script引入就很合适~

具体的使用之后再补充吧。

TypeScript+Webpack

其实,我一直以为TypeScript和Babel是两个完全不相干的东西,也以为两者一般要同时使用,但后来经过了解发现,反着这俩都能够转换到ES5,所以用TS也不一定要用Babel~

那么就来入坑TS吧,配一个TypeScript+Webpack的前端项目环境吧,这样就可以优雅的支持Module了~~~

最简单的TS+Webpack配置Demo

文件结构:

1
2
3
4
5
6
7
8
9
10
11
.
├── dist
│   ├── bundle.js
│   └── index.html
├── package-lock.json
├── package.json
├── src
│   ├── bar.ts
│   └── index.ts
├── tsconfig.json
└── webpack.config.js

安装依赖包:

1
2
3
4
5
6
7
8
9
{
...
"devDependencies": {
"ts-loader": "^5.2.2",
"typescript": "^3.1.3",
"webpack": "^4.22.0",
"webpack-cli": "^3.1.2"
}
}

tsconfig.json

1
2
3
4
5
6
7
8
9
10
11
{
"compilerOptions": {
"outDir": "./dist/",
"sourceMap": true,
"noImplicitAny": true,
"module": "es6",
"target": "es5",
"jsx": "react",
"allowJs": true
}
}

webpack.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const path = require('path');
module.exports = {
entry: './src/index.ts',
mode: 'production',
devtool: 'inline-source-map',
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
}
]
},
resolve: {
extensions: ['.tsx', '.ts', '.js']
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
};

src/index.ts

1
2
3
import { greet } from './bar'
greet("world")

src/bar.ts

1
2
3
4
5
const greet = (a: String) => {
console.log(`Hello ${a}`)
}
export { greet }

dist/index.html

1
2
3
4
5
6
7
8
9
10
11
12
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>test</title>
</head>
<body>
Hello World
<script src="bundle.js"></script>
</body>
</html>

执行:

1
npx webpack

bundle.js就生成了~

这个demo反正实现了webpack打包成一个单独的bundle.js文件,且是ES5的,这样一来就可以用高端的TypeScript了,感觉牛的不行,这已经达到了原来的功能。

如果用webpack来管理的话,思路和原来的是很不一样的,自己也需要重新学习webpack的思路与组织方式,这就放在之后的博客来说吧哈哈哈