vite.config.ts (101 lines of code) (raw):

import { defineConfig, UserConfig } from 'vite'; import { z } from 'zod'; import inject from '@rollup/plugin-inject'; import { resolve, relative } from 'path'; import { glob } from 'glob'; import babel from '@rollup/plugin-babel'; const INPUT_DIR = './static'; const OUTPUT_DIR = './static-build'; // Any js/less file in the root directory of js/css // is interpreted as an entrypoint and will be bundled // and served via vite. These files can be injected // into django templates and resolved correctly in dev/prod const jsFiles = glob.sync('./static/js/*.js'); const cssFiles = glob.sync('./static/css/*.less'); // format inputs with unique keys const input = [...jsFiles, ...cssFiles].reduce((acc, path) => { const relativePath = relative(INPUT_DIR, path); const entryName = relativePath.replace(/\.(js|less)$/, ''); acc[entryName] = resolve(path); return acc; }, {}); const jqueryGlobals = { $: 'jquery', jQuery: 'jquery', }; const envSchema = z.object({ ENV: z.enum(['local', 'build', 'dev', 'stage', 'prod']), STATIC_URL_PREFIX: z.string(), VITE_MANIFEST_FILE_NAME: z.string(), SITE_URL: z.string().optional(), }); const env = envSchema.parse(process.env); export default defineConfig(({ command }) => { const isLocal = env.ENV === 'local'; const isDev = command === 'serve'; return { // Ensure all static assets are treated as // 'in-scope' assets that can be tracked by vite // this ensures any imported static assets are correctly // mapped across file transformations. assetsInclude: `${INPUT_DIR}/*`, // Only log warnings and errors logLevel: 'warn', // exclude any automatic html bundling appType: 'custom', root: resolve(INPUT_DIR), // When serving, use a url prefix that forwards from nginx to the vite dev-server // When building, use a relative path to ensure import paths can be transformed // independently of where the importing file ends up in the bundle base: isDev ? `${env.STATIC_URL_PREFIX}bundle/` : './', resolve: { alias: { // Alias 'highcharts' to our local vendored copy // we cannot use npm to install due to licensing constraints highcharts: resolve(__dirname, 'static/js/lib/highcharts-module.js'), }, }, plugins: [ // Inject jQuery globals in the bundle for usage by npm packages // that rely on it being globally available. inject({ exclude: ['**/*.less'], ...jqueryGlobals, }), ], build: { // Disable inline assets. For performance reasons we want to serve // all static assets from dedicated URLs which in production will // be cached in our CDN. The incremental build size is worse than // the increase in number of requests. assetsInlineLimit: 0, // This value should be kept in sync with settings_base.py // which determines where to read static file paths // for production URL resolution manifest: env.VITE_MANIFEST_FILE_NAME, // Ensure we always build from an empty directory to prevent stale files emptyOutDir: true, // Configurable values helpful for debugging copyPublicDir: true, // Minify the output for non local builds minify: 'esbuild', cssMinify: 'esbuild', // Include sourcemaps in local builds only sourcemap: !isDev && isLocal, // This value should be kept in sync with settings_base.py // which includes this path as a staticfiles directory outDir: resolve(OUTPUT_DIR), rollupOptions: { input, output: { format: 'es', // Isolate vendor code into a separate chunk to avoid // polluting the UMD functions in legacy modules with the // rollup defined shims for module.exports / exports; manualChunks: (id) => { if (id.includes('node_modules')) { return 'vendor'; } }, }, plugins: [ // Use babel to ensure compatibility with all specified browsers babel({ extensions: ['.js', '.less'], // any helper code injected by babel will be bundled // along with the rest of the code babelHelpers: 'bundled', }), ], }, }, css: { preprocessorOptions: { less: { math: 'always', javascriptEnabled: true, }, }, }, optimizeDeps: { include: [ '@claviska/jquery-minicolors', 'jquery', 'jquery-ui', 'jquery.browser', 'jquery.cookie', 'timeago', ], }, server: { host: true, port: 5173, allowedHosts: true, origin: env?.SITE_URL ?? '127.0.0.1', strictPort: true, }, } satisfies UserConfig; });