Moves the `v2-` de-dup (needed because getPascalCaseRouteName folds the v2/ URL segment into the base) into the unit-tested v2RouteName helper and simplifies the vite.config.ts call site to v2RouteName(raw, nodePath). Removes the duplicated isV2 detection. No behavioural change: /v2/dashboard still resolves to route name v2-dashboard; v1 names unchanged. Addresses the Task 3 code-review Important finding. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
170 lines
5.3 KiB
TypeScript
170 lines
5.3 KiB
TypeScript
import { fileURLToPath } from 'node:url'
|
||
import vue from '@vitejs/plugin-vue'
|
||
import vueJsx from '@vitejs/plugin-vue-jsx'
|
||
import AutoImport from 'unplugin-auto-import/vite'
|
||
import Components from 'unplugin-vue-components/vite'
|
||
import {
|
||
VueRouterAutoImports,
|
||
getPascalCaseRouteName,
|
||
} from 'unplugin-vue-router'
|
||
import VueRouter from 'unplugin-vue-router/vite'
|
||
import { defineConfig } from 'vite'
|
||
import VueDevTools from 'vite-plugin-vue-devtools'
|
||
import MetaLayouts from 'vite-plugin-vue-meta-layouts'
|
||
import vuetify from 'vite-plugin-vuetify'
|
||
import tailwindcss from '@tailwindcss/vite'
|
||
import svgLoader from 'vite-svg-loader'
|
||
import { v2RouteName } from './src/plugins/1.router/v2RouteName'
|
||
|
||
// https://vitejs.dev/config/
|
||
export default defineConfig({
|
||
plugins: [
|
||
// Docs: https://github.com/posva/unplugin-vue-router
|
||
// ℹ️ This plugin should be placed before vue plugin
|
||
VueRouter({
|
||
// Parallel /v2/* tree (RFC-WS-GUI-REDESIGN AD-G1). The second
|
||
// routesFolder prefixes every v2 URL with /v2/; v2RouteName then
|
||
// prefixes the route NAME with `v2-` so file-name twins across
|
||
// pages/ and pages-v2/ cannot collide. Reverted at final cutover.
|
||
routesFolder: [
|
||
{ src: 'src/pages' },
|
||
{ src: 'src/pages-v2', path: 'v2/' },
|
||
],
|
||
getRouteName: routeNode => {
|
||
// Convert pascal case to kebab case
|
||
const raw = getPascalCaseRouteName(routeNode)
|
||
.replace(/([a-z\d])([A-Z])/g, '$1-$2')
|
||
.toLowerCase()
|
||
|
||
// Defensive path read: unplugin-vue-router 0.8.8 TreeNode exposes
|
||
// `.fullPath`; fall back to `.value.path` then '' so a future
|
||
// plugin bump can't silently drop the v2- prefix.
|
||
const nodePath
|
||
= (routeNode.fullPath
|
||
?? routeNode.value?.path
|
||
?? '') as string
|
||
|
||
// v2RouteName is the single authority for the /v2 name rule,
|
||
// including de-duping the `v2-` that getPascalCaseRouteName
|
||
// already folds in from the routesFolder URL prefix.
|
||
return v2RouteName(raw, nodePath)
|
||
},
|
||
}),
|
||
vue(),
|
||
VueDevTools(),
|
||
vueJsx(),
|
||
|
||
// Tailwind v4 (F3 — parallel-mode with Vuetify until F6). Placed after
|
||
// vue() so it sees compiled template content; placed before vuetify()
|
||
// so Vuetify's SCSS pipeline runs unimpeded.
|
||
tailwindcss(),
|
||
|
||
// Docs: https://github.com/vuetifyjs/vuetify-loader/tree/master/packages/vite-plugin
|
||
vuetify({
|
||
styles: {
|
||
// Absolute URL so resolution does not depend on process cwd (fixes common SASS 404s).
|
||
configFile: fileURLToPath(
|
||
new URL('./src/styles/settings.scss', import.meta.url),
|
||
),
|
||
},
|
||
}),
|
||
|
||
// Docs: https://github.com/dishait/vite-plugin-vue-meta-layouts?tab=readme-ov-file
|
||
MetaLayouts({
|
||
target: './src/layouts',
|
||
defaultLayout: 'default',
|
||
}),
|
||
|
||
// Docs: https://github.com/antfu/unplugin-vue-components#unplugin-vue-components
|
||
Components({
|
||
dirs: ['src/@core/components', 'src/views/demos', 'src/components'],
|
||
dts: true,
|
||
resolvers: [
|
||
componentName => {
|
||
// Auto import `VueApexCharts`
|
||
if (componentName === 'VueApexCharts') {
|
||
return {
|
||
name: 'default',
|
||
from: 'vue3-apexcharts',
|
||
as: 'VueApexCharts',
|
||
}
|
||
}
|
||
},
|
||
],
|
||
}),
|
||
|
||
// Docs: https://github.com/antfu/unplugin-auto-import#unplugin-auto-import
|
||
AutoImport({
|
||
imports: [
|
||
'vue',
|
||
VueRouterAutoImports,
|
||
'@vueuse/core',
|
||
'@vueuse/math',
|
||
'vue-i18n',
|
||
'pinia',
|
||
],
|
||
dirs: [
|
||
'./src/@core/utils',
|
||
'./src/@core/composable/',
|
||
'./src/composables/',
|
||
'./src/utils/',
|
||
'./src/plugins/*/composables/*',
|
||
],
|
||
vueTemplate: true,
|
||
|
||
// ℹ️ Disabled to avoid confusion & accidental usage
|
||
ignore: ['useCookies', 'useStorage'],
|
||
}),
|
||
|
||
svgLoader(),
|
||
],
|
||
define: { 'process.env': {} },
|
||
resolve: {
|
||
alias: {
|
||
'@': fileURLToPath(new URL('./src', import.meta.url)),
|
||
'@themeConfig': fileURLToPath(
|
||
new URL('./themeConfig.ts', import.meta.url),
|
||
),
|
||
'@core': fileURLToPath(new URL('./src/@core', import.meta.url)),
|
||
'@layouts': fileURLToPath(new URL('./src/@layouts', import.meta.url)),
|
||
'@images': fileURLToPath(
|
||
new URL('./src/assets/images/', import.meta.url),
|
||
),
|
||
'@styles': fileURLToPath(
|
||
new URL('./src/assets/styles/', import.meta.url),
|
||
),
|
||
'@configured-variables': fileURLToPath(
|
||
new URL(
|
||
'./src/assets/styles/variables/_template.scss',
|
||
import.meta.url,
|
||
),
|
||
),
|
||
},
|
||
},
|
||
server: {
|
||
port: 5174,
|
||
proxy: {
|
||
'/api': {
|
||
target: 'http://localhost:8000',
|
||
changeOrigin: true,
|
||
},
|
||
},
|
||
warmup: {
|
||
clientFiles: ['./src/pages/**/*.vue', './src/components/**/*.vue'],
|
||
},
|
||
},
|
||
build: {
|
||
chunkSizeWarningLimit: 5000,
|
||
|
||
// RFC-WS-7 §3.5 — sourcemaps generated at build, uploaded to GlitchTip
|
||
// by deploy.sh, then `find dist -name '*.map' -delete` strips them
|
||
// before nginx serves dist/. No public-mapped sources on production.
|
||
sourcemap: true,
|
||
},
|
||
optimizeDeps: {
|
||
exclude: ['vuetify'],
|
||
entries: ['./src/**/*.vue'],
|
||
force: true,
|
||
},
|
||
})
|