抽空研究了下umi代码非覆盖式打包部署将产物按环境 + 发布版本做隔离 & 收敛。

564 阅读2分钟

参考文章出处来自字节架构前端

基于当前项目部署完全依赖于package.json的scripts命令执行scp操作对代码进行推送时,发现被content-hash命名的的静态资源随着推送操作越来越多,混乱存放的历史代码非常难以管理,开始尝试做一下版本和内容隔离。

一开始的我的思路是每次推送代码到服务器之前,先把之前存放在服务器的资源文件夹删除掉,再把新的代码推送上去,但是这样也意味着服务器上的历史代码随着每次推送都会被销毁掉,一旦需要回滚代码,就需要从git进行回滚操作,并进行重新编译发布等流程。

基于上述的问题我开始尝试在umi架构的项目上能否通过一些打包配置将产物按环境 + 发布版本做隔离 & 收敛。

基于package.json做环境区分

企业微信截图_16544815394433.png 这里的build之所以加上if判断是为了保证每次编译之前先去判断历史产物是否存在,如果存在就去删除本地的build产物,这里需要注意的是umi在每一次完成编译后会在.umi-production文件夹下留存历史编译产物,如果重新编译新版本产物的时候没有删掉,会出现打包出以前的产物的问题,每次去删掉历史产物,可以保证每次推送的都是最新的编译产物。cross-env用于指定环境变量

声明全局环境变量

image.png 基于umi文档内容先声明一下全局环境变量

image.png

配置webpack打包规则

找到.umirc.ts配置文件的chainWebpack属性,将打包配置写入,依赖moment时间库生成当前时间版本编码,配置文件夹命名

import moment from 'moment';
let UMI_ENV = process.env.UMI_ENV || 'dev';
const nowTime = moment().format('YYYYMMDDhhmmss');
const staticDir = `v${nowTime}`;
const isDev = process.env.NODE_ENV === 'development';
export default defineConfig({
  nodeModulesTransform: {
    type: 'none',
  },
  base: '/xxx/',
  publicPath: '/xxx/',
  fastRefresh: {},
  //mfsu: {}, //最新umi方案,提高启动服务时间
  webpack5: {},
  hash: true,
  // 页面标题
  title: '管理端',
  antd: false,
    chainWebpack(config, { webpack }) {
        if (UMI_ENV === 'prod') {
          // 修改css输出目录
          config.plugin('extract-css').tap(() => [
            {
              filename: `${staticDir}/css/[name].[contenthash:8].css`,
              chunkFilename: `${staticDir}/css/[name].[contenthash:8].chunk.css`,
              ignoreOrder: true,
            },
          ]);

          config.module
            .rule('css')
            .oneOf('css')
            .use('extract-css-loader')
            .tap((options) => ({
              publicPath: '公共静态资源路径',
              hmr: isDev,
            }));

          config.module
            .rule('less')
            .oneOf('css')
            .use('extract-css-loader')
            .tap((options) => ({
              publicPath: '公共静态资源路径',
              hmr: isDev,
            }));

          // 修改js输出目录
          config.output
            .filename(`${staticDir}/js/[name].[hash:8].js`)
            .chunkFilename(`${staticDir}/js/[name].[contenthash:8].chunk.js`);

          // 修改image输出目录
          config.module
            .rule('images')
            .test(/\.(png|jpe?g|gif|webp|ico)(\?.*)?$/)
            .use('url-loader')
            .loader(require.resolve('@umijs/deps/compiled/url-loader'))
            .options({
              name: `${staticDir}/[name].[hash:8].[ext]`,
              // require 图片的时候不用加 .default
              esModule: false,
              fallback: {
                loader: require.resolve('@umijs/deps/compiled/file-loader'),
                options: {
                  name: `${staticDir}/images/[name].[hash:8].[ext]`,
                  esModule: false,
                },
              },
            });

          // 修改svg输出目录
          config.module
            .rule('svg')
            .test(/\.(svg)(\?.*)?$/)
            .use('file-loader')
            .loader(require.resolve('@umijs/deps/compiled/file-loader'))
            .tap((options) => ({
              ...options,
              name: `${staticDir}/images/[name].[hash:8].[ext]`,
              esModule: false,
            }));

          // 修改font输出目录
          config.module
            .rule('fonts')
            .test(/\.(eot|woff|woff2|ttf)(\?.*)?$/)
            .use('file-loader')
            .loader(require.resolve('@umijs/deps/compiled/file-loader'))
            .options({
              name: `${staticDir}/fonts/[name].[hash:8].[ext]`,
              esModule: false,
            });
       }
   },
});

生成代码如下

image.png

服务器多次部署情况如下

image.png