前言
webpack是一个模块打包工具(module bundler),它可以对Web前端和Node.js等应用进行打包。
了解webpack基本配置
安装webpack
首先 我们需要通过包管理工具(npm/pnpm/yarn等)来安装webpack所需要的包(webpack
、webpack-cli
), 这是最基本的文件。
shell
npm install webpack webpack-cli -D
// webpack为webpack的核心包,webpack-cli是webpack的命令行工具,运行webpack命令需要使用
//可以通过@来安装指定版本 如:webpack@5.21.2
webpack相关基本配置
介绍webpack的相关配置,详细可参考下文中的webpack.config.js示例。
context
基础目录,表示资源入口entry是以哪个目录为起点的。值为字符串,表示一个绝对路径。
entry
webpack打包的入口文件配置项。表示从哪个文件为入口开始打包。值可以为字符串,也可以为数组、对象、函数、描述符。
- 字符串形式:最简单的形式,表示打包入口的js文件。
- 数组形式:最后一个文件是资源的入口文件,数组的其余文件会被预先构建到入口文件中。(注:数组形式的entry本质上还是单一入口。)
- 对象形式:对象形式的entry又被称为多入口配置,与前两项不同,多入口文件配置打包后生成多个JS文件。
- 函数形式:函数形式取函数返回值作为入口配置,返回值为上述三项之一。可以做一些额外的逻辑处理,但搭脚手架时很少使用。
- 描述符形式:描述符形式也是一个对象,米哦啊书夫语法可以用来给入口传入额外的选项,例如设置dependOn选项时,可以与另一个入口chunk共享模块。
output
webpack打包后的资源出口配置项,四个属性:"path
"(输出路径)、"filename
"(输出文件名),"publicPath
","chunkFilename
"。
- filename:打包后生成的资源名称,可以是文件名称,也可以是相对地址('./js/bundle.js')。最终打包输出的文件地址时path绝对路径与filename拼接后的地址。支持生成动态文件名如:'[hash]-bundle.js'。
- path:表示资源打包后输出的位置,需要一个绝对路径,默认为dist目录。
- publicPath:资源访问路径,默认值为auto。
- chunkFailename:表示打包过程中非入口文件的chunk名称,通常在使用异步模块的时候,会生成非入口文件的chunk。
动态值
补充 :关于动态值有hash、fullhash、chunkhash、contenthash,与浏览器缓存相关,对于一些长期不变更的文件资源,通常会存储在本地磁盘,当文件变动时再去请求新的文件,而这种动态值如hash、chunkhash、contenthash是根据文件内容计算出来的,通过动态值得变化来判断文件有无变更。通常通过结合name(名字)、id(唯一序列号)来使用。 目前fullhash已经替代hash,使用hash会出现警告。
区别:
- 通常对于单文件我们使用hash(fullhash)即可。例如:
[name]-[fillhash:8].js
,hash是根据全部参与打包得文件计算出来的。 - 对于多文件通常使用chunkhash。chunkhash是通过当前打包的chunk计算出来的。
- 对于css文件,我们一般使用contenthash。主要用于计算css得hash值。
mode
webpack打包模式,有三种分别为"production
"(默认值),"development
","none
",production
和development
这两种模式分别按照线上生产和本地测试做一些优化处理。其中production
是给生产环境打包使用(压缩代码),none
会保留原始的打包结果。
预处理器
Loader:预处理器本质上是一个函数,它接收一个资源模块,然后将其处理成webpack能使用的形式。(解析模板),配置项为module
常用的一些预处理器:style-loader
、css-loader
、vue-loader
、ts-loader
、file-loader
、url-loader
、babel-loader
、sass-loader
等。 预处理配置项:exclude/include,通过字符串或正则表达式匹配文件,排除或进行处理。exclude优先级高。
插件
插件与预处理器不同,预处理器主要用来解析模板的,而插件是扩展wbepack的能力的。配置项为plugins
常用插件有:clean-webpack-plugin
、copy-webpack-plugin
、html-webpack-plugin
、mini-css-extract-plugin
、terser-webpack-plugin
、webpack-bundle-analyzer
等。
webpack本地服务
webpack官方提供了一个webpack服务工具webpack-dev-server,在本地开启一个网络服务器,可以用来处理网络请求。通过npm安装,npx启动服务。
shell
npm install webpack-dev-server -D
npx webpack-serve
webpack-dev-server常见配置,通过在webpack配置文件的devServer里来进行配置。
js
······
devServer:{
histroyApiFallback:true, //解决Html Histroy模式下 所有404重定向问题。
publicPath:'/', //服务器请求资源路径,默认值为'/'
open:true, //启动服务后是否自动打开浏览器
compress:true, // 是否为静态资源开启Gzip压缩
hot:false, //是否启动热替换功能
port:8080, // 服务端口号设置
}
······
环境变量
这里的环境指的是Node.js的环境变量,Node.js在执行JS代码是可以获取到环境变量,它们存放在process.env模块中。 在实际开发中我们可以通过cross-env来设置环境变量。
shell
npm install cross-env -D
通过在package.json中配置如:
json
"script":{
"start":"cross-env NODE_ENV=development webpack serve --config webpack.config.js"
"build":"cross-env NODE_ENV=production webpack --config webpack.config.js"
}
这样我们就可以通过不同命令来配置环境变量的值,并在webpack配置文件中使用。 当然我们还可以通过webpack自带插件,DefinePlugin来将环境变量注入到业务逻辑代码中。
js
plugins:[
new wbepack.DefinePlugin({
MY_DEV:'dev'
})
]
webpack.config.js 示例
通常我们使用webpack都会在项目根目录下配置webpack.config.js文件,当我们执行webpack命令时,webpack会自动寻找该文件并根据其配置信息进行打包。 示例:
javascript
//webpack.config.js文件配置
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports={
entry:'./a.js', //webpack入口文件
output:{ //输出文件
path:path.resolve(_dirname,'dist'), //输出文件路径
filename:'bundle.js' //输出文件名
},
mode:'none' //webpack打包模式,有三种分别为"production"(默认值),"development","none"
//production和development这两种模式分别按照线上生产和本地测试做一些优化处理。
//其中production是给生产环境打包使用(压缩代码),none会保留原始的打包结果。
module:{
rules:[{
test:'/\.(scss|css)$/',
use:['style-loader','css-loader','sass-loader']
// use:[MiniCssExtractPlugin.loader,'css-loader','sass-loader'] 生产
},
{
test: /\.vue$/, //解析vue 模板
use: "vue-loader"
},
{
test:/\.js$/,
use:{
loader:'babel-loader',
options:{
presets:['@babel/preset-env']
}
}
},
{
test:/\.(png|jpg)$/,
use:{
loader:'url-loader',
options:{
limit:1024*8,
}
}
}
]
},
plugins:[
new CleanWebpackPlugin(),
new CopyPlugin({
patterns:[
{
from:path.resolve(_dirname,'src/img/'),
to:path.resolve(_dirname,'dist/image/')
},
]
}),
new MiniCssExtractPlugin({
filename:'[name]-[contenthash:8].css',
chunkFilename:'[id].css',
})
new HtmlWebpackPlugin({
title:'webpack入门',
filename:'index.html',
// template:'./public/index.html'
}),
],
devServer:{
histroyApiFallback:true, //解决Html Histroy模式下 所有404重定向问题。
publicPath:'/', //服务器请求资源路径,默认值为'/'
open:true, //启动服务后是否自动打开浏览器
compress:true, // 是否为静态资源开启Gzip压缩
hot:false, //是否启动热替换功能
port:8080, // 服务端口号设置
}
}
//npm install webpack@5.21.2 webpack-cli@4.9.0 webpack-dev-server@3.11.2 -D
合并配置(开发环境与生产环境)
在实际开发中,开发环境和生产环境的配置有很多是相同的,通常我们把这些相同配置提取出来,以供开发环境和生产环境来使用。
我们可以通过配置NODE环境变量 通过判断来实现不同配置信息,webpack也提供了webpack-merage 可以帮助我们更简单方便的合并webpack配置文件。
shell
npm install webpack-merage -D
创建三个配置文件
- webpack.development.js 开发环境配置
- webpack.production.js 生产环境配置
- webpack.common.js 公共配置 webpack-merage语法:
js
//webpack.common.js
const path = require('path')
module.exports = {
······
//配置信息
}
//webpack.development.js
const { merge } = require('webpack-merage')
const common = require('./webpack.common.js')
module.exports = merge(common,{
····开发环境的配置信息
});
//webpack.production.js 与开发环境配置文件类似
通过配置packages.json文件来使用不同的配置文件 例:
json
"script":{
"start":"cross-env NODE_ENV=development webpack serve --config webpack.development.js"
"build":"cross-env NODE_ENV=production webpack --config webpack.production.js"
}
性能优化
webpack-bundle-analyzer
webpack-bundle-analyzer
是一个非常有用的webpack可视化优化分析工具,他可以帮我们分析打包后的资源体积大小,并可以分析该资源由哪些模块组成。
shell
npm install webpack-bundle-analyzer -D
js
//webpack.config.js
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
······
plugins:{
new BundleAnalyzerPlugin();
}
······
speed-measure-webpack-plugin
webpack优化需要关注得除资源组成与大小外,还需要关注打包花费的时间。speed-measure-webpack-plugin
可以帮我们分析打包过程中预处理器与插件等花费得时间。
js
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const smp = new SpeedMeasurePlugin();
let config = {
//配置项
}
module.exports = smp.wrap(config)
资源压缩
对于JS文件压缩,可以使用插件terser-webpack-plugin
,可以通过plugins
插件形式,也可以通过opotimization
配置 对于CSS文件压缩可以使用插件css-minimizer-webpack-plugin
,通过opotimization
配置。
例:
js
const TerserPlugin = require("terser-webpack-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
module.exoprts = {
module:{
rules:[{
test:'/\.(scss|css)$/',
use:[MiniCssExtractPlugin.loader,'css-loader','sass-loader']
}]
},
plugins:[
new MiniCssExtractPlugin({
filename:'[name]-[contenthash:8].css',
chunkFilename:'[id].css',
})
],
optimization : {
minimize:true,
minimizer:[new TerserPlugin(),new CssMinimizerPlugin()], //压缩器
}
}
缩小查找范围
exclude与include 设置处理范围
通过对预处理器设置exclude和include字段,设置处理范围。例如使用babel-loader,node_modules中的第三方包一般都进行过转码处理,所以可以将此目录排除在babel-loader处理范围。
module.noParse 排除解析模块
通过module.noParse,有些模块不需要被任何预处理器解析,例如jQuery,Lodash这一类的库。
resolve.modules 快速搜寻第三方包
用于配置webpack如何搜索第三方模块的路径。
resolve.extensions 匹配文件后缀名
用于webpack匹配文件后缀名。 import {name} from './b'; //省去了.js 通过配置 extensions : ['.js','.json']
splitChunks
用途:抽离公共代码。 参数:
- chunks:表示什么类型的chunks里提取代码,有三个字符串值,分别为:'
initial
(只从入口chunks提取代码)'、'async
(从动态加载的chunks提取)'、'all
(all表示从上两者中都提取代码)'可以使用,还可以通过函数来匹配要提取的chunks。默认值为async。 - miniSize:提取出来的chunk的最小体积,只有到达这个值才会被提取,默认20 000 (20Kb)
- maxSize:表示提取出来的chunk的最大体积,其默认值是0,表示不限制最大体积。它是一个可违反的值,在被违反时起到提示作用。
- minChunks:默认值是1,表示拆分前至少被多少个chunks引用的模块才会被提取。
- maxAsyncRequests:按需(异步)加载时的最大并行请求数。
- maxInitialRequests:入口点的最大并行请求数
- cacheGroups:缓存组,可以继承或覆盖来自
splitChunks.*
的任何配置,几个重要参数- priority:缓存组优先级。一个模块可以有多个缓存组,其priorty的默认值是负数,自定义组priority的默认值是0。
- reuseExistingChunk:是否重用chunk。若当前chunk中包含从主bundle中拆分出的模块,则它将被重用,而不是生成新的模块,其默认值为true。
- test:匹配模块资源路径或chunk名称,其值可以是布尔值、正则表达式或字符串,若其值缺省则会选择所有模块。
优先级 minSize > maxSize > maxInitialRequests/maxAsyncRequests
使用TreeShaking
Tree Shaking可以检测模块中没有用到的代码块,在webpack打包时将它们移除从而减小打包后的资源体积。 开启Tree Shaking,对于webpack5 已经可以做到深层次Tree Shaking。
注:生产环境我们不会开启Tree Shaking 会影响构建速度,生产环境我们将mode改为production,即可自动打开Tree Shaking。
手动开启Tree Shaking
js
const TerserPlugin = require("terser-webpack-plugin");
······
optimization:{
usedExports:true,
minimize:true,
minimizer:[new TerserPlugin()],
}
排除Tree Shaking文件 如polyfill
js
{
"sideEffects":[
"./polyfill.js"
]
}
通过webpack构建Vue项目
项目结构:
- src
- -- main.ts
- -- App.vue
- webpack.config.js
- index.html
- package.json
基础构建
一、构建项目目录
生产package.json文件
shell
npm init -y
新建webpack.config.js、index.html、src目录(下有mian.js、App.vue文件)。
二、安装相关依赖
安装webpack、webpack-cli(命令行)、webpack-dev-server(本地服务)、vue、vue-loader(解析vue文件)、html-webpack-plugin(使用html模板)。 也可以安装一些其他的插件 如:我们项目中需要使用sass,可以安装sass、sass-loader。 将css代码提取出来可以使用 mini-css-extract-plugin 。
shell
npm install webpack webpack-cli webpack-dev-server -D
npm install vue
npm install vue-loader -D
npm install sass sass-loader -D
npm install html-webpack-plugin -D
npm install mini-css-extract-plugin -D
三、配置webpack.config.js
注:参考示例,并不可直接使用。
js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { VueLoaderPlugin }= require('vue-loader');
module.exports = {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name]-[chunkhash].js',
clean:true;//清空上次打包的结果
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
},
{
test:'/\.(scss|css)$/',
use:['style-loader','css-loader','sass-loader']
// use:[MiniCssExtractPlugin.loader,'css-loader','sass-loader'] 生产
},
]
},
plugins:[
new HtmlWebpackPlugin({
template: './index.html',
}),
new VueLoaderPlugin(),
],
optimization: {
splitChunks: {
cacheGroups: {
moment: {
test: /[\\/]node_modules[\\/]/,
priority:-10,
chunks: "all",
reuseExistingChunk:true,
},
common: {
chunks: "all",
priority:-20
minChunks: 2,
reuseExistingChunk:true,
},
},
},
},
mode:'development',
}
可以通过npx webpack来打包 npx webpack serve 启动服务,也可以通过package.json文件配置脚本。
更多详细配置可以参考上文相关webpack基本配置介绍,比如说我们还可以通过插件压缩JS、CSS代码,压缩图片,通过splitChunks进行公共代码抽离。还可以通过安装ts和ts-loader来使用ts开发。
总结
本篇文章主要是对webpack基本配置的一些总结,其次通过webpack手动配置vue项目,可以帮助我们加深对webpack的了解,方便以后的灵活运用,对以后工作中的项目优化会提供一些帮助。
如果文章中有描述错误或不清晰的地方,希望可以帮忙指正。