小菜之前写过关于浏览器是如何缓存的nginx 缓存,感兴趣的小伙伴们可以看看。在前面小菜写的配置都是如何去缓存

//build/output.js

const srcPath = require('./base/path');
const config = require('./base/config');

let output = {
	path: srcPath.dist,
	filename: '[name].[hash].js',
	publicPath: config.publicPath
}

module.exports = output;

如果output.js中这样写filename:'[name].[hash].js',每次打包都会重新生成js文件(文件名不重名),上传到服务器,用户在客户端上刷新都会重新从服务器上拉取js文件,这样就会造成请求资源浪费。

1.演示

安装loadsh

之前没有安装过loadsh库伙伴需要安装一下

yarn add loadsh

index.js

import _ from 'loadsh';

let arr = ['hello','world'];

let str = _.join(arr,'--');
console.log(str)

编译webpack

yarn run prod

ssl

修改index.js

import _ from 'loadsh';

+  let arr = ['hello','wali'];

let str = _.join(arr,'--');
console.log(str)

编译webpack

yarn run prod

ssl

从上面两个截图可以发现,当我们修改index.js文件的代码后,重新打包生成main.jsvendors~main后面的hash值变了。因为我们修改index.js文件的代码,在index.js中引用的第三方库文件,loadsh是不需修改的,所以打包后我们希望mian.js的hash值变,而vendors~main的hash值不变。

2.配置webpack

为了实现上面的功能,我们需要对webpack配置做一些改变

build/output.js

const dirPath = require('./base/path');
const config = require('./base/config');

let output = {
	path:dirPath.dist,
+	filename: config.NODE_ENV == 'development'?'[name].js':'[name].[contenthash].js',
+	chunkFilename: config.NODE_ENV == 'development'?'[name].js':'[name].[contenthash].js',
	publicPath: config.publicPath
}

module.exports = output

build/optimization.js

let optimization = {
	usedExports: true,
	splitChunks: {
		chunks: 'all',
		minSize: 30000,
		maxSize: 0,
		minChunks: 1,
		maxAsyncRequests: 5,
		maxInitialRequests: 3,
		automaticNameDelimiter: '~',
		name: true,
		cacheGroups: {
			vendors: {
				test: /[\\/]node_modules[\\/]/,
				priority: -10
			},
			default: {
				minChunks: 2,
				priority: -20,
				reuseExistingChunk: true
			}
		}
	},
+	runtimeChunk:{
+		name: entrypoint => `runtimechunk~${entrypoint.name}`
+	}
}

module.exports = optimization

build/plugins.js

const dirpath = require('./base/path');
const config = require('./base/config');

const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');    //生成html文件
const { CleanWebpackPlugin } = require('clean-webpack-plugin');  //清除
const MiniCssExtractPlugin = require("mini-css-extract-plugin");  //css样式提取


let plugins = [
	new HtmlWebpackPlugin({
		title: '瓦力博客',
		template: dirpath.src + '/index.html'   //以src/index.html为编译模板
	}),
	new  MiniCssExtractPlugin({
		filename: config.NODE_ENV == 'development'?'[name.css]': `${dirpath.css}/[name].[hash].css`,
		chunkFilename: config.NODE_ENV == 'development'?'[id].css': `${dirpath.css}/[id].[hash].css`
	}),   //css提取
	new CleanWebpackPlugin(),
-	new webpack.HotModuleReplacementPlugin()	
]

+ if('development' == config.NODE_ENV){
+	plugins.push(new webpack.HotModuleReplacementPlugin());
+ }

module.exports = plugins;

index.js

import _ from 'loadsh';

let arr = ['hello','world'];

let str = _.join(arr,'--');
console.log(str)

运行webpack

yarn run prod

ssl

修改index.js

import _ from 'loadsh';

+ let arr = ['hello','wali'];

let str = _.join(arr,'--');
console.log(str)

运行webpack

yarn run prod

ssl

从上面两张截图中可以看出来,当我们修改index.js文件内容。main.js后面的hash值发生改变,vendors~main.js后面hash值保持不变。当用户在浏览页面时,我们修改本地代码,打包上传后,用户刷新浏览器,浏览器只会请求hash改变的js文件,而hash值没变的文件依旧从浏览器缓存读取。

3.总结

写本小节的时候,小菜遇到了两个问题,分享给大家

[contenthash]打包报错

小菜在调式时,直接在build/output.js文件中这样写

let output = {
	path:dirPath.dist,
+	filename: '[name].[contenthash].js',
+	chunkFilename: '[name].[contenthash].js',
	publicPath: config.publicPath
}

在运行yarn run prod报错,报错信息

ERROR in chunk runtimechunk~main [entry]
[name].[contenthash].js
Cannot use [chunkhash] or [contenthash] for chunk in '[name].[contenthash].js' (use[hash] instead)

不能使用[chunkhash][contenthash]在网上找到资料解决连接。在用new webpack.HotModuleReplacementPlugin()热更新插件的时候是不能使用[chunkhash][contenthash],所以小菜build/plugins.js中修改配置,添加了判断,只有在development模式下才在使用new webpack.HotModuleReplacementPlugin(),然后在output.js中添加判断,问题就解决了

const dirPath = require('./base/path');
const config = require('./base/config');

let output = {
	path:dirPath.dist,
+	filename: config.NODE_ENV == 'development'?'[name].js':'[name].[contenthash].js',
+	chunkFilename: config.NODE_ENV == 'development'?'[name].js':'[name].[contenthash].js',
	publicPath: config.publicPath
}

module.exports = output

运行yarn run dev命令本地服务器不来

说起来很搞笑,按道理到上面配置基本都没问题了,小菜就运行yarn run dev启动本地服务,发现页面起不来

ssl

   

ssl

这个问题排查了很久,最终发现小菜在build/base/config.js中将

let _mode = process.argv[process.argv.length - 1];
let env = _mode.replace(/--mode=(.+)/g,"$1");

let config = {
	NODE_ENV: env == 'development'?'development':'production',  //development 开发 production 线上
-	publicPath: env == 'development'?'./':'http://www.waliblog.com',
+	publicPath: env == 'development'?'/':'http://www.waliblog.com',
	apiUrl:'http://www.waliblog.com',
	port: 9999
}

module.exports = config;

本地服务路径./弄错了,所以服务起起来但是一直找不到根路径,页面也无法访问。当时这么写是因为想在生成index.html查看路径,后面一直没有改才会碰到这个问题。这个问题找到后,小菜将webpack-14这节配置重新写了一遍,之后又重新跑了一遍,所以小伙伴们可能遇不到我这个问题。

webpack4.x 教程

webpack 准备工作(1) webpack 手写最基本的配置(2) webpack 打包样式(3) webpack 让打包更便捷(4) webpack 打包图片(5) webpack iconfont打包(6) webpack devServer本地开发(7) webpack 处理ES6语法(8) webpack SourceMap配置(9) webpack Tree Shaking(10) webpack js代码分割(11) webpack 懒加载(12) webpack 打包分析,Preloading,Prefetching(13) webpack 模块化区分开发和生产(14) webpack 样式文件的代码分割(15) webpack 浏览器缓存(16) webpack shimming(17) webpack 环境变量(18) webpack Esline(19)