多页面项目优化webpack打包降低上线风险

947 阅读5分钟

目前的问题

项目中有多个入口,某些入口会提供出去给其他项目使用。这就要求项目的稳定性要高,如果出了问题可能会导致其他的相关联项目也无法正常使用。(要背锅)

由于目前整个项目的打包文件用的同一套版本号,导致当对某个组件进行了修改,进行打包后,所有模块的版本号都会更新,缓存将不能使用,所有模块都将更新,这会给项目上线带来一些风险。

不得不每次上线之后都去对所有的服务进行验证,哪怕是不涉及改动的,由于版本号更新了,也需要再去线上验证一下有没有问题。

目标

优化webpack打包配置,不同入口所打包出来的文件使用独立的版本号,只有当该入口所引用的文件内容被修改时,才对该入口重新打包的文件的版本号进行更新;所引用文件内容未被修改时,该入口打包文件的版本号不变。(概括为:改了才更新,不改不更新)

这样一来,就不用担心修改了项目某些组件后对其他的提供出去的服务造成影响,降低项目上线风险。

分析项目目前的webpack打包配置

目前项目的webpack配置如下,这里打包后文件名中版本号用的hash,hash跟整个项目的构建相关,所有文件哈希值相同,当项目中有文件被更改后,hash会改变,重新打包后所有打包文件的文件名中的版本号也会统一改为新的哈希值

//webpack.config.prod.js

var webpack = require('webpack');
var path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
var config = {
    entry:{
        index :__dirname + "/src/scripts/entries/Index.js",
        test :__dirname + "/src/scripts/entries/Test.js",
        main:__dirname + '/src/scripts/entries/main.js',
        weixin:__dirname + '/src/scripts/entries/weixin.js',
        jsbridge:__dirname + '/src/scripts/entries/jsbridge.js'
    },
    output: {
        path: path.resolve( __dirname,"dist"),
        publicPath: '/dist/',
        filename: '[name]-[hash:7].js'
    },

    ......//省略其他配置

    plugins: [
        new CleanWebpackPlugin(),
        new MiniCssExtractPlugin({
            filename: "[name]-[hash:7].css",
          })
    ]
};
module.exports = config;

目前使用hash作为文件打包版本号的打包效果

运行npm run build 打包后如下图可以看到,所有打包后的文件的文件名中的版本号都是一样的。

目前使用的hash作为版本号

更改test.js的内容,再次打包如下图,可以看到,哪怕是仅仅只修改了test.js,所有文件的哈希值都变了。

使用chunkhash作为文件打包版本号

经了解,webpack中关于缓存,还提供了其他的添加哈希值的方法:chunkhash

chunkhash可以根据模块内容来添加哈希值,只要模块内容没有变,就不会生成新的哈希值。emm,这貌似是我们想要的。

修改webpack配置如下:将hash替换为chunkhash

//webpack.config.prod.js

var webpack = require('webpack');
var path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
var config = {
    entry:{
        index :__dirname + "/src/scripts/entries/Index.js",
        test :__dirname + "/src/scripts/entries/Test.js",
        main:__dirname + '/src/scripts/entries/main.js',
        weixin:__dirname + '/src/scripts/entries/weixin.js',
        jsbridge:__dirname + '/src/scripts/entries/jsbridge.js'
    },
    output: {
        path: path.resolve( __dirname,"dist"),
        publicPath: '/dist/',
        filename: '[name]-[chunkhash:7].js'
    },

    ......//省略其他配置

    plugins: [
        new CleanWebpackPlugin(),
        new MiniCssExtractPlugin({
            filename: "[name]-[chunkhash:7].css",
          })
    ]
};
module.exports = config;

运行npm run build 打包后如下图可以看到,不同模块的打包文件使用了不同的哈希值。

更改test.js的内容,再次打包如下图,可以看到,test模块的打包文件发生了改变,其他模块的打包没有改变,nice啊,这就是我们想要的!

这样就可以做到只更新内容被修改了的模块而不影响其他模块的代码了,真棒!

使用contenthash作为文件打包版本号

使用chunkhash作为文件打包版本号,貌似已经解决了我们的问题,但是他还是有一点小小的缺陷,当我们只修改了test.js时,css部分的文件也被重新打包更新了,这样貌似不太好。

这是由于test.css被test.js引用了,所以共用相同的chunkhash值,如果test.js更改了代码,css文件就算内容没有任何改变,由于是该模块发生了改变,导致css文件会重复构建。

查询资料后学习到,我们可以使用contenthash来解决这个问题。

修改webpack配置如下:将css部分的chunkhash替换为contenthash

//webpack.config.prod.js

var webpack = require('webpack');
var path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
var config = {
    entry:{
        index :__dirname + "/src/scripts/entries/Index.js",
        test :__dirname + "/src/scripts/entries/Test.js",
        main:__dirname + '/src/scripts/entries/main.js',
        weixin:__dirname + '/src/scripts/entries/weixin.js',
        jsbridge:__dirname + '/src/scripts/entries/jsbridge.js'
    },
    output: {
        path: path.resolve( __dirname,"dist"),
        publicPath: '/dist/',
        filename: '[name]-[chunkhash:7].js'
    },

    ......//省略其他配置

    plugins: [
        new CleanWebpackPlugin(),
        new MiniCssExtractPlugin({
            filename: "[name]-[contenthash:7].css",
          })
    ]
};
module.exports = config;

运行npm run build 打包后如下图可以看到,相同模块的js文件和css文件也拥有了不同的哈希值。

更改test.js的内容,再次打包如下图,可以看到,test模块的js文件发生了改变,而css文件没有发生改变

更改test.css的内容,再次打包如下图,可以看到,test模块的css文件发生了改变,而js文件没有发生改变,nice!完美解决了问题。

总结

  • 使用hash:所有文件的哈希值都会相同;
  • 使用chunkhash:会根据不同的入口文件生成对应的哈希值;
  • 使用contenthash:计算出的哈希值与文件内容本身相关,主要用在抽取css文件时;
  • 这里采用chunkhash + contenthash 达到了我们想要的模块独立更新的效果,降低了项目上线更新的风险。