diff --git a/packages/vite/src/node/plugins/oxc.ts b/packages/vite/src/node/plugins/oxc.ts
index e0e30e8224d7b9..cea5f7778a343b 100644
--- a/packages/vite/src/node/plugins/oxc.ts
+++ b/packages/vite/src/node/plugins/oxc.ts
@@ -18,6 +18,7 @@ import type { ViteDevServer } from '../server'
import { JS_TYPES_RE, VITE_PACKAGE_DIR } from '../constants'
import type { Logger } from '../logger'
import { type ESBuildOptions, getTSConfigResolutionCache } from './esbuild'
+import { getRealPath } from './resolve'
// IIFE content looks like `var MyLib = (function() {` or `this.nested.myLib = (function() {`.
export const IIFE_BEGIN_RE: RegExp =
@@ -299,8 +300,9 @@ export function oxcPlugin(config: ResolvedConfig): Plugin {
return result
}
- const runtimeResolveBase = normalizePath(
- path.join(VITE_PACKAGE_DIR, 'package.json'),
+ const runtimePackageDir = getRealPath(
+ path.join(VITE_PACKAGE_DIR, 'node_modules', '@oxc-project', 'runtime'),
+ config.resolve.preserveSymlinks,
)
let server: ViteDevServer
@@ -315,13 +317,22 @@ export function oxcPlugin(config: ResolvedConfig): Plugin {
? {
resolveId: {
filter: {
- id: prefixRegex('@oxc-project/runtime/'),
+ id: prefixRegex('@oxc-project/runtime/helpers/'),
},
- async handler(id, _importer, opts) {
+ async handler(id, _importer, _opts) {
// @oxc-project/runtime imports will be injected by Oxc transform
// since it's injected by the transform, @oxc-project/runtime should be resolved to the one Vite depends on
- const resolved = await this.resolve(id, runtimeResolveBase, opts)
- return resolved
+ const helperName = id.slice(
+ '@oxc-project/runtime/helpers/'.length,
+ )
+ // Rolldown always uses the esm version of @oxc-project/runtime
+ // https://github.com/rolldown/rolldown/blob/v1.0.0-rc.9/crates/rolldown_plugin_oxc_runtime/src/lib.rs#L27
+ const helperId = path.posix.join(
+ runtimePackageDir,
+ 'src/helpers/esm',
+ helperName + (id.endsWith('.js') ? '' : '.js'),
+ )
+ return helperId
},
order: 'pre',
},
diff --git a/packages/vite/src/node/plugins/resolve.ts b/packages/vite/src/node/plugins/resolve.ts
index 89ed17efaac477..26a233ed635d98 100644
--- a/packages/vite/src/node/plugins/resolve.ts
+++ b/packages/vite/src/node/plugins/resolve.ts
@@ -1218,7 +1218,10 @@ function tryResolveRealFileOrType(
return
}
-function getRealPath(resolved: string, preserveSymlinks?: boolean): string {
+export function getRealPath(
+ resolved: string,
+ preserveSymlinks?: boolean,
+): string {
if (!preserveSymlinks) {
resolved = safeRealpathSync(resolved)
}
diff --git a/packages/vite/src/node/ssr/runtime/__tests__/fixtures/oxc-runtime-helper.ts b/packages/vite/src/node/ssr/runtime/__tests__/fixtures/oxc-runtime-helper.ts
new file mode 100644
index 00000000000000..c4e5d4d23c5fec
--- /dev/null
+++ b/packages/vite/src/node/ssr/runtime/__tests__/fixtures/oxc-runtime-helper.ts
@@ -0,0 +1,6 @@
+function html(strings: TemplateStringsArray, ...values: unknown[]) {
+ return strings.join('')
+}
+export const result = html``
diff --git a/packages/vite/src/node/ssr/runtime/__tests__/server-runtime.spec.ts b/packages/vite/src/node/ssr/runtime/__tests__/server-runtime.spec.ts
index 5114dab3b593bc..b659dd67f9f6c3 100644
--- a/packages/vite/src/node/ssr/runtime/__tests__/server-runtime.spec.ts
+++ b/packages/vite/src/node/ssr/runtime/__tests__/server-runtime.spec.ts
@@ -12,6 +12,7 @@ describe('module runner initialization', async () => {
const it = await createModuleRunnerTester({
resolve: {
external: ['tinyglobby'],
+ noExternal: ['@oxc-project/runtime'],
},
})
@@ -396,6 +397,15 @@ describe('module runner initialization', async () => {
)
})
+ it('oxc runtime helpers are loadable', async ({ runner }) => {
+ const mod = await runner.import('/fixtures/oxc-runtime-helper.ts')
+ expect(mod.result).toMatchInlineSnapshot(`
+ ""
+ `)
+ })
+
it(`handle Object variable`, async ({ runner }) => {
const mod = await runner.import('/fixtures/top-level-object.js')
expect(mod).toMatchInlineSnapshot(`