npm i webpack-dev-server -D
"serve": "webpack serve"
devServer: {
static:['public','content']//默认配置就是 public
},
port 设置监听的端口,默认情况下是 8080
open 是否打开浏览器:
compress 是否为静态文件开启gzip compression:默认值是 false,可以设置为 true
一般使用默认值
设置代理来解决跨域访问的问题
配置
配置 proxy(node 的代理)
axios.get('/api/users/list')
devServer: {
static: ["public", "content"],
liveReload: false,
proxy: {
"/api": {
target: "http://localhost:9000",
pathRewrite: {
"^/api": "",
},
changeOrigin:true
},
},
},
解决 SPA 页面在路由跳转之后,进行页面刷新时,返回 404 的错误
boolean 值:默认是 false
object 类型的值,可以配置 rewrites 属性
事实上 devServer 中实现historyApiFallback功能是通过connect-history-api-fallback库的:可以查看connect-history-api-fallback 文档
webpack 和 react 都对应进行了设置
entry: {
main: "./src/main.js",
index:'./src/index.js'
},
打包出来的东西放在不同的文件里面
// placeholder占位
filename: "[name]-bundle.js",
entry: {
main: {
import: "./src/main.js",
dependOn: shared,
},
index: { import: "./src/index.js", dependOn: shared },
shared: ["axios", "dayjs"],
},
btn1.onclick = function(){import(/*webpackChunName:"about"*/'./router/about').then(res=>{log(res.about() res.default())})}
export {about}
export default about
output: {
path: path.resolve(__dirname, "./build"),
// placeholder占位
filename: "[name]-bundle.js",
// 单独针对分包的文件进行命名
// id:有不同的设置方法
// name:可以进行魔法注释
// chunkFilename: "[id]_[name]_chunk.js",
chunkFilename: "[id]_[name]_chunk.js",
},
## 9.6 SplitChunks
另外一种分包的模式是 splitChunk,它底层是使用 SplitChunksPlugin 插件来实现的
Webpack 提供了 SplitChunksPlugin 默认的配置,也可以手动来修改它的配置
// 优化配置
optimization: {
splitChunks: {
// chuncks:'async'默认为async
chuncks:'all' //不管是动态还是第三方都会单独分包
}
}
vue /react 都是:主包、懒加载、第三方库
// 优化配置
optimization: {
splitChunks: {
// chuncks:'async'默认为async
chunks: 'all', //不管是动态还是第三方都会单独分包,
// 当一个包大于指定的大小时,继续进行拆包
maxSize: 20000,
// 将包拆分成不能小于这个大小
minSize: 10000,//默认值是20kb
cacheGroups:{
vendors: {
// window 上 / 和 mac 上面/ 是不一样的
// [] 中列出所有的可能性
// test:/[\\/]node_modules[\\/]/,完整写法
test:/node_modules/,//只要路径有node_modules
filename:'[name]_vendors.js'
}
}
}
}
optimization: {
// 设置生成的chunkId的算法
// development:named
// production:deterministic(确定性)
// webpack4使用的是:natural
chunkIds:'named',
}
btn1.onclick = function () {
import(
/* webpackChunkName:"about" */
/* webpackPrefetch:true*/
"./router/about"
).then((res) => {
res.about();
res.default();
});
};
内容分发网络(Content Delivery Network 或 Content Distribution Network,缩写:CDN)
在开发中,使用 CDN 主要是两种方式
方式一:打包的所有静态资源,放到CDN服务器,用户所有资源都是通过 CDN 服务器加载的
output: {
path: path.resolve(__dirname, "./build"),
// placeholder占位
filename: "[name]-bundle.js",
clean: true,
publicPath: "http://lili.com/",
},
方式二:一些第三方资源放到 CDN 服务器上
// 排除某些包不需要进行打包
externsal: {
// key:排除的框架的名称
// value:从 cdn地址 中拿到的名字 (可能与框架不同 )
react: "React",
axios: "axios",
},
某一类功能的统称
shimming 翻译为垫片,相当于给代码填充一些垫片来处理一些问题
webpack 并不推荐随意的使用 shimming
ProvidePlugin 能够帮助在每个模块中,通过一个变量来获取一个 package
如果 webpack 看到这个模块,将在最终的 bundle 中引入这个模块
ProvidePlugin 是 webpack 默认的一个插件,所以不需要专门导入
注意 axios 使用时候是一个 module!需要使用 default ,才是默认导出的对象
plugins: [
new ProvidePlugin({
dayjs: "dayjs",
axios: ["axios", "default"],
}),
],
作用:将 css 提取到一个独立的 css 文件中,该插件需要在 webpack4+ 才可以使用
使用
npm i style-loader css-loader -D
{
test: /\.css$/,
use: [
"style-loader",
"css-loader"
]
}
npm install mini-css-extract-plugin -D
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
new MiniCssExtractPlugin({
// css/ 放在单独的文件夹里面
filename: "css/[name].css",
chunkFilename: "css/[name]_chunk.css",
}),
{
test: /\.css$/,
use: [
//'style-loader',内联的方式,开发阶段
MiniCssExtractPlugin.loader, //提取到 css 文件当中,通过 link 进行引入,生产阶段
],
},
新建一个项目
npm install pnpm -g
pnpm init
pnpm add webpack webpack-cli -D
webpack.config.js
"build": "webpack"
在给打包的文件进行命名的时候,会使用 placeholder 进行占位
hash 值的生成和整个项目有关系
chunkhash 可以有效的解决上面的问题,它会根据不同的入口来解析来生成 hash 值
contenthash 表示生成的文件 hash 名称,只和内容有关系
只要用到 hash 尽量使用 contenthash
# 全局安装
npm install terser -g
# 局部安装
npm install terser -D
使用:若需要进一步的优化,可以使用 -c xxxxx -m yyyyy
terser [input files] [options]
# 举例说明
npx terser js/file1.js -o foo.min.js -c -m
Compress 和 Mangle 的 options
npx terser ./src/abc.js -o abc.min.js -c
arrows,arguments=true,dead_code -m
// 顶层作用域中的变量名称,进行丑化 保持 类的名字 函数的名字
toplevel=true,keep_classnames=true,keep_fnames=true
Terser 在 webpack 中配置
真实开发中,不需要手动的通过 terser 来处理代码,可以直接通过 webpack 来处理
首先,需要打开 minimize,让其对代码进行压缩(默认production模式下已经打开了)
其次,可以在minimizer创建一个 TerserPlugin
npm install css-minimizer-webpack-plugin -D
minimizer:[
new TerserPlugin({})
]
创建 config 文件夹
comm.config.js: entry、output、resolve、module(loader)、plugins(垫片、html)
const path = require("path");
const { merge } = require("webpack-merge");
const devConfig = require("./dev.config");
const prodConfig = require("./prod.config");
const commonConfig = {
entry: "./src/main.js",
output: {
clean: true,
path: path.resolve(__dirname, "../build"),
filename: "[name]_[hash]_bundle.js",
chunkFilename: "[chunkhash]_chunk.js",
},
// 解决路径后缀名
resolve: {
extensions: [".js", ".json", ".wasm", ".jsx", ".ts"],
},
// module
// plugins
};
// webpack 允许导出一个函数
module.exports = function (env) {
const isProduction = env.production;
let mergeConfig = isProduction ? prodConfig : devConfig;
// if (isProduction) {
// mergeConfig = prodConfig;
// } else {
// mergeConfig = devConfig;
// }
console.log(env);
return merge(mergeConfig,commonConfig);
};
package.json 脚本中配置参数
"scripts": {
"build": "webpack --config ./config/comm.config.js --env production",
"serve": "webpack serve --config ./config/comm.config.js --env development"
},
const path = require("path");
module.exports = {
mode: "development",
// 本地 服务器
devServer: {
static: ['public', 'content'],
port: 3000,
compress: true,
proxy: {
'/api': {
target: "http://localhost:9000",
pathRewrite: {
'^/api':''
},
changeOrigin:true
}
},
historyApiFallback:true
},
}
const path = require("path");
module.exports = {
mode: "production",
// 分包优化的配置放在生产环境
// optimization
}
把多个 webpack 配置进行合并:npm i webpack-merge -D
MiniCssExtractPlugin.loader、css-loader
const path = require("path");
const { merge } = require("webpack-merge");
const devConfig = require("./dev.config");
const prodConfig = require("./prod.config");
const getCommonConfig = function (isProduction) {
return {
entry: "./src/main.js",
output: {
clean: true,
path: path.resolve(__dirname, "../build"),
filename: "[name]_[hash]_bundle.js",
chunkFilename: "[chunkhash]_chunk.js",
},
// 解决路径后缀名
resolve: {
extensions: [".js", ".json", ".wasm", ".jsx", ".ts"],
},
// module
module: {
rules: [
{
test: /\.css$/,
use: [isProduction ? MiniCssExtractPlugin.loader : "css-loader", "css-loader"],
},
],
},
// plugins
};
};
// webpack 允许导出一个函数
module.exports = function (env) {
const isProduction = env.production;
let mergeConfig = isProduction ? prodConfig : devConfig;
// if (isProduction) {
// mergeConfig = prodConfig;
// } else {
// mergeConfig = devConfig;
// }
console.log(env);
return merge(mergeConfig, getCommonConfig(isProduction));
};
usedExports:Tree Shaking 的核心,通过标记某些函数是否被使用,之后通过 Terser来进行优化
sideEffects:跳过整个模块/文件,直接查看该文件是否有副作用
sideEffects 用于告知 webpack compiler 哪些模块是有副作用的
import './demo'
在 package.json 中设置 sideEffects 的值
"sideEffects":[
"./src/util/format.js",
"*.css"//这个东西不能 treeShaking
]
比如有一个 format.js、style.css 文件
在编写模块的时候,尽量编写纯模块
最佳方案
npm install purgecss-webpack-plugin -D
npm install mini-css-extract-plugin@1.3.6 -D
const path = require("path");
const glob = require("glob"); //node 提供的模块:但是没有内置,需要自己安装:`npm i glob -D`
const { PurgeCSSPlugin } = require("purgecss-webpack-plugin");
module.exports = {
mode: "production",
// 分包优化的配置放在生产环境
// optimization
plugins: [
// 对 css 进行 tree shaking
new PurgeCSSPlugin({
// 立即去找所有文件夹下面的所有文件
// nodir:不是文件夹
paths: glob.sync(`${path.resolve(__dirname, "./src")}/**/*`, { nodir: true }),
// 白名单
safelist: function () {
return {
standard: ["body"],
};
},
}),
],
};
概念
默认情况下 webpack 打包会有很多的函数作用域,包括一些(比如最外层的)IIFE
配置该插件,会查看哪些代码可以进行作用域的提升
const path = require("path");
const webpack = require('webpack')
module.exports = {
plugins: [
// 作用域提升
new webpack.optimize.ModuleConcatenationPlugin()
],
mode: "development",
}
Content-Encoding
使用 CompressionPlugin:npm install compression-webpack-plugin -D
配置
new CompressionPlugin({
test:/\.(css|js)$/,// 匹配哪些文件需要压缩
minRatio:0.7,// 至少的压缩比例
algorithm:"gzip",// 压缩算法
})
压缩得很彻底了,剩下 html 文件
使用了 HtmlWebpackPlugin 插件来生成 HTML 的模板,这个插件还有一些其他的配置
inject:设置打包的资源插入的位置
true
false
body
head
cache:设置为 true ,只有当文件改变时,才会生成新的文件(默认值也是true)
minify:默认会使用一个插件 html-minifier-terser
生产环境进行压缩
开发环境不压缩
设置变量:isProduction
new HtmlWebpackPlugin({
// 配置模板
template: "./index.html",
minify: isProduction
? {
// 压缩的时候移除注释
removeComments: true,
// 移除属性:空属性么有意思
removeEmptyAttributes: true,
// 移除默认属性:可要可不要
removeRedundantAttributes: true,
// 折叠空行
collapseWhitespace: true,
// 压缩内联的 css
minifyCSS: true,
// 压缩 js
minifyJS: {
mangle: {
toplevel: true,
},
},
}
: false,
}),
借助于一个插件:speed-measure-webpack-plugin
安装:npm install speed-measure-webpack-plugin -D
const SpeedMeasurePlugin = require("speed-measure-plugin");
const smp = new SpeedMeasurePlugin();
smp.wrap(finalConfig);
exclude:/node_modules/
生成一个 stats.json 的文件
"buiebpack ld:stats": "w--config ./config/webpack.common.js --env production --profile --json=stats.json",
yarn --version
npm i tarn -g
yarn
grant dev
/npm run dev
npm i grunt -g
stats.json
文件进行上传使用 webpack-bundle-analyzer 工具
npm install webpack-bundle-analyzer -D
const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");
// 对打包后的结果进行分析
new BundleAnalyzerPlugin(),