@solidjs/start 1.2.1 → 2.0.0-alpha.1

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 (191) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +2 -2
  3. package/dist/client/StartClient.d.ts +0 -1
  4. package/dist/client/StartClient.jsx +2 -4
  5. package/dist/client/index.d.ts +2 -3
  6. package/dist/client/index.jsx +2 -4
  7. package/dist/client/mount.d.ts +1 -7
  8. package/dist/client/mount.js +1 -91
  9. package/dist/client/spa/index.d.ts +1 -2
  10. package/dist/client/spa/index.jsx +1 -2
  11. package/dist/config/constants.d.ts +16 -0
  12. package/dist/config/constants.js +16 -0
  13. package/dist/config/dev-server.d.ts +2 -0
  14. package/dist/config/dev-server.js +108 -0
  15. package/dist/config/fs-router.d.ts +37 -0
  16. package/dist/config/fs-router.js +141 -0
  17. package/dist/config/fs-routes/fs-watcher.d.ts +3 -0
  18. package/dist/config/fs-routes/fs-watcher.js +49 -0
  19. package/dist/config/fs-routes/index.d.ts +7 -0
  20. package/dist/config/fs-routes/index.js +107 -0
  21. package/dist/config/fs-routes/router.d.ts +37 -0
  22. package/dist/config/fs-routes/router.js +136 -0
  23. package/dist/config/fs-routes/tree-shake.d.ts +2 -0
  24. package/dist/config/fs-routes/tree-shake.js +348 -0
  25. package/dist/config/index.d.ts +10 -0
  26. package/dist/config/index.js +214 -0
  27. package/dist/config/lazy.d.ts +3 -0
  28. package/dist/config/lazy.js +82 -0
  29. package/dist/config/manifest.d.ts +3 -0
  30. package/dist/config/manifest.js +74 -0
  31. package/dist/config/utils.d.ts +4 -0
  32. package/dist/config/utils.js +6 -0
  33. package/dist/config/vite-utils.d.ts +16 -0
  34. package/dist/config/vite-utils.js +81 -0
  35. package/dist/http/index.d.ts +81 -0
  36. package/dist/http/index.js +129 -0
  37. package/dist/index.d.ts +5 -5
  38. package/dist/index.jsx +5 -5
  39. package/dist/middleware/index.d.ts +6 -6
  40. package/dist/middleware/index.js +39 -0
  41. package/dist/{router/FileRoutes.js → router.jsx} +7 -8
  42. package/dist/server/StartServer.d.ts +3 -3
  43. package/dist/server/StartServer.jsx +9 -63
  44. package/dist/server/assets/index.d.ts +2 -0
  45. package/dist/server/assets/index.js +52 -0
  46. package/dist/server/assets/render.d.ts +19 -0
  47. package/dist/server/{renderAsset.jsx → assets/render.jsx} +1 -1
  48. package/dist/server/collect-styles.d.ts +3 -0
  49. package/dist/server/collect-styles.js +69 -0
  50. package/dist/server/fetchEvent.d.ts +4 -3
  51. package/dist/server/fetchEvent.js +12 -74
  52. package/dist/server/fetchEvent.spec.js +18 -197
  53. package/dist/server/handler.d.ts +6 -12
  54. package/dist/server/handler.js +193 -96
  55. package/dist/server/index.d.ts +9 -6
  56. package/dist/server/index.jsx +14 -6
  57. package/dist/server/manifest/client-manifest.d.ts +9 -0
  58. package/dist/server/manifest/client-manifest.js +6 -0
  59. package/dist/server/manifest/dev-client-manifest.d.ts +4 -0
  60. package/dist/server/manifest/dev-client-manifest.js +24 -0
  61. package/dist/server/manifest/dev-ssr-manifest.d.ts +5 -0
  62. package/dist/server/manifest/dev-ssr-manifest.js +23 -0
  63. package/dist/server/manifest/prod-client-manifest.d.ts +5 -0
  64. package/dist/server/manifest/prod-client-manifest.js +26 -0
  65. package/dist/server/manifest/prod-ssr-manifest.d.ts +6 -0
  66. package/dist/server/manifest/prod-ssr-manifest.js +85 -0
  67. package/dist/server/manifest/ssr-manifest.d.ts +4 -0
  68. package/dist/server/manifest/ssr-manifest.js +6 -0
  69. package/dist/{router → server}/routes.d.ts +5 -10
  70. package/dist/{router → server}/routes.js +32 -33
  71. package/dist/{runtime → server}/server-fns-runtime.d.ts +1 -1
  72. package/dist/{runtime → server}/server-fns-runtime.js +8 -7
  73. package/dist/server/server-functions-handler.d.ts +2 -0
  74. package/dist/{runtime/server-handler.js → server/server-functions-handler.js} +57 -97
  75. package/dist/server/server-runtime.d.ts +3 -0
  76. package/dist/{runtime → server}/server-runtime.js +17 -24
  77. package/dist/server/spa/StartServer.d.ts +1 -1
  78. package/dist/server/spa/StartServer.jsx +7 -9
  79. package/dist/server/spa/handler.d.ts +3 -3
  80. package/dist/server/spa/handler.js +9 -11
  81. package/dist/server/spa/index.d.ts +4 -3
  82. package/dist/server/spa/index.jsx +4 -3
  83. package/dist/server/types.d.ts +7 -9
  84. package/dist/server/util.d.ts +2 -0
  85. package/dist/server/util.js +8 -0
  86. package/dist/shared/ErrorBoundary.jsx +2 -2
  87. package/dist/shared/HttpHeader.jsx +4 -2
  88. package/dist/shared/{HttpStatusCode.jsx → HttpStatusCode.js} +3 -1
  89. package/dist/shared/dev-overlay/CodeView.d.ts +1 -1
  90. package/dist/shared/dev-overlay/CodeView.jsx +23 -34
  91. package/dist/shared/dev-overlay/DevOverlayDialog.d.ts +2 -2
  92. package/dist/shared/dev-overlay/DevOverlayDialog.jsx +73 -64
  93. package/dist/shared/dev-overlay/createStackFrame.js +3 -3
  94. package/dist/shared/dev-overlay/get-source-map.d.ts +1 -1
  95. package/dist/shared/dev-overlay/get-source-map.js +5 -5
  96. package/dist/shared/dev-overlay/icons.d.ts +10 -10
  97. package/dist/shared/dev-overlay/icons.jsx +91 -91
  98. package/dist/shared/dev-overlay/index.jsx +6 -9
  99. package/dist/shared/lazy.d.ts +3 -0
  100. package/dist/shared/lazy.js +42 -0
  101. package/dist/shared/serverFunction.d.ts +1 -1
  102. package/env.d.ts +2 -19
  103. package/package.json +44 -65
  104. package/scripts/build.js +15 -0
  105. package/scripts/validate-imports.js +316 -0
  106. package/src/client/StartClient.tsx +34 -0
  107. package/src/client/index.tsx +2 -0
  108. package/src/client/mount.ts +1 -0
  109. package/src/client/spa/index.tsx +9 -0
  110. package/src/config/constants.ts +19 -0
  111. package/src/config/dev-server.ts +145 -0
  112. package/{config/fs-router.js → src/config/fs-router.ts} +49 -29
  113. package/src/config/fs-routes/fs-watcher.ts +77 -0
  114. package/src/config/fs-routes/index.ts +136 -0
  115. package/src/config/fs-routes/router.ts +169 -0
  116. package/src/config/fs-routes/tree-shake.ts +371 -0
  117. package/src/config/index.ts +233 -0
  118. package/src/config/lazy.ts +100 -0
  119. package/src/config/manifest.ts +84 -0
  120. package/src/config/utils.ts +5 -0
  121. package/src/config/vite-utils.ts +109 -0
  122. package/src/env.d.ts +17 -0
  123. package/src/http/index.ts +216 -0
  124. package/src/index.tsx +7 -0
  125. package/src/internal.d.ts +14 -0
  126. package/src/middleware/index.ts +72 -0
  127. package/src/router.tsx +37 -0
  128. package/src/server/StartServer.tsx +56 -0
  129. package/src/server/assets/index.ts +70 -0
  130. package/src/server/assets/render.tsx +46 -0
  131. package/src/server/collect-styles.ts +87 -0
  132. package/src/server/fetchEvent.spec.ts +85 -0
  133. package/src/server/fetchEvent.ts +36 -0
  134. package/src/server/handler.ts +257 -0
  135. package/src/server/index.tsx +29 -0
  136. package/src/server/manifest/client-manifest.ts +8 -0
  137. package/src/server/manifest/dev-client-manifest.ts +21 -0
  138. package/src/server/manifest/dev-ssr-manifest.ts +23 -0
  139. package/src/server/manifest/prod-client-manifest.ts +21 -0
  140. package/src/server/manifest/prod-ssr-manifest.ts +109 -0
  141. package/src/server/manifest/ssr-manifest.ts +10 -0
  142. package/src/server/routes.ts +126 -0
  143. package/src/server/server-fns-runtime.ts +31 -0
  144. package/src/server/server-functions-handler.ts +339 -0
  145. package/src/server/server-runtime.ts +240 -0
  146. package/src/server/spa/StartServer.tsx +40 -0
  147. package/src/server/spa/handler.ts +29 -0
  148. package/src/server/spa/index.tsx +5 -0
  149. package/src/server/types.ts +82 -0
  150. package/src/server/util.ts +12 -0
  151. package/src/shared/ErrorBoundary.tsx +52 -0
  152. package/src/shared/GET.ts +8 -0
  153. package/src/shared/HttpHeader.tsx +42 -0
  154. package/src/shared/HttpStatusCode.ts +27 -0
  155. package/src/shared/clientOnly.ts +44 -0
  156. package/src/shared/dev-overlay/CodeView.tsx +92 -0
  157. package/src/shared/dev-overlay/DevOverlayDialog.tsx +316 -0
  158. package/src/shared/dev-overlay/createStackFrame.ts +74 -0
  159. package/src/shared/dev-overlay/download.ts +6 -0
  160. package/src/shared/dev-overlay/env.d.ts +4 -0
  161. package/src/shared/dev-overlay/get-source-map.ts +33 -0
  162. package/src/shared/dev-overlay/icons.tsx +456 -0
  163. package/src/shared/dev-overlay/index.tsx +63 -0
  164. package/src/shared/dev-overlay/styles.css +292 -0
  165. package/src/shared/lazy.ts +52 -0
  166. package/src/shared/serverFunction.ts +10 -0
  167. package/src/virtual.d.ts +27 -0
  168. package/tsconfig.json +23 -0
  169. package/vitest.config.ts +9 -0
  170. package/config/index.d.ts +0 -40
  171. package/config/index.js +0 -304
  172. package/config/server-components.js +0 -106
  173. package/dist/client/islands.d.ts +0 -7
  174. package/dist/client/islands.jsx +0 -10
  175. package/dist/middleware/index.jsx +0 -35
  176. package/dist/router/index.d.ts +0 -1
  177. package/dist/router/index.jsx +0 -2
  178. package/dist/router/lazyRoute.d.ts +0 -6
  179. package/dist/router/lazyRoute.js +0 -53
  180. package/dist/runtime/server-handler.d.ts +0 -2
  181. package/dist/runtime/server-runtime.d.ts +0 -3
  182. package/dist/server/islands/index.d.ts +0 -19
  183. package/dist/server/islands/index.jsx +0 -62
  184. package/dist/server/islands/utils.d.ts +0 -1
  185. package/dist/server/islands/utils.jsx +0 -85
  186. package/dist/server/pageEvent.d.ts +0 -2
  187. package/dist/server/pageEvent.js +0 -56
  188. package/dist/server/renderAsset.d.ts +0 -2
  189. /package/dist/{router/FileRoutes.d.ts → router.d.ts} +0 -0
  190. /package/dist/shared/{clientOnly.jsx → clientOnly.js} +0 -0
  191. /package/dist/shared/{serverFunction.jsx → serverFunction.js} +0 -0
@@ -0,0 +1,371 @@
1
+ // All credit for this work goes to the amazing Next.js team.
2
+ // https://github.com/vercel/next.js/blob/canary/packages/next/build/babel/plugins/next-ssg-transform.ts
3
+ // This is adapted to work with routeData functions. It can be run in two modes, one which preserves the routeData and the Component in the same file, and one which creates a
4
+
5
+ import type * as Babel from "@babel/core";
6
+ import type { NodePath, PluginObj, PluginPass } from "@babel/core";
7
+ import type { Binding } from "@babel/traverse";
8
+ import { basename } from "pathe";
9
+ import type { Plugin, ResolvedConfig, ViteDevServer } from "vite";
10
+
11
+ type State = Omit<PluginPass, "opts"> & {
12
+ opts: { pick: string[] };
13
+ refs: Set<any>;
14
+ done: boolean;
15
+ };
16
+
17
+ function treeShakeTransform({ types: t }: typeof Babel): PluginObj<State> {
18
+ function getIdentifier(path: any) {
19
+ const parentPath = path.parentPath;
20
+ if (parentPath.type === "VariableDeclarator") {
21
+ const pp = parentPath;
22
+ const name = pp.get("id");
23
+ return name.node.type === "Identifier" ? name : null;
24
+ }
25
+ if (parentPath.type === "AssignmentExpression") {
26
+ const pp = parentPath;
27
+ const name = pp.get("left");
28
+ return name.node.type === "Identifier" ? name : null;
29
+ }
30
+ if (path.node.type === "ArrowFunctionExpression") {
31
+ return null;
32
+ }
33
+ return path.node.id && path.node.id.type === "Identifier" ? path.get("id") : null;
34
+ }
35
+
36
+ function isIdentifierReferenced(ident: any) {
37
+ const b: Binding | undefined = ident.scope.getBinding(ident.node.name);
38
+ if (b?.referenced) {
39
+ if (b.path.type === "FunctionDeclaration") {
40
+ return !b.constantViolations
41
+ .concat(b.referencePaths)
42
+ .every(ref => ref.findParent(p => p === b.path));
43
+ }
44
+ return true;
45
+ }
46
+ return false;
47
+ }
48
+ function markFunction(path: any, state: any) {
49
+ const ident = getIdentifier(path);
50
+ if (ident && ident.node && isIdentifierReferenced(ident)) {
51
+ state.refs.add(ident);
52
+ }
53
+ }
54
+ function markImport(path: any, state: any) {
55
+ const local = path.get("local");
56
+ if (isIdentifierReferenced(local)) {
57
+ state.refs.add(local);
58
+ }
59
+ }
60
+
61
+ return {
62
+ visitor: {
63
+ Program: {
64
+ enter(path, state) {
65
+ state.refs = new Set();
66
+ state.done = false;
67
+ path.traverse(
68
+ {
69
+ VariableDeclarator(variablePath, variableState: any) {
70
+ if (variablePath.node.id.type === "Identifier") {
71
+ const local = variablePath.get("id");
72
+ if (isIdentifierReferenced(local)) {
73
+ variableState.refs.add(local);
74
+ }
75
+ } else if (variablePath.node.id.type === "ObjectPattern") {
76
+ const pattern = variablePath.get("id");
77
+ const properties = pattern.get("properties") as Array<NodePath>;
78
+ properties.forEach(p => {
79
+ const local = p.get(
80
+ p.node.type === "ObjectProperty"
81
+ ? "value"
82
+ : p.node.type === "RestElement"
83
+ ? "argument"
84
+ : (() => {
85
+ throw new Error("invariant");
86
+ })(),
87
+ );
88
+ if (isIdentifierReferenced(local)) {
89
+ variableState.refs.add(local);
90
+ }
91
+ });
92
+ } else if (variablePath.node.id.type === "ArrayPattern") {
93
+ const pattern = variablePath.get("id");
94
+ const elements = pattern.get("elements") as Array<NodePath>;
95
+ elements.forEach(e => {
96
+ let local: NodePath<any>;
97
+ if (e.node && e.node.type === "Identifier") {
98
+ local = e;
99
+ } else if (e.node && e.node.type === "RestElement") {
100
+ local = e.get("argument");
101
+ } else {
102
+ return;
103
+ }
104
+ if (isIdentifierReferenced(local)) {
105
+ variableState.refs.add(local);
106
+ }
107
+ });
108
+ }
109
+ },
110
+ ExportDefaultDeclaration(exportNamedPath) {
111
+ // if opts.keep is true, we don't remove the routeData export
112
+ if (state.opts.pick && !state.opts.pick.includes("default")) {
113
+ exportNamedPath.remove();
114
+ }
115
+ },
116
+ ExportNamedDeclaration(exportNamedPath) {
117
+ // if opts.keep is false, we don't remove the routeData export
118
+ if (!state.opts.pick) {
119
+ return;
120
+ }
121
+ const specifiers = exportNamedPath.get("specifiers");
122
+ if (specifiers.length) {
123
+ specifiers.forEach(s => {
124
+ if (
125
+ t.isIdentifier(s.node.exported)
126
+ ? s.node.exported.name
127
+ : state.opts.pick.includes(s.node.exported.value)
128
+ ) {
129
+ s.remove();
130
+ }
131
+ });
132
+ if (exportNamedPath.node.specifiers.length < 1) {
133
+ exportNamedPath.remove();
134
+ }
135
+ return;
136
+ }
137
+ const decl = exportNamedPath.get("declaration");
138
+ if (decl == null || decl.node == null) {
139
+ return;
140
+ }
141
+ switch (decl.node.type) {
142
+ case "FunctionDeclaration": {
143
+ const name = decl.node.id?.name;
144
+ if (name && state.opts.pick && !state.opts.pick.includes(name)) {
145
+ exportNamedPath.remove();
146
+ }
147
+ break;
148
+ }
149
+ case "VariableDeclaration": {
150
+ const inner = decl.get("declarations") as Array<NodePath<any>>;
151
+ inner.forEach(d => {
152
+ if (d.node.id.type !== "Identifier") {
153
+ return;
154
+ }
155
+ const name = d.node.id.name;
156
+ if (state.opts.pick && !state.opts.pick.includes(name)) {
157
+ d.remove();
158
+ }
159
+ });
160
+ break;
161
+ }
162
+ default: {
163
+ break;
164
+ }
165
+ }
166
+ },
167
+ FunctionDeclaration: markFunction,
168
+ FunctionExpression: markFunction,
169
+ ArrowFunctionExpression: markFunction,
170
+ ImportSpecifier: markImport,
171
+ ImportDefaultSpecifier: markImport,
172
+ ImportNamespaceSpecifier: markImport,
173
+ ImportDeclaration: (path, state) => {
174
+ if (
175
+ path.node.source.value.endsWith(".css") &&
176
+ state.opts.pick &&
177
+ !state.opts.pick.includes("$css")
178
+ ) {
179
+ path.remove();
180
+ }
181
+ },
182
+ },
183
+ state,
184
+ );
185
+
186
+ const refs = state.refs;
187
+ let count = 0;
188
+ const sweepFunction = (sweepPath: any) => {
189
+ const ident = getIdentifier(sweepPath);
190
+ if (ident && ident.node && refs.has(ident) && !isIdentifierReferenced(ident)) {
191
+ ++count;
192
+ if (
193
+ t.isAssignmentExpression(sweepPath.parentPath) ||
194
+ t.isVariableDeclarator(sweepPath.parentPath)
195
+ ) {
196
+ sweepPath.parentPath.remove();
197
+ } else {
198
+ sweepPath.remove();
199
+ }
200
+ }
201
+ };
202
+ function sweepImport(sweepPath: any) {
203
+ const local = sweepPath.get("local");
204
+ if (refs.has(local) && !isIdentifierReferenced(local)) {
205
+ ++count;
206
+ sweepPath.remove();
207
+ if (sweepPath.parent.specifiers.length === 0) {
208
+ sweepPath.parentPath.remove();
209
+ }
210
+ }
211
+ }
212
+ do {
213
+ path.scope.crawl();
214
+ count = 0;
215
+ path.traverse({
216
+ VariableDeclarator(variablePath) {
217
+ if (variablePath.node.id.type === "Identifier") {
218
+ const local = variablePath.get("id");
219
+ if (refs.has(local) && !isIdentifierReferenced(local)) {
220
+ ++count;
221
+ variablePath.remove();
222
+ }
223
+ } else if (variablePath.node.id.type === "ObjectPattern") {
224
+ const pattern = variablePath.get("id");
225
+ const beforeCount = count;
226
+ const properties = pattern.get("properties");
227
+ properties.forEach(p => {
228
+ const local = p.get(
229
+ p.node.type === "ObjectProperty"
230
+ ? "value"
231
+ : p.node.type === "RestElement"
232
+ ? "argument"
233
+ : (() => {
234
+ throw new Error("invariant");
235
+ })(),
236
+ );
237
+ if (refs.has(local) && !isIdentifierReferenced(local)) {
238
+ ++count;
239
+ p.remove();
240
+ }
241
+ });
242
+ if (beforeCount !== count && pattern.get("properties").length < 1) {
243
+ variablePath.remove();
244
+ }
245
+ } else if (variablePath.node.id.type === "ArrayPattern") {
246
+ const pattern = variablePath.get("id");
247
+ const beforeCount = count;
248
+ const elements = pattern.get("elements");
249
+ elements.forEach(e => {
250
+ let local: NodePath<any> | undefined;
251
+ if (e.node && e.node.type === "Identifier") {
252
+ local = e;
253
+ } else if (e.node && e.node.type === "RestElement") {
254
+ local = e.get("argument");
255
+ } else {
256
+ return;
257
+ }
258
+ if (refs.has(local) && !isIdentifierReferenced(local)) {
259
+ ++count;
260
+ e.remove();
261
+ }
262
+ });
263
+ if (beforeCount !== count && pattern.get("elements").length < 1) {
264
+ variablePath.remove();
265
+ }
266
+ }
267
+ },
268
+ FunctionDeclaration: sweepFunction,
269
+ FunctionExpression: sweepFunction,
270
+ ArrowFunctionExpression: sweepFunction,
271
+ ImportSpecifier: sweepImport,
272
+ ImportDefaultSpecifier: sweepImport,
273
+ ImportNamespaceSpecifier: sweepImport,
274
+ });
275
+ } while (count);
276
+ },
277
+ },
278
+ },
279
+ };
280
+ }
281
+
282
+ export function treeShake(): Plugin {
283
+ let config: ResolvedConfig;
284
+ const cache: Record<string, any> = {};
285
+ let server: ViteDevServer;
286
+
287
+ async function transform(id: string, code: string) {
288
+ const [path, queryString] = id.split("?");
289
+ const query = new URLSearchParams(queryString);
290
+ if (query.has("pick")) {
291
+ const babel = await import("@babel/core");
292
+ const transformed = await babel.transformAsync(code, {
293
+ plugins: [[treeShakeTransform, { pick: query.getAll("pick") }]],
294
+ parserOpts: {
295
+ plugins: ["jsx", "typescript"],
296
+ },
297
+ filename: basename(id),
298
+ ast: false,
299
+ sourceMaps: true,
300
+ configFile: false,
301
+ babelrc: false,
302
+ sourceFileName: id,
303
+ });
304
+
305
+ return transformed;
306
+ }
307
+ }
308
+ return {
309
+ name: "tree-shake",
310
+ enforce: "pre",
311
+ configResolved(resolvedConfig) {
312
+ config = resolvedConfig;
313
+ },
314
+ configureServer(s) {
315
+ server = s;
316
+ },
317
+ async handleHotUpdate(ctx) {
318
+ if (cache[ctx.file]) {
319
+ const mods = [];
320
+ const newCode = await ctx.read();
321
+ for (const [id, code] of Object.entries(cache[ctx.file])) {
322
+ const transformed = await transform(id, newCode);
323
+ if (!transformed) continue;
324
+
325
+ const { code: transformedCode } = transformed;
326
+
327
+ if (transformedCode !== code) {
328
+ const mod = server.moduleGraph.getModuleById(id);
329
+ if (mod) mods.push(mod);
330
+ }
331
+
332
+ cache[ctx.file] ??= {};
333
+ cache[ctx.file][id] = transformedCode;
334
+ // server.moduleGraph.setModuleSource(id, code);
335
+ }
336
+
337
+ return mods;
338
+ }
339
+ // const mods = [];
340
+ // [...server.moduleGraph.urlToModuleMap.entries()].forEach(([url, m]) => {
341
+ // if (m.file === ctx.file && m.id.includes("pick=")) {
342
+ // if (!m.id.includes("pick=loader")) {
343
+ // mods.push(m);
344
+ // }
345
+ // }
346
+ // });
347
+ // return mods;
348
+ // // this.router.updateRoute(ctx.path);
349
+ // }
350
+ },
351
+ async transform(code, id) {
352
+ const [path, queryString] = id.split("?");
353
+ if (!path) return;
354
+ const query = new URLSearchParams(queryString);
355
+ const ext = path.split(".").pop();
356
+ if (!ext) return;
357
+ if (query.has("pick") && ["js", "jsx", "ts", "tsx"].includes(ext)) {
358
+ const transformed = await transform(id, code);
359
+ if (!transformed?.code) return;
360
+
361
+ cache[path] ??= {};
362
+ cache[path][id] = transformed.code;
363
+
364
+ return {
365
+ code: transformed.code,
366
+ map: transformed.map,
367
+ };
368
+ }
369
+ },
370
+ };
371
+ }
@@ -0,0 +1,233 @@
1
+ import { TanStackServerFnPlugin } from "@tanstack/server-functions-plugin";
2
+ import { defu } from "defu";
3
+ import { globSync } from "node:fs";
4
+ import { extname, isAbsolute, join, normalize } from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ import { type PluginOption } from "vite";
7
+ import solid, { type Options as SolidOptions } from "vite-plugin-solid";
8
+
9
+ import { DEFAULT_EXTENSIONS, VIRTUAL_MODULES, VITE_ENVIRONMENTS } from "./constants.ts";
10
+ import { devServer } from "./dev-server.ts";
11
+ import { SolidStartClientFileRouter, SolidStartServerFileRouter } from "./fs-router.ts";
12
+ import { fsRoutes } from "./fs-routes/index.ts";
13
+ import type { BaseFileSystemRouter } from "./fs-routes/router.ts";
14
+ import lazy from "./lazy.ts";
15
+ import { manifest } from "./manifest.ts";
16
+ import { parseIdQuery } from "./utils.ts";
17
+
18
+ export interface SolidStartOptions {
19
+ solid?: Partial<SolidOptions>;
20
+ ssr?: boolean;
21
+ routeDir?: string;
22
+ extensions?: string[];
23
+ middleware?: string;
24
+ }
25
+
26
+ const absolute = (path: string, root: string) =>
27
+ path ? (isAbsolute(path) ? path : join(root, path)) : path;
28
+
29
+ export function solidStart(options?: SolidStartOptions): Array<PluginOption> {
30
+ const start = defu(options ?? {}, {
31
+ appRoot: "./src",
32
+ routeDir: "./routes",
33
+ ssr: true,
34
+ devOverlay: true,
35
+ experimental: {
36
+ islands: false,
37
+ },
38
+ solid: {},
39
+ extensions: [],
40
+ });
41
+ const extensions = [...DEFAULT_EXTENSIONS, ...(start.extensions || [])];
42
+ const routeDir = join(start.appRoot, start.routeDir);
43
+ const root = process.cwd();
44
+ const appEntryPath = globSync(join(root, start.appRoot, "app.{j,t}sx"))[0];
45
+ if (!appEntryPath) {
46
+ throw new Error(`Could not find an app jsx/tsx entry in ${start.appRoot}.`);
47
+ }
48
+ const entryExtension = extname(appEntryPath);
49
+ const handlers = {
50
+ client: `${start.appRoot}/entry-client${entryExtension}`,
51
+ server: `${start.appRoot}/entry-server${entryExtension}`,
52
+ };
53
+ return [
54
+ {
55
+ name: "solid-start:config",
56
+ enforce: "pre",
57
+ configEnvironment(name) {
58
+ return {
59
+ resolve: {
60
+ // remove when https://github.com/solidjs/vite-plugin-solid/pull/228 is released
61
+ externalConditions: ["solid", "node"],
62
+ },
63
+ };
64
+ },
65
+ async config(_, env) {
66
+ const clientInput = [handlers.client];
67
+ if (env.command === "build") {
68
+ const clientRouter: BaseFileSystemRouter = (globalThis as any).ROUTERS.client;
69
+ for (const route of await clientRouter.getRoutes()) {
70
+ for (const [key, value] of Object.entries(route)) {
71
+ if (value && key.startsWith("$") && !key.startsWith("$$")) {
72
+ function toRouteId(route: any) {
73
+ return `${route.src}?${route.pick.map((p: string) => `pick=${p}`).join("&")}`;
74
+ }
75
+ clientInput.push(toRouteId(value));
76
+ }
77
+ }
78
+ }
79
+ }
80
+ return {
81
+ appType: "custom",
82
+ build: { assetsDir: "_build/assets" },
83
+ environments: {
84
+ [VITE_ENVIRONMENTS.client]: {
85
+ consumer: "client",
86
+ build: {
87
+ write: true,
88
+ manifest: true,
89
+ outDir: "dist/client",
90
+ rollupOptions: {
91
+ input: clientInput,
92
+ treeshake: true,
93
+ preserveEntrySignatures: "exports-only",
94
+ },
95
+ },
96
+ },
97
+ [VITE_ENVIRONMENTS.server]: {
98
+ consumer: "server",
99
+ build: {
100
+ ssr: true,
101
+ write: true,
102
+ manifest: true,
103
+ copyPublicDir: false,
104
+ rollupOptions: {
105
+ input: "~/entry-server.tsx",
106
+ },
107
+ outDir: "dist/server",
108
+ commonjsOptions: {
109
+ include: [/node_modules/],
110
+ },
111
+ },
112
+ },
113
+ },
114
+ resolve: {
115
+ alias: {
116
+ "@solidjs/start/server/entry": handlers.server,
117
+ "~": join(process.cwd(), start.appRoot),
118
+ ...(!start.ssr
119
+ ? {
120
+ "@solidjs/start/server": "@solidjs/start/server/spa",
121
+ "@solidjs/start/client": "@solidjs/start/client/spa",
122
+ }
123
+ : {}),
124
+ },
125
+ },
126
+ define: {
127
+ "import.meta.env.MANIFEST": `globalThis.MANIFEST`,
128
+ "import.meta.env.START_SSR": JSON.stringify(start.ssr),
129
+ "import.meta.env.START_APP_ENTRY": `"${appEntryPath}"`,
130
+ "import.meta.env.START_CLIENT_ENTRY": `"${handlers.client}"`,
131
+ "import.meta.env.START_DEV_OVERLAY": JSON.stringify(start.devOverlay),
132
+ },
133
+ builder: {
134
+ sharedPlugins: true,
135
+ async buildApp(builder) {
136
+ const client = builder.environments[VITE_ENVIRONMENTS.client];
137
+ const server = builder.environments[VITE_ENVIRONMENTS.server];
138
+
139
+ if (!client) throw new Error("Client environment not found");
140
+ if (!server) throw new Error("SSR environment not found");
141
+
142
+ if (!client.isBuilt) await builder.build(client);
143
+ if (!server.isBuilt) await builder.build(server);
144
+ },
145
+ },
146
+ };
147
+ },
148
+ },
149
+ manifest(start),
150
+ fsRoutes({
151
+ routers: {
152
+ client: new SolidStartClientFileRouter({
153
+ dir: absolute(routeDir, root),
154
+ extensions,
155
+ }),
156
+ ssr: new SolidStartServerFileRouter({
157
+ dir: absolute(routeDir, root),
158
+ extensions,
159
+ dataOnly: !start.ssr,
160
+ }),
161
+ },
162
+ }),
163
+ lazy(),
164
+ // Must be placed after fsRoutes, as treeShake will remove the
165
+ // server fn exports added in by this plugin
166
+ TanStackServerFnPlugin({
167
+ // This is the ID that will be available to look up and import
168
+ // our server function manifest and resolve its module
169
+ manifestVirtualImportId: VIRTUAL_MODULES.serverFnManifest,
170
+ directive: "use server",
171
+ callers: [
172
+ {
173
+ envConsumer: "client",
174
+ envName: VITE_ENVIRONMENTS.client,
175
+ getRuntimeCode: () =>
176
+ `import { createServerReference } from "${normalize(
177
+ fileURLToPath(new URL("../server/server-runtime", import.meta.url)),
178
+ )}"`,
179
+ replacer: opts => `createServerReference('${opts.functionId}')`,
180
+ },
181
+ {
182
+ envConsumer: "server",
183
+ envName: VITE_ENVIRONMENTS.server,
184
+ getRuntimeCode: () =>
185
+ `import { createServerReference } from '${normalize(
186
+ fileURLToPath(new URL("../server/server-fns-runtime", import.meta.url)),
187
+ )}'`,
188
+ replacer: opts => `createServerReference(${opts.fn}, '${opts.functionId}')`,
189
+ },
190
+ ],
191
+ provider: {
192
+ envName: VITE_ENVIRONMENTS.server,
193
+ getRuntimeCode: () =>
194
+ `import { createServerReference } from '${normalize(
195
+ fileURLToPath(new URL("../server/server-fns-runtime", import.meta.url)),
196
+ )}'`,
197
+ replacer: opts => `createServerReference(${opts.fn}, '${opts.functionId}')`,
198
+ },
199
+ }),
200
+ {
201
+ name: "solid-start:virtual-modules",
202
+ async resolveId(id) {
203
+ const { filename, query } = parseIdQuery(id);
204
+
205
+ let base;
206
+ if (filename === VIRTUAL_MODULES.clientEntry) base = handlers.client;
207
+ if (filename === VIRTUAL_MODULES.serverEntry) base = handlers.server;
208
+ if (filename === VIRTUAL_MODULES.app) base = appEntryPath;
209
+
210
+ if (base) {
211
+ let id = (await this.resolve(base))?.id;
212
+ if (!id) return;
213
+
214
+ if (query.size > 0) id += `?${query.toString()}`;
215
+ return id;
216
+ }
217
+ },
218
+ },
219
+ {
220
+ name: "solid-start:capture-client-bundle",
221
+ enforce: "post",
222
+ generateBundle(_options, bundle) {
223
+ globalThis.START_CLIENT_BUNDLE = bundle;
224
+ },
225
+ },
226
+ devServer(),
227
+ solid({
228
+ ...start.solid,
229
+ ssr: true,
230
+ extensions: extensions.map(ext => `.${ext}`),
231
+ }),
232
+ ];
233
+ }
@@ -0,0 +1,100 @@
1
+ import type { PluginItem } from "@babel/core";
2
+ import babel from "@babel/core";
3
+ import * as t from "@babel/types";
4
+ import { sep as osSep } from "path";
5
+ import { basename, relative, sep } from "path/posix";
6
+ import type { PluginOption } from "vite";
7
+ import { VITE_ENVIRONMENTS } from "./constants.ts";
8
+
9
+ const idTransform = (id: string): PluginItem => {
10
+ return {
11
+ visitor: {
12
+ Program(path) {
13
+ path.node.body.unshift(
14
+ t.exportNamedDeclaration(
15
+ t.variableDeclaration("const", [
16
+ t.variableDeclarator(t.identifier("id$$"), t.stringLiteral(id)),
17
+ ]),
18
+ ),
19
+ );
20
+ },
21
+ },
22
+ };
23
+ };
24
+
25
+ const importTransform = (): PluginItem => {
26
+ return {
27
+ visitor: {
28
+ ImportDeclaration(path) {
29
+ if (path.node.source.value !== "solid-js") return;
30
+ path.traverse({
31
+ ImportSpecifier(subPath) {
32
+ if (subPath.node.local.name !== "lazy") return;
33
+ subPath.remove();
34
+ path.insertAfter(
35
+ t.importDeclaration(
36
+ [t.importSpecifier(t.identifier("lazy"), t.identifier("lazy"))],
37
+ t.stringLiteral("@solidjs/start/server"),
38
+ ),
39
+ );
40
+ },
41
+ });
42
+ },
43
+ },
44
+ };
45
+ };
46
+
47
+ const fileEndingRegex = /(ts|js)x(\?.*)?$/;
48
+
49
+ const lazy = (): PluginOption => {
50
+ const cwd = process.cwd().replaceAll(osSep, sep);
51
+ return {
52
+ name: "solid-lazy-css",
53
+ enforce: "pre",
54
+ applyToEnvironment(env) {
55
+ return env.name === VITE_ENVIRONMENTS.server;
56
+ },
57
+ async transform(src, id) {
58
+ if (!id.match(fileEndingRegex)) return;
59
+
60
+ // The transformed files either import "lazy" or css files
61
+ // Therefore we skip, if the src doesn't have any import
62
+ if (src.indexOf("import") === -1) return;
63
+
64
+ const plugins: PluginItem[] = [];
65
+
66
+ const hasDefaultExport = src.indexOf("export default") !== -1;
67
+ if (hasDefaultExport) {
68
+ const localId = relative(cwd, id);
69
+ plugins.push(idTransform(localId));
70
+ }
71
+
72
+ const hasLazy = src.indexOf("lazy(") !== -1;
73
+ if (hasLazy) plugins.push(importTransform());
74
+
75
+ if (!plugins.length) {
76
+ return;
77
+ }
78
+
79
+ const transformed = await babel.transformAsync(src, {
80
+ plugins,
81
+ parserOpts: {
82
+ plugins: ["jsx", "typescript"],
83
+ },
84
+ filename: basename(id),
85
+ ast: false,
86
+ sourceMaps: true,
87
+ configFile: false,
88
+ babelrc: false,
89
+ sourceFileName: id,
90
+ });
91
+
92
+ if (!transformed?.code) return;
93
+
94
+ const { code, map } = transformed;
95
+ return { code, map };
96
+ },
97
+ };
98
+ };
99
+
100
+ export default lazy;