interface/rsbuild.config.ts
Rama main · réplica de lectura del repositorio original.
import { pluginPWA } from './pluginPWA';
import path from 'node:path';
import { defineConfig } from '@rsbuild/core';
import { pluginBabel } from '@rsbuild/plugin-babel';
import { pluginReact } from '@rsbuild/plugin-react';
import { pluginSass } from '@rsbuild/plugin-sass';
const envName = process.env.NODE_ENV ?? 'development';
console.log(`Building for environment: ${envName}`);
const isDevelopment = envName !== 'production';
const interfaceSource = path.resolve(__dirname, 'src');
// If we are using development lite, then this changes the behavior of the config significantly. We instead proxy the
// staging or production API here to allow for frontend development only against real data. Requires a staging or
// production account.
const developmentLite = Boolean(process.env.MONETR_DEVELOPMENT_LITE ?? false);
const developmentLiteTarget = process.env.MONETR_DEVELOPMENT_LITE_TARGET ?? 'my.monetr.dev';
if (developmentLite) {
console.log(`development lite environment will be used, upstream: ${developmentLiteTarget}`);
}
const version = `v${process.env.RELEASE_VERSION ?? ''}`;
// HMR replacement gets **fucked** if we are using content hash. So use name when we are
// in development mode.
const filename = isDevelopment ? '[name]' : '[contenthash:8]';
export default defineConfig({
mode: isDevelopment ? 'development' : 'production',
source: {
define: {
CONFIG: JSON.stringify({}),
REVISION: JSON.stringify(process.env.RELEASE_REVISION),
RELEASE: JSON.stringify(version),
NODE_VERSION: process.version,
},
},
resolve: {
alias: {
'@monetr/interface': interfaceSource,
},
},
dev: {
hmr: isDevelopment,
liveReload: isDevelopment,
},
server: {
publicDir: {
name: path.resolve(__dirname, 'public'),
copyOnBuild: false,
},
port: 3000,
historyApiFallback: true,
host: developmentLite ? 'localhost' : '0.0.0.0',
proxy: developmentLite
? {
'/api': {
// When we are in development-lite mode, proxy API calls to the upstream API server that they have specified.
target: `https://${developmentLiteTarget}`,
changeOrigin: true,
cookieDomainRewrite: 'localhost',
ws: true, // For file uploads
},
}
: undefined,
},
html: {
template: path.resolve(__dirname, 'public/index.html'),
templateParameters: {
// When we are doing local dev then don't use anything, maybe use an env var in the future but thats it. But
// for a production build add the go template string in so that the server can provide the DSN.
SENTRY_DSN: isDevelopment ? `${process.env.MONETR_SENTRY_DSN ?? ''}` : '{{ .SentryDSN }}',
// The preconnect tag is built entirely on the server so that we can skip it for localhost or unset external
// URLs. In dev there is nothing to preconnect to, so collapse the placeholder to an empty string.
PRECONNECT_TAG: isDevelopment ? '' : '{{ .PreconnectTag }}',
},
// Dont use the favicon here, favicon is handled by the PWA plugin.
mountId: 'root',
},
performance: {
// Split vendor code into groups that change independently, so a dependency bump only busts the cache for its own
// group instead of one large vendor chunk.
chunkSplit: {
strategy: 'split-by-experience',
forceSplitting: {
'lib-sentry': /node_modules[\\/]@sentry/,
// Exclude date-fns locales, those are lazy loaded by useLocale and would otherwise be pulled into this chunk.
'lib-date': /node_modules[\\/](date-fns(?![\\/]locale)|@date-fns|react-day-picker|rrule)/,
'lib-query': /node_modules[\\/]@tanstack/,
'lib-forms': /node_modules[\\/](formik|lodash-es|downshift|react-number-format)/,
'lib-ui': /node_modules[\\/](@radix-ui|@monetr[\\/]vaul|lucide-react|cmdk)/,
},
},
preload: {
type: 'all-assets',
include: [/inter-latin-wght-normal.*\.woff2$/, /jetbrains-mono-latin-\d+-normal.*\.woff2$/],
},
},
output: {
target: 'web',
distPath: {
root: path.resolve(__dirname, '../server/ui/static'),
js: 'assets/scripts',
css: 'assets/styles',
image: 'assets/images',
font: 'assets/fonts',
},
filename: isDevelopment
? undefined
: {
js: `${filename}.js`,
css: `${filename}.css`,
image: `[name].${filename}[ext]`,
font: `[name].${filename}[ext]`,
},
cleanDistPath: false, // Handled by cmake
// Small font subsets were getting base64'd into the main CSS, keep them as files so they only load when needed.
dataUriLimit: {
font: 0,
},
charset: 'utf8',
filenameHash: true,
manifest: false,
minify: {
js: true,
css: true,
},
sourceMap: {
js: isDevelopment ? 'inline-source-map' : 'source-map',
css: true,
},
cssModules: isDevelopment
? undefined
: {
// Hash the class names when we are in a production build.
localIdentName: '[hash:base64:6]',
},
copy: [
{
from: 'public/manifest.json',
to: 'manifest.json',
},
{
from: 'public/robots.txt',
to: 'robots.txt',
},
],
},
security: {
sri: {
enable: !isDevelopment,
algorithm: 'sha512',
},
},
plugins: [
pluginReact(),
pluginSass(),
pluginBabel({
include: /\.(?:jsx|tsx)$/,
babelLoaderOptions(opts) {
opts.plugins?.unshift(['babel-plugin-react-compiler', { target: '19' }]);
},
}),
pluginPWA({
logo: path.resolve(__dirname, '../images/logo.png'),
background: '#19161f',
quality: 90,
}),
],
});