webpack3.0小案例系列,抛砖引玉,但愿你们多提意见,一块儿学习:css
前两节文章咱们手把手搭建了一个基于webpack的前端开发工程环境,并讲解了一些经常使用插件及loader的基本用法,包括代码分割、模板读取、文件清理、ES6编译及css处理等等,这篇文章我继续在前两篇的基础上,继续探讨:node
webpack对图片的处理经常使用的有url-loader、file-loader、image-webpack-loader,各个加载器都在打包过程当中有着本身的功能职责,在探讨他们的使用方法以前,老规矩,咱们先弄明白他们各自都作了什么。jquery
一、首先,咱们在src目录下新建assets文件夹用来放置全部的静态资源,在该目录下咱们放入两张图片bg_webpack-sm.jpg 和 bg_webpack-lg.jpg,大小分别是6kb和12kb(之因此放两张不一样大小的图片是用于体验url-loader的limit参数的做用)。webpack
二、打开style.less文件,新增一个container的css类,并在index.html中添加一个类名为container的divweb
.container{
width:300px;
height: 100px;
background: url('../assets/bg_webpack-lg.jpg')
}
复制代码
<body>
<div id="app"></div>
<div class="container"></div>
</body>
复制代码
三、 命令行定位到根目录下,安装file-loader,并在webpack配置文件中新增一条处理规则:express
cnpm install file-loader --save-dev
复制代码
...
module: {
rules: [
...
{
test: /\.(png|jpg|gif|svg)$/,
exclude: /node_modules/,
use: [{
loader: 'file-loader',
options: {}
}]
}
]
}
...
复制代码
再次执行webpack命令进行编译,咱们发下在dist目录下已经打包出了咱们引用的图片资源npm
如今,图片文件已经打包成功了,可是咱们发现两个问题:json
别着急,为了解决这两个问题,咱们须要先对file-loader的部分配置项参数做用有一个大体的了解:
name ,指定打包生成后资源文件的name值,file-loader给咱们指定了一些占位符来自定义name,咱们能够本身任意搭配占位符来获得咱们想要生成的文件名称的格式,默认状况下是:[hash].[ext]
名称 | 描述 |
---|---|
[ext] | 文件的后缀名,默认是原始资源的后缀名 |
[name] | 文件名称,也就是原始资源的名称 |
[path] | 文件存放的路径 |
[hash] | hash值,默认是md5 |
[N] | 数字 |
publicPath ,用来指定打包生成后的css或者url引用中路径的配置,也就是说pulicPath针对的是路径,并非文件自己。
outputPath,用来配置打包生成的文件输出的位置,它针对的是文件存储的位置,和代码中的路径引用无关。
useRelativePath, 配置打包生成后的路径是否为相对位置,默认状况下是false。须要注意的是,开启useRelativePath后,outputPath的设置会以src目录中的assets文件夹为准,设置其余的名称不会生效。
emitFile ,配置对打包的资源文件是否须要进行发布,默认为true。
从这些配置项中,咱们大体能够找到以上两个问题的缘由:
所以针对这两个问题,咱们对配置文件进行配置:
...
module: {
rules: [
...
{
test: /\.(png|jpg|gif|svg)$/,
exclude: /node_modules/,
use: [{
loader: 'file-loader',
options: {
name: '[hash].[ext]',
outputPath: '/assets/',//定义图片输出存放的文件夹位置
useRelativePath: true,//设置路径为相对位置
}
}]
}
]
}
...
复制代码
在配置项中,咱们定义了文件输出的名称以hash值来命名,并指定文件输出到dist下的assets文件夹下,而后开启路径为相对路径,再次执行webpack编译,发现文件已经按照设定生成到assets目录下了。
打开dist下的index.html,图片成功加载
固然,在设置file-loader的option的时候,因为paublicPath会去读取webpack出口中的publicPath的值,所以他们之间是有这联系的,出口中设定的publicPath不同就会致使file-loader中设定的要跟着改变,这一点要把握好。
前面咱们说过,url-loader是对file-loader的封装,所以,使用url-loader和file-loader方法基本同样,在这里,咱们就探讨一下他们不一样的地方,也就是limit参数。
一、首先,咱们安装好url-loader,并将以前的file-loader替换成url-loader,并在index.html页面中新增类名为container-sm的div元素。
cnpm install url-loader --save-dev
复制代码
// webpack.config.js
...
module: {
rules: [
...
{
test: /\.(png|jpg|gif|svg)$/i,
exclude: /node_modules/,
use: [{
loader: 'url-loader',
options: {
limit: 10240,
outputPath: 'assets/',
useRelativePath: true
}
}]
}
]
}
...
复制代码
配置项中,咱们指定图片大于10kb的图片进行文件加载,小于10kb的文件则直接转换出base64编码直接写入到css中,这样咱们刚刚放入的两张图片结果应该是大的一张以图片资源的方式加载,而小的一张则直接被编码成base64后写入到css文件中。最后效果以下:
能够发现结果和咱们预计的同样,表示url-loader已经生效。url-loader对咱们处理小型图片颇有帮助,他能够有效减少访问服务端的次数,减少访问时间,特别是针对一些icon图标的时候颇有效果。
使用url-loader的时候,咱们须要对limit大小界限值进行权衡;base64编码能够减小浏览器的访问次数,可是它的不足是编码特别长,这样很容易致使代码体积变大。而经过路径的方式能够减小代码的体积量,而且浏览器在屡次访问的时候也会对文件进行缓存处理,但毕竟会增长对服务器资源的访问次数。所以,如何设置limit的大小,须要根据项目的状况来定
因为url-loader在对文件处理的时候会增大文件的体积,好比对文件进行base64编码,就会使文件的体积比原版体积更大,所以,image-webpack-loader就应运而生,它的做用就是在进行url-loader处理以前,首先对静态资源进行压缩处理,处理事后的图片资源再决定是否用base64编码。
一、首先咱们对image-webpack-loader进行安装,而后再webpack配置中进行对配置的修改:
cnpm install image-webpack-loader --save-dev
复制代码
// webpack.config.js
...
module: {
rules: [
...
{
test: /\.(png|jpg|gif|svg)$/i,
exclude: /node_modules/,
use: [{
loader: 'url-loader',
options: {
limit: 10240,
outputPath: 'assets/',
useRelativePath: true
}
}, {
loader: 'image-webpack-loader',//新增image-webpack-loader
options: {
mozjpeg: {//设置对jpg格式的图片压缩的程度设置
progressive: true,
quality: 65
},
}
}]
}
]
}
...
复制代码
在配置项中,咱们对图片进行压缩处理,并设置对jpg类型的图片压缩到65%质量值,最后运行webpack命令,发现两张图片都被压缩成4.75kb大小的图片,在css中,两张图片都已经以base64编码的方式呈现了。
image-webpack-loader对不一样类型的图片都对应有不一样的处理配置设定,针对不一样的图片开发者能够自定义压缩比例。
到目前为止,咱们的小案例已经把经常使用的基本的loader梳理了一遍,可是咱们又发现了一些问题,好比每次更改代码后都须要进行webpack从新编译,而且,咱们的文件仍是以文件系统的方式在浏览器中打开的,这个彷佛不是webpack给咱们提供的编码姿式,所以,接下来,咱们将考虑如何让咱们的项目在服务器上跑起来等一系列问题。
既然咱们指定了webpack最终打包后的文件在dist目录下,那么如今咱们只要将dist内的文件在服务器端跑起来不就能够了吗,这彷佛可行的,那么我就先来尝试一下
一、在根目录下,新建一个server.js的文件,并安装express
cnpm install express --save-dev
复制代码
二、在server.js内,咱们利用express来写一个简单的服务器:
//server.js
var path = require('path');
var express = require('express');
var app = express();
var port = process.env.port || 3000;
app.use(express.static(path.join(__dirname, 'dist')));//设置可访问的静态资源目录
app.get('/', function(req, res, next) {
req.url = 'index.html';
next()
})
app.listen(port, function() {
console.log(`server is running at ${port}`)
});
复制代码
三、打开package.json,在script配置项下新增以下命令:
//package.json
...
"scripts": {
"server": "node server.js",//设置用node运行server.js
"build": "webpack"//设置webpack编译命令
}
...
复制代码
这样咱们就能够在控制台经过cnpm来运行项目了:
cnpm run build /*执行webpack打包命令*/
cnpm run server /*让编译后的文件经过服务器加载*/
复制代码
执行完以上命令后,在浏览器中输入:localhost:3000,便可访问最终打包的文件了,可是,咱们要的热更新依然没有,并且仍是须要每次都打包,除了用服务器跑起来彷佛并无解决咱们的问题(黑人郁闷脸)。
其实解决在开发中的这个实时编译问题,webpack早已为咱们提供了简便的方法。
webpack-dev-server是一个小型的nodejs express服务器,支持两种模式来自动刷新页面,而且都提供热更新,咱们的实践是以inline模式为例的
热更新的好处是只替换更新的部分,而不须要去页面重载。
一、安装webpack-dev-server
cnpm install webpack-dev-server --save-dev
复制代码
二、安装完成后,咱们打开package.json文件,在script配置项下新增:
//package.json
...
"scripts": {
"server": "node server.js",//设置用node运行server.js
"build": "webpack",//设置webpack编译命令
"dev": "webpack-dev-server"
}
...
复制代码
这样,咱们只要在命令行输入 “cnpm run dev ”既能够把项目运行起来。
三、 用webpack-dev-server运行的时候,默认端口是8080,所以,咱们在运行webpack-dev-server后,在浏览器执行 localhost:8080,便可访问项目,这个时候由于项目是处于开发环境,文件只是存储在内存中而并无真正打包出来,所以,项目中并不会生成dist文件夹,也正因如此,咱们动态改变代码的时候,webpack就会自动更新到界面上去。
webpack在配置项中也为咱们提供了配置webpack-dev-server的节点,也就是devServer配置项,在这个配置项中,咱们能够更改启动的端口号,加载模式(iframe或者inline)等等,但须要注意的是webpack3.0已经默认热更新,若是在devServer中再次设定hot属性的时候,热更新反而会失效
...
entry: path.resolve(__dirname, './src/main.js'),
output: {
path: path.resolve(__dirname, './dist'),
filename: 'js/[name]-[chunkhash].js'
},
devServer: {
// hot: true, 不要设置hot热更新属性,设定后反而会失效
port: 3000,
inline: true
},
...
复制代码
webpack优化是一个颇有技术性的话题,展开来讲的话估计又是一个比较长的话题,咱们这一节里先针对咱们目前的项目结构罗列几项,抛砖引玉。
UglifyJsPlugin是webpack默认提供的代码压缩优化器,当在配置项中使用了这个插件以后,打包后的js文件会进行代码压缩和注释删除等压缩手段,这个在项目build的时候,会减少打包后项目的体积。
...
plugins: [
//启用js压缩
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false,
drop_console: false,
}
}),
new htmlWebpackPlugin({
template: 'index.html',
filename: 'index.html'
}),
new cleanWebpackPlugin(
['dist'], {
verbose: false,
dry: false,
root: __dirname
}
)
]
...
复制代码
webpack的loader加载器设置中,每个loader都容许对处理文件进行指定,包括哪个或者不包括哪个文件夹内的文件,这样会很大程度上减少扫描的范围,减少打包时间。实际上,在咱们的项目中咱们已经设定了exclude参数,以排除loader对node_modules中文件的扫描。
{
test: /\.js$/,
use: [{ loader: "babel-loader" }],
exclude: /node_modules/,
include: /src/
}
复制代码
webpack默认提供的CommonsChunkPlugin插件能够将代码中公用的模块提取出来,好比经常使用的相似jquery、moment这样的额第三方插件,若是在每一个引用的js打包文件中都进行打包,最终的项目体积就会成倍增长,经过使用CommonsChunkPlugin能够将这些公用部分提取,有效减少项目体积。
babel编译是一个比较费时间的过程,对babel处理的设置,咱们不只要设置include && exclude来尽量准肯定位编译的文件,还能够充分利用缓存来进一步提高速度,设置babel的cacheDirectory为true,是一个很好的优化方式。
{
test: /\.js$/,
use: [{ loader: "babel-loader" ,cacheDirectory: true}],
exclude: /node_modules/,
include: /src/
}
复制代码
这一节咱们从webpack对静态资源相关的处理以及服务器加载和webpack打包优化等作了总结,其实好多依然讲的不全,不少地方也没有作详细的解释,但千里之行始于足下,一步一步来,我相信你终究会获得你想要的。
仍是不忘说一句,愿各位早日成为一名合格的前端高手,加油!