From 11810fbbd8824f50bd4462559b7a69e436d157c8 Mon Sep 17 00:00:00 2001 From: hkonsti <45428767+hkonsti@users.noreply.github.com> Date: Thu, 9 Jul 2026 17:44:40 -0700 Subject: [PATCH 1/2] fix: decouple editor plugin injection from core so headless renders work MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Renders were hanging under the renderer's Vite 8: makeProject's addEditorToProject() baked a Vite dev-server-internal URL (/@id/@revideo/2d/editor) into @revideo/core, which every project — including headless renders — imports. Vite 8's import-analysis rejects the unresolvable id in the optimized core bundle and the render page never loads. - core: remove addEditorToProject and its hardcoded /@id/ import; core no longer contains any Vite-internal string. - vite-plugin: inject editor plugins in the dev-only editor entry, driven by each scene's declared plugin specifiers (scene.plugins), constructing the /@id/ URL where it belongs — never in a render bundle. - vite-plugin: also inject the real, per-package versions (via the previously-disabled getVersions()) into the editor entry, replacing core's hardcoded createVersionObject('0.10.4'); fix getVersions so the vite-plugin's own version resolves. - template: set moduleResolution alongside module: CommonJS so the render tsconfig compiles (TS5095). --- packages/core/src/app/makeProject.ts | 19 ++------ packages/template/tsconfig.json | 3 +- packages/vite-plugin/src/partials/editor.ts | 54 +++++++++++++++------ packages/vite-plugin/src/versions.ts | 2 +- 4 files changed, 48 insertions(+), 30 deletions(-) diff --git a/packages/core/src/app/makeProject.ts b/packages/core/src/app/makeProject.ts index 35779d945..888e82da1 100644 --- a/packages/core/src/app/makeProject.ts +++ b/packages/core/src/app/makeProject.ts @@ -62,19 +62,10 @@ export function makeProject(project: UserProject): Project { settings: convertedSettings, plugins: [], logger: new Logger(), - versions: createVersionObject('0.10.4'), - }; -} - -export async function addEditorToProject(project: Project) { - const url = '/@id/@revideo/2d/editor'; - const imported = await import( - /* webpackIgnore: true */ /* @vite-ignore */ url - ); - const plugin = imported.default(); - - return { - ...project, - plugins: [...project.plugins, plugin], + // Placeholder only. The real, per-package versions are resolved from the + // installed `package.json` files and injected by the vite-plugin's editor + // entry (the sole consumer, the editor footer). They are never used during + // a headless render, so we don't try to resolve them here in core. + versions: createVersionObject('0.0.0'), }; } diff --git a/packages/template/tsconfig.json b/packages/template/tsconfig.json index d5b7dffb4..a5d918863 100644 --- a/packages/template/tsconfig.json +++ b/packages/template/tsconfig.json @@ -5,7 +5,8 @@ "noEmit": false, "outDir": "dist", "rootDir": "./src", - "module": "CommonJS", + "module": "NodeNext", + "moduleResolution": "NodeNext", "skipLibCheck": true }, "include": ["src"] diff --git a/packages/vite-plugin/src/partials/editor.ts b/packages/vite-plugin/src/partials/editor.ts index 1d8b9aa7f..7abe3d574 100644 --- a/packages/vite-plugin/src/partials/editor.ts +++ b/packages/vite-plugin/src/partials/editor.ts @@ -2,6 +2,7 @@ import fs from 'fs'; import path from 'path'; import type {Plugin} from 'vite'; import type {Projects} from '../utils'; +import {getVersions} from '../versions'; interface EditorPluginConfig { editor: string; @@ -19,6 +20,43 @@ export function editorPlugin({editor, projects}: EditorPluginConfig): Plugin { const resolvedEditorId = '\0virtual:editor'; + /** + * Generate the editor entry module for a single project. + * + * Editor plugins are declared per-scene as module specifiers (e.g. + * `'@revideo/2d/editor'`). We load them here, in the dev-server-only entry, + * and inject them into the project before handing it to the editor. This + * keeps the dynamic import — and the Vite-internal `/@id/` prefix used to + * resolve it — out of `@revideo/core`, so it never leaks into a headless + * render bundle. + * + * The real package versions (resolved from the installed `package.json` + * files) are injected here too — they're only ever shown in the editor + * footer, so this is the one place that has both the project and access to + * the file system. + */ + const editorEntry = (projectUrl: string) => { + const versions = JSON.stringify(getVersions()); + /* language=typescript */ + return `\ +import {editor} from '${editor}'; +import project from '/@fs/${path.resolve(projectUrl)}'; +const specifiers = [ + ...new Set((project.scenes ?? []).flatMap(scene => scene.plugins ?? [])), +]; +const plugins = await Promise.all( + specifiers.map(specifier => + import(/* @vite-ignore */ '/@id/' + specifier).then(mod => mod.default()), + ), +); +editor({ + ...project, + versions: ${versions}, + plugins: [...project.plugins, ...plugins], +}); +`; + }; + return { name: 'revideo:editor', @@ -27,26 +65,14 @@ export function editorPlugin({editor, projects}: EditorPluginConfig): Plugin { if (id.startsWith(resolvedEditorId)) { if (projects.list.length === 1) { - /* language=typescript */ - return `\ -import {editor} from '${editor}'; -import project from '/@fs/${path.resolve(projects.list[0].url)}'; -import {addEditorToProject} from '@revideo/core'; -editor(await addEditorToProject(project)); -`; + return editorEntry(projects.list[0].url); } if (query) { const params = new URLSearchParams(query); const name = params.get('project'); if (name && projects.lookup.has(name)) { - /* language=typescript */ - return `\ -import {editor} from '${editor}'; -import project from '/@fs/${path.resolve(projects.lookup.get(name)!.url)}'; -import {addEditorToProject} from '@revideo/core'; -editor(await addEditorToProject(project)); -`; + return editorEntry(projects.lookup.get(name)!.url); } } diff --git a/packages/vite-plugin/src/versions.ts b/packages/vite-plugin/src/versions.ts index 34d9c27f1..192aba81f 100644 --- a/packages/vite-plugin/src/versions.ts +++ b/packages/vite-plugin/src/versions.ts @@ -6,7 +6,7 @@ export function getVersions() { core: loadVersion('@revideo/core'), two: loadVersion('@revideo/2d'), ui: loadVersion('@revideo/ui'), - vitePlugin: loadVersion('..'), + vitePlugin: loadVersion('@revideo/vite-plugin'), }; } From 9bf25f61b6b73ee5b6e89b8cabd63ea8c190997f Mon Sep 17 00:00:00 2001 From: hkonsti <45428767+hkonsti@users.noreply.github.com> Date: Thu, 9 Jul 2026 17:46:32 -0700 Subject: [PATCH 2/2] chore: bump examples submodule for render tsconfig fix Points to midrender/examples 1c9dff8 (#29), which adds moduleResolution to the templates' render tsconfigs so a freshly scaffolded project compiles under the bundler-based base config. --- packages/create/examples | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/create/examples b/packages/create/examples index 61e05ee71..1c9dff8c0 160000 --- a/packages/create/examples +++ b/packages/create/examples @@ -1 +1 @@ -Subproject commit 61e05ee71d471aeb2e47855509838846c466234c +Subproject commit 1c9dff8c027195201846741735376d62e04cc983