@solidjs/start 2.0.0-alpha.1 → 2.0.0-alpha.3

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.
Files changed (119) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/dist/config/constants.d.ts +1 -1
  3. package/dist/config/constants.js +1 -1
  4. package/dist/config/dev-server.js +18 -0
  5. package/dist/config/env.d.ts +19 -0
  6. package/dist/config/env.js +81 -0
  7. package/dist/config/fs-routes/fs-watcher.js +14 -20
  8. package/dist/config/fs-routes/index.js +2 -2
  9. package/dist/config/fs-routes/router.js +7 -8
  10. package/dist/config/index.d.ts +16 -1
  11. package/dist/config/index.js +30 -29
  12. package/dist/config/lazy.js +35 -5
  13. package/dist/config/manifest.js +40 -6
  14. package/dist/config/vite-utils.d.ts +6 -1
  15. package/dist/config/vite-utils.js +7 -3
  16. package/dist/directives/bubble-function-declaration.d.ts +3 -0
  17. package/dist/directives/bubble-function-declaration.js +23 -0
  18. package/dist/directives/compile.d.ts +9 -0
  19. package/dist/directives/compile.js +40 -0
  20. package/dist/directives/generate-unique-name.d.ts +3 -0
  21. package/dist/directives/generate-unique-name.js +16 -0
  22. package/dist/directives/get-descriptive-name.d.ts +2 -0
  23. package/dist/directives/get-descriptive-name.js +37 -0
  24. package/dist/directives/get-import-identifier.d.ts +4 -0
  25. package/dist/directives/get-import-identifier.js +19 -0
  26. package/dist/directives/get-root-statement-path.d.ts +2 -0
  27. package/dist/directives/get-root-statement-path.js +12 -0
  28. package/dist/directives/index.d.ts +14 -0
  29. package/dist/directives/index.js +169 -0
  30. package/dist/directives/is-statement-top-level.d.ts +3 -0
  31. package/dist/directives/is-statement-top-level.js +9 -0
  32. package/dist/directives/paths.d.ts +9 -0
  33. package/dist/directives/paths.js +36 -0
  34. package/dist/directives/plugin.d.ts +21 -0
  35. package/dist/directives/plugin.js +302 -0
  36. package/dist/directives/remove-unused-variables.d.ts +3 -0
  37. package/dist/directives/remove-unused-variables.js +53 -0
  38. package/dist/directives/types.d.ts +10 -0
  39. package/dist/directives/xxhash32.d.ts +6 -0
  40. package/dist/directives/xxhash32.js +193 -0
  41. package/dist/{server/server-runtime.d.ts → fns/client.d.ts} +1 -1
  42. package/dist/fns/client.js +106 -0
  43. package/dist/fns/handler.d.ts +5 -0
  44. package/dist/{server/server-functions-handler.js → fns/handler.js} +55 -96
  45. package/dist/fns/registration.d.ts +2 -0
  46. package/dist/fns/registration.js +12 -0
  47. package/dist/fns/serialization.d.ts +6 -0
  48. package/dist/fns/serialization.js +208 -0
  49. package/dist/fns/server.d.ts +7 -0
  50. package/dist/{server/server-fns-runtime.js → fns/server.js} +7 -1
  51. package/dist/fns/shared.d.ts +17 -0
  52. package/dist/fns/shared.js +105 -0
  53. package/dist/http/index.d.ts +1 -1
  54. package/dist/middleware/index.d.ts +20 -0
  55. package/dist/middleware/index.js +21 -1
  56. package/dist/server/StartServer.jsx +2 -0
  57. package/dist/server/assets/PatchVirtualDevStyles.d.ts +4 -0
  58. package/dist/server/assets/PatchVirtualDevStyles.jsx +28 -0
  59. package/dist/server/collect-styles.js +9 -21
  60. package/dist/server/handler.d.ts +61 -3
  61. package/dist/server/handler.js +18 -15
  62. package/dist/server/spa/StartServer.jsx +2 -0
  63. package/dist/server/spa/handler.d.ts +30 -1
  64. package/dist/server/types.d.ts +1 -1
  65. package/dist/shared/dev-overlay/CodeView.jsx +4 -4
  66. package/dist/shared/dev-overlay/DevOverlayDialog.jsx +34 -34
  67. package/dist/shared/dev-overlay/index.jsx +2 -2
  68. package/dist/shared/dev-overlay/styles.css +40 -40
  69. package/package.json +27 -20
  70. package/src/config/constants.ts +1 -1
  71. package/src/config/dev-server.ts +12 -0
  72. package/src/config/env.ts +105 -0
  73. package/src/config/fs-routes/fs-watcher.ts +17 -24
  74. package/src/config/fs-routes/index.ts +2 -2
  75. package/src/config/fs-routes/router.ts +7 -8
  76. package/src/config/index.ts +44 -40
  77. package/src/config/lazy.ts +36 -5
  78. package/src/config/manifest.ts +40 -9
  79. package/src/config/vite-utils.ts +8 -4
  80. package/src/directives/bubble-function-declaration.ts +33 -0
  81. package/src/directives/compile.ts +54 -0
  82. package/src/directives/generate-unique-name.ts +22 -0
  83. package/src/directives/get-descriptive-name.ts +39 -0
  84. package/src/directives/get-import-identifier.ts +34 -0
  85. package/src/directives/get-root-statement-path.ts +14 -0
  86. package/src/directives/index.ts +232 -0
  87. package/src/directives/is-statement-top-level.ts +13 -0
  88. package/src/directives/paths.ts +63 -0
  89. package/src/directives/plugin.ts +389 -0
  90. package/src/directives/remove-unused-variables.ts +55 -0
  91. package/src/directives/types.ts +12 -0
  92. package/src/directives/xxhash32.ts +214 -0
  93. package/src/env.d.ts +1 -1
  94. package/src/fns/client.ts +141 -0
  95. package/src/fns/handler.spec.ts +85 -0
  96. package/src/{server/server-functions-handler.ts → fns/handler.ts} +65 -117
  97. package/src/fns/registration.ts +19 -0
  98. package/src/fns/serialization.ts +250 -0
  99. package/src/{server/server-fns-runtime.ts → fns/server.ts} +17 -2
  100. package/src/fns/shared.ts +116 -0
  101. package/src/middleware/index.ts +21 -1
  102. package/src/server/StartServer.tsx +2 -0
  103. package/src/server/assets/PatchVirtualDevStyles.tsx +31 -0
  104. package/src/server/collect-styles.ts +9 -26
  105. package/src/server/handler.ts +20 -16
  106. package/src/server/spa/StartServer.tsx +2 -0
  107. package/src/server/types.ts +1 -1
  108. package/src/shared/dev-overlay/CodeView.tsx +5 -7
  109. package/src/shared/dev-overlay/DevOverlayDialog.tsx +34 -34
  110. package/src/shared/dev-overlay/get-source-map.ts +1 -1
  111. package/src/shared/dev-overlay/index.tsx +4 -4
  112. package/src/shared/dev-overlay/styles.css +40 -40
  113. package/tsconfig.json +1 -0
  114. package/dist/server/fetchEvent.spec.js +0 -65
  115. package/dist/server/server-fns-runtime.d.ts +0 -1
  116. package/dist/server/server-functions-handler.d.ts +0 -2
  117. package/dist/server/server-runtime.js +0 -194
  118. package/src/server/server-runtime.ts +0 -240
  119. /package/dist/{server/fetchEvent.spec.d.ts → directives/types.js} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,38 @@
1
1
  # @solidjs/start
2
2
 
3
+ ## 2.0.0-alpha.3
4
+
5
+ ### Minor Changes
6
+
7
+ - 798b285: Updated dependencies.
8
+ - f6f0452: seroval json mode
9
+ - d4be1b6: Add new directives plugin with shorter function IDs and inner declaration support
10
+ - b9c4ade: feat: add `env:*` runtime environment variables support
11
+
12
+ ### Patch Changes
13
+
14
+ - ff9607c: import DevEnvironment and Rollup as type from vite
15
+ - 6da636b: The server function directives runtime is now internally accessed via package.json exports instead of relative paths, fixing inconsistencies in the file resolution. Also the server functions file inclusion/exclusion patterns can now be configured in the start plugin options via `serverFunctions`.
16
+ - 2885905: fix: clone request headers in single-flight to avoid mutating immutable headers
17
+ - abe3979: reload ssr server when new route files are created in dev
18
+ - 7c288f6: Sanitize Location header value in streaming redirect script
19
+ - 6c83886: update seroval to 1.5.4
20
+ - 9d5d783: Add support for Vite 8 asset manifest loading
21
+
22
+ ## 2.0.0-alpha.2
23
+
24
+ ### Minor Changes
25
+
26
+ - 10bf932: Fix path resolution on Windows
27
+ - 40d5a27: fix onBeforeResponse
28
+ - 9201e71: fix text/html missing when ssr is false
29
+ - a9cd2cc: add `vite preview` support
30
+
31
+ ### Patch Changes
32
+
33
+ - 7077a49: Fixed CSS from shared chunks not being collected via the chunk name.
34
+ - a620eeb: Fixed virtual module CSS not being collected in vite dev.
35
+
3
36
  ## 2.0.0-alpha.1
4
37
 
5
38
  ### Patch Changes
@@ -5,7 +5,7 @@ export declare const VIRTUAL_MODULES: {
5
5
  readonly getClientManifest: "solid-start:get-client-manifest";
6
6
  readonly getManifest: "solid-start:get-manifest";
7
7
  readonly middleware: "solid-start:middleware";
8
- readonly serverFnManifest: "solidstart:server-fn-manifest";
8
+ readonly serverFnManifest: "solid-start:server-fn-manifest";
9
9
  readonly clientEntry: "solid-start:client-entry";
10
10
  readonly serverEntry: "solid-start:server-entry";
11
11
  readonly app: "solid-start:app";
@@ -5,7 +5,7 @@ export const VIRTUAL_MODULES = {
5
5
  getClientManifest: "solid-start:get-client-manifest",
6
6
  getManifest: "solid-start:get-manifest",
7
7
  middleware: "solid-start:middleware",
8
- serverFnManifest: "solidstart:server-fn-manifest",
8
+ serverFnManifest: "solid-start:server-fn-manifest",
9
9
  clientEntry: "solid-start:client-entry",
10
10
  serverEntry: "solid-start:server-entry",
11
11
  app: "solid-start:app",
@@ -1,3 +1,11 @@
1
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
+ });
6
+ }
7
+ return path;
8
+ };
1
9
  import { NodeRequest, sendNodeResponse } from "srvx/node";
2
10
  import { isRunnableDevEnvironment, } from "vite";
3
11
  import { VITE_ENVIRONMENTS } from "./constants.js";
@@ -5,6 +13,16 @@ export function devServer() {
5
13
  return [
6
14
  {
7
15
  name: "solid-start-dev-server",
16
+ configurePreviewServer(server) {
17
+ return () => {
18
+ server.middlewares.use(async (req, res) => {
19
+ res.setHeader("content-encoding", "identity");
20
+ const webReq = new NodeRequest({ req, res });
21
+ const def = await import(__rewriteRelativeImportExtension(process.cwd() + "/dist/server/entry-server.js", true));
22
+ sendNodeResponse(res, await def.default.fetch(webReq));
23
+ });
24
+ };
25
+ },
8
26
  configureServer(viteDevServer) {
9
27
  globalThis.VITE_DEV_SERVER = viteDevServer;
10
28
  return async () => {
@@ -0,0 +1,19 @@
1
+ import { type Plugin } from "vite";
2
+ declare const LOADERS: {
3
+ node: string;
4
+ "cloudflare-workers": string;
5
+ "netlify-edge": string;
6
+ };
7
+ export interface EnvPluginOptions {
8
+ server?: {
9
+ runtime?: keyof typeof LOADERS | (string & {});
10
+ load?: (mode: string) => Record<string, string>;
11
+ prefix?: string;
12
+ };
13
+ client?: {
14
+ load?: (mode: string) => Record<string, string>;
15
+ prefix?: string;
16
+ };
17
+ }
18
+ export declare function envPlugin(options?: EnvPluginOptions): Plugin;
19
+ export {};
@@ -0,0 +1,81 @@
1
+ import { loadEnv } from "vite";
2
+ const LOADERS = {
3
+ node: `export default key => process.env[key];`,
4
+ "cloudflare-workers": `import { env } from 'cloudflare:workers';export default key => env[key];`,
5
+ "netlify-edge": `export default key => Netlify.env.get(key);`,
6
+ };
7
+ const SERVER_ENV = "env:server";
8
+ const CLIENT_ENV = "env:client";
9
+ const SERVER_RUNTIME_ENV = `${SERVER_ENV}/runtime`;
10
+ const SERVER_RUNTIME_LOADER = `${SERVER_RUNTIME_ENV}/loader`;
11
+ const DEFAULT_SERVER_PREFIX = "SERVER_";
12
+ const DEFAULT_CLIENT_PREFIX = "CLIENT_";
13
+ const SERVER_ONLY_MODULE = `throw new Error('Attempt to load server-only environment variables in client runtime.');`;
14
+ const SERVER_RUNTIME_CODE = `import load from '${SERVER_RUNTIME_LOADER}';
15
+
16
+ export default new Proxy({}, {
17
+ get(_, key) {
18
+ return load(key);
19
+ },
20
+ })`;
21
+ function convertObjectToModule(object) {
22
+ let result = "";
23
+ for (const key in object) {
24
+ result += `export const ${key} = ${JSON.stringify(object[key])};`;
25
+ }
26
+ return result;
27
+ }
28
+ export function envPlugin(options) {
29
+ const currentOptions = options ?? {};
30
+ let env;
31
+ const serverPrefix = currentOptions.server?.prefix ?? DEFAULT_SERVER_PREFIX;
32
+ const clientPrefix = currentOptions.client?.prefix ?? DEFAULT_CLIENT_PREFIX;
33
+ const runtime = options?.server?.runtime ?? "node";
34
+ const runtimeCode = runtime in LOADERS ? LOADERS[runtime] : runtime;
35
+ return {
36
+ name: "solid-start:env",
37
+ enforce: "pre",
38
+ configResolved(config) {
39
+ env = config.mode !== "production" ? "development" : "production";
40
+ },
41
+ resolveId(id) {
42
+ if (id === SERVER_ENV ||
43
+ id === CLIENT_ENV ||
44
+ id === SERVER_RUNTIME_ENV ||
45
+ id === SERVER_RUNTIME_LOADER) {
46
+ return id;
47
+ }
48
+ return undefined;
49
+ },
50
+ load(id, opts) {
51
+ if (id === SERVER_ENV) {
52
+ if (!opts?.ssr) {
53
+ return SERVER_ONLY_MODULE;
54
+ }
55
+ const vars = currentOptions.server?.load
56
+ ? currentOptions.server.load(env)
57
+ : loadEnv(env, '.', serverPrefix);
58
+ return convertObjectToModule(vars);
59
+ }
60
+ if (id === CLIENT_ENV) {
61
+ const vars = currentOptions.client?.load
62
+ ? currentOptions.client.load(env)
63
+ : loadEnv(env, '.', clientPrefix);
64
+ return convertObjectToModule(vars);
65
+ }
66
+ if (id === SERVER_RUNTIME_LOADER) {
67
+ if (!opts?.ssr) {
68
+ return SERVER_ONLY_MODULE;
69
+ }
70
+ return runtimeCode;
71
+ }
72
+ if (id === SERVER_RUNTIME_ENV) {
73
+ if (!opts?.ssr) {
74
+ return SERVER_ONLY_MODULE;
75
+ }
76
+ return SERVER_RUNTIME_CODE;
77
+ }
78
+ return undefined;
79
+ },
80
+ };
81
+ }
@@ -1,3 +1,4 @@
1
+ import { VITE_ENVIRONMENTS } from "../constants.js";
1
2
  import { moduleId } from "./index.js";
2
3
  function setupWatcher(watcher, routes) {
3
4
  watcher.on("unlink", path => routes.removeRoute(path));
@@ -8,29 +9,22 @@ function createRoutesReloader(server, routes, environment) {
8
9
  routes.addEventListener("reload", handleRoutesReload);
9
10
  return () => routes.removeEventListener("reload", handleRoutesReload);
10
11
  function handleRoutesReload() {
11
- if (environment === "ssr") {
12
- // Handle server environment HMR reload
13
- const serverEnv = server.environments.server;
14
- if (serverEnv && serverEnv.moduleGraph) {
15
- const mod = serverEnv.moduleGraph.getModuleById(moduleId);
16
- if (mod) {
17
- const seen = new Set();
18
- serverEnv.moduleGraph.invalidateModule(mod, seen);
19
- }
20
- }
12
+ const envName = environment === "ssr" ? VITE_ENVIRONMENTS.server : VITE_ENVIRONMENTS.client;
13
+ const devEnv = server.environments[envName];
14
+ if (!devEnv?.moduleGraph)
15
+ return;
16
+ const mod = devEnv.moduleGraph.getModuleById(moduleId);
17
+ if (mod) {
18
+ const seen = new Set();
19
+ devEnv.moduleGraph.invalidateModule(mod, seen);
21
20
  }
22
- else {
23
- // Handle client environment HMR reload
24
- const { moduleGraph } = server;
25
- const mod = moduleGraph.getModuleById(moduleId);
21
+ if (environment !== "ssr") {
26
22
  if (mod) {
27
- const seen = new Set();
28
- moduleGraph.invalidateModule(mod, seen);
29
- server.reloadModule(mod);
23
+ devEnv.reloadModule(mod);
24
+ }
25
+ else if (devEnv.hot) {
26
+ devEnv.hot.send({ type: "full-reload" });
30
27
  }
31
- }
32
- if (!server.hot) {
33
- server.ws.send({ type: "full-reload" });
34
28
  }
35
29
  }
36
30
  }
@@ -43,8 +43,8 @@ export function fsRoutes({ routers }) {
43
43
  const buildId = `${v.src}?${v.pick.map((p) => `pick=${p}`).join("&")}`;
44
44
  return {
45
45
  src: relative(root, buildId),
46
- build: isBuild ? `_$() => import(/* @vite-ignore */ '${buildId}')$_` : undefined,
47
- import: `_$() => import(/* @vite-ignore */ '${buildId}')$_`,
46
+ build: isBuild ? `_$() => import('${buildId}')$_` : undefined,
47
+ import: `_$() => import('${buildId}')$_`,
48
48
  };
49
49
  }
50
50
  return v;
@@ -1,12 +1,11 @@
1
- import { init } from "es-module-lexer";
2
- import { parse } from "es-module-lexer";
1
+ import { init, parse } from "es-module-lexer";
3
2
  import esbuild from "esbuild";
4
3
  import fg from "fast-glob";
5
- import fs from "fs";
4
+ import fs from "node:fs";
6
5
  import micromatch from "micromatch";
7
- import { posix } from "path";
6
+ import { posix } from "node:path";
8
7
  import { pathToRegexp } from "path-to-regexp";
9
- import { normalize } from "node:path";
8
+ import { normalizePath } from "vite";
10
9
  export { pathToRegexp };
11
10
  export const glob = (path) => fg.sync(path, { absolute: true });
12
11
  export function cleanPath(src, config) {
@@ -76,7 +75,7 @@ export class BaseFileSystemRouter extends EventTarget {
76
75
  this.routes.push(route);
77
76
  }
78
77
  async addRoute(src) {
79
- src = normalize(src);
78
+ src = normalizePath(src);
80
79
  if (this.isRoute(src)) {
81
80
  try {
82
81
  const route = this.toRoute(src);
@@ -99,7 +98,7 @@ export class BaseFileSystemRouter extends EventTarget {
99
98
  }));
100
99
  }
101
100
  async updateRoute(src) {
102
- src = normalize(src);
101
+ src = normalizePath(src);
103
102
  if (this.isRoute(src)) {
104
103
  try {
105
104
  const route = this.toRoute(src);
@@ -115,7 +114,7 @@ export class BaseFileSystemRouter extends EventTarget {
115
114
  }
116
115
  }
117
116
  removeRoute(src) {
118
- src = normalize(src);
117
+ src = normalizePath(src);
119
118
  if (this.isRoute(src)) {
120
119
  const path = this.toPath(src);
121
120
  if (path === undefined) {
@@ -1,10 +1,25 @@
1
- import { type PluginOption } from "vite";
1
+ import type { PluginOption } from "vite";
2
2
  import { type Options as SolidOptions } from "vite-plugin-solid";
3
+ import { type ServerFunctionsOptions } from "../directives/index.ts";
4
+ import { type EnvPluginOptions } from "./env.ts";
3
5
  export interface SolidStartOptions {
4
6
  solid?: Partial<SolidOptions>;
5
7
  ssr?: boolean;
6
8
  routeDir?: string;
7
9
  extensions?: string[];
8
10
  middleware?: string;
11
+ serialization?: {
12
+ /**
13
+ * The serialization mode to use for server functions/actions.
14
+ * The "js" mode uses a custom binary format that is more efficient than JSON, but requires a custom deserializer (with `eval()`) on the client.
15
+ * A strong CSP should block `eval()` executions, which would prevent the "js" mode from working.
16
+ * The "json" mode uses JSON for serialization, which is less efficient but can be deserialized with `JSON.parse` on the client.
17
+ *
18
+ * @default "json"
19
+ */
20
+ mode?: "js" | "json";
21
+ };
22
+ env?: EnvPluginOptions;
23
+ serverFunctions?: Pick<ServerFunctionsOptions, "filter">;
9
24
  }
10
25
  export declare function solidStart(options?: SolidStartOptions): Array<PluginOption>;
@@ -1,11 +1,11 @@
1
- import { TanStackServerFnPlugin } from "@tanstack/server-functions-plugin";
2
1
  import { defu } from "defu";
3
2
  import { globSync } from "node:fs";
4
- import { extname, isAbsolute, join, normalize } from "node:path";
5
- import { fileURLToPath } from "node:url";
3
+ import { extname, isAbsolute, join } from "node:path";
6
4
  import solid from "vite-plugin-solid";
5
+ import { serverFunctionsPlugin } from "../directives/index.js";
7
6
  import { DEFAULT_EXTENSIONS, VIRTUAL_MODULES, VITE_ENVIRONMENTS } from "./constants.js";
8
7
  import { devServer } from "./dev-server.js";
8
+ import { envPlugin } from "./env.js";
9
9
  import { SolidStartClientFileRouter, SolidStartServerFileRouter } from "./fs-router.js";
10
10
  import { fsRoutes } from "./fs-routes/index.js";
11
11
  import lazy from "./lazy.js";
@@ -66,6 +66,16 @@ export function solidStart(options) {
66
66
  return {
67
67
  appType: "custom",
68
68
  build: { assetsDir: "_build/assets" },
69
+ optimizeDeps: {
70
+ // Suppress TS errors from Vite 7 types when configuring Vite 8's Rolldown
71
+ ...{
72
+ rolldownOptions: {
73
+ transform: {
74
+ jsx: "react",
75
+ },
76
+ },
77
+ },
78
+ },
69
79
  environments: {
70
80
  [VITE_ENVIRONMENTS.client]: {
71
81
  consumer: "client",
@@ -108,13 +118,19 @@ export function solidStart(options) {
108
118
  }
109
119
  : {}),
110
120
  },
121
+ // Depending on the package manager and dependency structure Vite externalizes @solidjs/start
122
+ // This makes sure that @solidjs/start goes through the Vite build process
123
+ noExternal: ["@solidjs/start"],
111
124
  },
112
125
  define: {
113
126
  "import.meta.env.MANIFEST": `globalThis.MANIFEST`,
114
127
  "import.meta.env.START_SSR": JSON.stringify(start.ssr),
115
- "import.meta.env.START_APP_ENTRY": `"${appEntryPath}"`,
116
- "import.meta.env.START_CLIENT_ENTRY": `"${handlers.client}"`,
128
+ // Use JSON.stringify so backslashes on Windows are escaped and
129
+ // esbuild receives a valid JS string literal for the define value
130
+ "import.meta.env.START_APP_ENTRY": JSON.stringify(appEntryPath),
131
+ "import.meta.env.START_CLIENT_ENTRY": JSON.stringify(handlers.client),
117
132
  "import.meta.env.START_DEV_OVERLAY": JSON.stringify(start.devOverlay),
133
+ "import.meta.env.SEROVAL_MODE": JSON.stringify(start.serialization?.mode || "json"),
118
134
  },
119
135
  builder: {
120
136
  sharedPlugins: true,
@@ -149,32 +165,16 @@ export function solidStart(options) {
149
165
  },
150
166
  }),
151
167
  lazy(),
168
+ envPlugin(options?.env),
152
169
  // Must be placed after fsRoutes, as treeShake will remove the
153
170
  // server fn exports added in by this plugin
154
- TanStackServerFnPlugin({
155
- // This is the ID that will be available to look up and import
156
- // our server function manifest and resolve its module
157
- manifestVirtualImportId: VIRTUAL_MODULES.serverFnManifest,
158
- directive: "use server",
159
- callers: [
160
- {
161
- envConsumer: "client",
162
- envName: VITE_ENVIRONMENTS.client,
163
- getRuntimeCode: () => `import { createServerReference } from "${normalize(fileURLToPath(new URL("../server/server-runtime", import.meta.url)))}"`,
164
- replacer: opts => `createServerReference('${opts.functionId}')`,
165
- },
166
- {
167
- envConsumer: "server",
168
- envName: VITE_ENVIRONMENTS.server,
169
- getRuntimeCode: () => `import { createServerReference } from '${normalize(fileURLToPath(new URL("../server/server-fns-runtime", import.meta.url)))}'`,
170
- replacer: opts => `createServerReference(${opts.fn}, '${opts.functionId}')`,
171
- },
172
- ],
173
- provider: {
174
- envName: VITE_ENVIRONMENTS.server,
175
- getRuntimeCode: () => `import { createServerReference } from '${normalize(fileURLToPath(new URL("../server/server-fns-runtime", import.meta.url)))}'`,
176
- replacer: opts => `createServerReference(${opts.fn}, '${opts.functionId}')`,
171
+ serverFunctionsPlugin({
172
+ manifest: VIRTUAL_MODULES.serverFnManifest,
173
+ runtime: {
174
+ server: '@solidjs/start/fns/server',
175
+ client: '@solidjs/start/fns/client',
177
176
  },
177
+ filter: options?.serverFunctions?.filter,
178
178
  }),
179
179
  {
180
180
  name: "solid-start:virtual-modules",
@@ -200,8 +200,9 @@ export function solidStart(options) {
200
200
  {
201
201
  name: "solid-start:capture-client-bundle",
202
202
  enforce: "post",
203
- generateBundle(_options, bundle) {
203
+ generateBundle(options, bundle) {
204
204
  globalThis.START_CLIENT_BUNDLE = bundle;
205
+ globalThis.START_CLIENT_OUT_DIR = options.dir;
205
206
  },
206
207
  },
207
208
  devServer(),
@@ -1,7 +1,7 @@
1
1
  import babel from "@babel/core";
2
2
  import * as t from "@babel/types";
3
- import { sep as osSep } from "path";
4
- import { basename, relative, sep } from "path/posix";
3
+ import { sep as osSep } from "node:path";
4
+ import { basename, relative, sep } from "node:path/posix";
5
5
  import { VITE_ENVIRONMENTS } from "./constants.js";
6
6
  const idTransform = (id) => {
7
7
  return {
@@ -35,13 +35,42 @@ const importTransform = () => {
35
35
  const fileEndingRegex = /(ts|js)x(\?.*)?$/;
36
36
  const lazy = () => {
37
37
  const cwd = process.cwd().replaceAll(osSep, sep);
38
+ /**
39
+ * Maps module ids to their client-specific shared chunk names.
40
+ * Modules in shared chunks need to find their assets via the chunk name, instead of their module id.
41
+ *
42
+ * Vite includes assets of such modules in the manifest via the chunk name:
43
+ * https://github.com/vitejs/vite/blob/4be37a8389c67873880f826b01fe40137e1c29a7/packages/vite/src/node/plugins/manifest.ts#L179
44
+ * https://github.com/vitejs/vite/blob/4be37a8389c67873880f826b01fe40137e1c29a7/packages/vite/src/node/plugins/manifest.ts#L319
45
+ *
46
+ * Rollup occassionally creates shared chunks automatically,
47
+ * but they can also be manually created by the user via:
48
+ * https://rollupjs.org/configuration-options/#output-manualchunks
49
+ *
50
+ * More infos on Rollup's logic:
51
+ * https://github.com/rollup/rollup/issues/3772#issuecomment-689955168
52
+ */
53
+ const sharedChunkNames = {};
38
54
  return {
39
55
  name: "solid-lazy-css",
40
56
  enforce: "pre",
41
- applyToEnvironment(env) {
42
- return env.name === VITE_ENVIRONMENTS.server;
57
+ generateBundle(_, bundle) {
58
+ if (this.environment.name !== VITE_ENVIRONMENTS.client)
59
+ return;
60
+ for (const chunk of Object.values(bundle)) {
61
+ if (chunk.type !== "chunk" || !chunk.isDynamicEntry || chunk.facadeModuleId)
62
+ continue;
63
+ // Has to follow Vites implementation:
64
+ // https://github.com/vitejs/vite/blob/4be37a8389c67873880f826b01fe40137e1c29a7/packages/vite/src/node/plugins/manifest.ts#L179
65
+ const chunkName = `_${basename(chunk.fileName)}`;
66
+ for (const id of chunk.moduleIds) {
67
+ sharedChunkNames[id] = chunkName;
68
+ }
69
+ }
43
70
  },
44
71
  async transform(src, id) {
72
+ if (this.environment.name !== VITE_ENVIRONMENTS.server)
73
+ return;
45
74
  if (!id.match(fileEndingRegex))
46
75
  return;
47
76
  // The transformed files either import "lazy" or css files
@@ -52,7 +81,8 @@ const lazy = () => {
52
81
  const hasDefaultExport = src.indexOf("export default") !== -1;
53
82
  if (hasDefaultExport) {
54
83
  const localId = relative(cwd, id);
55
- plugins.push(idTransform(localId));
84
+ const chunkName = sharedChunkNames[id];
85
+ plugins.push(idTransform(chunkName ?? localId));
56
86
  }
57
87
  const hasLazy = src.indexOf("lazy(") !== -1;
58
88
  if (hasLazy)
@@ -1,5 +1,9 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { version as viteVersion } from "vite";
1
4
  import { findStylesInModuleGraph } from "../server/collect-styles.js";
2
5
  import { VIRTUAL_MODULES } from "./constants.js";
6
+ import { wrapId } from "./vite-utils.js";
3
7
  export function manifest(start) {
4
8
  let devServer = undefined;
5
9
  return {
@@ -34,7 +38,37 @@ export function manifest(start) {
34
38
  const entry = Object.values(globalThis.START_CLIENT_BUNDLE).find(v => "isEntry" in v && v.isEntry);
35
39
  if (!entry)
36
40
  throw new Error("No client entry found");
37
- clientViteManifest = JSON.parse(globalThis.START_CLIENT_BUNDLE[".vite/manifest.json"].source);
41
+ let rawManifest;
42
+ const viteMajor = parseInt(viteVersion.split('.')[0], 10);
43
+ const manifestKey = Object.keys(globalThis.START_CLIENT_BUNDLE).find(k => k.endsWith("manifest.json"));
44
+ if (manifestKey && viteMajor < 8) {
45
+ const manifestAsset = globalThis.START_CLIENT_BUNDLE[manifestKey];
46
+ rawManifest = manifestAsset.source;
47
+ }
48
+ else {
49
+ try {
50
+ const appRoot = start.appRoot || "./src";
51
+ let outDir = ".solid-start/client";
52
+ if (devServer?.environments?.client?.config?.build?.outDir) {
53
+ outDir = devServer.environments.client.config.build.outDir;
54
+ }
55
+ else if (this.environment?.config?.build?.outDir && this.environment?.config?.consumer === "client") {
56
+ outDir = this.environment.config.build.outDir;
57
+ }
58
+ else if (globalThis.START_CLIENT_OUT_DIR) {
59
+ outDir = globalThis.START_CLIENT_OUT_DIR;
60
+ }
61
+ const manifestPath = path.resolve(appRoot, "..", outDir, ".vite/manifest.json");
62
+ rawManifest = fs.readFileSync(manifestPath, "utf-8");
63
+ }
64
+ catch (e) {
65
+ throw new Error(`Manifest asset not found in bundle and could not be read from disk. Keys: ${Object.keys(globalThis.START_CLIENT_BUNDLE).join(", ")}. Error: ${e}`);
66
+ }
67
+ }
68
+ if (!rawManifest) {
69
+ throw new Error("Failed to extract or read raw manifest.");
70
+ }
71
+ clientViteManifest = JSON.parse(rawManifest);
38
72
  }
39
73
  return `export const clientViteManifest = ${JSON.stringify(clientViteManifest)};`;
40
74
  }
@@ -43,12 +77,12 @@ export function manifest(start) {
43
77
  else if (id.startsWith("/@manifest")) {
44
78
  if (this.environment.mode !== "dev")
45
79
  throw new Error("@manifest queries are only allowed in dev");
46
- const [path, query] = id.split("?");
80
+ const [urlPath, query] = id.split("?");
47
81
  const target = id.split("/")[2];
48
82
  const params = new URLSearchParams(query);
49
- if (!path || !query)
83
+ if (!urlPath || !query)
50
84
  return;
51
- if (path.endsWith("assets")) {
85
+ if (urlPath.endsWith("assets")) {
52
86
  const id = params.get("id");
53
87
  if (!id) {
54
88
  throw new Error("Missing id to get assets.");
@@ -61,10 +95,10 @@ export function manifest(start) {
61
95
  tag: "style",
62
96
  attrs: {
63
97
  type: "text/css",
64
- "data-vite-dev-id": "${key}",
98
+ "data-vite-dev-id": "${wrapId(key)}",
65
99
  "data-vite-ref": "0",
66
100
  },
67
- children: () => import("${value}?inline").then(mod => mod.default),
101
+ children: () => import("${wrapId(value)}?inline").then(mod => mod.default),
68
102
  }`);
69
103
  return `export default [${cssAssets.join(",")}]`;
70
104
  }
@@ -1,9 +1,14 @@
1
- import { DevEnvironment, Rollup } from "vite";
1
+ import type { DevEnvironment, Rollup } from "vite";
2
2
  export declare function cleanUrl(url: string): string;
3
3
  export declare const FS_PREFIX = "/@fs/";
4
4
  export declare const VALID_ID_PREFIX = "/@id/";
5
5
  export declare const NULL_BYTE_PLACEHOLDER = "__x00__";
6
6
  export declare function normalizeResolvedIdToUrl(environment: DevEnvironment, url: string, resolved: Rollup.PartialResolvedId): string;
7
+ /**
8
+ * Inspired by:
9
+ * https://github.com/withastro/astro/blob/fddde5fad81007795eb263c7fd0cea096b8e2cba/packages/astro/src/core/util.ts#L115
10
+ * https://github.com/vitejs/vite/blob/130e7181a55c524383c63bbfb1749d0ff7185cad/packages/vite/src/shared/utils.ts#L11
11
+ */
7
12
  export declare function wrapId(id: string): string;
8
13
  export declare function unwrapId(id: string): string;
9
14
  export declare function normalizeViteImportAnalysisUrl(environment: DevEnvironment, id: string): string;
@@ -7,6 +7,7 @@ export function cleanUrl(url) {
7
7
  export const FS_PREFIX = `/@fs/`;
8
8
  export const VALID_ID_PREFIX = `/@id/`;
9
9
  export const NULL_BYTE_PLACEHOLDER = `__x00__`;
10
+ const NULL_BYTE_REGEX = /^\0/;
10
11
  export function normalizeResolvedIdToUrl(environment, url, resolved) {
11
12
  const root = environment.config.root;
12
13
  const depsOptimizer = environment.depsOptimizer;
@@ -38,10 +39,13 @@ export function normalizeResolvedIdToUrl(environment, url, resolved) {
38
39
  }
39
40
  return url;
40
41
  }
42
+ /**
43
+ * Inspired by:
44
+ * https://github.com/withastro/astro/blob/fddde5fad81007795eb263c7fd0cea096b8e2cba/packages/astro/src/core/util.ts#L115
45
+ * https://github.com/vitejs/vite/blob/130e7181a55c524383c63bbfb1749d0ff7185cad/packages/vite/src/shared/utils.ts#L11
46
+ */
41
47
  export function wrapId(id) {
42
- return id.startsWith(VALID_ID_PREFIX)
43
- ? id
44
- : VALID_ID_PREFIX + id.replace("\0", NULL_BYTE_PLACEHOLDER);
48
+ return id.replace(NULL_BYTE_REGEX, `${VALID_ID_PREFIX}${NULL_BYTE_PLACEHOLDER}`);
45
49
  }
46
50
  export function unwrapId(id) {
47
51
  return id.startsWith(VALID_ID_PREFIX)
@@ -0,0 +1,3 @@
1
+ import type * as babel from "@babel/core";
2
+ import * as t from "@babel/types";
3
+ export declare function bubbleFunctionDeclaration(path: babel.NodePath<t.FunctionDeclaration>): void;
@@ -0,0 +1,23 @@
1
+ import * as t from "@babel/types";
2
+ export function bubbleFunctionDeclaration(path) {
3
+ const decl = path.node;
4
+ // Check if declaration is FunctionDeclaration
5
+ if (decl.id) {
6
+ const block = (path.findParent(current => current.isBlockStatement()) ||
7
+ path.scope.getProgramParent().path);
8
+ if (path.parentPath.isExportNamedDeclaration()) {
9
+ path.parentPath.replaceWith(t.exportNamedDeclaration(undefined, [t.exportSpecifier(decl.id, decl.id)]));
10
+ }
11
+ else if (path.parentPath.isExportDefaultDeclaration()) {
12
+ path.replaceWith(decl.id);
13
+ }
14
+ else {
15
+ path.remove();
16
+ }
17
+ const [tmp] = block.unshiftContainer("body", t.variableDeclaration("const", [
18
+ t.variableDeclarator(decl.id, t.functionExpression(decl.id, decl.params, decl.body, decl.generator, decl.async)),
19
+ ]));
20
+ block.scope.registerDeclaration(tmp);
21
+ tmp.skip();
22
+ }
23
+ }
@@ -0,0 +1,9 @@
1
+ import * as babel from "@babel/core";
2
+ import { type StateContext } from "./plugin.ts";
3
+ export interface CompileResult {
4
+ valid: boolean;
5
+ code: string;
6
+ map: babel.BabelFileResult["map"];
7
+ }
8
+ export type CompileOptions = Omit<StateContext, "count" | "hash" | "imports" | "valid">;
9
+ export declare function compile(id: string, code: string, options: CompileOptions): Promise<CompileResult>;