题记
本年度的前端研究方向之一是webpack
,之前就去看过一个webpack
的学习视频,自己按照课程写了一些配置文件,对webpack
的基本配置和使用有了一定的了解。后面参与开发智能客服和企业网关项目,使用了webpack+react+redux
,开发过程读了很多次webpack
的配置文件,并且进行了相应的修改,在实战中加强了对webpack
的理解。想要整理一下相关的知识和经验,又回看了一遍之前的学习视频,有了很多新的领悟。这里要提醒自己,学习视频回看是很有必要的。
整体把控
首先我们要理解webpack
是什么,一句话来解释就是一个模块打包器,一张图来解释就更为直观,下面是webpack
官网的图示。
从图上可以看出,webpack
可以把包含错综复杂依赖关系的模块化文件进行打包,生成若干静态文件。并且有处理多种类型文件的能力。
快速掌握
快速掌握webpack
的使用,只需要了解四个核心概念。
-
entry
指定程序入口文件,比如index.js
文件。webpack
会从这里开始解析各个文件之间的依赖关系并且进行处理。
module.exports = {
entry: './path/to/my/entry/index.js'
}; -
output
指定打包好的文件的信息,路径和文件名都可以在这里指定。
const path = require('path');module.exports = { entry: './path/to/my/entry/index.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'my-first-webpack.bundle.js' } };
-
loaders
对各种文件类型进行转换,让只能处理JavaScript
的webpack
可以处理多类型的文件。需要安装指定的loader
。写这篇博客的时候时候webpack
已经有了2.0版本,对于loaders
的配置与1.0版本有一些不同,这里使用最新的写法进行举例。
const path = require('path');const config = { entry: './path/to/my/entry/index.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'my-first-webpack.bundle.js' }, module: { rules: [ { test: /\.css$/, use: 'css-loader' } ] } }; module.exports = config;
在项目实战中,我们一般需要处理的文件有js,jsx,css,scss,less,png,jpg,gif
还有一些没有列出来的音频视频文件等等,它们都有对应的loaders
来处理。可以在使用的时候查看一下文档。
-
plugins
非常强大并且可定制。它的作用是什么呢,可以这样的简单理解一下,loaders
是对没有打包前的文件做一些预处理的工作,plugins
可以对编译和打包生成的块文件(当然,不仅仅局限于此)做一些操作或者实现一些自定义的功能。
const HtmlWebpackPlugin = require('html-webpack-plugin'); //installed via npm
const webpack = require('webpack'); //to access built-in plugins
const path = require('path');
const config = {
entry: './path/to/my/entry/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js'
},
module: {
rules: [
{ test: /\.css$/, use: 'css-loader' }
]
},
plugins: [
new webpack.optimize.UglifyJsPlugin(),
new HtmlWebpackPlugin({template: './src/index.html'})
]
};
module.exports = config;
在项目实战中plugins
是非常重要的一个环节,尤其是当你遇到一些问题,你会发现有很多问题都可以引入对应的插件来解决,后文也会有所介绍。上面例子中的两个plugins
的功能分别是压缩打包文件和按照模板文件自动生成注入文件引用的index.html
文件。
项目实战
- 配置文件目录
在看过学习视频,看过官方文档,还有自己写了一些小例子之后,以为实战开发会看到自己很熟悉的代码,没想到第一次看代码的时候打开根路径下的webpack.config.js
文件,并没有看到自己熟悉的代码。因为在项目实战的时候会考虑到各种环境的配置文件,基于模块划分的思想,一般会有一个cfg
文件夹,下面有基础配置文件,开发环境配置文件,线上环境配置文件,然后在webpack.config.js
中根据不同的环境选择不同的配置文件。
- 关于图片的打包
图片文件有两个值得注意的问题。
第一个问题是,如果我们选用url-loader
来处理图片文件的话,可以在后面跟一个limit
参数,例如limit=8192
,它的意思是,如果图片的大小小于limit
,那么会在图片出现的位置用base64
码的方式进行引用,省掉了http
请求。如果不想用base64
的方式引用,可以使用file-loader
来进行处理。具体的选择需要结合项目中图片的具体情况。如果图片经常重复出现,那可能选用浏览器能够缓存的方式(也就是传统引用方式)会更加利于性能优化。
第二个问题是,在项目中的js
模板代码中如果引入了图片文件,打包时我们会发现图片并没有成功引入。这时的处理方法是在js
代码中用require
的方式将图片引入,这样webpack
在处理的时候会将图片作为一个模块,打包进依赖树。
- 关于打包文件版本号的添加
部署环境的时候,为了代码能够时时的更新,我们需要在静态资源文件上加上版本号。webpack
可以很简单的做好这个工作,只需要我们在线上环境的配置文件中将output
配置修改一下即可。
output: {
path: path.join(__dirname, '/../dist'),
filename: '/assets/[name]-[Hash].js'
}
这样子生成的js
文件会带上五位的hash
值,在代码变动之后hash
值也会发生相应的变化,从而保证浏览器不会使用缓存过的静态资源文件,而是请求最新的静态资源文件。
生成了带版本号的静态资源文件之后,接下来要解决的问题是在index.html
中进行引用,总不能每次手动去根据最新的文件名来修改该文件。这时候,有强大的plugins
系统来解决我们的问题。
const HtmlWebpackPlugin = require('html-webpack-plugin'); //installed via npm
const webpack = require('webpack'); //to access built-in plugins
const path = require('path');
const config = {
entry: './path/to/my/entry/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename:'/assets/[name]-[Hash].js'
},
module: {
rules: [
{ test: /\.css$/, use: 'css-loader' }
]
},
plugins: [
new HtmlWebpackPlugin({
template:'src/index.html',
filename:'index.html',
inject:'body'
})
]
};
module.exports = config;
如上图示例,我们可以使用html-webpack-plugin
来解决这个问题,这个插件可以设置模板文件的名称,生成文件的名称,并且指定静态文件引入的位置(例子中为body
中引用)。这样子可以在打包之后获得一个引入了最新静态资源文件的index.html
文件。解决了手动修改的问题。
但是,问题并没有到这里就结束。如果我们选用了src
文件下的index.html
文件作为模板文件,我们会发现打包生成的index.html
文件中不仅仅引入了带hash
值的js
文件,还有<script type="text/javascript" src="/assets/app.js"></script>
这样的一行代码。原因也很简单,因为src
文件下的index.html
引入了js
文件。解决方法非常简单,新建一个干净的没有引入js
文件的模板文件即可解决。但是我们需要搞清楚的是,为什么src
文件下的index.html
文件一定要引入这样的js
文件呢,为什么不能用同样的方式,动态去插入引用的代码呢。这个问题困扰了我很久,最后我找到了原因。这是因为在项目中开发环境我们使用了webpack-dev-server
来起项目,其实它就是一个小型的轻量的Node.js Express
服务器。它需要默认入口路径中有一个index.html
文件,并且引入打包生成的静态资源文件(这个文件并没有真正的放在你的真实目录中,而是放在了内存中)。如果你的项目中没有使用webpack-dev-server
,而是自己配置了一个Express
,就可以避免这个问题,只用一个干净的模版index.html
文件就可以生成开发环境和线上环境需要的index.html
文件了。
网友评论