umi 项目增加支持放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录,就比如 vue-cli 的 assetDir

简介:最近需要做一个后台系统,时间又比较充足,antd 和 Ant Design Pro 都已经升级到了 v4 ,于是就果断尝鲜了一波,遇到的问题也比较多,比较难解决的就是类似 vue-cli 的 assetDir 的问题,现把解决方案整理如下。

提示: 不要配置 config.optimization.splitChunks ,会导致 umi 项目运行失败。

1.项目主要依赖

package.json

1
{
2
  "dependencies": {
3
    "@ant-design/icons": "^4.0.0",
4
    "@ant-design/pro-layout": "^5.0.16",
5
    "@ant-design/pro-table": "2.3.4",
6
    "antd": "4.3.3",
7
    "axios": "^0.19.2",
8
    "braft-editor": "^2.3.9",
9
    "braft-polyfill": "^0.0.2",
10
    "classnames": "^2.2.6",
11
    "cropperjs": "^1.5.7",
12
    "font-awesome": "^4.7.0",
13
    "js-cookie": "^2.2.1",
14
    "js-md5": "^0.7.3",
15
    "lodash": "^4.17.11",
16
    "moment": "^2.25.3",
17
    "omit.js": "^1.0.2",
18
    "path-to-regexp": "2.4.0",
19
    "prop-types": "^15.7.2",
20
    "qs": "^6.9.0",
21
    "react": "^16.8.6",
22
    "react-cropper": "^1.3.0",
23
    "react-dom": "^16.8.6",
24
    "react-helmet-async": "^1.0.4",
25
    "umi": "^3.1.2",
26
    "umi-request": "^1.0.8",
27
    "use-merge-value": "^1.0.1"
28
  }
29
}

2.项目结构

1
├── config                 # 配置文件,包含umi内置功能和插件的配置以及webpack和babel的配置。
2
│   ├── config.dev.js      # 开发环境变量
3
│   ├── config.js          # 配置文件
4
│   ├── config.prod.js     # 生产环境变量
5
│   └── defaultSettings.js # 网站和antd的配置
6
├── public                 # 静态文件,不变化的logo和icon等
7
├── src                    # 主代码文件
8
    ├── assets             # 静态文件,网站需要的图片,字体等
9
10
    ├── components         # jsx组件
11
    ├── global.jsx         # 全局js
12
    ├── global.less        # 全局样式
13
    ├── icons              # 自定义svg图标
14
    ├── layouts            # 网站基本布局,权限校验
15
    ├── locales            # 语言配置
16
    ├── models             # store数据仓库
17
    ├── pages              # 网站页面
18
    ├── routes             # 网站路由文件
19
20
    ├── service-worker.js  # pwa文件
21
    ├── services           # api接口
22
23
    ├── styles             # 全局样式
24
25
    └── utils              # 工具,包含请求库,本地存储等

3.主要修改 chainWebpack 配置 (defaultSettings 和 routes 文件可以根据自己项目删除)

config/config.js

1
// https://umijs.org/config/
2
import { defineConfig } from "umi";
3
import defaultSettings from "./defaultSettings";
4
import routes from "../src/routes";
5
6
const path = require("path");
7
const CompressionWebpackPlugin = require("compression-webpack-plugin");
8
const isEnvProduction = process.env.NODE_ENV === "production";
9
const isEnvDevelopment = process.env.NODE_ENV === "development";
10
const resolve = (dir) => path.join(__dirname, dir);
11
const assetDir = "static";
12
13
const config = defineConfig({
14
  history: { type: "hash" },
15
  publicPath: "./",
16
  hash: true,
17
  antd: {},
18
  dva: {
19
    hmr: true,
20
  },
21
  chainWebpack(config, { env, webpack, createCSSRule }) {
22
    // 修改js,js chunk文件输出目录
23
    config.output
24
      .filename(assetDir + '/js/[name].[hash:8].js')
25
      .chunkFilename(assetDir + '/js/[name].[contenthash:8].chunk.js')
26
27
    // 修改css输出目录
28
    config.plugin("extract-css").tap(() => [
29
      {
30
        filename: `${assetDir}/css/[name].[contenthash:8].css`,
31
        chunkFilename: `${assetDir}/css/[name].[contenthash:8].chunk.css`,
32
        ignoreOrder: true,
33
      },
34
    ]);
35
36
    // 修改图片输出目录
37
    config.module
38
      .rule("images")
39
      .test(/\.(png|jpe?g|gif|webp|ico)(\?.*)?$/)
40
      .use("url-loader")
41
      .loader(require.resolve("url-loader"))
42
      .tap((options) => {
43
        const newOptions = {
44
          ...options,
45
          name: assetDir + "/img/[name].[hash:8].[ext]",
46
          fallback: {
47
            ...options.fallback,
48
            options: {
49
              name: assetDir + "/img/[name].[hash:8].[ext]",
50
              esModule: false,
51
            },
52
          },
53
        };
54
        return newOptions;
55
      });
56
57
    // 修改svg输出目录
58
    config.module
59
      .rule("svg")
60
      .test(/\.(svg)(\?.*)?$/)
61
      .use("file-loader")
62
      .loader(require.resolve("file-loader"))
63
      .tap((options) => ({
64
        ...options,
65
        name: assetDir + "/img/[name].[hash:8].[ext]",
66
      }));
67
68
    // 修改fonts输出目录
69
    config.module
70
      .rule("fonts")
71
      .test(/\.(eot|woff|woff2|ttf)(\?.*)?$/)
72
      .use("file-loader")
73
      .loader(require.resolve("file-loader"))
74
      .tap((options) => ({
75
        ...options,
76
        name: assetDir + "/fonts/[name].[hash:8].[ext]",
77
        fallback: {
78
          ...options.fallback,
79
          options: {
80
            name: assetDir + "/fonts/[name].[hash:8].[ext]",
81
            esModule: false,
82
          },
83
        },
84
      }));
85
86
    // 添加gzip压缩
87
    config.when(isEnvProduction, (config) => {
88
      config
89
        .plugin("compression-webpack-plugin")
90
        .use(CompressionWebpackPlugin, [
91
          {
92
            filename: "[path].gz[query]",
93
            algorithm: "gzip",
94
            test: new RegExp("\\.(js|css)$"),
95
            threshold: 10240,
96
            minRatio: 0.8,
97
          },
98
        ]);
99
    });
100
  },
101
  // 生产环境去除console日志打印
102
  terserOptions: {
103
    compress: {
104
      drop_console: isEnvProduction,
105
    },
106
  },
107
  locale: {
108
    // default zh-CN
109
    default: "zh-CN",
110
    // default true, when it is true, will use `navigator.language` overwrite default
111
    antd: true,
112
    baseNavigator: true,
113
  },
114
  dynamicImport: {
115
    loading: "@/components/PageLoading/index",
116
  },
117
  targets: {
118
    ie: 11,
119
  },
120
  // umi routes: https://umijs.org/docs/routing
121
  routes,
122
  // Theme for antd: https://ant.design/docs/react/customize-theme-cn
123
  theme: {
124
    // ...darkTheme,
125
    "primary-color": defaultSettings.primaryColor,
126
  },
127
  // @ts-ignore
128
  title: defaultSettings.title,
129
  ignoreMomentLocale: true,
130
  manifest: {
131
    basePath: "/",
132
  },
133
  devServer: {
134
    open: true,
135
    port: 8367,
136
  },
137
});
138
139
export default config;

4.打包后输出的 dist 目录

1
├── asset-manifest.json
2
├── favicon.ico
3
├── index.html
4
└── static
5
    ├── css
6
    ├── fonts
7
    ├── img
8
    └── js

参考链接

1.https://github.com/umijs/umi/blob/master/packages/bundler-webpack/src/getConfig/getConfig.ts

问题来源

1.https://github.com/umijs/umi/issues/4490