@solidjs/vite-plugin 3.0.0-next.35 → 3.0.0-next.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.cjs +88 -25
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/esm/index.mjs +89 -26
- package/dist/esm/index.mjs.map +1 -1
- package/dist/types/src/ssr/index.d.ts +6 -0
- package/package.json +1 -1
package/dist/esm/index.mjs
CHANGED
|
@@ -6,7 +6,7 @@ import { mergeAndConcat } from 'merge-anything';
|
|
|
6
6
|
import { createRequire } from 'module';
|
|
7
7
|
import path from 'path';
|
|
8
8
|
import { Readable } from 'node:stream';
|
|
9
|
-
import { createFilter, normalizePath, loadEnv, runnerImport, defaultClientConditions, defaultServerConditions } from 'vite';
|
|
9
|
+
import { createFilter, normalizePath, loadEnv, runnerImport, defaultClientConditions, defaultServerConditions, defaultExternalConditions } from 'vite';
|
|
10
10
|
import { pathToFileURL, fileURLToPath } from 'node:url';
|
|
11
11
|
import { crawlFrameworkPkgs } from 'vitefu';
|
|
12
12
|
|
|
@@ -63,7 +63,16 @@ function webRequestFromNode(req, urlPath, res) {
|
|
|
63
63
|
signal = controller.signal;
|
|
64
64
|
}
|
|
65
65
|
const method = req.method || 'GET';
|
|
66
|
-
|
|
66
|
+
// Only attach a body when the request actually carries one. A web Request
|
|
67
|
+
// built by the browser for a bodyless POST has `body === null`, and the
|
|
68
|
+
// runtime keys off that (a present body that decodes to nothing is a 400
|
|
69
|
+
// since @solidjs/web 2.0.0-rc.5) — so an unconditionally attached (empty)
|
|
70
|
+
// stream misparses bodyless calls. HTTP/1 signals a body via
|
|
71
|
+
// Content-Length/Transfer-Encoding (RFC 9112 §6); the h2 compat API sets
|
|
72
|
+
// `stream.endAfterHeaders` when END_STREAM rode the headers frame.
|
|
73
|
+
const h2Stream = req.stream;
|
|
74
|
+
const hasBody = method !== 'GET' && method !== 'HEAD' && (h2Stream ? !h2Stream.endAfterHeaders : req.headers['transfer-encoding'] !== undefined || req.headers['content-length'] !== undefined && req.headers['content-length'] !== '0');
|
|
75
|
+
const body = hasBody ? Readable.toWeb(req) : undefined;
|
|
67
76
|
return new Request(url, {
|
|
68
77
|
method,
|
|
69
78
|
headers,
|
|
@@ -1167,9 +1176,11 @@ function serverFunctions(options = {}, internal = {}) {
|
|
|
1167
1176
|
`export function handleServerFunctionRequest(request, options) {`, ` const { event: eventInit, ...rest } = options || {};`, ` return handle(request, {`, ` provideEvent: provideRequestEvent,`, ` ...(eventInit ? { createEvent: (req) => ({ request: req, locals: {}, ...eventInit }) } : {}),`, ` ...rest,`, ` });`, `}`].join('\n');
|
|
1168
1177
|
}
|
|
1169
1178
|
|
|
1170
|
-
// Function IDs are
|
|
1171
|
-
//
|
|
1172
|
-
//
|
|
1179
|
+
// Function IDs are `<name>-<xxHash32(root-relative path)>[-<ordinal>]`
|
|
1180
|
+
// (identity-keyed, solidjs/solid#3109). The name is a JS identifier and
|
|
1181
|
+
// never contains `-`, so the hash is always the second segment and maps
|
|
1182
|
+
// an incoming ID back to its module. Rebuilt whenever a transform has
|
|
1183
|
+
// grown the manifest.
|
|
1173
1184
|
const hashIndex = new Map();
|
|
1174
1185
|
let hashIndexSize = -1;
|
|
1175
1186
|
function moduleForFunctionId(functionId) {
|
|
@@ -1181,7 +1192,7 @@ function serverFunctions(options = {}, internal = {}) {
|
|
|
1181
1192
|
}
|
|
1182
1193
|
hashIndexSize = manifest.server.size;
|
|
1183
1194
|
}
|
|
1184
|
-
return hashIndex.get(functionId.split('-'
|
|
1195
|
+
return hashIndex.get(functionId.split('-')[1]);
|
|
1185
1196
|
}
|
|
1186
1197
|
function moduleDevUrl(entry) {
|
|
1187
1198
|
const relative = path.relative(root, entry).split(path.sep).join('/');
|
|
@@ -1219,10 +1230,11 @@ function serverFunctions(options = {}, internal = {}) {
|
|
|
1219
1230
|
if (internal.externalDevServer || !isRunnableEnvironment(ssrEnvironment)) {
|
|
1220
1231
|
return;
|
|
1221
1232
|
}
|
|
1222
|
-
// A call's address is `<endpoint>/<id>`
|
|
1223
|
-
//
|
|
1224
|
-
//
|
|
1225
|
-
//
|
|
1233
|
+
// A call's address is `<endpoint>/<id>` — plain HTTP — or
|
|
1234
|
+
// `<endpoint>/data/<id>` — the scripted transport's own path
|
|
1235
|
+
// (solidjs/solid#3076, #3094). Bare-mount requests still reach the
|
|
1236
|
+
// runtime handler (it answers 404), so misdirected posts fail
|
|
1237
|
+
// through the endpoint rather than falling through to SSR.
|
|
1226
1238
|
const underMount = (pathname, mount) => pathname === mount || pathname.startsWith(mount + '/');
|
|
1227
1239
|
server.middlewares.use((req, res, next) => {
|
|
1228
1240
|
const url = new URL(req.url || '/', 'http://localhost');
|
|
@@ -1241,9 +1253,15 @@ function serverFunctions(options = {}, internal = {}) {
|
|
|
1241
1253
|
// Make sure the referenced module has been evaluated in the SSR
|
|
1242
1254
|
// environment so its registration exists — functions only client
|
|
1243
1255
|
// code references are never loaded by the SSR render itself.
|
|
1244
|
-
// The id lives in the path segment after the mount
|
|
1256
|
+
// The id lives in the path segment after the mount — behind a
|
|
1257
|
+
// literal `data` segment on the scripted transport's address
|
|
1258
|
+
// (solidjs/solid#3094). Segment count keeps the two apart: an id
|
|
1259
|
+
// occupies exactly one segment, so `data/<id>` is only ever a
|
|
1260
|
+
// data address, and a function id spelled `data` still parses at
|
|
1261
|
+
// the bare one.
|
|
1245
1262
|
const mount = basePrefixed ? resolvedEndpoint : endpoint;
|
|
1246
|
-
|
|
1263
|
+
let segment = url.pathname.slice(mount.length + 1);
|
|
1264
|
+
if (segment.startsWith('data/')) segment = segment.slice(5);
|
|
1247
1265
|
let functionId = null;
|
|
1248
1266
|
if (segment && !segment.includes('/')) {
|
|
1249
1267
|
try {
|
|
@@ -1252,14 +1270,6 @@ function serverFunctions(options = {}, internal = {}) {
|
|
|
1252
1270
|
// not an address; the runtime handler answers the 404
|
|
1253
1271
|
}
|
|
1254
1272
|
}
|
|
1255
|
-
if (!functionId) {
|
|
1256
|
-
// TRANSITIONAL (remove before 3.0 stable): the retired header
|
|
1257
|
-
// and `?id=` addressing, kept only for the RC window where this
|
|
1258
|
-
// plugin meets a @solidjs/web older than the path-addressing
|
|
1259
|
-
// change (solidjs/solid#3076).
|
|
1260
|
-
const headerId = req.headers['x-server-function-id'];
|
|
1261
|
-
functionId = (typeof headerId === 'string' ? headerId.split('#')[0] : undefined) || url.searchParams.get('id');
|
|
1262
|
-
}
|
|
1263
1273
|
if (functionId) {
|
|
1264
1274
|
const entry = moduleForFunctionId(functionId);
|
|
1265
1275
|
if (entry) await ssrEnvironment.runner.import(moduleDevUrl(entry));
|
|
@@ -1898,7 +1908,8 @@ function startServe(options, internal = {}) {
|
|
|
1898
1908
|
lines.push(``, `async function dispatchRequest(request, event, options) {`);
|
|
1899
1909
|
if (composeServerFunctions) {
|
|
1900
1910
|
lines.push(
|
|
1901
|
-
// A call's address is `<endpoint>/<id>`
|
|
1911
|
+
// A call's address is `<endpoint>/<id>` or `<endpoint>/data/<id>`
|
|
1912
|
+
// (solidjs/solid#3076, #3094); the prefix gate covers both, and the
|
|
1902
1913
|
// bare mount still routes so a misaddressed request 404s through the
|
|
1903
1914
|
// runtime handler instead of rendering a page at it.
|
|
1904
1915
|
` const requestPath = new URL(request.url).pathname;`, ` if (requestPath === endpoint || requestPath.startsWith(endpoint + '/')) {`,
|
|
@@ -1971,6 +1982,7 @@ function startServe(options, internal = {}) {
|
|
|
1971
1982
|
devtoolsResolutions = {};
|
|
1972
1983
|
devtoolsIds = {};
|
|
1973
1984
|
entries = resolveEntries(root, options, clientMode);
|
|
1985
|
+
internal.onDocumentResolved?.(entries.document);
|
|
1974
1986
|
middlewarePath = options.middleware ? path.resolve(root, normalizeUserPath(root, options.middleware, 'middleware')) : null;
|
|
1975
1987
|
// Server-mode only, like `entryServer`/`external` (a documented
|
|
1976
1988
|
// no-op in client mode so configs survive the `ssr` boolean flip).
|
|
@@ -2964,6 +2976,11 @@ const LAZY_PLACEHOLDER_PREFIX = '__SOLID_LAZY_MODULE__:';
|
|
|
2964
2976
|
* solid-refresh#85 — is no longer used at all).
|
|
2965
2977
|
*/
|
|
2966
2978
|
const REFRESH_RUNTIME_SOURCE = 'solid-js/refresh';
|
|
2979
|
+
|
|
2980
|
+
// Appended to the document shell's client compile instead of a refresh
|
|
2981
|
+
// boundary (see documentModuleId in solidPlugin): self-accept, then
|
|
2982
|
+
// invalidate — Vite's spelling for "this module cannot hot-update, reload".
|
|
2983
|
+
const DOCUMENT_HMR_DECLINE = '\nif (import.meta.hot) {\n import.meta.hot.accept(() => import.meta.hot.invalidate());\n}\n';
|
|
2967
2984
|
const DEFAULT_STYLE_EXCLUDE = /node_modules/;
|
|
2968
2985
|
const VIRTUAL_MANIFEST_ID = 'virtual:solid-manifest';
|
|
2969
2986
|
const RESOLVED_VIRTUAL_MANIFEST_ID = '\0' + VIRTUAL_MANIFEST_ID;
|
|
@@ -3255,6 +3272,15 @@ function solidPlugin(options = {}) {
|
|
|
3255
3272
|
const externalDevServer = !!options.ssr && !!startOptions?.external;
|
|
3256
3273
|
let needHmr = false;
|
|
3257
3274
|
let replaceDev = false;
|
|
3275
|
+
// Resolved absolute path of the start-mode document shell (normalized to
|
|
3276
|
+
// forward slashes, matching Vite ids), reported back by the start plugin's
|
|
3277
|
+
// config hook. The document is the one module whose client compile must
|
|
3278
|
+
// decline HMR instead of taking a refresh boundary: it hydrates the whole
|
|
3279
|
+
// `document`, and no component swap can re-claim `document.documentElement`
|
|
3280
|
+
// — an accepted update would be absorbed with nothing visibly changing
|
|
3281
|
+
// (solidjs/solid#3151). Declining makes a save invalidate the module, so
|
|
3282
|
+
// Vite falls back to a full page reload: the honest cost.
|
|
3283
|
+
let documentModuleId = null;
|
|
3258
3284
|
// The live dev server, kept so the dev manifest module can bake the bridge
|
|
3259
3285
|
// endpoint URL in when its code is generated (see devManifestBridgeUrl).
|
|
3260
3286
|
let devServer = null;
|
|
@@ -3497,6 +3523,20 @@ function solidPlugin(options = {}) {
|
|
|
3497
3523
|
// real server build resolves (isServer true).
|
|
3498
3524
|
...(isTestMode && !serverTestPosture && !opts.isSsrTargetWebworker ? ['browser'] : []), ...config.resolve.conditions];
|
|
3499
3525
|
|
|
3526
|
+
// `resolve.conditions` above only governs modules Vite inlines.
|
|
3527
|
+
// Externalized server deps are resolved by `fetchModule` with
|
|
3528
|
+
// `resolve.externalConditions` (default `['node', 'module-sync']`) and
|
|
3529
|
+
// handed to the module runner as concrete file paths — without
|
|
3530
|
+
// `development` there, packages that select their dev build through
|
|
3531
|
+
// the `development` export condition (@solidjs/web's server-functions
|
|
3532
|
+
// runtime among them) run their PRODUCTION copy under `vite dev`:
|
|
3533
|
+
// server errors reach the client sanitized to "Internal Server Error"
|
|
3534
|
+
// instead of carrying the real message, dev-only diagnostics vanish.
|
|
3535
|
+
// So the dev flag has to reach both lists.
|
|
3536
|
+
if (replaceDev && config.consumer !== 'client' && name !== 'client') {
|
|
3537
|
+
config.resolve.externalConditions = ['development', ...(config.resolve.externalConditions ?? defaultExternalConditions)];
|
|
3538
|
+
}
|
|
3539
|
+
|
|
3500
3540
|
// Set resolve.noExternal and resolve.external for the SSR environment.
|
|
3501
3541
|
// Only set resolve.external if noExternal is not true (to avoid conflicts with plugins like Cloudflare)
|
|
3502
3542
|
if (name === 'ssr' && solidPkgsConfig) {
|
|
@@ -3555,7 +3595,8 @@ function solidPlugin(options = {}) {
|
|
|
3555
3595
|
};
|
|
3556
3596
|
},
|
|
3557
3597
|
hotUpdate({
|
|
3558
|
-
modules
|
|
3598
|
+
modules,
|
|
3599
|
+
file
|
|
3559
3600
|
}) {
|
|
3560
3601
|
// solid-refresh only injects HMR boundaries into client modules, so
|
|
3561
3602
|
// non-client environments have no accept handlers. Without this, Vite
|
|
@@ -3575,6 +3616,19 @@ function solidPlugin(options = {}) {
|
|
|
3575
3616
|
this.environment.hot.send({
|
|
3576
3617
|
type: 'full-reload'
|
|
3577
3618
|
});
|
|
3619
|
+
// Server-only modules are the exception to the suppression: a file
|
|
3620
|
+
// with no modules in the client graph has no browser HMR path at
|
|
3621
|
+
// all — nothing client-side accepts it, so staying silent leaves
|
|
3622
|
+
// the browser rendering stale server output until a manual refresh
|
|
3623
|
+
// (e.g. the document shell, which only the server ever imports;
|
|
3624
|
+
// solidjs/solid#3151). Reload the page: the honest cost, and there
|
|
3625
|
+
// is no client update to race with by construction.
|
|
3626
|
+
const clientEnv = devServer?.environments.client;
|
|
3627
|
+
if (clientEnv && !clientEnv.moduleGraph.getModulesByFile(file)?.size) {
|
|
3628
|
+
clientEnv.hot.send({
|
|
3629
|
+
type: 'full-reload'
|
|
3630
|
+
});
|
|
3631
|
+
}
|
|
3578
3632
|
}
|
|
3579
3633
|
return [];
|
|
3580
3634
|
}
|
|
@@ -3678,7 +3732,12 @@ function solidPlugin(options = {}) {
|
|
|
3678
3732
|
if (shouldBeProcessedWithTypescript) {
|
|
3679
3733
|
plugins.push('typescript');
|
|
3680
3734
|
}
|
|
3681
|
-
|
|
3735
|
+
|
|
3736
|
+
// See the documentModuleId declaration: the document shell declines HMR
|
|
3737
|
+
// (no refresh boundary, explicit self-invalidation) so edits full-reload.
|
|
3738
|
+
const isDocumentShell = documentModuleId !== null && id === documentModuleId;
|
|
3739
|
+
const needRefresh = needHmr && !isSsr && !inNodeModules && !isDocumentShell;
|
|
3740
|
+
const declineHmr = isDocumentShell && needHmr && !isSsr;
|
|
3682
3741
|
const babelUserOptions = await getBabelUserOptions(options, source, id, !!isSsr);
|
|
3683
3742
|
|
|
3684
3743
|
// The native compiler picks its parser dialect from the file
|
|
@@ -3750,7 +3809,7 @@ function solidPlugin(options = {}) {
|
|
|
3750
3809
|
maps.push(result.map);
|
|
3751
3810
|
const finalCode = injectSsrModuleId(await resolveLazyModuleUrls(this, result.code || '', id), moduleId, !!isSsr);
|
|
3752
3811
|
return {
|
|
3753
|
-
code: finalCode,
|
|
3812
|
+
code: declineHmr ? finalCode + DOCUMENT_HMR_DECLINE : finalCode,
|
|
3754
3813
|
map: combineSourcemaps(maps)
|
|
3755
3814
|
};
|
|
3756
3815
|
}
|
|
@@ -3771,7 +3830,7 @@ function solidPlugin(options = {}) {
|
|
|
3771
3830
|
maps.push(result.map);
|
|
3772
3831
|
const finalCode = injectSsrModuleId(await resolveLazyModuleUrls(this, result.code || '', id), moduleId, !!isSsr);
|
|
3773
3832
|
return {
|
|
3774
|
-
code: finalCode,
|
|
3833
|
+
code: declineHmr ? finalCode + DOCUMENT_HMR_DECLINE : finalCode,
|
|
3775
3834
|
map: combineSourcemaps(maps)
|
|
3776
3835
|
};
|
|
3777
3836
|
}
|
|
@@ -3805,7 +3864,11 @@ function solidPlugin(options = {}) {
|
|
|
3805
3864
|
serverComponents,
|
|
3806
3865
|
ssr: !!options.ssr,
|
|
3807
3866
|
styleFilter: filterDevStyles,
|
|
3808
|
-
diagnostics: !!options.diagnostics
|
|
3867
|
+
diagnostics: !!options.diagnostics,
|
|
3868
|
+
onDocumentResolved(documentPath) {
|
|
3869
|
+
// Normalize to forward slashes to match Vite's transform ids.
|
|
3870
|
+
documentModuleId = documentPath ? documentPath.split(path.sep).join('/') : null;
|
|
3871
|
+
}
|
|
3809
3872
|
}));
|
|
3810
3873
|
}
|
|
3811
3874
|
|