webpack系列文章:
- 【Webpack 性能优化系列(9) - 多进程打包】极大的提升项目打包构建速度!!!
- 【Webpack 性能优化系列(8) - PWA】使用渐进式网络应用程序为我们的项目添加离线体验
- 【Webpack 性能优化系列(7) - 懒加载和预加载】
- 【Webpack 性能优化系列(6) - code splitting 】通过代码分割来获取更小的 bundle,优化资源加载
- 【Webpack 性能优化系列(5) - tree shaking 】去除未引用代码,减少代码体积!!!
- 【Webpack 性能优化系列(4) - 缓存 】详解如何做bable缓存和文件资源缓存
- 【Webpack 性能优化系列(3) - oneOf】
- 【Webpack 性能优化系列(2) - source-map】
- 【Webpack 性能优化系列(1) - HMR 热模块替换】
- 【Webpack 生产环境配置】近两万字长文总结学习如何提取css为单独文件、css的压缩和兼容性处理,如何压缩html和js、如何做js语法检查eslint和js兼容性处理babel!!!
- 【Webpack 简介及五个核心概念】
文章目录
webpack.config.js
webpack 开箱即用,可以无需使用任何配置文件。然而,webpack 会假定项目的入口起点为 src/index.js
,然后会在 dist/main.js
输出结果,并且在生产环境开启压缩和优化。
通常你的项目还需要继续扩展此能力,为此你可以在项目根目录下创建一个 webpack.config.js
文件,然后 webpack 会自动使用它。
webpack.config.js
是webpack的配置文件。 作用是:指示 webpack 干哪些活(当你运行 webpack 指令时,会加载里面的配置)
所有构建工具都是基于nodejs平台运行的~模块化默认采用commonjs。
下面开始介绍webpack的这个配置文件
创建配置文件
1. 创建文件 webpack.config.js
2. 配置内容如下
const { resolve } = require('path'); // node 内置核心模块,用来处理路径问题。
module.exports = {
entry: './src/js/index.js', // 入口文件
output: { // 输出配置
filename: './built.js', // 输出文件名
path: resolve(__dirname, 'build/js') // 输出文件路径配置
},
mode: 'development' //开发环境
};
如何打包样式资源以及loader执行顺序是什么
打包 CSS 资源
1. 下载安装 loader 包
npm i css-loader style-loader less-loader less -D
2. 修改配置文件
/*
webpack.config.js webpack的配置文件
作用: 指示 webpack 干哪些活(当你运行 webpack 指令时,会加载里面的配置)
所有构建工具都是基于nodejs平台运行的~模块化默认采用commonjs。
*/
// resolve用来拼接绝对路径的方法
const { resolve } = require('path');
module.exports = {
// webpack配置
// 入口起点
entry: './src/index.js',
// 输出
output: {
// 输出文件名
filename: 'built.js',
// 输出路径
// __dirname nodejs的变量,代表当前文件的目录绝对路径
path: resolve(__dirname, 'build')
},
// loader的配置
module: {
rules: [
// 详细loader配置
// 不同文件必须配置不同loader处理
{
// 匹配哪些文件
test: /\.css$/,
// 使用哪些loader进行处理
use: [
// use数组中loader执行顺序:从右到左,从下到上 依次执行
// 创建style标签,将js中的样式资源插入进行,添加到head中生效
'style-loader',
// 将css文件变成commonjs模块加载js中,里面内容是样式字符串
'css-loader'
]
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
// 将less文件编译成css文件
// 需要下载 less-loader和less
'less-loader'
]
}
]
},
// plugins的配置
plugins: [
// 详细plugins的配置
],
// 模式
mode: 'development', // 开发模式
// mode: 'production'
}
模块loader可以链式调用。链中的每个loader都将对资源进行转换。链会逆序执行。第一个loader将其结果(被转换后的资源)传递给下一个loader,依此类推。最后,webpack期望链中的最后的loader 返回 JavaScript。
应保证 loader 的先后顺序:‘style-loader’ 在前,而 ‘css-loader’ 在后。如果不遵守此约定,webpack 可能会抛出错误。
不同文件必须配置不同loader处理
css文件要用style-loader
和css-loader
less文件要用less-loader
,style-loader
和css-loader
具体这三个loder的作用见上面代码注释。
loader执行顺序(非常重要,切记!!!):
use数组中loader执行顺序:从右到左,从下到上 依次执行
其实所谓的从下到上就是把数组里的每个元素换行展示了,本质还是数组从右至左。
如何打包html资源
打包html资源需要用到html-webpack-plugin
这个插件,下载安装 plugin 包
npm install --save-dev html-webpack-plugin
实例文件目录:
和loader
使用的一个区别是,插件plugin
下载后需要引入后才能使用:
// 引入
const HtmlWebpackPlugin = require('html-webpack-plugin');
默认配置:
/*
loader: 1. 下载 2. 使用(配置loader)
plugins: 1. 下载 2. 引入 3. 使用
*/
const { resolve } = require('path');
// 引入
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
// loader的配置
]
},
plugins: [
// plugins的配置
// html-webpack-plugin
// 功能:默认会创建一个空的HTML,自动引入打包输出的所有资源(JS/CSS)
new HtmlWebpackPlugin()
],
mode: 'development'
};
html-webpack-plugin
插件的功能:默认会创建一个空的HTML,自动引入打包输出的所有资源(JS/CSS)
实际开发中我们的需求:需要有结构的HTML文件
我们可以通过对HtmlWebpackPlugin
添加配置选项template
,添加目标html文件的路径即可,具体配置如下:
/*
loader: 1. 下载 2. 使用(配置loader)
plugins: 1. 下载 2. 引入 3. 使用
*/
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
// loader的配置
]
},
plugins: [
// plugins的配置
// html-webpack-plugin
// 功能:默认会创建一个空的HTML,自动引入打包输出的所有资源(JS/CSS)
// 需求:需要有结构的HTML文件
new HtmlWebpackPlugin({
// 复制 './src/index.html' 文件,并自动引入打包输出的所有资源(JS/CSS)
template: './src/index.html'
})
],
mode: 'development'
};
目标html文件:
打包出来的文件:
对html-webpack-plugin
插件设置template
配置属性的功能:复制 ‘./src/index.html’ 文件,并自动引入打包输出的所有资源(JS/CSS)
如何打包图片资源
为什么需要对webpack做打包图片的配置?我们先看一个在样式中引入图片(background-image
)的实例:
实例目录结构如下:
index.html
:
index.js
:
index.less
:
如果我们不对图片资源做配置的话,基础的webpack.config.js
配置如下:
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.less$/,
// 要使用多个loader处理用use
use: ['style-loader', 'css-loader', 'less-loader']
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'development'
};
对项目进行打包后,我们发现图片资源处理不了,在打包图片的时候是报错的:
所以我们需要对图片进行单独的处理
我们使用url-loader
来处理图片资源,这里需要下载url-loader
和file-loade
两个loader:
npm i url-loader file-loade -D
url-loader
有相应的优化配置属性limit
,写在options
里,
limit
属性的作用:图片大小小于指定数值时,就会被base64处理
- 优点:减少请求数量(减轻服务器压力)
- 缺点:图片体积会更大(文件请求速度更慢)
配置如下:
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.less$/,
// 要使用多个loader处理用use
use: ['style-loader', 'css-loader', 'less-loader']
},
{
// 问题:默认处理不了html中img图片
// 处理图片资源
test: /\.(jpg|png|gif)$/,
// 使用一个loader
// 下载 url-loader file-loader
loader: 'url-loader',
options: {
// 图片大小小于8kb,就会被base64处理
// 优点: 减少请求数量(减轻服务器压力)
// 缺点:图片体积会更大(文件请求速度更慢)
limit: 8 * 1024
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'development'
};
配置完成后再次打包运行:
图片资源没有报错。
这里我们备注一下上面代码里我们用到的三张图片资源:
angular.jpg,12kb大小:
react.png,74kb大小:
vue.jpg,4kb大小:
再来看一下输出的资源:
我们发现打包后的资源输出了两张图片,一张74kb,一张12kb,但我们实际上引入了三张图片,还有以这样图片去哪里呢?
我们看build:
我们发现vue.jpg
经过了base64
处理,变成了一个非常长的编码字符串,变成了字符串的形式,而不会输出成一张图片,所以我们输出的结果就少了一张图片。这正是前面url-loader
做优化配置属性limit
后的效果。
我们打开build文件下的index.html文件验证一下效果:
三张图片正常显示
我们检查一下html结构,可以发现box1盒子背景图片(vue.jpg)的url
是一个base64的地址:
到这里我们处理了样式里的图片资源,只是这样还不够,因为除了在样式中引入图片以外,我们还可能在html中通过<img>
标签的方式引入图片:<img src="./angular.jpg" alt="angular">
在html中通过<img>
标签的方式引入图片后,在原有的配置中我们再打包一次,发现没有报错,输出的结果和之前一样,打开build下的index.html:
img的路径还是src="./angular.jpg"
,./
是相对路径,但是相对路径下没有angular.jpg
这张图片:
我们打开build下的index.html,发现<img src="./angular.jpg" alt="angular">
这张图片是找不到的:
这是因为上面url-loader
的配置有一个问题:默认处理不了html中img图片
这里我们还要再加一个loader:html-loader
,作用是:处理html文件的img图片(负责引入img,从而能被url-loader进行处理)
下载html-loader
:
npm i html-loader -D
配置:
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.less$/,
// 要使用多个loader处理用use
use: ['style-loader', 'css-loader', 'less-loader']
},
{
// 问题:默认处理不了html中img图片
// 处理图片资源
test: /\.(jpg|png|gif)$/,
// 使用一个loader
// 下载 url-loader file-loader
loader: 'url-loader',
options: {
// 图片大小小于8kb,就会被base64处理
// 优点: 减少请求数量(减轻服务器压力)
// 缺点:图片体积会更大(文件请求速度更慢)
limit: 8 * 1024
}
},
{
test: /\.html$/,
// 处理html文件的img图片(负责引入img,从而能被url-loader进行处理)
loader: 'html-loader'
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'development'
};
上面的配置打包后发现还是没有报错,但是build下的index.html文件里img
的src变成了[object Module]
这是为什么呢?
这是 因为url-loader默认使用es6模块化解析,而html-loader引入图片是common.js,url-loader
以es6模块去解析common.js模块,解析不了。
解决方法:关闭url-loader的es6模块化,使用commonjs解析
{
// 问题:默认处理不了html中img图片
// 处理图片资源
test: /\.(jpg|png|gif)$/,
// 使用一个loader
// 下载 url-loader file-loader
loader: 'url-loader',
options: {
// 图片大小小于8kb,就会被base64处理
// 优点: 减少请求数量(减轻服务器压力)
// 缺点:图片体积会更大(文件请求速度更慢)
limit: 8 * 1024,
// 问题:因为url-loader默认使用es6模块化解析,而html-loader引入图片是commonjs
// 解析时会出问题:[object Module]
// 解决:关闭url-loader的es6模块化,使用commonjs解析
esModule: false
}
},
关闭url-loader的es6模块化,再次打包,没有报错
查看build下的index.html文件
img
的src变成[object Module]
的问题已经解决,变成了完整的绝对路径,上面的长字符串是根据图片内容生成的唯一hash值。
打开build下的index.html文件,html里的图片显示正常:
我们发现打包后图片的名字有点长,这是根据图片内容生成的唯一hash值:
不想让图片名字这么长可以通过url-loader
里的name
属性来给图片进行重命名:name: '[hash:10].[ext]'
- [hash:10]取图片的hash的前10位
- [ext]取文件原来扩展名
对图片资源最终的配置如下:
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.less$/,
// 要使用多个loader处理用use
use: ['style-loader', 'css-loader', 'less-loader']
},
{
// 问题:默认处理不了html中img图片
// 处理图片资源
test: /\.(jpg|png|gif)$/,
// 使用一个loader
// 下载 url-loader file-loader
loader: 'url-loader',
options: {
// 图片大小小于8kb,就会被base64处理
// 优点: 减少请求数量(减轻服务器压力)
// 缺点:图片体积会更大(文件请求速度更慢)
limit: 8 * 1024,
// 问题:因为url-loader默认使用es6模块化解析,而html-loader引入图片是commonjs
// 解析时会出问题:[object Module]
// 解决:关闭url-loader的es6模块化,使用commonjs解析
esModule: false,
// 给图片进行重命名
// [hash:10]取图片的hash的前10位
// [ext]取文件原来扩展名
name: '[hash:10].[ext]'
}
},
{
test: /\.html$/,
// 处理html文件的img图片(负责引入img,从而能被url-loader进行处理)
loader: 'html-loader'
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'development'
};
打包后的图片名称已经变成取图片的hash的前10位
另外我们还可以发现webpack打包的一个优势:
上面的例子中html里引用了一次angular.jpg
,在样式文件里也引用了一次angular.jpg
,但打包之后其实只生成了一张angular.jpg
的图片文件
所以在这里就是当webpack在解析的时候发现我们使用了同一个文件,它不会重复打包,它只会输出一次,这也是webpack的一个优势,它不会重复打包某一个文件。
如何打包其他资源
什么是其他资源呢?比如说字体图标icon
字体图标的特点就是我们不需要做任何处理,只需要原封不动的输出出去就ok了,这就是其他资源,不需要做优化,也不需要做压缩啊等等,这类资源统一归类于其他资源。
我们先下载一个字体图标,这里使用iconfont图标,随便选择一个,直接点击下载代码
下载完之后解压一下,这里包含了字体图标的所有配置
我们这里使用font-class 引用
我们新建文件夹,src/index.html,使用字体图标看一看效果
再写一个入口js文件,index.js,作用就是负责引入字体图标样式文件
iconfont.css
文件里又引用了.eot
、.woff
、ttf
和.svg
资源,我们也需要放入项目中,具体看前面的实例项目文件目录
打包其他资源我们可以使用exclude
排除已经处理过或者不需要处理的资源,然后使用file-loader
对其他资源进行处理,一个小的优化就是可以对打包后的文件名称做一个缩短优化
具体配置:
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
// 打包其他资源(除了html/js/css资源以外的资源)
{
// 排除css/js/html资源
exclude: /\.(css|js|html|less)$/,
loader: 'file-loader',
options: {
name: '[hash:10].[ext]'
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'development'
};
打包运行项目,字体图标显示正常
如何配置devServer
webpack-dev-server
具有实时重新加载 (live reloading) 的功能。用来自动化(自动编译,自动打开浏览器,自动刷新浏览器~~)
特点:只会在内存中编译打包,不会有任何输出
启动devServer指令为:npx webpack-dev-server
webpack devServer
启动gzip压缩:compress: true
配置如下:
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
// 打包其他资源(除了html/js/css资源以外的资源)
{
// 排除css/js/html资源
exclude: /\.(css|js|html|less)$/,
loader: 'file-loader',
options: {
name: '[hash:10].[ext]'
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'development',
// 开发服务器 devServer:用来自动化(自动编译,自动打开浏览器,自动刷新浏览器~~)
// 特点:只会在内存中编译打包,不会有任何输出
// 启动devServer指令为:npx webpack-dev-server
devServer: {
// 项目构建后路径
contentBase: resolve(__dirname, 'build'),
// 启动gzip压缩
compress: true,
// 端口号
port: 3000,
// 自动打开浏览器
open: true
}
};
配置好devServer,启动devServer,打开浏览器,输入:localhos:3000
,这就是我们使用devServer搭建的服务器,这个服务器启动的项目。
开发环境配置总结——一个完整的开发环境配置
除了之前的配置,我们还要做一些处理,之前编写的实例目录有点乱
我们划分一下目录
把原来的路径修改好后,输入命令webpack
打包项目,看一下输出结果:
我们发现所有的资源都输出到一块了,没有任何的差别
如果希望打包后的资源和原来的结构一样的,可以一个一个调
首先让先js文件输出到js的目录下,要修改output
的filename
属性,在built.js
前加js/
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
重新构建一下项目,可以发现build下面就多了一个js目录
图片资源修改构建路径要在url-loader
中添加outputPath
配置属性:outputPath: 'imgs'
{
// 处理图片资源
test: /\.(jpg|png|gif)$/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
// 关闭es6模块化
esModule: false,
outputPath: 'imgs'
}
},
这样图片资源就会构建在build下面的imgs
文件夹下
其他资源修改构建路径也是添加outputPath
配置属性:outputPath: 'media'
{
// 处理其他资源
exclude: /\.(html|js|css|less|jpg|png|gif)/,
loader: 'file-loader',
options: {
name: '[hash:10].[ext]',
outputPath: 'media'
}
把build目录删掉,重新打包一次,就可以看到清晰的结构
有人可能会问,为什么构建后的资源没有看到之前写的css文件?这是因为css-loader
把css文件打包到js当中了(复习环节),它是跟js文件融为一体的,所以没有被单独打包出去
{
// 匹配哪些文件
test: /\.css$/,
// 使用哪些loader进行处理
use: [
// use数组中loader执行顺序:从右到左,从下到上 依次执行
// 创建style标签,将js中的样式资源插入进行,添加到head中生效
'style-loader',
// 将css文件变成commonjs模块加载js中,里面内容是样式字符串
'css-loader'
]
},
完整的开发环境配置:
/*
开发环境配置:能让代码运行
运行项目指令:
webpack 会将打包结果输出出去
npx webpack-dev-server 只会在内存中编译打包,没有输出
*/
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
// loader的配置
{
// 处理less资源
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
},
{
// 处理css资源
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
// 处理图片资源
test: /\.(jpg|png|gif)$/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
// 关闭es6模块化
esModule: false,
outputPath: 'imgs'
}
},
{
// 处理html中img资源
test: /\.html$/,
loader: 'html-loader'
},
{
// 处理其他资源
exclude: /\.(html|js|css|less|jpg|png|gif)/,
loader: 'file-loader',
options: {
name: '[hash:10].[ext]',
outputPath: 'media'
}
}
]
},
plugins: [
// plugins的配置
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'development',
devServer: {
contentBase: resolve(__dirname, 'build'),
compress: true,
port: 3000,
open: true
}
};
结尾
我是圆圆,如果我的文章对你的学习成长有所帮助,欢迎 点 赞 👍 支持,您的 点 赞 👍 支持是我进行创作和分享的动力!
如果有问题可以留言评论或者私信我,我都会一一解答~笔芯🤞
参考
- https://www.bilibili.com/video/BV1e7411j7T5?p=6
- https://webpack.docschina.org/concepts/