import { execFileSync } from 'node:child_process';
import path from 'node:path';
import { svgSprites } from '@oomfware/vite-plugin-svg-sprites';
import { vanillaExtractPlugin } from '@oomfware/vite-plugin-vanilla-extract';
import react from '@vitejs/plugin-react';
import { defineConfig, type Rolldown } from 'vite';
import oauthMetadata from './public/oauth-client-metadata.json' with { type: 'json' };
import { serviceWorkerPrecache } from './scripts/sw-precache-plugin.ts';
const root = process.cwd();
const serverHost = '127.0.0.1';
const serverPort = 19006;
const resolveCommitHash = (): string => {
const injected = process.env.WORKERS_CI_COMMIT_SHA;
if (injected) {
return injected.slice(0, 7);
}
try {
return execFileSync('git', ['rev-parse', '--short=7', 'HEAD'], { encoding: 'utf8' }).trim();
} catch {
return '';
}
};
export default defineConfig(({ command, mode }) => {
const isBuild = command === 'build';
const isProduction = mode === 'production';
const oauthScope = process.env.PUBLIC_OAUTH_SCOPE || oauthMetadata.scope;
const oauthRedirectPath = new URL(oauthMetadata.redirect_uris[0]!).pathname;
const oauthRedirectUri = isProduction
? process.env.PUBLIC_OAUTH_REDIRECT_URI || oauthMetadata.redirect_uris[0]!
: `http://${serverHost}:${serverPort}${oauthRedirectPath}`;
const oauthClientId = isProduction
? process.env.PUBLIC_OAUTH_CLIENT_ID || oauthMetadata.client_id
: `http://localhost?redirect_uri=${encodeURIComponent(oauthRedirectUri)}` +
`&scope=${encodeURIComponent(oauthScope)}`;
const codeSplitting: Rolldown.CodeSplittingOptions = {
minShareCount: 24,
groups: [
// #region eager tier
// claim the initial graph before mixed groups can pull lazy modules onto the critical path.
{
name: 'react',
tags: ['$initial'],
test: /node_modules[\\/]@oomfware[\\/]scion[\\/]/,
minShareCount: 1,
priority: 100,
},
{ name: 'vendor-eager', tags: ['$initial'], test: /node_modules[\\/]/, minShareCount: 1, priority: 95 },
{ name: 'app-eager', tags: ['$initial'], minShareCount: 1, priority: 90 },
// #endregion
// #region lazy tier
{ name: 'messages', test: /[\\/]src[\\/]paraglide[\\/]/, minShareCount: 4, priority: 20 },
{ name: 'icons', test: /[\\/]src[\\/]icons[\\/]/, minShareCount: 1, priority: 20 },
{ name: 'base-ui', test: /node_modules[\\/](?:@base-ui|@floating-ui)[\\/]/, priority: 15 },
{ name: 'atproto', test: /node_modules[\\/](?:@atcute|@jsr[\\/]mary__)/, priority: 15 },
{ name: 'common', priority: 0 },
// #endregion
],
};
return {
plugins: [
react({ compiler: { panicThreshold: 'none' } }),
vanillaExtractPlugin(),
svgSprites({
target: 'react19-jsx',
splitting: 'chunk',
spriteName: 'sprites',
}),
isProduction && serviceWorkerPrecache(path.resolve(root, 'src/lib/sw-template.js')),
],
envPrefix: 'PUBLIC_',
define: {
'import.meta.env.PUBLIC_GIT_COMMIT_HASH': JSON.stringify(isProduction ? resolveCommitHash() : ''),
'import.meta.env.PUBLIC_OAUTH_CLIENT_ID': JSON.stringify(oauthClientId),
'import.meta.env.PUBLIC_OAUTH_REDIRECT_URI': JSON.stringify(oauthRedirectUri),
'import.meta.env.PUBLIC_OAUTH_SCOPE': JSON.stringify(oauthScope),
},
resolve: {
alias: [
{ find: /^react$/, replacement: '@oomfware/scion/react' },
{ find: /^react\/compiler-runtime$/, replacement: '@oomfware/scion/compiler-runtime' },
{ find: /^react\/jsx-dev-runtime$/, replacement: '@oomfware/scion/jsx-runtime' },
{ find: /^react\/jsx-runtime$/, replacement: '@oomfware/scion/jsx-runtime' },
{ find: /^react-dom$/, replacement: '@oomfware/scion/react-dom' },
{ find: /^react-dom\/client$/, replacement: '@oomfware/scion/react-dom-client' },
{ find: /^scheduler$/, replacement: '@oomfware/scion/scheduler' },
{
find: /^use-sync-external-store\/shim$/,
replacement: '@oomfware/scion/use-sync-external-store-shim',
},
{ find: /^#\//, replacement: `${path.resolve(root, 'src')}/` },
],
},
server: {
host: serverHost,
port: serverPort,
strictPort: true,
proxy: {
'/xrpc': 'http://127.0.0.1:8787',
},
},
build: {
outDir: 'web-build',
emptyOutDir: true,
sourcemap: true,
minify: 'terser',
terserOptions: {
compress: {
drop_console: isProduction,
passes: 2,
},
},
// prevent content hashes from cascading through importers.
chunkImportMap: isBuild,
modulePreload: { polyfill: false },
rolldownOptions: {
output: {
chunkFileNames: 'assets/js/[hash:7].js',
assetFileNames: 'assets/[ext]/[hash:7][extname]',
codeSplitting,
},
},
},
worker: {
format: 'es',
},
};
});