Improve building of twenty-sdk (#17913)

## Split twenty-sdk build into separate Node and browser targets

The SDK was bundling Node.js code (CLI, SDK API) and browser code (UI
components, front-component renderer) through a single Vite config. This
caused incorrect externalization — Node builtins leaked into browser
bundles and browser-specific chunking logic applied to CLI output.

This PR splits the build into `vite.config.node.ts` and
`vite.config.browser.ts` so each target gets the right externals and
output format.

Also includes a few housekeeping renames:
- `front-component` export path → `front-component-renderer` (matches
what it actually is)
- `front-component-common` merged into `front-component-api` (was a
needless extra module)
This commit is contained in:
Charles Bochet
2026-02-13 15:58:19 +01:00
committed by GitHub
parent 463ce43442
commit f17cc4d190
64 changed files with 1575 additions and 217 deletions
@@ -0,0 +1,93 @@
import { ThreadWebWorker, release, retain } from '@quilted/threads';
import { RemoteReceiver } from '@remote-dom/core/receivers';
import { useEffect, useRef } from 'react';
import { type FrontComponentHostCommunicationApi } from '../../types/FrontComponentHostCommunicationApi';
import { type WorkerExports } from '../../types/WorkerExports';
import { createRemoteWorker } from '../worker/utils/createRemoteWorker';
type FrontComponentWorkerEffectProps = {
componentUrl: string;
applicationAccessToken?: string;
apiUrl?: string;
frontComponentHostCommunicationApi: FrontComponentHostCommunicationApi;
setReceiver: React.Dispatch<React.SetStateAction<RemoteReceiver | null>>;
setThread: React.Dispatch<
React.SetStateAction<ThreadWebWorker<
WorkerExports,
FrontComponentHostCommunicationApi
> | null>
>;
setError: React.Dispatch<React.SetStateAction<Error | null>>;
};
export const FrontComponentWorkerEffect = ({
componentUrl,
applicationAccessToken,
apiUrl,
frontComponentHostCommunicationApi,
setReceiver,
setThread,
setError,
}: FrontComponentWorkerEffectProps) => {
const frontComponentHostCommunicationApiRef = useRef(
frontComponentHostCommunicationApi,
);
frontComponentHostCommunicationApiRef.current =
frontComponentHostCommunicationApi;
useEffect(() => {
const newReceiver = new RemoteReceiver({ retain, release });
const worker = createRemoteWorker();
worker.onerror = (event: ErrorEvent) => {
const workerError =
event.error ??
new Error(event.message || 'Unknown worker error');
console.error('[FrontComponentRenderer] Worker error:', workerError);
setError(workerError);
};
// Expose host functions to the worker via stable refs to avoid recreating threads
const stableFrontComponentHostCommunicationApi: FrontComponentHostCommunicationApi =
{
navigate: (...args) =>
frontComponentHostCommunicationApiRef.current.navigate(...args),
};
const thread = new ThreadWebWorker<
WorkerExports,
FrontComponentHostCommunicationApi
>(worker, {
exports: stableFrontComponentHostCommunicationApi,
});
setThread(thread);
thread.imports
.render(newReceiver.connection, {
componentUrl,
applicationAccessToken,
apiUrl,
})
.catch((error: Error) => {
setError(error);
});
setReceiver(newReceiver);
return () => {
setThread(null);
worker.terminate();
};
}, [
componentUrl,
applicationAccessToken,
apiUrl,
setError,
setReceiver,
setThread,
]);
return null;
};