Skip to content

fix(start): resolve the server function filter and lazy ids against Vite's root - #2357

Open
dennev wants to merge 2 commits into
solidjs:mainfrom
dennev:fix/server-functions-filter-root
Open

dennev wants to merge 2 commits into
solidjs:mainfrom
dennev:fix/server-functions-filter-root

Conversation

@dennev

@dennev dennev commented Oct 19, 2026

Copy link
Copy Markdown
Contributor

PR Checklist

Please check if your PR fulfills the following requirements:

What is the current behavior?

serverFunctionsPlugin creates its filter when the plugin is created, with relative default patterns and no resolve option, so they are resolved against process.cwd(). The lazy plugin names each module relative to process.cwd() as well. On Windows a working directory entered through a junction or symlink keeps that path, while Vite resolves every module id, and since 8.2 also config.root, to the real path. Then:

  • the filter matches no module, so no "use server" function is compiled: its body ends up in the client bundle, and a build whose server functions import @solidjs/start/http fails with Attempt to import 'server-only' in a client module;
  • the id$$ of a lazily loaded route component matches no client manifest key, so its CSS is missing from the server-rendered HTML.

#2356 has the steps.

What is the new behavior?

The filter is created in configResolved, with config.root as the base for relative patterns. lazy derives id$$ from this.environment.config.root the way Vite derives its manifest keys (normalizePath(path.relative(root, id))), and the dev style lookup resolves that id against the root instead of process.cwd(). Since Vite 8.2 resolves the root like every module id (to the real path; with resolve.preserveSymlinks, since 8.2.2 the root keeps the link path as the ids do), this works when the working directory is a junction or symlink to the project; when it is the root itself, nothing changes. Relative patterns passed through the serverFunctions.filter option now resolve against the root too.

The tests make process.cwd() differ from Vite's root, which is what a junction gives on Windows, so they run on any OS:

  • src/directives/index.spec.ts (new): a module under the root's src is compiled, one outside it is left alone, and a relative custom include resolves against the root.
  • src/config/lazy.spec.ts: id$$ is relative to the root (without the change it is ../../real/app/src/routes/page.tsx); the existing cases pass the root through the plugin context.
  • src/server/collect-styles.spec.ts (new): the dev style lookup finds the styles of a root-relative id.

Without the change, four of the five new tests fail (the guard for a module outside src passes either way), and the 266 existing tests pass. A changeset is included.

Other information

Checked on Windows (Node 26.10.0, Vite 8.3.4) with the basic template and the route from #2356, plus a route whose server function imports nothing. With 2.0.6, the build through a junction fails, whether the junction is on the project's drive or on another; without the server-only import it builds, but that function's body is in the client bundle. With this branch packed and installed, both junction builds pass, the client chunks hold server references instead of function bodies, and the server-rendered index page links the same stylesheets as a build from the real path.

Not covered here: solidStart() also takes process.cwd() as its root (app entry, ~ alias, file routers), and relative css.filter patterns are resolved against it as well. Through a junction, the ~ alias treats every app module as another package's, so in vite dev a page that imports ~/... does not finish rendering (the template's index page: the request was still open after 20 s; with a relative import it renders). The file routers match the real paths in Vite's watcher events against a glob built on the link path, so route changes are probably missed in dev (from reading the code, not tried). The template still builds only because Rolldown applies its tsconfig paths to ~; without that mapping the build fails as well. solidStart() runs before Vite resolves its root, so moving these to the root means restructuring it; I left that for a separate change. With Vite before 8.2 the root keeps the link path while module ids do not, so the filter part of this change does not help there (this repository's lockfile still resolves Vite 8.1.5); the lazy ids follow Vite's own key formula either way.

…ite's root

The server function filter's default patterns are relative, and createFilter
resolved them against process.cwd(); the lazy plugin also named each module
relative to process.cwd(). On Windows a working directory entered through a
junction or symlink keeps that path, while Vite (8.2 and later) resolves its
root and every module id to the real path.

The filter then matched no module, so no "use server" function was compiled:
its body shipped in the client bundle, and a build whose server functions
import server-only code such as @solidjs/start/http failed with "Attempt to
import 'server-only' in a client module". The lazy ids matched no client
manifest key, so the CSS of lazily loaded route components was missing from
the server-rendered HTML.

Create the filter once the config is resolved, with config.root as the base
for relative patterns, and derive lazy ids from the environment's root the way
Vite derives its manifest keys. The dev style lookup resolves those ids
against the root as well.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@netlify

netlify Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for solid-start-landing-page ready!

Name Link
🔨 Latest commit 6278519
🔍 Latest deploy log https://app.netlify.com/projects/solid-start-landing-page/deploys/6ad7d51fe1201ed1b8383701
😎 Deploy Preview https://deploy-preview-2357--solid-start-landing-page.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@changeset-bot

changeset-bot Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 6278519

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@solidjs/start Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@solidjs/start@2357

commit: 6278519

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.

[Bug?]: "use server" functions are not compiled when the project is opened through a junction or symlink on Windows

3 participants