You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Vue 3+Vite 4构建多页应用时,如何规范资源/Chunk命名?

Vite多页应用构建配置问题:按页面拆分CSS并指定输出结构

场景与需求

使用Vite 4.1.4 + Vue 3.2.45构建多页应用(非库模式),部署在以Razor Pages(cshtml)为入口的ASP.NET Core网站中。需求如下:

  • 每个页面/入口构建为包含所有JS和CSS的独立文件夹,允许模块重复
  • 理想状态下CSS按页面拆分(与输入文件匹配)并做作用域隔离;若无法实现,需预先指定主CSS输出包名称,避免随Vite自动生成的模块(如BusyButton)变化

项目src目录结构

├───assets
│      /*Assets here*/
├───components
│       /*components here*/
├───composables
│       /*composables here*/
├───pages
│   │   ErrorNotFound.vue
|   |   /* Pages here */
│   ├───Propertylistings
│   │       propertylistings.ts
│   │       PropertyListings.vue
│   ├───Tasks
│   │       tasks.ts
│   │       Tasks.vue
│   │       TasksDetail.vue
│   │       TasksGrid.vue
│   └───Users
│           users.ts
│           Users.vue
│           UsersDetail.vue
│           UsersGrid.vue
├───router
│       taskRouter.ts
│       userRouter.ts
|       /* Others here*/
├───services
│   │   Services.ts
│   └───api
│           Api.ts
└───viewmodels
        TaskDTO.ts
        UserDTO.ts
        /* etc */

当前Vite配置

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { fileURLToPath, URL } from 'url'
import glob from 'glob';
import path from 'node:path';

var inputFiles = (glob.globSync('src/pages/**/*.ts')).map(file => [
  // 移除`src/`前缀和文件扩展名,例如src/nested/foo.js变为nested/foo
  path.relative(
    'src',
    file.slice(0, file.length - path.extname(file).length)
  ),
  // 将相对路径转为绝对路径,例如src/nested/foo变为/project/src/nested/foo.js
  fileURLToPath(new URL(file, import.meta.url))
]);

const outputDir = "../wwwroot/client";

export default defineConfig({
  plugins: [
    vue()
  ],
  build: {
    outDir: outputDir,
    emptyOutDir: true,
    manifest: "manifest.json",
    sourcemap: true,
    cssCodeSplit: false, /* 生成单个样式文件 */
    rollupOptions: {
      input: Object.fromEntries(inputFiles),
      output: {
        format: "es",
        sourcemap: true,
        exports: 'named',
        assetFileNames: (assetInfo) => {
          console.log("AssertInfo %s, %s", assetInfo.name, assetInfo.type)
          let extType = assetInfo.name.split('.').pop();
          if (/png|jpe?g|svg|gif|tiff|bmp|ico/i.test(extType)) {
            extType = 'img';
          }
          return `assets/[name]-[hash][extname]`;
        },
      },
    }
  },
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  },
  server: {
    /*开发环境代理配置 */
  }
})

当前构建输出结构

│   manifest.json
│
└───assets
    │   BusyButton-e579a0b5.js /* 该名称随机生成,BusyButton是被多组件引用的自定义组件 */
    │   BusyButton-e579a0b5.js.map
    │   ErrorNotFound-a6c93dbd.js
    │   ErrorNotFound-a6c93dbd.js.map
    │   style-341893d8.css /* 需要按页面拆分并正确命名 */
    │   _plugin-vue_export-helper-175348a6.js
    │   _plugin-vue_export-helper-175348a6.js.map
    │
    └───pages
        ├───Propertylistings
        │       propertylistings-4859e993.js
        │       propertylistings-4859e993.js.map
        │
        ├───Tasks
        │       tasks-a58b1702.js
        │       tasks-a58b1702.js.map
        │
        └───Users
                users-0e4c54f0.js
                users-0e4c54f0.js.map

现存问题

  • BusyButton作为被多组件引用的自定义组件,被随机选为了主输出文件名,导致输出文件命名不可控
  • 开启cssCodeSplit: false时生成单个style-xxx.css文件;移除该选项后,CSS文件会被命名为BusyButton-xxx.css,均无法按页面拆分
  • 无法实现每个页面入口对应独立的CSS文件,输出结构不符合预期

期望输出结构

└───pages
        ├───Propertylistings
        |       propertylistings-4859e993.css /* 每个页面入口对应独立CSS文件 */
        │       propertylistings-4859e993.js
        │       propertylistings-4859e993.js.map
        │
        ├───Tasks
        |       tasks-a58b1702.css /* 每个页面入口对应独立CSS文件 */
        │       tasks-a58b1702.js
        │       tasks-a58b1702.js.map
        │
        └───Users
                users-0e4c54f0.css /* 每个页面入口对应独立CSS文件 */
                users-0e4c54f0.js
                users-0e4c54f0.js.map

内容的提问来源于stack exchange,提问作者Jonathan Counihan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 12:23:12