import { createReadStream, existsSync } from 'node:fs'; import { extname, join, sep } from 'node:path'; import { defineSSGServiceConfig, discoverEntries, mergeConfig, umamiAnalytics, } from '@ermnvldmr/ssg/dev'; import { localDevServer } from '@ermnvldmr/rsbuild-config/dev'; import { THEME_INIT_SCRIPT, THEME_INIT_STYLES } from '@ermnvldmr/ui/dev'; import { TRUSTED_TYPES_INIT_SCRIPT } from '@ermnvldmr/stl'; import { localeRsbuildConfig } from '@ermnvldmr/i18n/dev'; import { RsdoctorRspackPlugin } from '@rsdoctor/rspack-plugin'; import { pluginMdx } from '@rsbuild/plugin-mdx'; import remarkFrontmatter from 'remark-frontmatter'; import remarkMdxFrontmatter from 'remark-mdx-frontmatter'; const MIME: Record = { '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.png': 'image/png', '.gif': 'image/gif', '.webp': 'image/webp', '.svg': 'image/svg+xml', '.avif': 'image/avif', '.ico': 'image/x-icon', '.woff': 'font/woff', '.woff2': 'font/woff2', '.ttf': 'font/ttf', '.css': 'text/css', '.js': 'application/javascript', '.json': 'application/json', '.txt': 'text/plain', }; const UMAMI_WWW_WEBSITE_ID = '4fca5ac2-4fe4-4626-b708-933c37bfe918'; export default defineSSGServiceConfig( mergeConfig(localeRsbuildConfig(), { server: localDevServer({ port: 3000 }), analytics: [ umamiAnalytics({ serverUrl: '/beacon', scriptName: 'beacon.js', hostUrl: '/beacon', websiteId: UMAMI_WWW_WEBSITE_ID, domains: 'ermnvldmr.com,www.ermnvldmr.com', doNotTrack: true, }), ], dev: { // Serve public/static/* at /static/* directly, bypassing server.base. // Without this, server.base (e.g. /en) would push the public dir to // /en/static/*, making /static/* unreachable in dev. setupMiddlewares: [ (middlewares) => { middlewares.unshift((req, res, next) => { const url = (req as { url?: string }).url ?? ''; if (!url.startsWith('/static/')) return next(); // Strip the leading slash so the '/static/...' segment is treated as // relative to public/ (an absolute segment would otherwise let a // resolved path escape it), then confine the result to public/ to // block '..' path traversal. const publicDir = join(import.meta.dirname, 'public'); const requestedPath = (url.split('?')[0] ?? url).replace(/^\/+/, ''); const filePath = join(publicDir, requestedPath); if (!filePath.startsWith(publicDir + sep) || !existsSync(filePath)) return next(); const mime = MIME[extname(filePath)] ?? 'application/octet-stream'; res.setHeader('Content-Type', mime); createReadStream(filePath).pipe(res as import('node:stream').Writable); }); return middlewares; }, ], }, tools: { rspack: { plugins: [ process.env.RSDOCTOR === 'true' && new RsdoctorRspackPlugin({ disableClientServer: true, output: { reportDir: './rsdoctor', mode: 'brief' }, }), ].filter(Boolean), }, }, plugins: [ pluginMdx({ mdxLoaderOptions: { remarkPlugins: [remarkFrontmatter, [remarkMdxFrontmatter, { name: 'frontmatter' }]], }, }), ], source: { entry: discoverEntries(import.meta.dirname, './src/app/**/*.tsx'), preEntry: ['./src/static/global.css'], }, performance: { preload: { type: 'all-assets', include: [/(lato-400|lato-700|eb-garamond-var)\..*\.woff2$/], }, }, html: { tags: [ { tag: 'script', children: TRUSTED_TYPES_INIT_SCRIPT, head: true }, { tag: 'script', children: THEME_INIT_SCRIPT, head: true }, { tag: 'style', children: THEME_INIT_STYLES, head: true }, ], }, }) );