WebPack
核心概念
Entry(输入):定义打包文件从哪个文件开始打包
Output(输出):定义文件打包后放在哪里,包叫什么
Loader(翻译):定义非js文件处理逻辑,把这些文件转换为js文件
Plugins(插件):做一些更复杂的操作,包括压缩解压
Mode(模式):分为生产模式和开发模式
配置
初始化:npm init
下载:webpack_test
npm i webpack webpack-cli
开发依赖:npm i webpack webpack-cli -D
新建文件夹:src和build(处理打包后文件)
打包指令:
开发环境:webpack (入口文件路径(要打包的文件路径)) --output-path=(出口文件路径(打包后的文件放置目录)) --output-filename=(出口文件名)--mode=development
生产环境:webpack (入口文件路径(要打包的文件路径)) --output-path=(出口文件路径(打包后的文件放置目录)) --output-filename=(出口文件名)--mode=production
结论:
1、webpack能处理js/json文件,不能处理css/img等文件
2、生产环境和开发环境是将ES6模块化变异常浏览器能识别的模块化
3、生产环境比开发环境多一个压缩js代码
开发模式&生产模式
开发模式:能让代码本地调试运行的环境(将写的代码变成浏览器能识别的代码)
生产模式:能让代码优化上线运行的环境(闪屏现象,代码压缩,兼容性问题)
开发模式
打包样式资源
新建webpack.config.js文件:
配置(最好在最外面文件夹下载):
npm init
npm i webpack webpack-cli -D
npm i css-loader style-loader less-loader -D
npm i less -D
打包css文件:
const {resolve}=require('path')
module.exports={
//webpack配置
//入口起点(index.js文件里面引入需要打包的文件)
entry:'./src/index.js',
//输出
output:{
//文件名
filename:'built.js',
//输出路径
//__dirname node.js的变量,表示当前文件目录的绝对路径,然后输出到build目录下
path:resolve(__dirname,'build')
},
//loader的配置
module:{
rules:[
//详细的loader配置
{
//匹配哪些文件
test:/\.css$/,
use:[//use中的执行顺序:从右到左,从下到上
//创建style标签,将js中的洋柿子园插入进行,添加到head中生效
'style-loader',
//将css文件变成commonjs模块加载js中,里面内容是样式字符串
'css-loader'
]
},
]
},
//plugins的配置
plugin:[],
//模式
mode:'development',
// mode:'production'
}
打包less文件:
const {resolve}=require('path')
module.exports={
entry:'./src/index.js',
output:{
filename:'built.js',
path:resolve(__dirname,'build')
},
module:{
rules:[
{
test:/\.less$/,
use:[
'style-loader',
'css-loader',
// 把less文件编译成css文件
'less-loader'
]
}
]
},
plugin:[],
mode:'development',
// mode:'production'
}
页面呈现:
build/index.html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>wabpack</title>
</head>
<body>
//引入打包后的js文件
<script src="./built.js"></script>
</body>
</html>
打包文件配置运行:webpack(在需要运行的文件下运行)
打包html资源
配置:npm i html-webpack-plugin -D
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:[]
},
plugins:[
//处理html资源
//功能:默认创建一个空的HTML,自动引入打包输出的所有资源(JS/CSS)
//new HtmlWebpackPlugin()
new HtmlWebpackPlugin({
//复制 ./src/index.html 文件,并自动引入打包输出的所有资源(JS/CSS)
template:'./src/index.html'
})
],
mode:"development"
}
注:不要自己在build/index.html文件中再引入一次
打包图片资源
配置:
npm i url-loader file-loader -D
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$/,
use:['style-loader','css-loader','less-loader']
},
{
test:/\.(jpg|png|gif)$/,
loader:'url-loader',
options:{
//图片大小小于8kb,就会被base64
//优点:减少请求数量(减轻服务器压力)
//缺点:图片体积会更大(文件请求速度更慢)
//一般会弄小图片
limit:8*1024
}
},
]
},
plugins:[
new HtmlWebpackPlugin({
template:'./src/index.html'
})
],
mode:'development'
}
注:这个只能用来打包样式里面的图片资源,无法打包html里面的图片资源
处理html里面的图片:
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$/,
use:['style-loader','css-loader','less-loader']
},
//默认处理不了html图片资源
{
test:/\.(jpg|png|gif)$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 8 * 1024 // 小于 8KB 的图片转为 Base64
}
},
generator: {
filename: '[name].[hash:6][ext]' // 打包后的图片路径
}
},
//用来处理html文件中的图片、字体、样式表等资源的引入,相当于辅助plugins处理这些资源
{
test:/\.html$/,
use:{
loader:'html-loader',
options:{
esModule:false
}
}
}
]
},
plugins:[
new HtmlWebpackPlugin({
template:'./src/index.html'
})
],
mode:'development'
}
注:html-loader是用来处理html文件中的图片、字体、样式表等资源的引入,相当于辅助plugins处理这些资源,不要和HtmlWebpackPlugin弄混了
处理其他资源(asset/resource)
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']
},
{
// 排除 css|js|html 以外的资源
exclude: /\.(css|js|html)$/,
type: 'asset/resource',
generator: {
filename: '[name].[hash:6][ext]'
}
}
]
},
plugins:[
new HtmlWebpackPlugin({
template:'./src/index.html'
})
],
mode:'development'
}
编译运行自动化(devServer)
配置:npm i webpack-dev-server -D
启动指令:npx webpack-dev-server
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']
},
{
exclude: /\.(css|js|html)$/,
type: 'asset/resource',
generator: {
filename: '[name].[hash:6][ext]'
}
}
]
},
plugins:[
new HtmlWebpackPlugin({
template:'./src/index.html'
})
],
mode:'development',
//开发服务器 devServer,用来自动编译,自动打开浏览器,自动刷新浏览器
//特点:只会在内存中编译打包,不会有任何输出
//启动指令:npx webpack-dev-server
devServer: {
// 使用 static 选项代替 contentBase
static: resolve(__dirname, 'build'),
// 启动 gzip 压缩
compress: true,
// 指定开发服务器端口号
port: 3000,
// 自动打开浏览器
open: true
}
}
注:webpack会将打包的文件输出到某个目录下
npx webpack-dev-server只会在内存中编译打包,不会输出
构建环境配置
const {resolve}=require('path');
const HtmlWebpackPlugin=require('html-webpack-plugin')
module.exports={
entry:'./src/js/index.js',
output:{
filename:'built.js',
path:resolve(__dirname,'build'),
clean: true, // 清空 build 目录
},
module:{
rules:[
{
test:/\.css$/,
use:['style-loader','css-loader']
},
{
test:/\.less$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
url: true
}
},
'less-loader'
]
},
{
test: /\.(jpg|png|gif)$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 8 * 1024
}
},
generator: {
filename: '[name].[hash:6][ext]'
}
},
{
test:/\.html$/,
use:{
loader:'html-loader',
options:{
esModule:false
}
},
},
{
exclude: /\.(css|js|html)$/,
type: 'asset/resource',
generator: {
filename: '[name].[hash:6][ext]'
}
}
]
},
plugins:[
new HtmlWebpackPlugin({
template:'./src/index.html'
}),
],
devServer: {
static: resolve(__dirname, 'build'),
compress: true,
port: 3031,
open: true,
},
mode:'development'
}
如果less文件无法加载,可以将style-loader换成MiniCssExtractPlugin.loader(注:这个属于生产环境):
配置:npm install --save-dev mini-css-extract-plugin
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
//其它代码
module.exports={
//其它代码
module:{
rules:[
//其它代码
{
test:/\.less$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
url: true
}
},
'less-loader'
]
},
plugins:[
new HtmlWebpackPlugin({
template:'./src/index.html'
}),
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css',
chunkFilename: '[id].[contenthash].css'
})
],
//其它代码
}
]
},
//其它代码
}
MiniCssExtractPlugin
是一个非常重要的 Webpack 插件,主要用于以下场景:
生产环境:将 CSS 提取为单独的文件,优化性能和缓存。
代码分割:支持按需加载 CSS,减少初始加载时间。
与 HTML 插件配合:自动生成
<link>
标签,简化开发流程
生产环境
处理样式文件
webpack.config.js文件:
const HtmlWebpackPlugin = require('html-webpack-plugin');
const {resolve}=require('path');;
const MiniCssExtractPlugin=require('mini-css-extract-plugin')
module.exports={
entry:'./src/js/index.js',
output:{
filename:'js/built.js',
path:resolve(__dirname,'build')
},
module:{
rules:[
{
test:/\.css$/,
use:[
MiniCssExtractPlugin.loader,
'css-loader'
]
}
]
},
plugins:[
new HtmlWebpackPlugin({
template:'./src/index.html'
}),
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css', // 定义输出的 CSS 文件名
chunkFilename: '[id].[contenthash].css'
})
],
mode:'production'
}
css文件兼容性处理
配置:npm i postcss-loader postcss-preset-env -D
webpack.config.js文件:
const HtmlWebpackPlugin = require('html-webpack-plugin');
const {resolve}=require('path');;
const MiniCssExtractPlugin=require('mini-css-extract-plugin')
process.env.NODE_ENV='development'//设置开发环境为默认环境变量,如果不设置默认为生产环境
module.exports={
entry:'./src/js/index.js',
output:{
filename:'js/built.js',
path:resolve(__dirname,'build')
},
module:{
rules:[
{
test:/\.css$/,
use:[
MiniCssExtractPlugin.loader,
'css-loader',
/*css兼容性处理:postcss-->postcss-loader plstcss-preset-env
帮postcss找到package.json中browserslist里面的配置,通过配置加载指定的css兼容性样式
*/
//使用loader的默认配置
// 'postcss-loader',
//修改loader配置
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [
require('postcss-preset-env')()
]
}
}
}
]
}
]
},
plugins:[
new HtmlWebpackPlugin({
template:'./src/index.html'
}),
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css', // 定义输出的 CSS 文件名
chunkFilename: '[id].[contenthash].css'
})
],
mode:'production'
}
package.json文件(补充,其他不动):
"browserslist":{
"development":[
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
//默认是看生产环境,如果要默认为开发环境,则要设置node.js的环境变量process.env.NODE_ENV='development'
"production":[
">0.2%",
"not dead",
"not op_mini all"
]
},
压缩css资源
配置:npm install css-minimizer-webpack-plugin -D
const HtmlWebpackPlugin = require('html-webpack-plugin');
const {resolve}=require('path');;
const MiniCssExtractPlugin=require('mini-css-extract-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
process.env.NODE_ENV='development'//设置开发环境为默认环境变量,如果不设置默认为生产环境
module.exports={
entry:'./src/js/index.js',
output:{
filename:'js/built.js',
path:resolve(__dirname,'build')
},
module:{
rules:[
{
test:/\.css$/,
use:[
MiniCssExtractPlugin.loader,
'css-loader',
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [
require('postcss-preset-env')()
]
}
}
}
]
}
]
},
plugins:[
new HtmlWebpackPlugin({
template:'./src/index.html'
}),
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css',
chunkFilename: '[id].[contenthash].css'
})
],
optimization:{
minimize:true,
minimizer:[new CssMinimizerPlugin()]
},
mode:'development'
}
const HtmlWebpackPlugin = require('html-webpack-plugin');
const {resolve}=require('path');;
const MiniCssExtractPlugin=require('mini-css-extract-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
module.exports={
entry:'./src/js/index.js',
output:{
filename:'js/built.js',
path:resolve(__dirname,'build')
},
module:{
rules:[
{
test:/\.css$/,
use:[
MiniCssExtractPlugin.loader,
'css-loader',
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [
require('postcss-preset-env')()
]
}
}
}
]
}
]
},
plugins:[
new HtmlWebpackPlugin({
template:'./src/index.html'
}),
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css', // 定义输出的 CSS 文件名
chunkFilename: '[id].[contenthash].css'
})
],
optimization:{
minimize:true,
minimizer:[new CssMinimizerPlugin()]
},
//环境设置为生产环境,同时也不要 process.env.NODE_ENV='development'
mode:'production'
}
js语法检查
配置:npm i eslint-loader eslint eslint-config-airbnb-base eslint-plugin-import -D
package.json文件(补充):
"eslintConfig":{
"extends": "airbnb-base"
},
其他的语法可以查找网站npmjs
webpack.config.js文件:
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:[
/*
语法检查:eslint-loader eslint
只检查源代码,不检查第三方库的代码
设置检查规则:在package.json中eslintConfig中设置
*/
{
test:/\.js$/,
exclude:/node_modules/,
loader:'eslint-loader',
options:{
//自动修复eslint的错误
fix:true
}
}
]
},
plugins:[
new HtmlWebpackPlugin({
template:'./src/index.html'
})
],
mode:'development'
}
js文件兼容性处理
配置:npm i babel-loader @babel/core @babel/preset-env -D
方法一(简单处理):
webpack.config.js文件:
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:[
/*
js兼容性处理:babel-loader @babel/core @babel/preset-env
*/
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
//传递配置选项
options: {
//指定 Babel 使用的插件
presets: [
[
'@babel/preset-env',
{
//指定希望支持的目标环境
targets: {
"esmodules": false,//是否生成 ES 模块语法的代码
"browsers": [//指定希望支持的浏览器版本
"last 2 versions", // 支持最近两个版本的浏览器
"ie >= 11" // 支持 IE 11
]
}
}
]
]
}
}
}
]
},
plugins:[
new HtmlWebpackPlugin({
template:'./src/index.html'
})
],
mode:'development'
}
缺点:只能处理简单的js兼容性,promise处理不了
处理全部的js文件兼容性:
方法二(按需加载):
配置:npm i core-js -D
webpack.config.js文件:
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:[
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
//按需加载
useBuiltIns: 'usage',
corejs: { version: 3 },
targets: {
"esmodules": false,
"browsers": [
"last 2 versions",
"ie >= 11"
],
chrome:'60',
firefox:'60',
ie:'9',
safari:'10',
edge:'17'
}
}
]
]
}
}
}
]
},
plugins:[
new HtmlWebpackPlugin({
template:'./src/index.html'
})
],
mode:'development'
}
注:使用方法三则不能使用方法二的import '@babel/polyfill',需要注释掉
优势:减小built.js的体积,同时能处理所有需要兼容性处理的js资源
压缩js&html资源
压缩js资源:生产环境下会自动压缩js代码,不需要额外配置,把mode设为production即可
压缩html资源:
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')
},
plugins:[
new HtmlWebpackPlugin({
template:'./src/index.html',
//压缩html代码
minify:{
//移除空格
collapseWhitespace:true,
//移除注释
removeComments:true
}
})
],
mode:'production'
}
构建环境配置
const {resolve}=require('path')
const HtmlWebpackPlugin=require('html-webpack-plugin')
const MiniCssExtractPlugin=require('mini-css-extract-plugin')
const CssMinimizerPlugin=require('css-minimizer-webpack-plugin')
module.exports={
entry:'./src/js/index.js',
output:{
filename:'js/built.js',
path:resolve(__dirname,'build')
},
module:{
rules:[
{
test:'/\.css$/',
use:[
MiniCssExtractPlugin.loader,
'css-loader'
]
},
{
test:'/\.less$/',
use:[
MiniCssExtractPlugin.loader,
'css-loader',
'less-loader'
]
},
{
test:'/\.js$/',
exclude:'(/node_modules/)|(webpack.config.js)',
loader:'eslint-loader',
options:{
fis:true
}
},
{
test:'/\.js$/',
exclude:'/node_modules/',
loader:'babel-loader',
options:{
presets:[
'@babel/preset-env',
{
useBuiltIns:'usage',
corejs:{version:3},
targets:{
'esmodules':false,
'browsers':['last 2 version',
'ie>=11'],
chrome:'60',
firefox:'60',
ie:'9',
safari:'10',
edge:'17'
}
}
]
}
},
{
test:'/\.(jpg|png|gif)$/',
type:'asset',
parset:{
dataUrlCondition:{
maxSize:8*1024
}
},
generator:{
filename:'[name].[hash:6][ext]'
}
},
{
test:'/\.html$/',
use:{
loader:'html-loader',
options:{
esModule:false
}
}
},
{
exclude:/\..(js|css|less|html|jpg|png|gif)$/,
type:'asset/resource',
generator:{
filename:'[name].[hash:6][ext]'
}
}
]
},
plugins:[
new MiniCssExtractPlugin({
filename:'css/built.css'
}),
new CssMinimizerPlugin(),
new HtmlWebpackPlugin({
template:'./src/index.html',
minify:{
collapseWhitespace:true,
removeComments:true
}
}),
],
mode:"production"
}
性能优化
开发环境性能优化
优化打包构建速度
优化代码调试
HMR-模块热替换
解决问题:不管哪个模块发生变化,整个打包文件也会重新全部加载,效率低。
解决方式:一个模块发生变化,只会重新打包这一个模块,不会重新打包所有模块
注:当修改了webpack配置(plugins),必须重启server(Ctrl+C),且只有开发环境可以用HMR,生产环境不可以用
样式文件:
webpack.config.js文件:
const {resolve}=require('path');
const HtmlWebpackPlugin=require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports={
entry:'./src/js/index.js',
output:{
filename:'built.js',
path:resolve(__dirname,'build'),
clean: true,
},
module:{
rules:[
{
test:/\.css$/,
use:['style-loader','css-loader']
},
{
test: /\.(jpg|png|gif)$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 8 * 1024
}
},
generator: {
filename: '[name].[hash:6][ext]'
}
},
{
test:/\.html$/,
use:{
loader:'html-loader',
options:{
esModule:false
}
},
},
{
exclude: /\.(css|js|html)$/,
type: 'asset/resource',
generator: {
filename: '[name].[hash:6][ext]'
}
}
]
},
plugins:[
new HtmlWebpackPlugin({
template:'./src/index.html'
}),
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css',
chunkFilename: '[id].[contenthash].css'
})
],
devServer: {
static: resolve(__dirname, 'build'),
compress: true,
port: 3031,
open: true,
//模块热替换
hot:true
},
mode:'development'
}
注:webpack配置文件中的css和less文件解析必须是'style-loader'而不是'MiniCssExtractPlugin.loader'
js文件:
webpack.config.js文件不变
index.js文件:
//导入模块文件
//自己的文件代码
//监听模块更新
if(module.hot){
module.hot.accept('模块文件相对路径',()=>{
const 模块名=require(模块文件路径).default;
模块名();
})
html文件(不能热更新(HMR),但是可以正常更新):
webpack.config.js:
//其它代码
module.exports={
//将html文件引入入口
entry:['./src/js/index.js','./src/index.html'],
//其它代码
}
source-map(源代码到构建后代码映射技术)
如果构建后代码出错了,通过映射可以追踪源代码错误(控制台会报出源文件的具体错误位置)
webpack.config.js文件:
//其它代码
module.exports={
//其它代码
devtool:'source-map'
}
devtool配置:
source-map、inline-source-map和eval-source-map可以生成错误代码准确信息和源代码错误位置,其他不能全部生成。
开发环境:从速度快和友好要求下,建议eval-source-map>eval-cheap-module-source-map(只有行没有列提示)
生产环境:从占用内存和友好要求下,建议source-map>cheap-module-source-map
生产环境性能优化
优化打包构建速度
优化代码运行的性能
oneOf
每个文件只会匹配一个module的rules配置,不会每个都过一遍
//其它代码
module.exports={
entry:'./src/js/index.js',
output:{
filename:'js/built.js',
path:resolve(__dirname,'build')
},
module:{
rules:[
{
oneOf:[
{
test:'/\.css$/',
use:[
MiniCssExtractPlugin.loader,
'css-loader'
]
},
{
test:'/\.less$/',
use:[
MiniCssExtractPlugin.loader,
'css-loader',
'less-loader'
]
},
{
test:'/\.js$/',
exclude:'(/node_modules/)|(webpack.config.js)',
loader:'eslint-loader',
options:{
fis:true
}
},
{
test:'/\.js$/',
exclude:'/node_modules/',
loader:'babel-loader',
options:{
presets:[
'@babel/preset-env',
{
useBuiltIns:'usage',
corejs:{version:3},
targets:{
'esmodules':false,
'browsers':['last 2 version',
'ie>=11'],
chrome:'60',
firefox:'60',
ie:'9',
safari:'10',
edge:'17'
}
}
]
}
},
{
test:'/\.(jpg|png|gif)$/',
type:'asset',
parset:{
dataUrlCondition:{
maxSize:8*1024
}
},
generator:{
filename:'[name].[hash:6][ext]'
}
},
{
test:'/\.html$/',
use:{
loader:'html-loader',
options:{
esModule:false
}
}
},
{
exclude:/\..(js|css|less|html|jpg|png|gif)$/,
type:'asset/resource',
generator:{
filename:'[name].[hash:6][ext]'
}
}
]
},
]
},
plugins:[
new MiniCssExtractPlugin({
filename:'css/built.css'
}),
new CssMinimizerPlugin(),
new HtmlWebpackPlugin({
template:'./src/index.html',
minify:{
collapseWhitespace:true,
removeComments:true
}
}),
],
mode:"production"
}
注:如果有两个配置处理同一个文件的,则需要将这几个配置大于一个的配置放到oneOf外面:
//其它代码
module.exports={
entry:'./src/js/index.js',
output:{
filename:'js/built.js',
path:resolve(__dirname,'build')
},
module:{
rules:[
{
test:'/\.js$/',
exclude:'/node_modules/',
loader:'babel-loader',
options:{
presets:[
'@babel/preset-env',
{
useBuiltIns:'usage',
corejs:{version:3},
targets:{
'esmodules':false,
'browsers':['last 2 version',
'ie>=11'],
chrome:'60',
firefox:'60',
ie:'9',
safari:'10',
edge:'17'
}
}
]
}
},
{
oneOf:[
{
test:'/\.css$/',
use:[
MiniCssExtractPlugin.loader,
'css-loader'
]
},
{
test:'/\.less$/',
use:[
MiniCssExtractPlugin.loader,
'css-loader',
'less-loader'
]
},
{
test:'/\.js$/',
exclude:'(/node_modules/)|(webpack.config.js)',
loader:'eslint-loader',
options:{
fis:true
}
},
{
test:'/\.(jpg|png|gif)$/',
type:'asset',
parset:{
dataUrlCondition:{
maxSize:8*1024
}
},
generator:{
filename:'[name].[hash:6][ext]'
}
},
{
test:'/\.html$/',
use:{
loader:'html-loader',
options:{
esModule:false
}
}
},
{
exclude:/\..(js|css|less|html|jpg|png|gif)$/,
type:'asset/resource',
generator:{
filename:'[name].[hash:6][ext]'
}
}
]
},
]
},
plugins:[
new MiniCssExtractPlugin({
filename:'css/built.css'
}),
new CssMinimizerPlugin(),
new HtmlWebpackPlugin({
template:'./src/index.html',
minify:{
collapseWhitespace:true,
removeComments:true
}
}),
],
mode:"production"
}
缓存
将编译好的文件进行缓存处理,如果没有变化,则直接运行缓存的文件,如果变化了再重新编译缓存运行
本质:第二次构建的时候会读取之前的缓存:
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.[contenthash:10].js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules|webpack\.config\.js$/,
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',
corejs: { version: 3 },
targets: {
esmodules: false,
browsers: ['last 2 versions', 'ie >= 11'],
chrome: '60',
firefox: '60',
ie: '9',
safari: '10',
edge: '17'
}
}
]
],
//开启babel缓存,第二次构建的时候会读取之前的缓存
cacheDirectory: true
}
},
{
oneOf: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader'
]
},
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'less-loader'
]
},
{
test: /\.js$/,
exclude: /node_modules|webpack\.config\.js$/,
loader: 'eslint-loader',
options: {
fix: true
}
},
{
test: /\.(jpg|png|gif)$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 8 * 1024
}
},
generator: {
filename: '[name].[hash:6][ext]'
}
},
{
test: /\.html$/,
use: {
loader: 'html-loader',
options: {
esModule: false
}
}
},
{
exclude: /\.(js|css|less|html|jpg|png|gif)$/,
type: 'asset/resource',
generator: {
filename: '[name].[contenthash:6][ext]'
}
}
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/built.[contenthash:10].css'
}),
new CssMinimizerPlugin(),
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
})
],
mode: "production",
devtool: "source-map"
};
注:js文件和css文件打包后的文件名必须是每次修改后都不一样的才能正确更新,建议直接定义为built.[contenthash:10].css/js,这样,每次修改都会生成一个新的哈希值,这样能保证文件的正常更新,且两个文件的哈希值不相同。
测试缓存:
服务器开启(server.js):
//服务器代码
const express=require('express');
const app=express();
app.use(express.static('build',{maxAge:1000*3600}));
app.listen(3030);
运行server.js:node server.js
每次修改完文件要重新输入指令:webpack
终止端口占用:
1、终端输入 netstat -ano | findstr :端口名
2、获取 LISTENING后面的数字
3、 taskkill /PID LISTENING后面的数字 /F
tree_shaking(去除无用代码)
前提:
1、使用ES6模块化
2、开启production环境
优点:减少代码体积
package.json文件:
//将这个插入到配置中
"sideEffects":false
表示所有代码都可以进行去除无用代码
副作用:会把css/@babel/polyfill文件删除
解决:将"sideEffects":false改为"sideEffects":["*css",...]//将可能会被删除的文件放到数组里面,相当于屏蔽这些类型文件的tree_shaking作用,防止被删除。
code split(代码分割)
方法一(直接设置两个入口文件):
webpack.config.js文件:
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
main:'./src/js/index.js',
test:'./src/js/test.js'
},
//其它代码
};
注:输出的时候文件名可以设置为[name].[contenthash:10].js,防止打包文件名不好区分
方法二:
webpack.config.js文件:
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
main:'./src/js/index.js',
test:'./src/js/test.js'
},
output: {
filename: 'js/[name].[contenthash:10].js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules|webpack\.config\.js$/,
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',
corejs: { version: 3 },
targets: {
esmodules: false,
browsers: ['last 2 versions', 'ie >= 11'],
chrome: '60',
firefox: '60',
ie: '9',
safari: '10',
edge: '17'
}
}
]
],
cacheDirectory: true
}
},
{
oneOf: [
{
test: /\.js$/,
exclude: /node_modules|webpack\.config\.js$/,
loader: 'eslint-loader',
options: {
fix: true
}
},
{
test: /\.(jpg|png|gif)$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 8 * 1024
}
},
generator: {
filename: '[name].[hash:6][ext]'
}
},
{
test: /\.html$/,
use: {
loader: 'html-loader',
options: {
esModule: false
}
}
},
{
exclude: /\.(js|css|less|html|jpg|png|gif)$/,
type: 'asset/resource',
generator: {
filename: '[name].[contenthash:6][ext]'
}
}
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
})
],
//可以将node_modules中代码单独打包一个chunk最终输出,自动分析多入口chunk中,有没有公共的文件,如果有会打包成一个单独的chunk
optimization:{
splitChunks:{
chunks:'all'
}
},
mode: "production",
};
要打包的js文件(每一个都要):
import $ from 'jquery'
优点:可以将node_modules中代码单独打包一个chunk最终输出,自动分析多入口chunk中,有没有公共的文件,如果有会打包成一个单独的chunk
方法三:
webpack.config.js文件:
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/[name].[contenthash:10].js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules|webpack\.config\.js$/,
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',
corejs: { version: 3 },
targets: {
esmodules: false,
browsers: ['last 2 versions', 'ie >= 11'],
chrome: '60',
firefox: '60',
ie: '9',
safari: '10',
edge: '17'
}
}
]
],
cacheDirectory: true
}
},
{
oneOf: [
{
test: /\.js$/,
exclude: /node_modules|webpack\.config\.js$/,
loader: 'eslint-loader',
options: {
fix: true
}
},
{
test: /\.(jpg|png|gif)$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 8 * 1024
}
},
generator: {
filename: '[name].[hash:6][ext]'
}
},
{
test: /\.html$/,
use: {
loader: 'html-loader',
options: {
esModule: false
}
}
},
{
exclude: /\.(js|css|less|html|jpg|png|gif)$/,
type: 'asset/resource',
generator: {
filename: '[name].[contenthash:6][ext]'
}
}
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
})
],
optimization:{
splitChunks:{
chunks:'all'
}
},
mode: "production",
};
index.js文件:
//通过js代码,让某个文件被单独打包成一个chunk,能将某个文件单独打包
import (/*webpackChunkName:'test'*/'./test')
.then((mul,count)=>{
//eslint-disable-next-line
console.log(mul(2,5),count);
}).catch(err=>{
console.log(err);
})
//其它代码
/*webpackChunkName:'test'*/指的是生成的打包文件名以test开头,不是注释
lazy loading(懒加载和预加载)
懒加载(事件触发的时候才加载引入的文件)
index.js文件(test.js文件懒加载):
document.getElementById('btn').onclick=function(){
//懒加载(点击了按钮才会下载test.js文件,从而打印test文件中的输出,避免了一加载页面时就下载test.js文件)
import (/*webpackChunkName:'test'*/'./test').then(({mul})=>{
console.log(mul(4,5));
})
}
预加载(页面加载的时候就加载好引入的文件,但是不使用,等事件触发的时候再使用)
index.js文件:
document.getElementById('btn').onclick=function(){
import (/*webpackChunkName:'test',webpackPrefetch:true*/'./test').then(({mul})=>{
console.log(mul(4,5));
})
}
要点:在import文件中注释webpackPrefetch:true
PWA(渐进式网络开发应用程序:离线也可以访问)
配置:
下载workbox:npm i workbox-webpack-plugin -D
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const WorkboxWebpackPlugin=require('workbox-webpack-plugin');
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.[contenthash:10].js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules|webpack\.config\.js$/,
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',
corejs: { version: 3 },
targets: {
esmodules: false,
browsers: ['last 2 versions', 'ie >= 11'],
chrome: '60',
firefox: '60',
ie: '9',
safari: '10',
edge: '17'
}
}
]
],
cacheDirectory: true
}
},
{
oneOf: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader'
]
},
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'less-loader'
]
},
{
test: /\.js$/,
exclude: /node_modules|webpack\.config\.js$/,
loader: 'eslint-loader',
options: {
fix: true
}
},
{
test: /\.(jpg|png|gif)$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 8 * 1024
}
},
generator: {
filename: '[name].[hash:6][ext]'
}
},
{
test: /\.html$/,
use: {
loader: 'html-loader',
options: {
esModule: false
}
}
},
{
exclude: /\.(js|css|less|html|jpg|png|gif)$/,
type: 'asset/resource',
generator: {
filename: '[name].[contenthash:6][ext]'
}
}
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/built.[contenthash:10].css'
}),
new CssMinimizerPlugin(),
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
}),
//生成一个serviceworker配置文件
new WorkboxWebpackPlugin.GenerateSW({
clientsClaim:true,//帮助serviceworker快速启动
skipWaiting:true//删除旧的serviceworker
})
],
mode: "production",
devtool: "source-map"
};
index.js文件:
//其它代码
//注册代码
if('serviceWorker' in navigator){
window.addEventListener('load',()=>{
navigator.serviceWorker.register('/service-worker.js').then(reg=>{
console.log('service worker注册成功',reg);
}).catch(err=>{
console.log('service worker注册失败',err);
})
})
}
多进程打包
配置:npm i thread-loader -D
webpack.config.js文件:
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const WorkboxWebpackPlugin=require('workbox-webpack-plugin');
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.[contenthash:10].js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules|webpack\.config\.js$/,
use:[
{
loader: 'thread-loader',
options:{
workers:2//进程2个
}
},
{
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',
corejs: { version: 3 },
targets: {
esmodules: false,
browsers: ['last 2 versions', 'ie >= 11'],
chrome: '60',
firefox: '60',
ie: '9',
safari: '10',
edge: '17'
}
}
]
],
cacheDirectory: true
}
}
]
},
//其它代码
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/built.[contenthash:10].css'
}),
new CssMinimizerPlugin(),
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
}),
new WorkboxWebpackPlugin.GenerateSW({
clientsClaim:true,
skipWaiting:true,
runtimeCaching: [
{
urlPattern: /\.css$/,
handler: 'CacheFirst',
options: {
cacheName: 'css-cache',
expiration: {
maxEntries: 50,
maxAgeSeconds: 7 * 24 * 60 * 60 // 7天
}
}
}
]
})
],
mode: "production",
devtool: "source-map"
};
externals(拒绝打包)
webpack.config.js:
//其它代码
module.exports={
//其它代码
externals:{
//拒绝jQuery被打包进来,如果有这个则相应的包不会引进,如果要使用则要在html文件中手动引入
jquery:'jQuery'
}
}
用处:有些包是由cdn引进来的,需要屏蔽打包,手动引入
dll(将第三方库进行单独打包)
新建webpack.dll.js文件:
const {resolve}=require('path');
const webpack=require('webpack');
module.exports={
entry:{
jquery:['jquery']//打包生成的名字:['要打包的库']
},
output:{
filename:'[name].js',
path:resolve(__dirname,'dll'),
library:'[name]_[hash]'//打包的库里面向外暴露出去的内容名字
},
plugins:[
//打包生成json文件,并提供jquery映射的内容的名称
new webpack.DllPlugin({
name:'[name]_[hash]',//映射库的暴露的内容名称
path:resolve(__dirname,'dll/manifest.json')//输出文件路径
})
],
mode:'production'
}
运行:webpack --config webpack.dll.js
webpack.config.js文件:
配置:npm i add-asset-html-webpack-plugin -D
const {resolve}=require('path');
const HtmlWebpackPlugin=require('html-webpack-plugin')
const webpack=require('webpack');
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin');
module.exports={
entry:'./src/index.js',
output:{
filename:'built.js',
path:resolve(__dirname,'build')
},
module:{
rules:[
]
},
plugins:[
new HtmlWebpackPlugin({
template:'./src/index.html'
}),
//告诉webpack哪些库不参与打包,同时使用的时候名称要变
new webpack.DllReferencePlugin({
manifest:resolve(__dirname,'dll/manifest.json')
}),
//将某个文件打包输出去,并在html中自动引入该资源
new AddAssetHtmlPlugin({
filepath:resolve(__dirname,'dll/jquery.js')
})
],
mode:"production"
}