Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/honor-host-noexternal-patterns.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@solidjs/vite-plugin': patch
---

Honor the host's `resolve.noExternal` patterns when adding vitefu's externals to the SSR environment. The plugin already refused to re-externalize anything `noExternal` inlines, but it compared literal names only, while Vite treats string entries as picomatch patterns and RegExp entries as tests (`createFilter(undefined, noExternal, { resolve: false })`). Since 3.0.0-next.41 the crawl also reaches the packages that consume the Solid runtime, and their non-Solid dependencies land in `ssr.external` — so a host that inlines its packages by pattern (TanStack Start's `@tanstack/start**`, whose `@tanstack/start-server-core` resolves its `#tanstack-*` imports only when Vite processes it) saw them re-externalized, and `vite dev` failed with `ERR_PACKAGE_IMPORT_NOT_DEFINED: Package import specifier "#tanstack-router-entry" is not defined`. The externals are now filtered with the same matcher Vite uses, and a single string or RegExp `noExternal` value is kept instead of being dropped.
25 changes: 23 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1270,8 +1270,13 @@ export default function solidPlugin(options: Partial<Options> = {}): Plugin[] {
// Only set resolve.external if noExternal is not true (to avoid conflicts with plugins like Cloudflare)
if (name === 'ssr' && solidPkgsConfig) {
if (config.resolve.noExternal !== true) {
const hostNoExternal = config.resolve.noExternal;
const noExternal = [
...(Array.isArray(config.resolve.noExternal) ? config.resolve.noExternal : []),
...(Array.isArray(hostNoExternal)
? hostNoExternal
: hostNoExternal
? [hostNoExternal]
: []),
...solidPkgsConfig.ssr.noExternal,
];
config.resolve.noExternal = noExternal;
Expand All @@ -1282,9 +1287,25 @@ export default function solidPlugin(options: Partial<Options> = {}): Plugin[] {
// @tanstack/solid-router 2.0.0-rc.7 → @solidjs/web) would therefore
// re-externalize a core inlined above and split the runtime again.
// Nothing inlined may appear in `external`.
//
// "Inlined" means whatever `noExternal` claims, judged the way Vite
// judges it (`createFilter(undefined, noExternal, { resolve:
// false })` in its `createIsConfiguredAsExternal`): string entries
// are picomatch patterns, RegExp entries test the id. A literal
// `includes` check only caught exact names, so a host that inlines
// its packages by pattern — TanStack Start's `@tanstack/start**`,
// whose start-server-core resolves `#tanstack-*` imports only when
// Vite processes it — saw them re-externalized once the
// semi-framework crawl reached them through its Solid adapter
// (their non-Solid dependencies land in vitefu's `ssr.external`),
// and `vite dev` failed with ERR_PACKAGE_IMPORT_NOT_DEFINED.
const keepsExternal =
noExternal.length > 0
? createFilter(undefined, noExternal, { resolve: false })
: () => true;
config.resolve.external = [
...(Array.isArray(config.resolve.external) ? config.resolve.external : []),
...solidPkgsConfig.ssr.external.filter((dep) => !noExternal.includes(dep)),
...solidPkgsConfig.ssr.external.filter((dep) => keepsExternal(dep)),
];
}
}
Expand Down
Loading