Files
twenty/packages/twenty-front/vite.config.ts
Félix Malfait 322c8a1852 Upgrade to Node22 (#12488)
BlocknoteJS requires an ESM module where our server is CJS, this forced
us to pin the server-util version, which led us to force the resolution
of several packages, leading to bugs downstream.

From Node 22.12 Node supports requiring ESM modules (available from Node
22.0 with a flag). So I upgrade the module.
I picked Node 22 and not Node 23 or Node 24 because 22 is the LTS and we
don't plan to change node versions frequently.

If you remain on Node 18, things should still mostly work, except if you
edit a Rich Text field.

I also starting changing the default runtime for Serverless Functions
which isn't directly related. This means new serverless functions will
be created on Node 22, but we will still need another PR to migrate
existing serverless functions before September (end of support by AWS).

(In this PR I also remove the upgrade commands from 0.43 since they rely
on Blocknote and I didn't want to have to deal with this)

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2025-06-06 18:35:30 +02:00

283 lines
9.2 KiB
TypeScript

/* eslint-disable no-console */
import { lingui } from '@lingui/vite-plugin';
import { isNonEmptyString } from '@sniptt/guards';
import react from '@vitejs/plugin-react-swc';
import wyw from '@wyw-in-js/vite';
import fs from 'fs';
import path from 'path';
import { visualizer } from 'rollup-plugin-visualizer';
import { defineConfig, loadEnv, PluginOption, searchForWorkspaceRoot } from 'vite';
import checker from 'vite-plugin-checker';
import svgr from 'vite-plugin-svgr';
import tsconfigPaths from 'vite-tsconfig-paths';
type Checkers = Parameters<typeof checker>[0];
export default defineConfig(({ command, mode }) => {
const env = loadEnv(mode, __dirname, '');
const {
REACT_APP_SERVER_BASE_URL,
VITE_BUILD_SOURCEMAP,
VITE_DISABLE_TYPESCRIPT_CHECKER,
VITE_DISABLE_ESLINT_CHECKER,
VITE_HOST,
SSL_CERT_PATH,
SSL_KEY_PATH,
REACT_APP_PORT,
IS_DEBUG_MODE,
} = env;
const port = isNonEmptyString(REACT_APP_PORT)
? parseInt(REACT_APP_PORT)
: 3001;
const isBuildCommand = command === 'build';
const tsConfigPath = isBuildCommand
? path.resolve(__dirname, './tsconfig.build.json')
: path.resolve(__dirname, './tsconfig.dev.json');
const CHUNK_SIZE_WARNING_LIMIT = 1024 * 1024; // 1MB
// Please don't increase this limit for main index chunk
// If it gets too big then find modules in the code base
// that can be loaded lazily, there are more!
const MAIN_CHUNK_SIZE_LIMIT = 4.7 * 1024 * 1024; // 4.7MB for main index chunk
const OTHER_CHUNK_SIZE_LIMIT = 5 * 1024 * 1024; // 5MB for other chunks
const checkers: Checkers = {
overlay: false,
};
if (VITE_DISABLE_TYPESCRIPT_CHECKER === 'true') {
console.log(
`VITE_DISABLE_TYPESCRIPT_CHECKER: ${VITE_DISABLE_TYPESCRIPT_CHECKER}`,
);
}
if (VITE_DISABLE_ESLINT_CHECKER === 'true') {
console.log(`VITE_DISABLE_ESLINT_CHECKER: ${VITE_DISABLE_ESLINT_CHECKER}`);
}
if (VITE_BUILD_SOURCEMAP === 'true') {
console.log(`VITE_BUILD_SOURCEMAP: ${VITE_BUILD_SOURCEMAP}`);
}
if (VITE_DISABLE_TYPESCRIPT_CHECKER !== 'true') {
checkers['typescript'] = {
tsconfigPath: tsConfigPath,
};
}
if (VITE_DISABLE_ESLINT_CHECKER !== 'true') {
checkers['eslint'] = {
lintCommand:
// Appended to packages/twenty-front/.eslintrc.cjs
'eslint ../../packages/twenty-front --report-unused-disable-directives --max-warnings 0 --config .eslintrc.cjs',
};
}
return {
root: __dirname,
cacheDir: '../../node_modules/.vite/packages/twenty-front',
server: {
port: port,
...(VITE_HOST ? { host: VITE_HOST } : {}),
...(SSL_KEY_PATH && SSL_CERT_PATH
? {
protocol: 'https',
https: {
key: fs.readFileSync(env.SSL_KEY_PATH),
cert: fs.readFileSync(env.SSL_CERT_PATH),
},
}
: {
protocol: 'http',
}),
fs: {
allow: [
searchForWorkspaceRoot(process.cwd()),
'**/@blocknote/core/src/fonts/**',
],
},
},
plugins: [
react({
jsxImportSource: '@emotion/react',
plugins: [['@lingui/swc-plugin', {}]],
}),
tsconfigPaths({
projects: ['tsconfig.json'],
}),
svgr(),
lingui({
configPath: path.resolve(__dirname, './lingui.config.ts'),
}),
checker(checkers),
// TODO: fix this, we have to restrict the include to only the components that are using linaria
// Otherwise the build will fail because wyw tries to include emotion styled components
wyw({
include: [
'**/CurrencyDisplay.tsx',
'**/EllipsisDisplay.tsx',
'**/ContactLink.tsx',
'**/BooleanDisplay.tsx',
'**/LinksDisplay.tsx',
'**/RoundedLink.tsx',
'**/OverflowingTextWithTooltip.tsx',
'**/Chip.tsx',
'**/Tag.tsx',
'**/MultiSelectFieldDisplay.tsx',
'**/RatingInput.tsx',
'**/RecordTableCellContainer.tsx',
'**/RecordTableCellDisplayContainer.tsx',
'**/Avatar.tsx',
'**/RecordTableBodyDroppable.tsx',
'**/RecordTableCellBaseContainer.tsx',
'**/RecordTableCellTd.tsx',
'**/RecordTableTd.tsx',
'**/RecordTableHeaderDragDropColumn.tsx',
'**/ActorDisplay.tsx',
'**/BooleanDisplay.tsx',
'**/CurrencyDisplay.tsx',
'**/TextDisplay.tsx',
'**/EllipsisDisplay.tsx',
'**/AvatarChip.tsx',
'**/URLDisplay.tsx',
'**/EmailsDisplay.tsx',
'**/PhonesDisplay.tsx',
'**/MultiSelectDisplay.tsx',
],
babelOptions: {
presets: ['@babel/preset-typescript', '@babel/preset-react'],
},
}),
visualizer({
open: true,
gzipSize: true,
brotliSize: true,
filename: 'dist/stats.html',
}) as PluginOption, // https://github.com/btd/rollup-plugin-visualizer/issues/162#issuecomment-1538265997,
],
optimizeDeps: {
exclude: [
'../../node_modules/.vite',
'../../node_modules/.cache',
'../../node_modules/twenty-ui',
],
},
build: {
minify: 'esbuild',
outDir: 'build',
sourcemap: VITE_BUILD_SOURCEMAP === 'true',
rollupOptions: {
// Don't use manual chunks as it causes many issue
// including this one we wasted a lot of time on:
// https://github.com/rollup/rollup/issues/2793
output: {
// Set chunk size warning limit (in bytes) - warns at 1MB
chunkSizeWarningLimit: CHUNK_SIZE_WARNING_LIMIT,
// Custom plugin to fail build if chunks exceed max size
plugins: [
{
name: 'chunk-size-limit',
generateBundle(_options, bundle) {
const oversizedChunks: string[] = [];
Object.entries(bundle).forEach(([fileName, chunk]) => {
if (chunk.type === 'chunk' && chunk.code) {
const size = Buffer.byteLength(chunk.code, 'utf8');
const isMainChunk = fileName.includes('index') && chunk.isEntry;
const sizeLimit = isMainChunk ? MAIN_CHUNK_SIZE_LIMIT : OTHER_CHUNK_SIZE_LIMIT;
const limitType = isMainChunk ? 'main' : 'other';
if (size > sizeLimit) {
oversizedChunks.push(`${fileName} (${limitType}): ${(size / 1024 / 1024).toFixed(2)}MB (limit: ${(sizeLimit / 1024 / 1024).toFixed(2)}MB)`);
}
}
});
if (oversizedChunks.length > 0) {
const errorMessage = `Build failed: The following chunks exceed their size limits:\n${oversizedChunks.map(chunk => ` - ${chunk}`).join('\n')}`;
this.error(errorMessage);
}
}
},
// TODO; later - think about prefetching modules such
// as date time picker, phone input etc...
/*
{
name: 'add-prefetched-modules',
transformIndexHtml(html: string,
ctx: {
path: string;
filename: string;
server?: ViteDevServer;
bundle?: import('rollup').OutputBundle;
chunk?: import('rollup').OutputChunk;
}) {
const bundles = Object.keys(ctx.bundle ?? {});
let modernBundles = bundles.filter(
(bundle) => bundle.endsWith('.map') === false
);
// Remove existing files and concatenate them into link tags
const prefechBundlesString = modernBundles
.filter((bundle) => html.includes(bundle) === false)
.map((bundle) => `<link rel="prefetch" href="${ctx.server?.config.base}${bundle}">`)
.join('');
// Use regular expression to get the content within <head> </head>
const headContent = html.match(/<head>([\s\S]*)<\/head>/)?.[1] ?? '';
// Insert the content of prefetch into the head
const newHeadContent = `${headContent}${prefechBundlesString}`;
// Replace the original head
html = html.replace(
/<head>([\s\S]*)<\/head>/,
`<head>${newHeadContent}</head>`
);
return html;
},
}*/
]
}
},
},
envPrefix: 'REACT_APP_',
define: {
_env_: {
REACT_APP_SERVER_BASE_URL,
},
'process.env': {
REACT_APP_SERVER_BASE_URL,
IS_DEBUG_MODE,
},
},
css: {
modules: {
localsConvention: 'camelCaseOnly',
},
},
resolve: {
alias: {
path: 'rollup-plugin-node-polyfills/polyfills/path',
// https://github.com/twentyhq/twenty/pull/10782/files
// This will likely be migrated to twenty-ui package when built separately
'@tabler/icons-react': '@tabler/icons-react/dist/esm/icons/index.mjs',
},
},
};
});