@solidjs/vite-plugin 3.0.0-next.28 → 3.0.0-next.29

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.
@@ -910,7 +910,15 @@ function serverFunctions(options = {}, internal = {}) {
910
910
  // the same value (config merges per key), but the handler graph cannot
911
911
  // depend on that: in dev, a mutation from an already-open page can be
912
912
  // the first request after a server restart.
913
- `configureServerFunctionsServer({ provideEvent: provideRequestEvent, endpoint: ${JSON.stringify(resolvedEndpoint)}${components ? ', transformResult: frameTransformResult, transformFlightResult: frameTransformFlightResult, transformDirectResult: frameTransformDirectResult' : ''} });`, `export const endpoint = ${JSON.stringify(resolvedEndpoint)};`, `export function handleServerFunctionRequest(request, options) {`, ` return handle(request, { provideEvent: provideRequestEvent, ...options });`, `}`].join('\n');
913
+ `configureServerFunctionsServer({ provideEvent: provideRequestEvent, endpoint: ${JSON.stringify(resolvedEndpoint)}${components ? ', transformResult: frameTransformResult, transformFlightResult: frameTransformFlightResult, transformDirectResult: frameTransformDirectResult' : ''} });`, `export const endpoint = ${JSON.stringify(resolvedEndpoint)};`,
914
+ // `options.event` is the same wrapper->event extension seam the SSR
915
+ // handler's handleRequest carries (conventionally `nativeEvent`, the
916
+ // platform's raw request object). The runtime's standalone handler
917
+ // creates its own event (`{ request, locals }`) with no init
918
+ // parameter, so the extension threads through its existing
919
+ // `createEvent` option instead — spread before `...options` so an
920
+ // explicit host-provided createEvent still wins.
921
+ `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');
914
922
  }
915
923
 
916
924
  // Function IDs are `xxHash32(root-relative path)-<count>` (see compile.ts),
@@ -994,7 +1002,15 @@ function serverFunctions(options = {}, internal = {}) {
994
1002
  // middleware chain and one stub-backed request event front the
995
1003
  // endpoint exactly as they front page SSR.
996
1004
  const handler = await server.ssrLoadModule(internal.ssrHandler ?? HANDLER_ID$1);
997
- const response = internal.ssrHandler ? await handler.handleRequest(webRequestFromNode(req, dispatchUrl)) : await handler.handleServerFunctionRequest(webRequestFromNode(req, dispatchUrl));
1005
+ // Both dispatch shapes carry the raw Node request on the event
1006
+ // (the `options.event` seam), matching the SSR dev middleware
1007
+ // and what a production Node entry passes.
1008
+ const dispatchOptions = {
1009
+ event: {
1010
+ nativeEvent: req
1011
+ }
1012
+ };
1013
+ const response = internal.ssrHandler ? await handler.handleRequest(webRequestFromNode(req, dispatchUrl), dispatchOptions) : await handler.handleServerFunctionRequest(webRequestFromNode(req, dispatchUrl), dispatchOptions);
998
1014
  await sendWebResponse(res, response);
999
1015
  })().catch(error => {
1000
1016
  if (error instanceof Error) server.ssrFixStacktrace(error);
@@ -1566,7 +1582,14 @@ function startServe(options, internal = {}) {
1566
1582
  // The runtime's response-head lifecycle: commit at shell flush,
1567
1583
  // pre-flush Location as a real redirect, post-flush Location as the
1568
1584
  // script fallback; the transform injects the doctype/head pieces.
1569
- ` return createSSRResponse(result, event, {`, ` responseInit: options.responseInit,`, ` nonce: options.nonce,`, ` transformChunk: createHtmlChunkTransform(clientEntry, options.devHead),`, ` });`, `}`, ``, `export async function handleRequest(request, options = {}) {`, ` const event = createRequestEvent(request);`,
1585
+ ` return createSSRResponse(result, event, {`, ` responseInit: options.responseInit,`, ` nonce: options.nonce,`, ` transformChunk: createHtmlChunkTransform(clientEntry, options.devHead),`, ` });`, `}`, ``, `export async function handleRequest(request, options = {}) {`,
1586
+ // `options.event` is the public wrapper->event extension seam: extra
1587
+ // fields (conventionally `nativeEvent`, the platform's raw request
1588
+ // object) spread over the event's defaults at creation, so hosts and
1589
+ // custom server entries can extend what getRequestEvent() answers
1590
+ // with — no new convention beyond createRequestEvent's own init
1591
+ // parameter (spreading undefined is a no-op).
1592
+ ` const event = createRequestEvent(request, options.event);`,
1570
1593
  // Middleware runs inside the request scope, after event creation —
1571
1594
  // getRequestEvent() answers in middleware exactly as in app code, and
1572
1595
  // nothing reaches the wire until the outermost middleware returns.
@@ -1781,7 +1804,14 @@ function startServe(options, internal = {}) {
1781
1804
  // server-function endpoint) and hands the URL to application
1782
1805
  // code, so restore the base — the deployed production handler
1783
1806
  // receives base-prefixed URLs and preview must match it.
1784
- const response = await handler.handleRequest(webRequestFromNode(req, joinBase(base, req.url || '/')));
1807
+ const response = await handler.handleRequest(webRequestFromNode(req, joinBase(base, req.url || '/')),
1808
+ // Same event extension the dev middleware and a production
1809
+ // Node entry pass: the raw Node request as `nativeEvent`.
1810
+ {
1811
+ event: {
1812
+ nativeEvent: req
1813
+ }
1814
+ });
1785
1815
  // Preview's compression middleware buffers whole responses;
1786
1816
  // opting HTML out keeps SSR streaming observable, matching
1787
1817
  // production behavior.
@@ -1833,7 +1863,14 @@ function startServe(options, internal = {}) {
1833
1863
  // deployed handler receives base-prefixed requests).
1834
1864
  const response = await handler.handleRequest(webRequestFromNode(req, joinBase(base, req.url || '/')), {
1835
1865
  devHead,
1836
- pageRequest
1866
+ pageRequest,
1867
+ // The raw Node request on the event, matching what a
1868
+ // production Node server entry passes through the
1869
+ // `options.event` seam — getRequestEvent().nativeEvent
1870
+ // answers the same in dev as deployed.
1871
+ event: {
1872
+ nativeEvent: req
1873
+ }
1837
1874
  });
1838
1875
  // A non-page request the chain never handled: the terminal
1839
1876
  // dispatch answered with the marked 404 — hand it back to
@@ -1914,6 +1951,11 @@ function startServe(options, internal = {}) {
1914
1951
  // time work, secrets rotate without a rebuild, and no secret value exists
1915
1952
  // in any dist artifact. Build-time server-value failures downgrade to a
1916
1953
  // warning (boot enforces); dev failures stay hard errors — dev IS runtime.
1954
+ // Boot validation is synchronous by design: the generated server module
1955
+ // contains no top-level await (a TLA chunk forces esnext on downstream
1956
+ // bundlers — Nitro's node-server preset rejects it), which is why async
1957
+ // validators are rejected for `server` keys (client keys may stay async;
1958
+ // they are awaited at build time where the values are baked).
1917
1959
  //
1918
1960
  // A failed validation fails the build; in dev it renders Vite's error
1919
1961
  // overlay with the per-key report (the virtual modules throw it on load)
@@ -2184,7 +2226,23 @@ function startEnv(option) {
2184
2226
  for (const side of ['server', 'client']) {
2185
2227
  for (const [key, validator] of Object.entries(schema[side] ?? {})) {
2186
2228
  let result = validator['~standard'].validate(raw[key]);
2187
- if (result instanceof Promise) result = await result;
2229
+ if (result instanceof Promise) {
2230
+ // Async validation is fine for `client` keys — their values are
2231
+ // baked right here at build time, where awaiting costs nothing.
2232
+ // `server` keys validate process.env at boot through generated
2233
+ // code that is deliberately synchronous (a top-level await in the
2234
+ // server env chunk forces esnext on every downstream bundle
2235
+ // target — Nitro's node-server preset rejects it outright), so a
2236
+ // Promise-returning server validator could only ever fail at
2237
+ // deploy boot. Async-ness is a property of the schema, not the
2238
+ // value, so fail fast here with the fix in the message. Boot
2239
+ // still backstops (schemas whose sync prefix short-circuits at
2240
+ // build time can go async on real values).
2241
+ if (side === 'server') {
2242
+ throw new Error(`[@solidjs/vite-plugin] server env var "${key}" in ${envFile} uses an async ` + `validator (validate() returned a Promise). Server env is validated ` + `synchronously at boot — the generated module contains no top-level ` + `await, so server bundles work on non-esnext targets — which async ` + `validators cannot do. Make the validator synchronous (drop async ` + `refinements/transforms), or run the async check in application code.`);
2243
+ }
2244
+ result = await result;
2245
+ }
2188
2246
  if (result.issues && result.issues.length) {
2189
2247
  for (const issue of result.issues) {
2190
2248
  const at = (issue.path ?? []).map(segment => typeof segment === 'object' && segment !== null && 'key' in segment ? String(segment.key) : String(segment)).join('.');
@@ -2261,6 +2319,16 @@ function startEnv(option) {
2261
2319
  // means. Platform-injected vars that don't exist at build time work,
2262
2320
  // secrets rotate without a rebuild, and no secret value exists in any
2263
2321
  // dist artifact.
2322
+ //
2323
+ // The generated code is deliberately free of top-level await. Module
2324
+ // init is the only point where "validated and frozen before any
2325
+ // importer's body runs" can be guaranteed — user server modules read
2326
+ // `env.KEY` at their own top level — and the only async thing here is
2327
+ // Standard Schema's option to return a Promise from validate(). A TLA
2328
+ // chunk breaks every downstream bundler with a non-esnext target
2329
+ // (Nitro's node-server preset in practice), so validation runs
2330
+ // synchronously and a Promise-returning server validator is itself a
2331
+ // boot issue (build/config time rejects it earlier when detectable).
2264
2332
  function serverEnvModuleCode(loaded) {
2265
2333
  const serverKeys = Object.keys(loaded.schema.server ?? {});
2266
2334
  const baked = `const __env = ${JSON.stringify(loaded.client)};`;
@@ -2271,7 +2339,7 @@ function startEnv(option) {
2271
2339
  };
2272
2340
  }
2273
2341
  return {
2274
- code: [`// Generated by @solidjs/vite-plugin (start.env) — server env.`, `// Server values are read from process.env and validated at boot;`, `// client (public) values are baked at build time.`, `import __schema from ${JSON.stringify(envFileAbs)};`, baked, `const __issues = [];`, `for (const __key of ${JSON.stringify(serverKeys)}) {`, ` let __result = __schema.server[__key]['~standard'].validate(process.env[__key]);`, ` if (__result instanceof Promise) __result = await __result;`, ` if (__result.issues && __result.issues.length) {`, ` for (const __issue of __result.issues) __issues.push(' \\u2717 ' + __key + ': ' + __issue.message);`, ` } else {`, ` __env[__key] = __result.value;`, ` }`, `}`, `if (__issues.length) {`, ` throw new Error(`, ` '[@solidjs/vite-plugin] server env validation failed at boot (' + __issues.length +`, ` ' issue' + (__issues.length === 1 ? '' : 's') + ') \\u2014 schema: ' + ${JSON.stringify(envFile)} +`, ` '\\n\\n' + __issues.join('\\n') +`, ` '\\n\\nServer env is read from process.env at boot, not baked at build time: set the ' +`, ` 'variables in the server process environment.'`, ` );`, `}`, `export const env = Object.freeze(__env);`, `export default env;`].join('\n'),
2342
+ code: [`// Generated by @solidjs/vite-plugin (start.env) — server env.`, `// Server values are read from process.env and validated at boot;`, `// client (public) values are baked at build time. Boot validation is`, `// synchronous on purpose: a top-level await here would force esnext`, `// on every downstream bundle target (Nitro's node-server preset and`, `// anything else below esnext rejects a TLA chunk outright).`, `import __schema from ${JSON.stringify(envFileAbs)};`, baked, `const __issues = [];`, `for (const __key of ${JSON.stringify(serverKeys)}) {`, ` const __result = __schema.server[__key]['~standard'].validate(process.env[__key]);`, ` if (__result && typeof __result.then === 'function') {`, ` __issues.push(' \\u2717 ' + __key + ': validator returned a Promise \\u2014 async validators are not supported for server keys (boot validation is synchronous so the server bundle carries no top-level await); make this validator synchronous');`, ` } else if (__result.issues && __result.issues.length) {`, ` for (const __issue of __result.issues) __issues.push(' \\u2717 ' + __key + ': ' + __issue.message);`, ` } else {`, ` __env[__key] = __result.value;`, ` }`, `}`, `if (__issues.length) {`, ` throw new Error(`, ` '[@solidjs/vite-plugin] server env validation failed at boot (' + __issues.length +`, ` ' issue' + (__issues.length === 1 ? '' : 's') + ') \\u2014 schema: ' + ${JSON.stringify(envFile)} +`, ` '\\n\\n' + __issues.join('\\n') +`, ` '\\n\\nServer env is read from process.env at boot, not baked at build time: set the ' +`, ` 'variables in the server process environment.'`, ` );`, `}`, `export const env = Object.freeze(__env);`, `export default env;`].join('\n'),
2275
2343
  moduleType: 'js'
2276
2344
  };
2277
2345
  }
@@ -2947,12 +3015,19 @@ function solidPlugin(options = {}) {
2947
3015
  exclude: solidPkgsConfig.optimizeDeps.exclude,
2948
3016
  // Vite 8+ uses Rolldown for dependency scanning. Rolldown defaults to
2949
3017
  // React's automatic JSX runtime for .tsx files, injecting a
2950
- // react/jsx-dev-runtime import. Tell it to preserve JSX as-is since
2951
- // this plugin handles JSX transformation via babel-preset-solid.
3018
+ // react/jsx-dev-runtime import that fails to resolve and aborts the
3019
+ // scan. 'preserve' is no fix: the scanner re-parses the transformed
3020
+ // output as plain JS, so any preserved JSX is a hard parse error
3021
+ // (issue #262). The classic runtime is the only scan-safe lowering:
3022
+ // it emits bare `React.createElement` calls without injecting any
3023
+ // import, and the scan output is never executed — it only exists so
3024
+ // rolldown can walk the import graph.
2952
3025
  ...(isVite8 ? {
2953
3026
  rolldownOptions: {
2954
3027
  transform: {
2955
- jsx: 'preserve'
3028
+ jsx: {
3029
+ runtime: 'classic'
3030
+ }
2956
3031
  }
2957
3032
  }
2958
3033
  } : {})