Files
crewli/apps/app/vite.config.ts
bert.hausmans 90d5c1678c feat(tailwind): install Tailwind v4 alongside Vuetify (parallel mode)
Three additions wire Tailwind v4 into the SPA without disturbing the
existing Vuetify pipeline:

- apps/app/src/assets/styles/tailwind.css — Tailwind v4 CSS-first entry.
  Uses @import "tailwindcss"; @plugin "tailwindcss-primeui"; and
  @source pointing at apps/app/src/ to scan template content.

- apps/app/vite.config.ts — adds the @tailwindcss/vite plugin between
  vue() and vuetify(). After vue() so it sees compiled template
  content; before vuetify() so Vuetify's SCSS pipeline runs unimpeded.

- apps/app/src/main.ts — imports tailwind.css before the Vuetify/Vuexy
  SCSS so utility classes are available alongside Vuetify's cascade.

optimizeDeps.exclude remains ['vuetify'] (no PrimeVue addition) — HMR
behaves correctly in dev with the current config; revisit if needed.

Verification:
- pnpm typecheck — clean.
- pnpm build — succeeds in 13.97s; CSS emitted per-route as expected.
- pnpm test — 402 tests pass unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 01:02:05 +02:00

148 lines
4.2 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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'
// 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({
getRouteName: routeNode => {
// Convert pascal case to kebab case
return getPascalCaseRouteName(routeNode)
.replace(/([a-z\d])([A-Z])/g, '$1-$2')
.toLowerCase()
},
}),
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,
},
})