Webpack
一、Webpack简介
1.1 Webpack是什么
Webpack是一种前端资源构建工具,一个静态模块打包器。在Webpack看来,前端的所有资源文件都会作为模块处理,它将根据模块的依赖关系进行静态分析,打包生成对应的静态资源(bundle)。
1.2 Webpack五个核心概念
1.2.1 Entry
入口(Entry)指示Webpack以哪个文件为入口起点开始打包,分析构建内部依赖图。
1.2.2 Output
输出(Output)指示Webpack打包后的资源bundles输出到哪里去,以及如何命名。
1.2.3 Loader
Loader让Webpack能够去处理那些非JavaScript文件(webpack自身只理解JavaScript)
1.2.4 Plugins
插件(Plugins)可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量等。
1.2.5 Mode
模式(Mode)指示Webpack使用对应模式的配置。
选项 | 描述 | 特点 | development | 会将process.env.NODE_ENV 的值设为development 。启用NamedChunksPlugin 和NamedModulesPlugin 。 | 能让代码本地调试运行的环境 | production | 会将process.env.NODE_ENV 的值设为production 。启用FlagDependencyUsagePlugin , FlagIncludedChunksPlugin , ModuleConcatenationPlugin , NoEmitOnErrorsPlugin , OccurrenceOrderPlugin , SideEffectsFlagPlugin 和UglifyJsPlugin 。 | 能让代码优化上线运行的环境 |
---|
二、Webpack初体验
2.1 运行指令
开发环境:webpack ./src/index.js -o ./build/build.js --mode=development
生产环境:webpack ./src/index.js -o ./build/build.js --mode=production
webpack会以./src/index.js
为入口文件开始打包,打包后输出到./build/build.js
,整体打包环境是开发/生产环境
结论:
- webpack能处理js/json资源,不能处理css/img等其他资源
- 生成环境和开发环境将ES6模块编译成浏览器能识别的模块化
- 生成环境比开发环境多一个压缩js代码
2.2 webpack配置
webpack.config.js
:webpack的配置文件。指示webpack干哪些活(当你运行webpack指令时,会加载里面的配置);
所有构件工具都是基于nodejs平台运行的,模块化默认使用commonjs
/*
loader:1. 下载 2. 使用(配置loader)
plugins:1.下载 2. 引入 3. 使用
*/
// resolve用来拼接绝对路径的方法
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
// 设置nodejs环境变量
process.env.NODE_ENV = 'development';
// 复用loader
const commonCssLoader = [
// use数组中loader执行顺序:从右到左,从下到上,依次执行。
// 创建style标签,将js中的样式资源插入进行,添加到head中生效
// 'style-loader',
// 这个loader取代style-loader。作用:提取js中的css成单独文件
MiniCssExtractPlugin.loader,
// 将css文件变成commonjs模块加载js中,里面内容时样式字符串
'css-loader',
/*
css兼容性处理:postcss --> postcss-loaderpost-preset-env
帮postcss找到packet.json中browerslist里面的配置,通过配置加载指定的css兼容性样式
"browserslist": {
// 开发环境 --> 设置node环境变量: process.env.NODE_ENV = 'development'
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version",
],
// 生产环境:默认是生产环境
"production": [
">0.2%",
"not dead",
"not op_mini all"
]
}
*/
// 使用loader的默认配置
// 'post-loader',
// 修改loader配置
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [
// postcss的插件
require('postcss-preset-env')()
]
}
}
];
module.exports = {
// webpack配置
// 入口起点
entry: './src/index.js',
// 输出
output: {
// 输出文件名
filename: 'js/build.js',
// 输出路径
// __dirname nodejs的变量,代表当前文件的目录的绝对路径
path: resolve(__dirname, 'build')
},
// loader的配置
modules: {
rules: [
// 详细loader配置
// 不同文件必须配置不同loader处理
{
// 匹配哪些文件
test: /\.css$/,
// 使用哪些loader进行处理
use: [...commonCssLoader]
},
{
test: /\.less$/,
use: [
...commonCssLoader,
// 将less文件编译成css文件
// 需要下载less-loader和less
'less-loader'
]
},
{
// 处理样式中的图片资源 —— 默认处理不了html中的图片资源
test: /\.(jpg|png|gif)$/,
// 下载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]',
outputPath: 'imgs'
}
},
// 打包其他资源(除了html/js/css资源以外的资源)
{
test: /\.html$/,
// 处理html文件中的img图片(负责引入img,从而能被url-loader进行处理)
loader: 'html-loader'
},
{
exclude: /\.(html|css|js|less|jpg|png|gif)$/,
loader: 'file-loader',
options: {
name: '[hash:10].[ext]',
outputPath: 'media'
}
},
// 正常来讲,一个文件只能被一个loader处理,当被多个loader处理,一定要指定loader执行的先后顺序:先执行eslint再执行babel
{
/*
语法检查: eslint-loader eslint
注意:只检查自己写的源代码,第三方的库是不用检查的
设置检查规则:
package.json中eslintConfig中设置:
“eslintConfig”: {
"extend": "airbnb-base"
}
airbnb --> eslint-config-airbnb-base eslint-plugin-import eslint
*/
test: /\.js$/,
exclude: /node_modules/,
// 优先执行
enforce: 'pre',
loader: 'eslint-loader',
options: {
// 自动修复eslint的错误
fix: true
}
},
/*
js兼容性处理:babel-loader @babel/core @babel/preset-env
1. 基本js兼容性处理 ==》 @babel/preset-env
问题:只能转换基本语法,如promise不能转换
2. 全部js兼容性处理 ==》 @babel/polyfill
问题:我只要解决部分兼容性问题,但是所有兼容性代码全部引入,提及太大
3. 需要做兼容性处理的就做:按需加载 ==》 core-js
*/
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
// 预设:指示babel做怎么样的兼容性处理
presets: [
[
'@babel/preset-env',
{
// 按需加载
useBuiltIns: 'usage',
// 指定core-js版本
corejs: { version: 3 },
// 指定兼容性做到哪个版本的浏览器
targets: {
chrome: '60',
firefox: '60',
ie: '9',
safari: '10',
edge: '17'
}
}
]]
}
}
]
},
// plugins配置
plugins: [
// 详细plugins配置
// html-webpack-plugin —— 默认会创建一个空的HTML,自动引入打包输出的所有资源(JS/CSS)
new HtmlWebpackPlugin({
// 复制'./src/index.html'文件,并自动引入打包输出的所有资源(JS/CSS)
template: './src/index.html',
// 压缩html
minify: {
// 移除空格
collapseWhitspace: true,
// 移除注释
removeComments: true
}
}),
new MiniCssExtractPlugin({
// 对输出的css文件重命名
filename: 'css/build.css'
}),
// 压缩css
new OptimizeCssAssetsWebpackPlugin()
],
// 模式
mode: 'development',
// mode: 'production',
// 开发服务器devServer:用来自动化(自动编译、自动打开浏览器、自动刷新浏览器)
// 特点:只会在内存中编译打包,不会有任何输出
// 启动devServer指令为:`npx webpack-dev-server`
devServer: {
// 项目构建后路径
contentBase: resolve(__dirname, 'build'),
// 启动gzip压缩
compress: true,
// 端口号
port: 3000,
// 自动打开浏览器
open: true
}
}
三、Webpack性能优化
3.1 开发环境性能优化
3.1.1 优化打包构建速度
HMR:hot module replacement 热模块替换/模块热替换
作用:一个模块发生变化,只会重新打包这一个模块(而不是打包所有模块),极大提升构建速度。
样式文件:可以使用HMR功能:因为style-loader内部实现了
js文件:默认不能使用HMR功能。 --> 需要修改js代码,添加支持HMR功能的代码
注意:HMR功能对js的处理,只能处理非入口文件的其他文件。
if(module.hot){module.hot.accept('文件路径', function(){...})}
html文件:默认不能使用HMR功能,同时会导致html文件不能热更新。(不用做HMR功能)
解决:修改entry入口,将html文件引入
entry: ['./src/index.html']
devServer: {
// 开启HMR功能
hot: true,
}
3.1.2 优化代码调试
source-map:一种提供源代码到构建后代码映射的技术(如果构建后代码出错了,通过映射可以追踪源代码错误)
[inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map
source-map
:外部
----> 错误代码准确信息 和 源代码的错误位置
inline-source-map
:内联;只生产一个内联source-map
----> 错误代码准确信息 和 源代码的错误位置
hidden-source-map
:外部;
----> 错误代码错误原因,但是没有错误位置;不能跟踪源代码错误,只能提示到构建后代码的错误位置
eval-source-map
:内联;每一个文件都生产对应的source-map,都在eval里
----> 错误代码准确信息 和 源代码的错误位置
nosources-source-map
: 外部
----> 错误代码准确信息但是没有任何源代码
cheap-source-map
:外部
----> 错误代码准确信息 和 源代码的错误位置;只能精确到行
cheap-module-source-map
:外部
----> 错误代码准确信息 和 源代码的错误位置;只能精确到行
----> module会将loader的source map加入
内联和外部的区别:1. 外部生成了文件,内联没有;2. 内联构建速度更快
开发环境:速度快,调试更友好
速度快:eval>inline>cheap>...
eval-cheap-source-map
eval-source-map
调试更友好
source-map
cheap-module-source-map
cheap-source-map
--> eval-source-map / eval-cheap-module-source-map
生产环境:源代码要不要隐藏?调试要不要更友好?
内联会让代码体积变大,所以在生产环境不用内联
nosources-source-map 全部隐藏
hidden-source-map 只隐藏源代码,会提示构建后代码错误信息
--> source-map / cheap-module-source-map
module.exports = {
...,
devtool: 'source-map';
}
3.2 生产环境性能优化
3.2.1 优化打包构建速度
3.2.1.1 oneof
const { resolve } = require('path');
const commonCssLoader = [
MiniCssExtractPlugin.loader,
'css-loader',
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [
// postcss的插件
require('postcss-preset-env')()
]
}
}
];
module.exports = {
entry: './src/index.js',
output: {
filename: 'js/build.js',
path: resolve(__dirname, 'build')
},
modules: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
enforce: 'pre',
loader: 'eslint-loader',
options: {
fix: true
}
},
{
// 一个文件只会匹配一个loader,匹配到了不会向下继续匹配
oneof: [
{
test: /\.css$/,
use: [...commonCssLoader]
},
{
test: /\.less$/,
use: [
...commonCssLoader,
'less-loader'
]
},
{
test: /\.(jpg|png|gif)$/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
esModule: false,
name: '[hash:10].[ext]',
outputPath: 'imgs'
}
},
{
test: /\.html$/,
loader: 'html-loader'
},
{
exclude: /\.(html|css|js|less|jpg|png|gif)$/,
loader: 'file-loader',
options: {
name: '[hash:10].[ext]',
outputPath: 'media'
}
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',
corejs: { version: 3 },
targets: {
chrome: '60',
firefox: '60',
ie: '9',
safari: '10',
edge: '17'
}
}
]]
}
}
]
}
]
},
// mode: 'development',
mode: 'production',
}
3.2.1.2 babel缓存
/*
babel缓存 --> 第二次打包构建速度更快
cacheDirectory: true
*/
module.exports = {
entry: './src/index.js',
output: {
filename: 'js/build.js',
path: resolve(__dirname, 'build')
},
modules: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [[
'@babel/preset-env',
{
useBuiltIns: 'usage',
corejs: { version: 3 },
targets: {
chrome: '60',
firefox: '60',
ie: '9',
safari: '10',
edge: '17'
}
}
]],
// 开启babel缓存
// 第二次构建时,会读取之前的缓存
cacheDirectory: true
}
}
]
}
}
3.2.1.3 多进程
module.exports = {
entry: './src/index.js',
output: {
filename: 'js/build.[contenthash:10].js',
path: resolve(__dirname, 'build')
},
modules: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: [
/*
开启多进程打包
进程启动大概为600ms,进程通信也有开销
只有工作消耗时间比较长,才需要多进程打包
*/
{
loader: 'thread-loader',
options: {
workers: 2 // 开启2个进程
}
},
{
loader: 'babel-loader',
options: {
presets: [[
'@babel/preset-env',
{
useBuiltIns: 'usage',
corejs: { version: 3 },
targets: {
chrome: '60',
firefox: '60',
ie: '9',
safari: '10',
edge: '17'
}
}
]],
// 开启babel缓存
// 第二次构建时,会读取之前的缓存
cacheDirectory: true
}
}
]
}
]
}
}
3.2.1.4 externals
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
// [name] 取文件名
filename: 'js/[name].[contenthash:10].js',
path: resolve(__dirname, 'build')
},
...
mode: 'production',
externals: {
// 拒绝jQuery被打包 -- npm包名
// 需要手动引入cdn - jQuery
jquery: 'jQuery'
}
}
3.2.1.5 dll
/*
使用dll技术,对某些库(第三方库:jquery、react、vue...)进行单独打包
当你运行webpack时,默认查找webpack.comfig.js配置文件
需要运行:webpack.dll.js文件
--> webpack --config webpack.dll.js
*/
const { resolve } = require('path');
const webpack = require('webpack');
module.exports = {
entry: {
// 最终打包生成的[name] --> jquery
// ['jquery'] --> 要打包的库是jquery
jquery: ['jquery']
},
output: {
filename: '[name].js',
path: resolve(__dirname, 'dll'),
library: '[name]_[hash]', // 打包库里面向外暴露出去的内容叫什么名字
},
plugins: [
// 打包生成一个manifest.json --> 提供和jquery映射
new webpack.DllPlugin({
name: '[name]_[hash]', // 映射库的暴露的内容名称
path: resolver(__dirname, 'dll/manifest.json') // 输出文件路径
})
],
mode: 'production'
}
// webpack.config.js
const webpack = require('webpack');
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');
plugins: [
...
new webpack.DllReferencePlugin({
// 告诉webpack哪些库不参与打包,同时使用时的名称也得变
manifest: resolve(__dirname, 'dll/manifest.json')
}),
// 将某个文件打包输出去,并在html中自动引入该资源
new AddAssetHtmlWebpackPlugin({
filepath: resolve(__dirname, 'dll/jquery.js')
})
]
3.2.2 优化代码运行的性能
3.2.2.1 文件缓存
/*
文件资源缓存 --> 让代码上线运行缓存更好使用
问题:强缓存命中,无法获取最新资源
hash:每次webpack构建时会生产唯一的hash值
问题:因为js和css同时使用一个hash值,如果重新打包,会导致所有缓存失效(无论改动几个文件)
chunkhash:根据chunk生产的hash值,如果打包来源于同一个chunk,那么hash值就一样
问题:js和css的hash值还是一样的,因为css时在js中被引入的,所以同属于一个chunk
contenthash:根据文件内容生产hash值,不同文件hash值一定不一样
*/
module.exports = {
entry: './src/index.js',
output: {
// filename: 'js/build.[hash:10].js',
// filename: 'js/build.[chunkhash:10].js',
filename: 'js/build.[contenthash:10].js',
path: resolve(__dirname, 'build')
},
...
}
3.2.2.2 tree shaking
/*
tree shaking:去除无用代码
前提:1. 必须使用ES6模块化
2. 开启production环境
作用:减少代码体积
在package.json中配置
"sideEffects": false 所有代码都没有副作用(都可以进行tree shaking)
问题:可能会把css、/@babel/polyfill文件干掉
"sideEffects": ["*.css", "*.less"]
*/
3.2.2.3 code split
// demo1
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// 单入口
// entry: './src/index.js',
entry: {
// 多入口:输出多个bundle
index: './src/index.js',
test: './src/test.js'
},
output: {
// [name] 取文件名
filename: 'js/[name].[contenthash:10].js',
path: resolve(__dirname, 'build')
},
...
}
// demo2
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// 单入口
//entry: './src/index.js',
entry: {
// 多入口:输出多个bundle
index: './src/index.js',
test: './src/test.js'
},
output: {
// [name] 取文件名
filename: 'js/[name].[contenthash:10].js',
path: resolve(__dirname, 'build')
},
/*
1. 可以将node_modules中代码单独打包一个chunk最终输出
2. 自动分析,多入口文件中有没有公共的文件,如果有会打包成一个单独的chunk
*/
optimization: {
splitChunks: {
chunks: all
}
}
...
}
// demo3
/*
基于webpack配置optimization,通过js代码,让某个文件被单独打包成一个chunk
import动态导入语法:能将某个文件单独打包
*/
// 限定名字
import(/*webpackChunkName: 'test'*/'./test')
.then(result => { })
.catch(() => { })
3.2.2.4 lazy loading
// 基于3.2.1.4代码分割实现懒加载
document.getElementById('btn').onclick = function(){
// 懒加载:当文件需要使用时才加载
// 预加载 prefetch:会在使用之前,提前加载js文件
// 正常加载可以认为是并行加载(同一时间加载多个文件)
// 预加载会等其他资源加载完毕,浏览器空闲了,再偷偷加载资源
import(/*webpackChunkName: 'test', webpackPrefetch: true*/'./test')
.then(({mul}) => {
console.log(mul(4,5))
})
}
3.2.2.5 PWA
/*
PWA:渐进式网络开发应用程序(离线可访问)
workbox --> workbox-webpack-plugin
*/
const WorkboxWebpackPlugin = require('workbox-webpack-plugin');
module.exports = {
...
plugins: [
...
/*
1. 帮助serviceworker快速启动
2. 删除旧的serviceworker
生成一个serviceworker配置文件
*/
new WorkboxWebpackPlugin.GenerateSW({
clientsClaim: true,
skipWaiting: true
})
]
}
/*
1. eslint不认识window、navigator全局变量
解决:需要修改package.json中eslintConfig配置
"env": {
"brower": true // 支持浏览器端全局变量
}
2. sw代码必须运行在服务器上
--> nodejs
--> npm i serve -g
serve -s build 启动服务器,将build目录下的所有资源作为静态资源暴露出去
*/
// index.js 入口文件
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker
.register('/service-worker.js')
.then(() => { })
.catch(() => { })
})
}
四、webpack配置详解
4.1 entry
/*
entry: 入口起点
1. string --> './src/index.js'
打包形成一个chunk,输出一个bundle文件。
此时chunk的默认名称是main
2. array --> ['./src/js', './src/add.js']
多入口
所有入口文件最终只会形成一个chunk,输出一个bundle文件
--> 一般用于HMR功能中让html热更新生效
3. object
多入口
有几个入口文件就形成几个chunk,输出几个bundle文件
此时chunk的名称是key
--> 特殊用法 3里面包含1+2两种形式
*/
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
// entry: './src/index.js',
// entry: ['./src/index.js', './src/add.js'],
entry: {
// index: './src/index.js',
index: ['./src/index.js', './src/add.js'],
add: './src/add.js'
},
output: {
filename: '[name].js'
path: resolve(__dirname, 'build')
},
plugins: [new HtmlWebpackPlugin()],
mode: 'development'
}
4.2 output
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: './src/index.js',
output: {
// 文件名称(指定名称+目录)
filename: 'js/[name].js'
// 输出文件目录(将来所有资源输出的公共目录)
path: resolve(__dirname, 'build')
// 所有资源引入公共路径前缀: 'imgs/a.jpg' --> '/imgs/a.jpg'
publicPath: '/',
chunkFilename: '[name]_chunk.js', // 非入口chunk的名称
// library: '[name]', // 整个库向外暴露的变量名 + 一般结合dll一起使用
// libraryTarget: 'window' // 变量名添加到哪个上 browser
// libraryTarget: 'global' // 变量名添加到哪个上 node
// libraryTarget: 'commonjs' // 模块化语法
},
plugins: [new HtmlWebpackPlugin()],
mode: 'development'
}
4.3 module
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: './src/index.js',
output: {
filename: 'js/[name].js'
path: resolve(__dirname, 'build')
},
module: {
rules: [
// loader的配置
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.js$/,
// 排除node_modules下的js文件
exclude: /node_modules/,
// 只检查src下的js文件
include: resolve(__dirname, 'src'),
// 优先执行
enfore: 'pre',
// 延后执行
// enfore: 'post',
// 单个loader使用loader
loader: 'eslint-loader',
options: {}
},
{
// 一下配置只会生效一个
oneof: []
}
]
},
plugins: [new HtmlWebpackPlugin()],
mode: 'development'
}
4.4 resolve
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: './src/index.js',
output: {
filename: 'js/[name].js'
path: resolve(__dirname, 'build')
},
module: {
rules: [
// loader的配置
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
]
},
plugins: [new HtmlWebpackPlugin()],
mode: 'development',
// 解析模块的规则
resolve: {
// 配置解析模块路径别名: 简写路径
alias: {
$css: resovle(__dirname, 'src/css')
},
// 配置省略文件路径的后缀名
extensions: ['js', 'json', 'css', 'jsx'],
// 告诉webpack解析模块是去找哪个目录
modules: [resolve(__dirname, '../../node_modules'), 'node_modules']
}
}
4.5 devServer
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: './src/index.js',
output: {
filename: 'js/[name].js'
path: resolve(__dirname, 'build')
},
module: {
rules: [
// loader的配置
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
]
},
plugins: [new HtmlWebpackPlugin()],
mode: 'development',
devServer: {
// 运行代码的目录
contentBase: resolve(__dirname, 'build'),
// 见识contenBase目录下的所有文件,一旦文件变化就会reload
watchContentBase: true,
watchOptions: {
// 忽略文件
ignored: /node_modules/
},
// 启动gzip压缩
compress: true,
// 端口号
port: 5000,
// 域名
host: 'localhost',
// 自动打开浏览器
open: true,
// 开启HMR功能
hot: true,
// 不要显示启动服务器日志信息
clientLogLevel: 'none',
// 除了一些基本启动信息以外,其他内容都不要显示
quiet: true,
// 如果出错了,不要全屏提示
overlay: false,
// 服务器代理 --> 解决开发环境跨域问题
proxy: {
// 一旦devServer(5000)服务器接收到/api/xxx的请求,就会把请求转发到另一个服务器
'/api': {
target: 'http://localhost:3000',
// 发送请求时,请求路径重写:将/api/xx --> /xxx;(去掉/api)
pathRewrite: {
'^/api': ''
}
}
}
}
}
4.6 optimization
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const TerserWebpackPlugin = require('terser-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'js/[name].js'
path: resolve(__dirname, 'build')
},
module: {
rules: [
// loader的配置
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
]
},
plugins: [new HtmlWebpackPlugin()],
mode: 'production',
optimization: {
splitChunks: {
chunks: 'all',
// 以下为默认值
/*
minSize: 30 * 1024, // 分割的chunk最小为30kb
maxSize: 0, // 最大没有限制
minChunks: 1, // 要提取的chunk最少被引用1次
maxAsyncRequests: 5, // 按需加载时并行加载的文件最大数量
maxInitialRequests: 3, // 入口js文件最大并行请求数量
automaticNameDelimiter: '~', // 名称链接符
name: true, // 可以使用命名规则
cacheGroups: {
// 分割chunk的组
// node_modules文件会被打包到wendors组的chunk中。 --> vendors~xxx.js
// 满足上面的公共规则,如:大小超过30kb,至少被引用一次
vendors: {
test: /[\\/]node_modules[\\/]/,
// 优先级
priority: -10
},
default: {
// 要提取的chunk最少被引用2次
minChunks: 2,
// 优先级
priority: -20,
// 如果当前要打包的模块,和之前已经被提取的模块是同一个,就会复用
reuseExistingChunk: true
}
}
*/
},
// 将当前模块的记录其他模块的hash单独打包为一个文件runtime
// 解决:修改a文件导致b文件的contenthash变化
runtimeChunk: {
name: entrypoint => `runtime-${entrypoint.name}`
},
minimizer: {
// 配置生成环境的压缩方案:js和css
new TerserWebpackPlugin({
// 开启缓存
cache: true,
// 开启多线程打包
parallel: true
// 启动source-map
sourceMap: true
})
}
}
}
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!