这几天连着巴拉巴拉发了好多关于前端的文章。。。。呃呃 ,因为作为一个全站开发人员,前后端分离必然是大势所趋。。。所以只能顺势而为了。。。
什么是Webpack
Webpack是一个模块打包器,它的主要目标是将JavaScript文件打包在一起,打包后的文件用于在浏览器中使用。 —-Webpack中文文档
说白了,它最大的用处就是分析一个网页的各种依赖,并且自动化地将这些依赖打包在一起并且压缩,供网页使用。当然它的功能不止如此,比如依赖loader,它还可以将JavaScript ES6(很多老浏览器不一定支持)转换成支持更加多浏览器的老版本JavaScript。
总之,它在前端的模块化开发中占有重要的作用,如果想让自己的项目变得更加整洁,开发更加有效率,Webpack有必要一学。
在开始之前
在介绍Webpack之前,很有必要先介绍一下Node.js和npm,如果你已经对着两者有着深刻的了解,可以直接跳过,看下一节,如果你之前从未听说过Node.js,可以仔细看看这一节对这两者的介绍,Webpack的使用一定程度上依赖着这两者。
Node.js是一个基于Chrome V8引擎驱动的JavaScript运行时。Node.js使用高效、轻量级的事件驱动、非阻塞I/O模型。它的包生态系统,npm,是目前世界上最大的开源库生态系统。 —-Node.js官网
看了是不是感觉Node.js官网的介绍,感觉这玩意十分高深莫测,说实话我第一次看到的时候也没有太看懂。接下来用人话给大家翻译一下,众所周知,JavaScript是Web开发中不可或缺的语言,它可以为网页添加许多动态效果,也能为网页添加更多可能性,如果连JavaScript都不知道,请先学习一下Web开发御三家(html, css, js),但是JavaScript的硬伤是只能在浏览器上运行,脱离浏览器,就无法运行。而Node.js就解决了这么一个问题,它将Chrome V8的JavaScript引擎提取出来,使得JavaScript能够脱离浏览器而运行,这样就为JavaScript提供了无限的可能性。至于它的更多,现在先不用了解那么深,对于Node.js,你现在只需要了解到这里就行了。
而npm,则是Node.js自带的包管理系统,npm的作用跟python的pip很像,你只需要敲一行命令,就能获取到世界上任何一个角落的人发布在其上的源码并且使用。显然,JavaScript开发模块化,npm也在其中做出了很大贡献。
接下来,先安装Node.js吧,打开Node.js的官网Node.js
简单粗暴的页面,你可以选择稳定版LTS和最新版Current下载,自行安装即可。当安装完成后,你可以在命令行输入
1 |
node -v |
如果正确显示了Node.js的版本号,就说明你的Node.js成功安装了,当然,npm是Node.js的一部分,Node.js安装成功的同时,npm也就可以使用了。
开始学习Webpack
如果你还没有安装Node.js,请移步上一节并认真安装好Node.js,如果你已经安装了Node.js,就可以开始学习Webpack了。
首先,先建立一个文件夹,用来作为学习Webpack的项目文件夹,文件夹名随意,接着在项目使用命令行中初始化npm
1 |
npm init |
运行该命令会询问你你这一个项目的基本信息,比如项目名、作者、描述、Git仓库等等,这是因为init指令实际上是将项目文件夹变成一个npm包,你甚至在日后可以将这个npm包发布给他人使用,当然,我们现在只是学习,一路回车就行,如果你实在比较较真,也没关系,这些东西日后可以在配置文件中修改。如果你不想敲回车,也可以直接使用
1 |
npm init -y |
当npm初始化完成之后,项目下会自动生成一个package.json文件,上面详细说明了你这一个npm包中的信息,我们暂时可以不用关注这些内容。接下来在项目中安装Webpack。
1 2 |
npm install --save-dev webpack npm install --save-dev webpack-cli |
这两行命令会为你的项目安装webpack和webpack-cli包,前者是webpack的核心库,后者是分离出来的webpack命令行功能,我们需要使用webpack-cli来进行项目的打包等操作。
不使用Webpack时,项目的问题
我们先看一下不使用webpack进行构建时,项目的缺陷。
先在项目文件夹中创建几个目录和文件,项目结构如下图所示,前面带加号的是需要你自己创建的文件和目录:
1 2 3 4 5 |
webpack-learning |- package.json + |- index.html + |- /src + |- index.js |
src/index.js
1 2 3 4 5 6 7 8 9 10 |
function component() { var element = document.createElement('div'); // Lodash(目前通过一个 script 脚本引入)对于执行这一行是必需的 element.innerHTML = _.join(['Hello', 'webpack'], ' '); return element; } document.body.appendChild(component()); |
index.html
1 2 3 4 5 6 7 8 9 10 |
<!doctype html> <html> <head> <title>Getting Started</title> <script src="https://unpkg.com/lodash@4.16.6"></script> </head> <body> <script src="./src/index.js"></script> </body> </html> |
这里的Lodash是一个JavaScript库,这里引用的意味就是给大家展示一下我们平时使用第三方JavaScript库的做法,这样的做法会产生很多问题,因为通过index.html的联系,很明显,index.js对第三方库lodash产生了隐形依赖,之所以说是隐形依赖,是因为在lodash被引用之前,index.js中的双下划线变量(lodash提供的一个变量)还是未知的,只有在lodash被引用之后,这个变量才能发挥作用,显而易见,这样做的很危险的,这样会产生很多问题:
1.无法立即体现,脚本的执行依赖于外部扩展库(external library)。
2.如果依赖不存在,或者引入顺序错误,应用程序将无法正常运行。
3.如果依赖被引入但是并没有使用,浏览器将被迫下载无用代码。
Webpack的价值就这样体现出来了,当你的项目中引用的JavaScript文件,html页面越来越多,就会出现一些不可避免的依赖问题,而我们通过Webpack可以解决这一问题,对于一个html页面,我们可以该页面依赖的所有JavaScript文件打包在一起,构成一个JavaScript文件,这样,html页面只需要引用这一个JavaScript文件即可,上面说的问题,就可以完全被避免。当然自己打包也是可以的,不过通过Webpack这一神器,就没那么麻烦了,你只要告诉它,你需要把哪些文件打包,输出到哪里,它就可以自动分析所有JavaScript的依赖关系,然后帮你打包成一个文件。
接下来,我们就来打包一次试试。
使用Webpack打包
在打包之前,我们还需要做一点小小的调整—-将开发环境和生产环境分开:
1 2 3 4 5 6 7 |
webpack-learning |- package.json + |- /dist + |- index.html - |- index.html |- /src |- index.js |
这样一来,src文件夹里面,放的就是我们开发的环境,所有的代码编写都在这里进行,而相对稳定的html文件就直接放入dist文件夹中,作为生产环境的文件,这样有一个好处,每一次更新src之后,只需要把src中的东西重新打包,然后供生产环境中的html文件使用,就行了,而html文件本身,几乎不用被更改。
因为我们用到了lodash包,所以需要在npm中安装lodash依赖:
1 |
npm install --save lodash |
细心的朋友可能注意到,这里使用的是–save而不是–save-dev,两者的区别是,–save是生产环境的依赖,也就是供给用户使用的依赖,而–save-dev是开发环境的依赖,比如Webpack,在代码完成并且打包之后,就不需要再使用到它了,显然用户是无需接触到Webpack的,所以这里Webpack属于开发环境的依赖。
添加lodash依赖之后,我们就可以在js文件中导入并且使用了:
src/index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 |
+ import _ from 'lodash'; + function component() { var element = document.createElement('div'); - // Lodash, currently included via a script, is required for this line to work + // Lodash, now imported by this script element.innerHTML = _.join(['Hello', 'webpack'], ' '); return element; } document.body.appendChild(component()); |
因为接下来我们要使用Webpack打包所有的js,这样的话,我们就不需要再自己在html引入JavaScript库了,而只需要引入打包之后的文件就行了,我们先约定以后打包的文件名叫做bundle.js,那么接下来,修改html文件:
dist/index.html
1 2 3 4 5 6 7 8 9 10 11 |
<!doctype html> <html> <head> <title>Getting Started</title> - <script src="https://unpkg.com/lodash@4.16.6"></script> </head> <body> - <script src="./src/index.js"></script> + <script src="bundle.js"></script> </body> </html> |
这样的话,我们就可以开始打包了。
在命令行输入
1 |
webpack-cli src/index.js --output dist/bundle.js |
如果不行的话,尝试
1 2 3 4 |
// linux node_modules/.bin/webpack-cli src/index.js --output dist/bundle.js // windows node_modules\.bin\webpack-cli src/index.js --output dist/bundle.js |
这一行的意思是执行Webpack命令行程序,将src/index.js作为入口文件,自动分析index.js的依赖,并且将所有依赖和index.js本身一起打包成一个文件,输出到dist/bundle.js,执行这一行,可以看到Webpack打包成功的输出信息:
1 2 3 4 5 6 7 8 9 10 11 |
Hash: 61bf2519e9ef5fa0eb5e Version: webpack 4.1.0 Time: 4080ms Built at: 2018-3-7 16:58:36 Asset Size Chunks Chunk Names bundle.js 69.6 KiB 0 [emitted] main Entrypoint main = bundle.js [1] (webpack)/buildin/module.js 519 bytes {0} [built] [2] (webpack)/buildin/global.js 509 bytes {0} [built] [3] ./src/index.js 231 bytes {0} [built] + 1 hidden module |
打包成功并且输出之后,你就可以打开html文件看看结果了:
可见打包之后的JavaScript能够成功运行,并且解决了之前说的几个问题,这就是Webpack的主要功能。
但是你可能会问,每次都要自己输入巴拉巴拉一大串命令,那也太麻烦了吧,Webpack显然想到了这一点,它是支持配置文件的,你只需要在项目根目录下新建一个配置文件webpack.config.js,并且按照Webpack中文文档给出的语法进行编写就行了。下面给出一个配置文件的例子:
webpack.config.js
1 2 3 4 5 6 7 8 9 |
const path = require('path'); module.exports = { entry: './src/index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') } }; |
完成配置文件之后,你需要打包时,就不需要再自己输入入口和输出了,直接这样就行了
1 2 3 4 5 6 |
webpack-cli // 如果不行尝试 // linux node_modules/.bin/webpack-cli // windows node_modules\.bin\webpack-cli |
NPM脚本
有了配置文件你可以还不满足,我既然有npm,为什么不能直接让npm帮我运行呢,答案是可以的,npm支持用户自定义脚本,用户可以在npm的配置文件中添加自己的脚本内容,然后使用下面给出的指令来运行用户的脚本
1 |
npm run 脚本名 |
这样的话,我们不是可以自己定义一个build脚本,让它完成Webpack打包的任务呢。
package.json
1 2 3 4 5 6 7 |
{ ... "scripts": { "build": "webpack-cli" }, ... } |
这样一来,只要
1 |
npm run build |
世界我有,打包全自动!