前端模块化

一、模块化进化史

对于 js 的编写,不能像其他语言一样很好的支持模块化,很多程序会比较臃肿的丢在一个文件里,要把这个程序拆分开使用,两个文件之前变量的传递就是个问题。

模块化的的第一个阶段,是使用的全局模式。假如一个文件要使用另一个文件中的变量,就需要将这个变量定为全局变量,挂到 window 对象上面,这样虽然解决了变量共享的问题,但是这样不仅污染全局对象,而且很容易引起命名冲突覆盖之前的变量。于是,前端模块化的又摸索开始了。

到了第二个阶段,人们开始用对象分装这些数据,这样做避免了命名冲突,但是这些数据可以通过对象直接访问到,即没有做到数据私有化。使得数据不安全。

到了第三个阶段,立即执行函数的引入,很好的解决了数据是私有的问题,但是当前这个模块依赖另一个模块时就不好处理了。

到了第四个阶段,开始出现引入依赖的思想,诸如 commonjs、AMD、ES6 等等规范,他们都是将一个文件作为一个模块来看待,但是浏览器并不识别他们,所以中间就需要一个东西来翻译一下,让浏览器看的懂,即将他们转成浏览器能读懂的 js ,这个时候 webpack 就出现了,它就充当了这个翻译的角色。

下面看一个 demo 感受一下。这个 demo 要实现的主体效果是我一个文件里定义了变量,在另一个文件里引用它输出。

二、传统开发

先看没有使用 webpack 的场景。首先在你的工程下创建一个 index.html 文件,在 js 目录下再分别创建 a.js 和 b.js 文件。

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="./js/a.js"></script>
<script src="./js/b.js"></script>
</body>
</html>

1)定义变量

a.js 文件中定义一个变量,要想让令一个文件中能访问到,就要把它挂到全局。

1
2
3
(function () {
window.msg = 'yin';
})()

2)引用变量

b.js 文件中输出这个变量。

1
console.log('msg: ', msg);

3)查看结果

打开浏览器控制台可以看到如下效果:

三、模块化开发

1)导出变量

使用 exports 导出变量

1
2
3
var msg = 'yin';

module.exports = {msg: msg};

2)引入变量

在另一个文件中,以 require 的方式导入数据

1
2
var msg = require('./a.js').msg;
console.log('msg: ', msg);

3)运行

在控制台运行 b.js 文件

1
node b.js

可以看到控制台输出内容,但是到了浏览器中刷新的时候,会发现报错

这是意料之中的事情,因为浏览器本身不认识 node,要让它认识就需要拿 webpack 来编译一下。所以用 npm 先全局装一下 webpack

1
2
3
npm install webpack -g

npm install webpack-cli -g

这里将编译后的内容放到 dist 目录下,命名为 bundle.js,所以 html 文件中重新改一下引用方式。

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="./dist/bundle.js"></script>
</body>
</html>

最后编译一下,刷新浏览器,内容就又正常显示了。

1
webpack ./js/b.js -o ./dist/bundle.js

四、优化

1)配置 package.json 文件

对于编程来说,每次编译跑这么长代码很不优雅,webpack 给我们提供了很多配置,其中可以对指令进行配置,首先运行 npm init 安装 package.json 文件,然后局部安装 webpack,并在 scripts 中配置 “build”: “node_modules/.bin/webpack” 这一行,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "node_modules/.bin/webpack"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^4.42.0",
"webpack-cli": "^3.3.11"
}
}

2)配置 webpack.config.js 文件

这里写程序编译的出口和入口。

1
2
3
4
5
6
7
8
9
const path = require('path');

module.exports = {
entry: './js/b.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
}

3)运行

每次编译只需要运行npm run build 即可,刷新浏览器,控制台内容也正常输出。最终项目结构如下:

微信打赏