携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第16天,点击查看活动详情
缓存
webpack打包后生成 dist 目录,然后启动服务器就可以访问这个目录里的资源了。浏览器会自动缓存 dist 目录的资源,当我们修改代码后,重新去获取资源,如果有 100 个资源,修改了 1 个,就没有必要去重新获取所有资源,所以通过必要的配置,以确保 webpack 编译生成的文件能够被客户端缓存,而在文件内容变化后,能够请求到新的文件。
webpack.config.js
output: {
path: path.join(__dirname, "./dist"),
//contenthash:每个文件都会根据内容生成hash,所以各个文件之间肯定不一样
filename: "[name].[contenthash].bundle.js",
clean: true,
assetModuleFilename: "images/[name]-[contenthash][ext]",
},
文件保存后,再重新打包时,如果文件内容有修改,hash就肯定不一样,如果没修改,hash就还是之前那个。
像一些
nod_modules的第三方库,不用频繁被修改,就可以提取出来长期缓存,减少服务器请求资源。
webpack.config.js
runtimeChunk: "single", //值 "single" 会创建一个在所有生成 chunk 之间共享的运行时文件
moduleIds: "deterministic", //文件代码修改才会重新打包
splitChunks: {
//缓存组
cacheGroups: {
vendors: {
test: /[\/]node_modules[\/]/,
name: "vendors",
chunks: "all",
}
},
},
执行
npm run build看看效果吧
生产环境
development(开发环境) :强大的 source map 和一个有着 live reloading(实时重新加载) 或 hot module replacement(热模块替换) 能力的 localhost server。
production(生产环境) 压缩 bundle、更轻量的 source map、资源优化等,通过这些优化方式改善加载时间。
通常建议为每个环境编写彼此独立的 webpack 配置。
-
安装
webpack-merge,终端执行npm i webpack-merge,创建三个配置文件webpack.common.js、webpack.dev.js、webpack.pros.js -
在 webpack.common.js 文件中
const path = require("path"); //引入html打包插件 const HtmlWebpackPlugin = require("html-webpack-plugin"); //引入独立css文件的插件 const MiniCssExtractPlugin = require("mini-css-extract-plugin"); //压缩css const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); const toml = require('toml'); const yaml = require('yamljs'); const json5 = require('json5'); module.exports = { //代码分离方式一 // entry: { // index: { // import: "./src/index.js", // dependOn: "shared", // }, // welcome: { // import: "./src/welcome.js", // dependOn: "shared", // }, // shared: ["jquery", "./src/CalcArea.js"], // }, entry: { index: "./src/index.js", welcome: "./src/welcome.js", }, output: { path: path.join(__dirname, "./dist"), //出口路径必须是绝对路径 // name是入口文件的key // hash随机生成的字符串 filename: "[name].[contenthash].bundle.js", clean: true, // 每次打包都会删除上次打包的文件 //配置图片文件的打包路径和文件名 assetModuleFilename: "images/[name]-[contenthash][ext]", }, // watch: true, //监听代码修改,保存后自动重新打包 //创建本地服务器 devServer: { static: { directory: path.join(__dirname, "./dist"), }, //使用gzip压缩 compress: true, port: 8080, // open配置服务器打开时,自动打开的页面 // open: true, // host: "0.0.0.0", //默认值 hot: true, //热更新 默认开启 // liveReload: false, //热加载 默认开启 proxy: { "/abc": { target: "http://localhost:3000", pathRewrite: { "/abc": "" }, }, }, }, module: { rules: [ //编译css文件 { test: /.css$/, use: [MiniCssExtractPlugin.loader, "css-loader"], }, { test: /.txt$/, use: ["raw-loader"], }, { test: /.(png|jpg|jpeg|gif|svg|webp)$/, type: "asset", parser: { dataUrlCondition: { maxSize: 10 * 1024, }, }, // 比assetModuleFilename优先高,就近原则 // generator: { // filename: "imgs/[name][ext]", // }, }, { test: /.(woff|woff2|eot|ttf|otf)$/i, type: "asset/resource", generator: { filename: "fonts/[name][ext]", }, }, { test: /.(csv|tsv)$/i, use: ["csv-loader"], }, { test: /.xml$/i, use: ["xml-loader"], }, { test: /.toml$/i, type: "json", parser: { parse: toml.parse, }, }, { test: /.(yaml|yml)$/i, type: "json", parser: { parse: yaml.parse, }, }, { test: /.json5$/i, type: "json", parser: { parse: json5.parse, }, }, ], }, resolve: { alias: { "@": path.resolve(__dirname, './src') }, extensions: ['.js', '.json'], }, optimization: { usedExports: true, // runtimeChunk: "single", //值 "single" 会创建一个在所有生成 chunk 之间共享的运行时文件 minimizer: [ // 在 webpack@5 中,你可以使用 `...` 语法来扩展现有的 minimizer(即 `terser-webpack-plugin`) `...`, new CssMinimizerPlugin(), ], //第二种代码分离 // splitChunks: { // chunks: "all", // minSize: 10, //设置能够打包的最小体积,默认是20000Bytes // minChunks: 2, //打包的模块的最小引用次数,默认是1 // name: "vendors" //指定output中打包文件的name // }, moduleIds: "deterministic", //文件代码修改才会重新打包 splitChunks: { //缓存组 cacheGroups: { vendors: { test: /[\/]node_modules[\/]/, name: "vendors", chunks: "all", }, // commons: { // test: /src/, // name: 'commons', // chunks: 'all', // minSize: 10, // }, }, }, }, plugins: [ //创建一个实例,打包html文件 new HtmlWebpackPlugin({ //以路径中的文件为模板 template: "./src/index.html", filename: "index.html", inject: "body", }), new MiniCssExtractPlugin({ filename: "index.css", }), ], //CDN方式代码分离 // externalsType: "script", // externals: { // jquery: ["https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js", "$"], // }, }; -
在 webpack.dev.js 文件中
const { merge } = require('webpack-merge'); const common = require('./webpack.common.js'); const path = require("path"); module.exports = merge(common, { mode: 'development', //源码映射 devtool: "inline-source-map", //创建本地服务器 devServer: { static: { directory: path.join(__dirname, "./dist"), }, //使用gzip压缩 compress: true, port: 8080, // open配置服务器打开时,自动打开的页面 // open: true, // host: "0.0.0.0", //默认值 // hot: true, //热更新 默认开启 liveReload: true, //热加载 默认开启 proxy: { "/abc": { target: "http://localhost:3000", pathRewrite: { "/abc": "" }, }, }, }, module: { rules:[ //使用babel将ES6+代码转换成ES5的代码 { test: /.m?js$/, exclude: /node_modules/, use: { loader: "babel-loader", }, }, ] } }); -
在 webpack.prod.js 文件中
const { merge } = require('webpack-merge'); const common = require('./webpack.common.js'); module.exports = merge(common, { mode: 'production', }); -
在 package.json 文件中
"serve": "webpack serve --config ./webpack.prod.js", "start": "webpack --config ./webpack.prod.js", "build": "webpack --config ./webpack.dev.js",
上面的配置几乎包含了全部基础配置
开发环境执行
npm run build生产环境执行
npm run serve
Tree Shaking
在打包时有些没有使用到的模块也会被打包进dist目录,造成了资源的浪费,所以需要移除 JavaScript 上下文中的未引用代码(dead-code)。
配置也非常简单,在webpack.common.js中
optimization:{
usedExports: true,
}
sideEffects
"side effect(副作用)" 的定义是,在导入时会执行特殊行为的代码,而不是仅仅暴露一个 export 或多个 export。也就是尽管导出并在另一个文件导入了这个模块,如果没有使用,还是会被删除。
在 package.json 文件中
"sideEffects": false
注意,所有导入文件都会受到 tree shaking 的影响。这意味着,如果在项目中使用类似 css-loader 并 import 一个 CSS 文件,则需要将其添加到 side effect 列表中,以免在生产模式中无意中将它删除:
"sideEffects": ["*.css",……你不想被删除的模块]
Shimming 预置依赖
shimming预置全局变量
在webpack.common.js文件中
const webpack = require("webpack");
//在plugins数组中
new webpack.ProvidePlugin({
$: 'jquery',
join: ["lodash","join"]
}),
现在可以不用导入jQuery模块,在任何地方使用 $ 来使用jQuery了,还可以直接将模块的方法变成全局方法,在任何地方都可以直接使用lodash的join方法了
细粒度 Shimming
假设index.js中有如下代码:
// 假设我们处于 `window` 上下文
this.alert('hello world')
此时用服务器打开,hello world并没有弹出,是因为此时的this是指向
module.exports这个对象,并没有指向window。
在webpack.common.js文件中
module: {
rules: [
{
test: require.resolve('./src/index.js'),
use: 'imports-loader?wrapper=window',
},
],
},
通过使用
imports-loader覆盖this指向,此时在指向命令打开服务器就可以看到弹出 hello world 了。
小结
webpack完,官网webpack