Skip to content

feat: support full bundle mode in ssr#21626

Open
sheremet-va wants to merge 59 commits into
vitejs:mainfrom
sheremet-va:fix/support-full-bundle-mode-in-ssr
Open

feat: support full bundle mode in ssr#21626
sheremet-va wants to merge 59 commits into
vitejs:mainfrom
sheremet-va:fix/support-full-bundle-mode-in-ssr

Conversation

@sheremet-va

@sheremet-va sheremet-va commented Feb 12, 2026

Copy link
Copy Markdown
Member

I am exploring how full bundle mode can be supported in SSR. At the moment the goal is to support environments.ssr.runner.import and environment.fetchModule. Module graph, transformRequest, pluginContainer are out of scope of this PR, but they will be revisited later.

Known quirks (to discuss)

  • url in runner.import(url) is not resolved with resolveId like it is done usually. Instead it accepts:
    • Absolute URL to the bundled entry point specified in rolldownOptions.input
    • Relative URL (relative to root) to the bundled entry point
    • The chunk name
    • Relative URL to the bundled entry point starting with / (/entry-point.js vs ./entry-point.js)
    • The url must be an actual filename or a URL with the extension at the end
  • import.meta.url, import.meta.filename and import.meta.dirname reference "would be" (or "virtual") files, these are the URLs that would exist if vite kept the bundle on the file system. Doing something like readFileSync(import.meta.filename) will throw an error because the file does not exist on disk
    • For example for the build configuration like { ourDir: './dist' }, the filename would be something like <root>/dist/asset/chunk-1.js

To enable full bundle mode in SSR, add this to the config:

export default defineConfig({
  environments: {
    ssr: {
      isBundled: true,
    },
  },
})

@sheremet-va sheremet-va changed the title feat: support ful bundle mode in ssr feat: support full bundle mode in ssr Feb 12, 2026
@jamesopstad

Copy link
Copy Markdown
Contributor

Very excited to see the beginnings of this!

Comment thread packages/vite/src/node/server/environments/fullBundleEnvironment.ts Outdated
Comment thread packages/vite/src/module-runner/createImportMeta.ts Outdated
Comment thread packages/vite/src/module-runner/runner.ts
Comment thread packages/vite/src/module-runner/runner.ts Outdated
Comment on lines +56 to +57
// We need the proxy because the runtime MUST be ready before the first import is processed.
// Because `context['__rolldown_runtime__']` is passed down before the modules are executed as a function argument.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this part be simple if the runtime class was created on the module runner side?
I wonder if that's possible by setting implement: '' and calling new ViteDevRuntime here directly.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it would be nice if we could somehow pass it down

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we have to have it in the environment to keep things simpler, actually. So that both client and ssr implementation don't diverge too much. The ViteDevRuntime could be defined in a different chunk and tracking it can become hard for no gain, really. Having a proxy and delayed initialization works fine, in my opinion

Comment thread packages/vite/src/node/config.ts Outdated
Comment thread packages/vite/src/node/ssr/fetchModule.ts Outdated
@sheremet-va

Copy link
Copy Markdown
Member Author

Both HMR and dynamic imports should work now. Unfortunately, if there is an external dependency in a dynamic import, it won't be loaded properly for now (this is a bug in rolldown)

@sheremet-va sheremet-va marked this pull request as ready for review May 25, 2026 14:01
Comment thread packages/vite/src/node/ssr/fetchModule.ts Outdated
createFullBundleRunnableDevEnvironment,
isFullBundleRunnableDevEnvironment,
// TODO: should have a unified FBM Dev Environment, not split between client and ssr
FullBundleRunnableDevEnvironment,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
FullBundleRunnableDevEnvironment,
type FullBundleRunnableDevEnvironment,

I guess it's ok not to expose the class value.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it being an alternative to DevEnvironment which we do expose, makes it a requirement to expose this

Comment on lines 20 to 26
dynamicRelative: await import(nameRelative),
dynamicAbsolute: await import(nameAbsolute),
dynamicAbsoluteExtension: await import(nameAbsoluteExtension),
dynamicAbsoluteFull: await import(
(process.platform === 'win32' ? '/@fs/' : '') + absolutePath
),
dynamicFileUrl: await import(fileUrl),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these the ones not working because of the bug in Rolldown?

if (!ssrResult) {
throw new Error(`[vite] cannot apply ssr transform to '${url}'.`)
}
result.code = ssrResult.code

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to update the sourcemap here?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably should, but I am not sure how we update the source maps after HMR happens since we only get patches there

Comment thread packages/vite/src/node/ssr/runtime/__tests__/server-hmr.spec.ts Outdated

it('exports is not modifiable', async ({ runner }) => {
it('exports is not modifiable', async ({ runner, skip, fullBundle }) => {
// TODO: fix in rolldown

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread packages/vite/src/node/server/environments/fullBundleRunnableEnvironment.ts Outdated
Comment thread packages/vite/src/node/ssr/runtime/__tests__/server-hmr.spec.ts Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants