返回文章列表

打包相关

2026-03-315 min read

Gzip压缩#

安装vite-plugin-compression插件#

TYPESCRIPT
// https://vitejs.dev/config/
import { defineConfig, loadEnv } from "vite";
import react from "@vitejs/plugin-react-swc";
import path from "path";
import { createHtmlPlugin } from "vite-plugin-html";
import eslintPlugin from "vite-plugin-eslint";
import tailwindcss from "tailwindcss";
import autoprefixer from "autoprefixer";
// import { visualizer } from "rollup-plugin-visualizer";
import compression from "vite-plugin-compression";
// 解析路径
const _resolve = (dir) => path.resolve(__dirname, ".", dir);

const vendorChunkNames = [
    "react",
    "antd",
    "handsontable",
    "devextreme-datagrid",
    "devextreme-contextmenu",
    "devextreme-misc",
    "devextreme-plugins",
    "visactor",
    "dataUtils",
    "network",
    "router",
    "state",
    "charts",
    "tables",
    "utils",
    "excel",
    "styles",
    "vendor",
];

// eslint-disable-next-line @typescript-eslint/no-unused-vars
export default defineConfig(({ command, mode }) => {
    // 加载所有环境变量
    const env = loadEnv(mode, "environment", "");
    return {
        plugins: [
            react(),
            createHtmlPlugin({
                minify: true,
                inject: {
                    data: {
                        title: env.VITE_SITE_TITLE,
                    },
                },
            }),
            eslintPlugin({
                include: ["src/**/*.ts", "src/!**/!*.tsx"],
            }),
            // visualizer({ open: false, filename: "dist/stats.html", gzipSize: true }),
            compression({
                algorithm: "gzip",
                ext: ".gz",
                threshold: 1024, // 小于 1kb 的文件不压缩
                deleteOriginFile: false, // 不要删除原文件,保留 .js 和 .js.gz
            }),
        ],
        css: {
            postcss: {
                plugins: [tailwindcss, autoprefixer],
            },
        },
        resolve: {
            alias: {
                "@": _resolve("src"),
                inferno: command === "build" ? "inferno/dist/index.esm.js" : "inferno/dist/index.dev.esm.js",
            },
        },
        build: {
            assetsDir: "assets",
            minify: "terser",
            terserOptions: {
                compress: {
                    drop_console: true, // 移除 console
                    drop_debugger: true, // 移除 debugger
                },
            },
            rollupOptions: {
                output: {
                    // 分包配置
                    manualChunks: {
                        react: ["react", "react-dom"],
                        antd: ["antd", "@ant-design/icons", "@ant-design/pro-components"],
                        handsontable: ["@handsontable/react", "handsontable"],
                        "devextreme-datagrid": ["devextreme-react/data-grid"],
                        "devextreme-contextmenu": ["devextreme-react/context-menu"],
                        "devextreme-misc": [
                            "devextreme-react/select-box",
                            "devextreme-react/tree-list",
                            "devextreme-react/date-box",
                        ],
                        "devextreme-plugins": [],
                        visactor: ["@visactor/react-vtable", "@visactor/vtable"],
                        dataUtils: ["lodash", "dayjs", "decimal.js", "numbro"],
                        network: ["axios", "rxjs"],
                        router: ["react-router-dom", "history"],
                        state: ["zustand"],
                        charts: ["echarts"],
                        tables: ["@dnd-kit/core", "@dnd-kit/sortable", "@dnd-kit/utilities"],
                        utils: ["uuid", "qrcode", "localforage", "ahooks", "classnames"],
                        excel: ["xlsx"],
                        styles: ["@emotion/react", "@emotion/styled", "@mui/material"],
                        vendor: ["@fingerprintjs/fingerprintjs", "normalize.css", "lz-string", "modern-screenshot"],
                    },
                    entryFileNames: (chunkInfo) => {
                        if (vendorChunkNames.includes(chunkInfo.name)) {
                            return "js/vendor/[name].[hash].js";
                        }
                        return `js/[name].[hash].js`;
                    },
                    chunkFileNames: (chunkInfo) => {
                        if (vendorChunkNames.includes(chunkInfo.name)) {
                            return "js/vendor/[name].[hash].js";
                        }
                        return `js/[name].[hash].js`;
                    },
                    assetFileNames: (assetInfo) => {
                        if (assetInfo.name.endsWith(".css")) {
                            if (
                                assetInfo.name.includes("vendor") ||
                                assetInfo.name.includes("antd") ||
                                assetInfo.name.includes("handsontable") ||
                                assetInfo.name.includes("devextreme") ||
                                assetInfo.name.includes("visactor")
                            ) {
                                return "css/vendor/[name].css";
                            }
                            return "css/[name].[hash].css";
                        }
                        return "assets/[name].[hash][extname]";
                    },
                },
            },
        },
        envDir: "environment",
    };
});

配置nginx#

image

查看是否生效

image

content-encoding 为 gzip的时候,代表已经生效

打包产物#

image
image

会有js和js.gz两份文件,一般是都留着,为了兼容性,当没有gz的时候,返回原始资源