Compare commits

...

7 Commits

Author SHA1 Message Date
Lucas Smith fae1798eeb fix: add typecheck to build.sh 2026-03-13 14:06:48 +11:00
Lucas Smith 69e08ac7cd fix: make typecheck work 2026-03-13 12:32:10 +11:00
Lucas Smith f69f3c9473 chore: hoist dev deps 2026-03-13 12:16:24 +11:00
Lucas Smith 9747fd1800 fix: tidy 2026-03-13 12:03:05 +11:00
Lucas Smith 53afafe5db fix: remove hacks 2026-03-13 11:49:56 +11:00
Lucas Smith 38ab1cd4a7 fix: add babel-plugin-macros as explicit devDependency
Required at runtime by @lingui/core/macro when code runs outside
Vite/Rolldown (e.g. prisma seed scripts via tsx). Previously a
transitive dependency of the now-removed vite-plugin-babel-macros.
2026-03-13 10:34:19 +11:00
Lucas Smith b3ef92feb9 perf: upgrade to vite 8, migrate rollup to rolldown, and optimise build pipeline
- Upgrade vite from v7 to v8 (Rolldown-based bundler)
- Migrate server build from rollup to rolldown, eliminating 5 plugins
  (rolldown handles TS, JSX, JSON, CJS, and node resolution natively)
- Replace vite-plugin-babel-macros with targeted lingui macro plugin
  that skips files without macro imports (~90% of files)
- Replace vite-tsconfig-paths with native resolve.tsconfigPaths
- Remove redundant lingui error-reporter plugin (51% of plugin time)
- Narrow optimizeDeps.entries from ~1060 to ~460 files
- Move typecheck out of build into separate CI job (43s -> 24s build)
- Fix card.tsx var() typo exposed by LightningCSS
- Remove 30 unused packages (rollup, babel presets, rollup plugins, etc.)
- Add vite override for peer dep compatibility
- Patch @lingui/vite-plugin with moduleType for Rolldown compat
2026-03-13 10:06:15 +11:00
15 changed files with 2208 additions and 1406 deletions
+14
View File
@@ -12,6 +12,20 @@ concurrency:
cancel-in-progress: true
jobs:
typecheck:
name: Typecheck
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 2
- uses: ./.github/actions/node-install
- name: Typecheck
run: npm run typecheck -w @documenso/remix
build_app:
name: Build App
runs-on: ubuntu-latest
+1 -5
View File
@@ -14,9 +14,5 @@
"luxon": "^3.7.2",
"next": "15.5.12"
},
"devDependencies": {
"@types/node": "^20",
"@types/react": "18.3.27",
"typescript": "5.6.2"
}
"devDependencies": {}
}
+6 -2
View File
@@ -19,6 +19,9 @@ start_time=$(date +%s)
echo "[Build]: Extracting and compiling translations"
npm run translate --prefix ../../
echo "[Build]: Typechecking app"
npm run typecheck
echo "[Build]: Building app"
npm run build:app
@@ -28,10 +31,11 @@ npm run build:server
# Copy over the entry point for the server.
cp server/main.js build/server/main.js
# Copy over all web.js translations
# Copy over all web.js translations.
# Rolldown preserveModules mirrors the source tree under build/server/hono/.
cp -r ../../packages/lib/translations build/server/hono/packages/lib/translations
# Time taken
end_time=$(date +%s)
echo "[Build]: Done in $((end_time - start_time)) seconds"
echo "[Build]: Done in $((end_time - start_time)) seconds"
+3 -33
View File
@@ -4,8 +4,8 @@
"type": "module",
"scripts": {
"build": "./.bin/build.sh",
"build:app": "npm run typecheck && cross-env NODE_ENV=production react-router build",
"build:server": "cross-env NODE_ENV=production rollup -c rollup.config.mjs",
"build:app": "react-router typegen && cross-env NODE_ENV=production react-router build",
"build:server": "cross-env NODE_ENV=production rolldown -c rolldown.config.mjs",
"dev": "npm run with:env -- react-router dev",
"dev:billing": "bash .bin/stripe-dev.sh",
"start": "npm run with:env -- cross-env NODE_ENV=production node build/server/main.js",
@@ -74,36 +74,6 @@
"ua-parser-js": "^1.0.41",
"uqr": "^0.1.2"
},
"devDependencies": {
"@babel/core": "^7.28.5",
"@babel/preset-react": "^7.28.5",
"@babel/preset-typescript": "^7.28.5",
"@lingui/babel-plugin-lingui-macro": "^5.6.0",
"@lingui/vite-plugin": "^5.6.0",
"@react-router/dev": "^7.12.0",
"@react-router/remix-routes-option-adapter": "^7.12.0",
"@rollup/plugin-babel": "^6.1.0",
"@rollup/plugin-commonjs": "^28.0.9",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^16.0.3",
"@rollup/plugin-typescript": "^12.3.0",
"@types/content-disposition": "^0.5.9",
"@types/formidable": "^3.4.6",
"@types/luxon": "^3.7.1",
"@types/node": "^20",
"@types/papaparse": "^5.5.0",
"@types/react": "18.3.27",
"@types/react-dom": "^18",
"@types/ua-parser-js": "^0.7.39",
"cross-env": "^10.1.0",
"esbuild": "^0.27.0",
"remix-flat-routes": "^0.8.5",
"rollup": "^4.53.3",
"tsx": "^4.20.6",
"typescript": "5.6.2",
"vite": "^7.2.4",
"vite-plugin-babel-macros": "^1.0.6",
"vite-tsconfig-paths": "^5.1.4"
},
"devDependencies": {},
"version": "2.8.0"
}
+37
View File
@@ -0,0 +1,37 @@
import babel from '@rolldown/plugin-babel';
import { defineConfig } from 'rolldown';
/**
* Rolldown config for building the Hono server entry.
*
* Replaces the previous rollup.config.mjs. Rolldown provides built-in
* TypeScript, JSX (automatic runtime), JSON, CJS interop, and node
* resolution — so we only need a single plugin for lingui macro compilation.
*/
export default defineConfig({
input: 'server/router.ts',
output: {
dir: 'build/server/hono',
format: 'esm',
sourcemap: true,
preserveModules: true,
preserveModulesRoot: '.',
},
// Externalize all third-party deps from node_modules.
// Workspace packages (@documenso/*) resolve to their actual source paths
// (outside node_modules) via npm workspace symlinks, so they get bundled.
external: [/node_modules/],
platform: 'node',
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],
tsconfigFilename: 'tsconfig.json',
},
plugins: [
babel({
plugins: ['@lingui/babel-plugin-lingui-macro'],
parserOpts: {
plugins: ['typescript', 'jsx'],
},
}),
],
});
-54
View File
@@ -1,54 +0,0 @@
import linguiMacro from '@lingui/babel-plugin-lingui-macro';
import babel from '@rollup/plugin-babel';
import commonjs from '@rollup/plugin-commonjs';
import json from '@rollup/plugin-json';
import resolve from '@rollup/plugin-node-resolve';
import typescript from '@rollup/plugin-typescript';
import path from 'node:path';
/** @type {import('rollup').RollupOptions} */
const config = {
/**
* We specifically target the router.ts instead of the entry point so the rollup doesn't go through the
* already prebuilt RR7 server files.
*/
input: 'server/router.ts',
output: {
dir: 'build/server/hono',
format: 'esm',
sourcemap: true,
preserveModules: true,
preserveModulesRoot: '.',
},
external: [/node_modules/],
plugins: [
typescript({
noEmitOnError: true,
moduleResolution: 'bundler',
include: ['server/**/*', '../../packages/**/*', '../../packages/lib/translations/**/*'],
jsx: 'preserve',
}),
resolve({
rootDir: path.join(process.cwd(), '../..'),
preferBuiltins: true,
resolveOnly: [
'@documenso/api/*',
'@documenso/auth/*',
'@documenso/lib/*',
'@documenso/trpc/*',
'@documenso/email/*',
],
extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],
}),
json(),
commonjs(),
babel({
babelHelpers: 'bundled',
extensions: ['.ts', '.tsx'],
presets: ['@babel/preset-typescript', ['@babel/preset-react', { runtime: 'automatic' }]],
plugins: [linguiMacro],
}),
],
};
export default config;
+20 -10
View File
@@ -1,14 +1,13 @@
import { lingui } from '@lingui/vite-plugin';
import { reactRouter } from '@react-router/dev/vite';
import babel from '@rolldown/plugin-babel';
import autoprefixer from 'autoprefixer';
import serverAdapter from 'hono-react-router-adapter/vite';
import { createRequire } from 'node:module';
import path from 'node:path';
import tailwindcss from 'tailwindcss';
import { defineConfig, normalizePath } from 'vite';
import macrosPlugin from 'vite-plugin-babel-macros';
import { viteStaticCopy } from 'vite-plugin-static-copy';
import tsconfigPaths from 'vite-tsconfig-paths';
const require = createRequire(import.meta.url);
@@ -40,16 +39,24 @@ export default defineConfig({
},
],
}),
babel({
plugins: ['@lingui/babel-plugin-lingui-macro'],
// @rolldown/plugin-babel's built-in TypeScript parser overrides use
// `test: "**/*.tsx"` globs which fail to match when React Router appends
// query strings (e.g. `?__react-router-build-client-route`) to module IDs.
// Specify parser plugins explicitly so they apply unconditionally.
parserOpts: {
plugins: ['typescript', 'jsx'],
},
}),
lingui().filter((plugin) => plugin.name === 'vite-plugin-lingui'),
reactRouter(),
macrosPlugin(),
lingui(),
tsconfigPaths(),
serverAdapter({
entry: 'server/router.ts',
}),
],
ssr: {
noExternal: ['react-dropzone', 'plausible-tracker'],
noExternal: ['react-dropzone'],
external: [
'@napi-rs/canvas',
'@node-rs/bcrypt',
@@ -62,10 +69,8 @@ export default defineConfig({
],
},
optimizeDeps: {
entries: ['./app/**/*', '../../packages/ui/**/*', '../../packages/lib/**/*'],
include: ['prop-types', 'file-selector', 'attr-accept'],
exclude: [
'node_modules',
'@napi-rs/canvas',
'@node-rs/bcrypt',
'sharp',
@@ -75,6 +80,7 @@ export default defineConfig({
],
},
resolve: {
tsconfigPaths: true,
alias: {
https: 'node:https',
'.prisma/client/default': path.resolve(
@@ -89,11 +95,15 @@ export default defineConfig({
},
},
/**
* Note: Re run rollup again to build the server afterwards.
* Note: Re run rolldown again to build the server afterwards.
*
* See rollup.config.mjs which is used for that.
* See rolldown.config.mjs which is used for that.
*/
build: {
// LightningCSS (Vite 8 default) is stricter and rejects nested @page
// rules and some Tailwind theme() edge cases. Use esbuild for CSS
// minification until LightningCSS support matures or the CSS is updated.
cssMinify: 'esbuild',
rollupOptions: {
external: [
'@napi-rs/canvas',
+2062 -1282
View File
File diff suppressed because it is too large Load Diff
+22 -1
View File
@@ -47,19 +47,37 @@
"node": ">=22.0.0"
},
"devDependencies": {
"@babel/core": "^7.28.5",
"@types/babel__core": "^7.20.5",
"@commitlint/cli": "^20.1.0",
"@commitlint/config-conventional": "^20.0.0",
"@datadog/pprof": "^5.13.5",
"@lingui/babel-plugin-lingui-macro": "^5.6.0",
"@lingui/cli": "^5.6.0",
"@lingui/vite-plugin": "^5.6.0",
"@prisma/client": "^6.19.0",
"@react-router/dev": "^7.12.0",
"@react-router/remix-routes-option-adapter": "^7.12.0",
"@rolldown/plugin-babel": "^0.2.0",
"@trpc/client": "11.8.1",
"@trpc/react-query": "11.8.1",
"@trpc/server": "11.8.1",
"@ts-rest/core": "^3.52.1",
"@ts-rest/open-api": "^3.52.1",
"@ts-rest/serverless": "^3.52.1",
"@types/content-disposition": "^0.5.9",
"@types/formidable": "^3.4.6",
"@types/luxon": "^3.7.1",
"@types/node": "^20",
"@types/papaparse": "^5.5.0",
"@types/react": "18.3.27",
"@types/react-dom": "^18",
"@types/ua-parser-js": "^0.7.39",
"babel-plugin-macros": "^3.1.0",
"cross-env": "^10.1.0",
"dotenv": "^17.2.3",
"dotenv-cli": "^11.0.0",
"esbuild": "^0.27.0",
"eslint": "^8.57.0",
"husky": "^9.1.7",
"inngest-cli": "^1.16.1",
@@ -75,11 +93,13 @@
"prisma-extension-kysely": "^3.0.0",
"prisma-json-types-generator": "^3.6.2",
"prisma-kysely": "^2.3.0",
"remix-flat-routes": "^0.8.5",
"rimraf": "^6.1.2",
"superjson": "^2.2.5",
"syncpack": "^14.0.0-alpha.27",
"tsx": "^4.20.6",
"turbo": "^1.13.4",
"vite": "^7.2.4",
"vite": "^8.0.0",
"vite-plugin-static-copy": "^3.1.4",
"zod-openapi": "^4.2.4",
"zod-prisma-types": "3.3.5"
@@ -104,6 +124,7 @@
"lodash": "4.17.23",
"pdfjs-dist": "5.4.296",
"typescript": "5.6.2",
"vite": "$vite",
"zod": "$zod",
"fumadocs-mdx": {
"zod": "^4.3.5"
+2 -3
View File
@@ -14,7 +14,6 @@
"eslint-config-turbo": "^1.13.4",
"eslint-plugin-package-json": "^0.85.0",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-unused-imports": "^4.3.0",
"typescript": "5.6.2"
"eslint-plugin-unused-imports": "^4.3.0"
}
}
}
-1
View File
@@ -64,7 +64,6 @@
},
"devDependencies": {
"@playwright/browser-chromium": "1.56.1",
"@types/luxon": "^3.7.1",
"@types/pg": "^8.15.6"
}
}
+1 -6
View File
@@ -32,10 +32,5 @@
"zod": "^3.25.76",
"zod-prisma-types": "3.3.5"
},
"devDependencies": {
"dotenv": "^17.2.3",
"dotenv-cli": "^11.0.0",
"tsx": "^4.20.6",
"typescript": "5.6.2"
}
"devDependencies": {}
}
+1 -5
View File
@@ -19,11 +19,7 @@
"devDependencies": {
"@documenso/tailwind-config": "*",
"@documenso/tsconfig": "*",
"@types/luxon": "^3.7.1",
"@types/react": "18.3.27",
"@types/react-dom": "^18",
"react": "^18",
"typescript": "5.6.2"
"react": "^18"
},
"dependencies": {
"@documenso/lib": "*",
+3 -4
View File
@@ -30,15 +30,14 @@ const Card = React.forwardRef<HTMLDivElement, CardProps>(
} as React.CSSProperties
}
className={cn(
'bg-background text-foreground group relative rounded-lg border-2',
'group relative rounded-lg border-2 bg-background text-foreground',
{
'backdrop-blur-[2px]': backdropBlur,
'gradient-border-mask before:pointer-events-none before:absolute before:-inset-[2px] before:rounded-lg before:p-[2px] before:[background:linear-gradient(var(--card-gradient-degrees),theme(colors.primary.DEFAULT/50%)_5%,theme(colors.border/80%)_30%)]':
gradient,
'dark:gradient-border-mask before:pointer-events-none before:absolute before:-inset-[2px] before:rounded-lg before:p-[2px] before:[background:linear-gradient(var(--card-gradient-degrees),theme(colors.primary.DEFAULT/70%)_5%,theme(colors.border/80%)_30%)]':
gradient,
'shadow-[0_0_0_4px_theme(colors.gray.100/70%),0_0_0_1px_theme(colors.gray.100/70%),0_0_0_0.5px_var(colors.primary.DEFAULT/70%)]':
true,
'shadow-[0_0_0_4px_theme(colors.gray.100/70%),0_0_0_1px_theme(colors.gray.100/70%),0_0_0_0.5px_theme(colors.primary.DEFAULT/70%)]': true,
'dark:shadow-[0]': true,
},
className,
@@ -77,7 +76,7 @@ const CardDescription = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
>(({ className, ...props }, ref) => (
<p ref={ref} className={cn('text-muted-foreground text-sm', className)} {...props} />
<p ref={ref} className={cn('text-sm text-muted-foreground', className)} {...props} />
));
CardDescription.displayName = 'CardDescription';
+36
View File
@@ -0,0 +1,36 @@
diff --git a/node_modules/@lingui/vite-plugin/dist/index.cjs b/node_modules/@lingui/vite-plugin/dist/index.cjs
index cb4db5d..c0a881a 100644
--- a/node_modules/@lingui/vite-plugin/dist/index.cjs
+++ b/node_modules/@lingui/vite-plugin/dist/index.cjs
@@ -114,8 +114,12 @@ You see this error because \`failOnMissing=true\` in Vite Plugin configuration.`
}
return {
code,
- map: null
+ map: null,
// provide source map if available
+ // Vite 8+ (Rolldown) auto-detects module types by file extension.
+ // Since .po files are transformed to JS, we must explicitly declare
+ // the module type to avoid misinterpretation.
+ moduleType: "js"
};
}
}
diff --git a/node_modules/@lingui/vite-plugin/dist/index.mjs b/node_modules/@lingui/vite-plugin/dist/index.mjs
index 609d48d..66fa6cc 100644
--- a/node_modules/@lingui/vite-plugin/dist/index.mjs
+++ b/node_modules/@lingui/vite-plugin/dist/index.mjs
@@ -106,8 +106,12 @@ You see this error because \`failOnMissing=true\` in Vite Plugin configuration.`
}
return {
code,
- map: null
+ map: null,
// provide source map if available
+ // Vite 8+ (Rolldown) auto-detects module types by file extension.
+ // Since .po files are transformed to JS, we must explicitly declare
+ // the module type to avoid misinterpretation.
+ moduleType: "js"
};
}
}