前端模块化
一、模块化进化史
对于 js 的编写,不能像其他语言一样很好的支持模块化,很多程序会比较臃肿的丢在一个文件里,要把这个程序拆分开使用,两个文件之前变量的传递就是个问题。
模块化的的第一个阶段,是使用的全局模式。假如一个文件要使用另一个文件中的变量,就需要将这个变量定为全局变量,挂到 window 对象上面,这样虽然解决了变量共享的问题,但是这样不仅污染全局对象,而且很容易引起命名冲突覆盖之前的变量。于是,前端模块化的又摸索开始了。
到了第二个阶段,人们开始用对象分装这些数据,这样做避免了命名冲突,但是这些数据可以通过对象直接访问到,即没有做到数据私有化。使得数据不安全。
到了第三个阶段,立即执行函数的引入,很好的解决了数据是私有的问题,但是当前这个模块依赖另一个模块时就不好处理了。
到了第四个阶段,开始出现引入依赖的思想,诸如 commonjs、AMD、ES6 等等规范,他们都是将一个文件作为一个模块来看待,但是浏览器并不识别他们,所以中间就需要一个东西来翻译一下,让浏览器看的懂,即将他们转成浏览器能读懂的 js ,这个时候 webpack 就出现了,它就充当了这个翻译的角色。
下面看一个 demo 感受一下。这个 demo 要实现的主体效果是我一个文件里定义了变量,在另一个文件里引用它输出。
二、传统开发
先看没有使用 webpack 的场景。首先在你的工程下创建一个 index.html 文件,在 js 目录下再分别创建 a.js 和 b.js 文件。
1 |
|
1)定义变量
a.js 文件中定义一个变量,要想让令一个文件中能访问到,就要把它挂到全局。
1 | (function () { |
2)引用变量
b.js 文件中输出这个变量。
1 | console.log('msg: ', msg); |
3)查看结果
打开浏览器控制台可以看到如下效果:
三、模块化开发
1)导出变量
使用 exports 导出变量
1 | var msg = 'yin'; |
2)引入变量
在另一个文件中,以 require 的方式导入数据
1 | var msg = require('./a.js').msg; |
3)运行
在控制台运行 b.js 文件
1 | node b.js |
可以看到控制台输出内容,但是到了浏览器中刷新的时候,会发现报错
这是意料之中的事情,因为浏览器本身不认识 node,要让它认识就需要拿 webpack 来编译一下。所以用 npm 先全局装一下 webpack
1 | npm install webpack -g |
这里将编译后的内容放到 dist 目录下,命名为 bundle.js,所以 html 文件中重新改一下引用方式。
1 |
|
最后编译一下,刷新浏览器,内容就又正常显示了。
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)配置 webpack.config.js 文件
这里写程序编译的出口和入口。
1 | const path = require('path'); |
3)运行
每次编译只需要运行npm run build 即可,刷新浏览器,控制台内容也正常输出。最终项目结构如下: