@solidjs/vite-plugin 3.0.0-next.36 → 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 +74 -25
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/esm/index.mjs +74 -25
- 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
|
@@ -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;
|
|
@@ -3569,7 +3595,8 @@ function solidPlugin(options = {}) {
|
|
|
3569
3595
|
};
|
|
3570
3596
|
},
|
|
3571
3597
|
hotUpdate({
|
|
3572
|
-
modules
|
|
3598
|
+
modules,
|
|
3599
|
+
file
|
|
3573
3600
|
}) {
|
|
3574
3601
|
// solid-refresh only injects HMR boundaries into client modules, so
|
|
3575
3602
|
// non-client environments have no accept handlers. Without this, Vite
|
|
@@ -3589,6 +3616,19 @@ function solidPlugin(options = {}) {
|
|
|
3589
3616
|
this.environment.hot.send({
|
|
3590
3617
|
type: 'full-reload'
|
|
3591
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
|
+
}
|
|
3592
3632
|
}
|
|
3593
3633
|
return [];
|
|
3594
3634
|
}
|
|
@@ -3692,7 +3732,12 @@ function solidPlugin(options = {}) {
|
|
|
3692
3732
|
if (shouldBeProcessedWithTypescript) {
|
|
3693
3733
|
plugins.push('typescript');
|
|
3694
3734
|
}
|
|
3695
|
-
|
|
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;
|
|
3696
3741
|
const babelUserOptions = await getBabelUserOptions(options, source, id, !!isSsr);
|
|
3697
3742
|
|
|
3698
3743
|
// The native compiler picks its parser dialect from the file
|
|
@@ -3764,7 +3809,7 @@ function solidPlugin(options = {}) {
|
|
|
3764
3809
|
maps.push(result.map);
|
|
3765
3810
|
const finalCode = injectSsrModuleId(await resolveLazyModuleUrls(this, result.code || '', id), moduleId, !!isSsr);
|
|
3766
3811
|
return {
|
|
3767
|
-
code: finalCode,
|
|
3812
|
+
code: declineHmr ? finalCode + DOCUMENT_HMR_DECLINE : finalCode,
|
|
3768
3813
|
map: combineSourcemaps(maps)
|
|
3769
3814
|
};
|
|
3770
3815
|
}
|
|
@@ -3785,7 +3830,7 @@ function solidPlugin(options = {}) {
|
|
|
3785
3830
|
maps.push(result.map);
|
|
3786
3831
|
const finalCode = injectSsrModuleId(await resolveLazyModuleUrls(this, result.code || '', id), moduleId, !!isSsr);
|
|
3787
3832
|
return {
|
|
3788
|
-
code: finalCode,
|
|
3833
|
+
code: declineHmr ? finalCode + DOCUMENT_HMR_DECLINE : finalCode,
|
|
3789
3834
|
map: combineSourcemaps(maps)
|
|
3790
3835
|
};
|
|
3791
3836
|
}
|
|
@@ -3819,7 +3864,11 @@ function solidPlugin(options = {}) {
|
|
|
3819
3864
|
serverComponents,
|
|
3820
3865
|
ssr: !!options.ssr,
|
|
3821
3866
|
styleFilter: filterDevStyles,
|
|
3822
|
-
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
|
+
}
|
|
3823
3872
|
}));
|
|
3824
3873
|
}
|
|
3825
3874
|
|