Skip to content

feat: built-in +server support (via Universal Deploy, deprecating vike-photon)#3106

Open
magne4000 wants to merge 178 commits intomainfrom
magne4000/dev
Open

feat: built-in +server support (via Universal Deploy, deprecating vike-photon)#3106
magne4000 wants to merge 178 commits intomainfrom
magne4000/dev

Conversation

@magne4000
Copy link
Member

@magne4000 magne4000 commented Feb 18, 2026

TODO doc

  • doc: /migration/universal-deploy
  • doc: /server
  • doc: any reference to photon
  • Complete test/vite-plugin-vercel tests
  • Hide UM usage

@magne4000 magne4000 changed the title Magne4000/dev feat: native support for +middleware files Feb 18, 2026
Copy link
Member Author

@magne4000 magne4000 left a comment

Choose a reason for hiding this comment

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

@brillout I think we can have a first pass of review

@brillout
Copy link
Member

@brillout I think we can have a first pass of review

What's the scope of the current state? Asking because I ain't sure what is temporary or not.

@magne4000
Copy link
Member Author

It's feature complete. So the only temporary thing is the remaining TODO comment regarding HttpMethod typing

@brillout
Copy link
Member

E.g. the res object returned by UM isn't exposed and instead is merely used to generate a pageContext.httpResponse — I guess that's temporary?

I guess the goal is to have to distinct response types, either:

  1. The barebone httpResponse for backwards compatibility, and for fully manual integration (without UM)
  2. The full res standard HttpResponse object that the user integrates in his server entry (either via UM's apply() or manually via custom integration)

I think we can either return only 1 or only 2. Not sure whether returning both would make sense.

@brillout
Copy link
Member

Actually, I'm realizing maybe it could make sense: using UM internally to add support for +middlewares with all the current renderPage() integrations 👀

@magne4000 magne4000 force-pushed the magne4000/dev branch 2 times, most recently from 6238f15 to 560107a Compare February 18, 2026 15:54
@brillout
Copy link
Member

FYI did some minor refactoring 234f499 — should be equivalent. Bonus: the PR diff is now a lot more readable.

@brillout
Copy link
Member

Let me do a final round of reviewing and then I'm good on my side.

@brillout
Copy link
Member

LGTM (except #3106 (comment))

@magne4000 magne4000 changed the title feat: native support for +middleware files feat: native support for Universal Deploy Feb 26, 2026
@brillout brillout changed the title feat: native support for Universal Deploy feat: built-in vike-photon features (via Universal Deploy) Feb 26, 2026
magne4000 and others added 7 commits February 27, 2026 11:51
# Conflicts:
#	packages/vike/package.json
#	pnpm-lock.yaml
# Conflicts:
#	pnpm-lock.yaml
@magne4000
Copy link
Member Author

Since last review:

  • Now using @vikejs/* packages instead of UM
  • UD framework developers doc
  • test/vite-plugin-vercel migrated to v11 (beta, I'll release stable just before we merge this PR)
  • updated doc + migration

@magne4000 magne4000 requested a review from brillout March 11, 2026 12:21
@magne4000
Copy link
Member Author

I'm also creating @universal-deploy/auto to replace most of pluginUniversalDeploy.ts

@brillout
Copy link
Member

So id in addEntry({ id }) is a fetch handler. Maybe we should document this (e.g. at https://github.com/photon-js/universal-deploy/blob/main/docs/framework-developers.md), with a note saying that fetch is becoming the de-facto server entry standard.

@brillout
Copy link
Member

Even though most frameworks won't use it, I guess it'd sill useful to document @universal-deploy/node (or whatever package Vike ends up using) because framework authors will likely look at how Vike does it. A little paragraph might be enough.

@brillout
Copy link
Member

local emulation: it ensures your development environment behaves exactly like your production environment by supporting features specific to deployment providers that also use universal-deploy

What does it mean?

@brillout
Copy link
Member

universal-deploy provides two optional plugins

They don't sound that optional.

it's also invaluable for deployment providers that only support a single server entry point (such as Netlify Functions or AWS Lambda)

So these deployment plugins expect a single entry (a single fetch handler) whereas the framework can defines multiple entries (fetch handlers, via addEntry()), so catchAll() is required then? Ah, wait, I think I understand: if the framework already provides a single fetch entry, then catchAll() isn't required, correct?

In Vike's case, it's only required if the user doesn't define +server.js. If the user defines +server.js then the user-defined server entry acts as the single global entry, correct?

@brillout
Copy link
Member

feat: use UD auto plugin

👍 I wonder what node.importer: 'vike' is 👀

I wonder if we can/should make it completely zero-config. AFAICT it's possible, but not sure if it's what we want. I'll think about it.

What I mean with completely zero-config:

import universalDeploy from '@universal-deploy/vite'

function pluginUniversalDeploy(vikeConfig: VikeConfigInternal): Plugin | null {
  if (hasVikeServerOrVikePhoton(vikeConfig)) return null

  return (
    // That's it: a single plugin that takes care of it all
    universalDeploy({
      // UD entries can be passed via this parameter => no need to import @universal-deploy/store
      entries: [
        ...getPageEntries(),
        // Default catch-all route
        {
          id: serverEntryVike,
          route: '/**',
          // If `serverEntryVike` is the path of +server.js
          isFilesystemPath: true // => UD implements the `resolveId()` hook
        }
      ],
      prependToGlobalEntry: `import "${vikeVirtualEntry}";`,
    })
  )
}

@magne4000
Copy link
Member Author

magne4000 commented Mar 11, 2026

👍 I wonder what node.importer: 'vike' is 👀

I'm trying to find a solution for that 🤔. It's currently used to help resolve @universal-deploy/node/serve internally

EDIT: found a solution :)

@brillout
Copy link
Member

I wonder if we can/should make it completely zero-config. AFAICT it's possible, but not sure if it's what we want. I'll think about it.

I like it and IMO we should do it, with one exception: I think entries should still be added via addEntry() imported from @universal-deploy/store. It's slightly less zero-config but it shows/preserves how flexible UD is.

WDYT?

@brillout
Copy link
Member

Am I understanding it correctly that Netlify/Fastly/EdgeOne adopting UD simply means using @universal-deploy/store and that's the only UD dependency for them?

// node_modules/@{netlify,fastly,edgeone}/vite

// The only UD dependency:
import { store } from '@universal-deploy/store'

// The only API used by Vite deployment plugins:
store.entries.forEach(entry => { /* ... */ })

Or am I missing something?

@brillout
Copy link
Member

How about:

- virtual:ud:catch-all
+ virtual:global-entry

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants