@solidjs/start 1.2.0 → 2.0.0-alpha.0

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 (184) hide show
  1. package/README.md +88 -8
  2. package/dist/client/StartClient.d.ts +0 -1
  3. package/dist/client/StartClient.jsx +2 -4
  4. package/dist/client/index.d.ts +2 -3
  5. package/dist/client/index.jsx +2 -4
  6. package/dist/client/mount.js +10 -2
  7. package/dist/client/spa/index.d.ts +1 -2
  8. package/dist/client/spa/index.jsx +1 -2
  9. package/dist/config/constants.d.ts +16 -0
  10. package/dist/config/constants.js +16 -0
  11. package/dist/config/dev-server.d.ts +2 -0
  12. package/dist/config/dev-server.js +108 -0
  13. package/dist/config/fs-router.d.ts +37 -0
  14. package/dist/config/fs-router.js +153 -0
  15. package/dist/config/fs-routes/fs-watcher.d.ts +3 -0
  16. package/dist/config/fs-routes/fs-watcher.js +49 -0
  17. package/dist/config/fs-routes/index.d.ts +7 -0
  18. package/dist/config/fs-routes/index.js +109 -0
  19. package/dist/config/fs-routes/router.d.ts +37 -0
  20. package/dist/config/fs-routes/router.js +136 -0
  21. package/dist/config/fs-routes/tree-shake.d.ts +2 -0
  22. package/dist/config/fs-routes/tree-shake.js +357 -0
  23. package/dist/config/index.d.ts +10 -0
  24. package/dist/config/index.js +217 -0
  25. package/dist/config/lazy.d.ts +3 -0
  26. package/dist/config/lazy.js +82 -0
  27. package/dist/config/manifest.d.ts +3 -0
  28. package/dist/config/manifest.js +74 -0
  29. package/dist/config/utils.d.ts +4 -0
  30. package/dist/config/utils.js +6 -0
  31. package/dist/config/vite-utils.d.ts +16 -0
  32. package/dist/config/vite-utils.js +81 -0
  33. package/dist/http/index.d.ts +84 -0
  34. package/dist/http/index.js +131 -0
  35. package/dist/index.d.ts +6 -5
  36. package/dist/index.jsx +5 -5
  37. package/dist/middleware/index.d.ts +6 -6
  38. package/dist/middleware/index.js +39 -0
  39. package/dist/{router/FileRoutes.js → router.jsx} +5 -6
  40. package/dist/server/StartServer.d.ts +3 -3
  41. package/dist/server/StartServer.jsx +9 -63
  42. package/dist/server/assets/index.d.ts +2 -0
  43. package/dist/server/assets/index.js +52 -0
  44. package/dist/server/assets/render.d.ts +19 -0
  45. package/dist/server/{renderAsset.jsx → assets/render.jsx} +1 -1
  46. package/dist/server/collect-styles.d.ts +3 -0
  47. package/dist/server/collect-styles.js +69 -0
  48. package/dist/server/fetchEvent.d.ts +4 -3
  49. package/dist/server/fetchEvent.js +12 -74
  50. package/dist/server/fetchEvent.spec.js +18 -197
  51. package/dist/server/handler.d.ts +6 -12
  52. package/dist/server/handler.js +180 -97
  53. package/dist/server/index.d.ts +8 -6
  54. package/dist/server/index.jsx +14 -6
  55. package/dist/server/manifest/client-manifest.d.ts +9 -0
  56. package/dist/server/manifest/client-manifest.js +6 -0
  57. package/dist/server/manifest/dev-client-manifest.d.ts +4 -0
  58. package/dist/server/manifest/dev-client-manifest.js +24 -0
  59. package/dist/server/manifest/dev-ssr-manifest.d.ts +5 -0
  60. package/dist/server/manifest/dev-ssr-manifest.js +23 -0
  61. package/dist/server/manifest/prod-client-manifest.d.ts +5 -0
  62. package/dist/server/manifest/prod-client-manifest.js +26 -0
  63. package/dist/server/manifest/prod-ssr-manifest.d.ts +6 -0
  64. package/dist/server/manifest/prod-ssr-manifest.js +90 -0
  65. package/dist/server/manifest/ssr-manifest.d.ts +4 -0
  66. package/dist/server/manifest/ssr-manifest.js +6 -0
  67. package/dist/{router → server}/routes.d.ts +5 -10
  68. package/dist/{router → server}/routes.js +35 -36
  69. package/dist/{runtime → server}/server-fns-runtime.d.ts +1 -1
  70. package/dist/{runtime → server}/server-fns-runtime.js +7 -6
  71. package/dist/server/server-functions-handler.d.ts +2 -0
  72. package/dist/{runtime/server-handler.js → server/server-functions-handler.js} +65 -100
  73. package/dist/server/server-runtime.d.ts +3 -0
  74. package/dist/{runtime → server}/server-runtime.js +9 -16
  75. package/dist/server/spa/StartServer.d.ts +1 -1
  76. package/dist/server/spa/StartServer.jsx +7 -9
  77. package/dist/server/spa/handler.d.ts +3 -3
  78. package/dist/server/spa/handler.js +9 -11
  79. package/dist/server/spa/index.d.ts +4 -3
  80. package/dist/server/spa/index.jsx +4 -3
  81. package/dist/server/types.d.ts +7 -9
  82. package/dist/server/util.d.ts +2 -0
  83. package/dist/server/util.js +8 -0
  84. package/dist/shared/ErrorBoundary.jsx +2 -2
  85. package/dist/shared/HttpHeader.jsx +4 -2
  86. package/dist/shared/{HttpStatusCode.jsx → HttpStatusCode.js} +3 -1
  87. package/dist/shared/dev-overlay/DevOverlayDialog.d.ts +2 -2
  88. package/dist/shared/dev-overlay/DevOverlayDialog.jsx +75 -66
  89. package/dist/shared/dev-overlay/createStackFrame.js +3 -3
  90. package/dist/shared/dev-overlay/index.jsx +5 -8
  91. package/dist/shared/lazy.d.ts +3 -0
  92. package/dist/shared/lazy.js +40 -0
  93. package/dist/shared/serverFunction.d.ts +1 -1
  94. package/package.json +45 -67
  95. package/scripts/build.js +15 -0
  96. package/scripts/validate-imports.js +316 -0
  97. package/src/client/StartClient.tsx +34 -0
  98. package/src/client/index.tsx +2 -0
  99. package/src/client/mount.ts +114 -0
  100. package/src/client/spa/index.tsx +9 -0
  101. package/src/config/constants.ts +19 -0
  102. package/src/config/dev-server.ts +149 -0
  103. package/src/config/fs-router.ts +177 -0
  104. package/src/config/fs-routes/fs-watcher.ts +81 -0
  105. package/src/config/fs-routes/index.ts +138 -0
  106. package/src/config/fs-routes/router.ts +169 -0
  107. package/src/config/fs-routes/tree-shake.ts +392 -0
  108. package/src/config/index.ts +236 -0
  109. package/src/config/lazy.ts +100 -0
  110. package/src/config/manifest.ts +84 -0
  111. package/src/config/utils.ts +5 -0
  112. package/src/config/vite-utils.ts +113 -0
  113. package/src/env.d.ts +35 -0
  114. package/src/http/index.ts +253 -0
  115. package/src/index.tsx +19 -0
  116. package/src/internal.d.ts +14 -0
  117. package/src/middleware/index.ts +82 -0
  118. package/src/router.tsx +36 -0
  119. package/src/server/StartServer.tsx +62 -0
  120. package/src/server/assets/index.ts +70 -0
  121. package/src/server/assets/render.tsx +42 -0
  122. package/src/server/collect-styles.ts +94 -0
  123. package/src/server/fetchEvent.spec.ts +89 -0
  124. package/src/server/fetchEvent.ts +36 -0
  125. package/src/server/handler.ts +250 -0
  126. package/src/server/index.tsx +16 -0
  127. package/src/server/manifest/client-manifest.ts +8 -0
  128. package/src/server/manifest/dev-client-manifest.ts +19 -0
  129. package/src/server/manifest/dev-ssr-manifest.ts +21 -0
  130. package/src/server/manifest/prod-client-manifest.ts +18 -0
  131. package/src/server/manifest/prod-ssr-manifest.ts +125 -0
  132. package/src/server/manifest/ssr-manifest.ts +8 -0
  133. package/src/server/routes.ts +138 -0
  134. package/src/server/server-fns-runtime.ts +31 -0
  135. package/src/server/server-functions-handler.ts +364 -0
  136. package/src/server/server-runtime.ts +240 -0
  137. package/src/server/spa/StartServer.tsx +40 -0
  138. package/src/server/spa/handler.ts +29 -0
  139. package/src/server/spa/index.tsx +5 -0
  140. package/src/server/types.ts +82 -0
  141. package/src/server/util.ts +12 -0
  142. package/src/shared/ErrorBoundary.tsx +52 -0
  143. package/src/shared/GET.ts +8 -0
  144. package/src/shared/HttpHeader.tsx +42 -0
  145. package/src/shared/HttpStatusCode.ts +27 -0
  146. package/src/shared/clientOnly.ts +44 -0
  147. package/src/shared/dev-overlay/CodeView.tsx +95 -0
  148. package/src/shared/dev-overlay/DevOverlayDialog.tsx +316 -0
  149. package/src/shared/dev-overlay/createStackFrame.ts +77 -0
  150. package/src/shared/dev-overlay/download.ts +6 -0
  151. package/src/shared/dev-overlay/env.d.ts +4 -0
  152. package/src/shared/dev-overlay/get-source-map.ts +35 -0
  153. package/src/shared/dev-overlay/icons.tsx +288 -0
  154. package/src/shared/dev-overlay/index.tsx +63 -0
  155. package/src/shared/dev-overlay/styles.css +292 -0
  156. package/src/shared/lazy.ts +51 -0
  157. package/src/shared/serverFunction.ts +10 -0
  158. package/src/virtual.d.ts +27 -0
  159. package/tsconfig.json +23 -0
  160. package/vitest.config.ts +9 -0
  161. package/config/fs-router.js +0 -142
  162. package/config/index.d.ts +0 -40
  163. package/config/index.js +0 -304
  164. package/config/server-components.js +0 -106
  165. package/dist/client/islands.d.ts +0 -7
  166. package/dist/client/islands.jsx +0 -10
  167. package/dist/middleware/index.jsx +0 -35
  168. package/dist/router/index.d.ts +0 -1
  169. package/dist/router/index.jsx +0 -2
  170. package/dist/router/lazyRoute.d.ts +0 -6
  171. package/dist/router/lazyRoute.js +0 -53
  172. package/dist/runtime/server-handler.d.ts +0 -2
  173. package/dist/runtime/server-runtime.d.ts +0 -3
  174. package/dist/server/islands/index.d.ts +0 -19
  175. package/dist/server/islands/index.jsx +0 -62
  176. package/dist/server/islands/utils.d.ts +0 -1
  177. package/dist/server/islands/utils.jsx +0 -85
  178. package/dist/server/pageEvent.d.ts +0 -2
  179. package/dist/server/pageEvent.js +0 -56
  180. package/dist/server/renderAsset.d.ts +0 -2
  181. package/env.d.ts +0 -26
  182. /package/dist/{router/FileRoutes.d.ts → router.d.ts} +0 -0
  183. /package/dist/shared/{clientOnly.jsx → clientOnly.js} +0 -0
  184. /package/dist/shared/{serverFunction.jsx → serverFunction.js} +0 -0
@@ -0,0 +1,316 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Import Extension Validation Script for SolidStart
5
+ *
6
+ * This script validates that all relative imports in the src/ directory have
7
+ * explicit file extensions, which is mandated by Node.js ESM (ES Modules).
8
+ *
9
+ * Node.js requires explicit file extensions for relative imports when using
10
+ * ES modules to avoid ambiguity and improve performance. This script ensures
11
+ * compliance with this requirement.
12
+ *
13
+ * Features:
14
+ * - Scans all .ts and .tsx files in the src/ directory recursively
15
+ * - Detects relative imports (starting with ./ or ../) without extensions
16
+ * - Prevents .js/.jsx imports in TypeScript files (should use .ts/.tsx)
17
+ * - Ignores commented code, CSS imports, and dynamic imports (handled by bundlers)
18
+ * - Provides detailed error reporting with line numbers and suggestions
19
+ * - Exits with appropriate status codes for CI/CD integration
20
+ *
21
+ * Usage:
22
+ * npm run validate-imports
23
+ *
24
+ * Exit codes:
25
+ * 0 - All relative imports have valid extensions
26
+ * 1 - Found relative imports without extensions
27
+ *
28
+ * Valid extensions for TypeScript files: .ts, .tsx, .json
29
+ * Invalid extensions for TypeScript files: .js, .jsx (use .ts/.tsx instead)
30
+ *
31
+ * @example
32
+ * // ❌ Invalid - missing extension
33
+ * import { config } from "./config/index";
34
+ *
35
+ * // ❌ Invalid - .js extension in TypeScript file
36
+ * import { config } from "./config/index.js";
37
+ *
38
+ * // ✅ Valid - has .ts extension
39
+ * import { config } from "./config/index.ts";
40
+ *
41
+ * // ✅ Valid - external package import (no extension needed)
42
+ * import { something } from "external-package";
43
+ */
44
+
45
+ import { readFileSync, readdirSync, statSync } from "node:fs";
46
+ import { join, dirname, extname } from "node:path";
47
+ import { fileURLToPath } from "node:url";
48
+
49
+ const __filename = fileURLToPath(import.meta.url);
50
+ const __dirname = dirname(__filename);
51
+
52
+ // Configuration
53
+ const SRC_DIR = join(__dirname, "..", "src");
54
+ const VALID_EXTENSIONS = [".ts", ".tsx", ".json"];
55
+ const INVALID_EXTENSIONS = [".js", ".jsx"];
56
+ const FILE_EXTENSIONS = [".ts", ".tsx"];
57
+
58
+ /**
59
+ * Recursively find all files with specified extensions
60
+ */
61
+ function findFiles(dir, extensions, files = []) {
62
+ try {
63
+ const entries = readdirSync(dir);
64
+
65
+ for (const entry of entries) {
66
+ const fullPath = join(dir, entry);
67
+ const stat = statSync(fullPath);
68
+
69
+ if (stat.isDirectory()) {
70
+ findFiles(fullPath, extensions, files);
71
+ } else if (extensions.includes(extname(entry))) {
72
+ files.push(fullPath);
73
+ }
74
+ }
75
+ } catch (error) {
76
+ console.error(`Error reading directory ${dir}: ${error.message}`);
77
+ }
78
+
79
+ return files;
80
+ }
81
+
82
+ /**
83
+ * Check if a path is a relative import (starts with . or ..)
84
+ */
85
+ function isRelativeImport(path) {
86
+ return path.startsWith("./") || path.startsWith("../");
87
+ }
88
+
89
+ /**
90
+ * Check if an import path has a valid file extension
91
+ */
92
+ function hasValidExtension(path) {
93
+ return VALID_EXTENSIONS.some(ext => path.endsWith(ext));
94
+ }
95
+
96
+ /**
97
+ * Check if an import path has an invalid extension for TypeScript files
98
+ */
99
+ function hasInvalidExtension(path) {
100
+ return INVALID_EXTENSIONS.some(ext => path.endsWith(ext));
101
+ }
102
+
103
+ /**
104
+ * Extract import/export statements from file content
105
+ * Matches both import and export statements with from clauses
106
+ */
107
+ function extractImportExportStatements(content, filePath) {
108
+ const statements = [];
109
+ const lines = content.split("\n");
110
+
111
+ // Regex patterns for different import/export statements
112
+ const patterns = [
113
+ // Standard imports: import { ... } from '...'
114
+ /import\s+(?:(?:\{[^}]*\}|\*\s+as\s+\w+|\w+)\s+from\s+)?['"`]([^'"`]+)['"`]/g,
115
+ // Export from: export { ... } from '...'
116
+ /export\s+(?:\{[^}]*\}|\*)\s+from\s+['"`]([^'"`]+)['"`]/g,
117
+ // Export default from: export { default } from '...'
118
+ /export\s+\{\s*default\s*\}\s+from\s+['"`]([^'"`]+)['"`]/g
119
+ // Note: Dynamic imports are excluded as they're handled by bundlers
120
+ ];
121
+
122
+ lines.forEach((line, lineNumber) => {
123
+ const trimmedLine = line.trim();
124
+
125
+ // Skip commented lines, dynamic imports, and TypeScript type-only imports in d.ts files
126
+ if (
127
+ trimmedLine.startsWith("//") ||
128
+ trimmedLine.startsWith("/*") ||
129
+ trimmedLine.startsWith("*") ||
130
+ (filePath.endsWith(".d.ts") && trimmedLine.includes("import(")) ||
131
+ // Skip CSS imports as they're handled by bundlers
132
+ /import\s+['"`][^'"`]*\.css['"`]/.test(trimmedLine) ||
133
+ // Skip dynamic imports as they're handled by bundlers
134
+ /import\s*\(\s*['"`]/.test(trimmedLine)
135
+ ) {
136
+ return;
137
+ }
138
+
139
+ patterns.forEach(pattern => {
140
+ let match;
141
+ // Reset regex lastIndex to avoid issues with global flag
142
+ pattern.lastIndex = 0;
143
+ while ((match = pattern.exec(line)) !== null) {
144
+ const importPath = match[1];
145
+ if (importPath) {
146
+ statements.push({
147
+ path: importPath,
148
+ line: lineNumber + 1,
149
+ fullLine: line.trim(),
150
+ filePath
151
+ });
152
+ }
153
+ }
154
+ });
155
+ });
156
+
157
+ return statements;
158
+ }
159
+
160
+ /**
161
+ * Validate a single file for relative imports without extensions
162
+ */
163
+ function validateFile(filePath) {
164
+ const errors = [];
165
+
166
+ try {
167
+ const content = readFileSync(filePath, "utf8");
168
+ const statements = extractImportExportStatements(content, filePath);
169
+
170
+ statements.forEach(statement => {
171
+ if (isRelativeImport(statement.path)) {
172
+ if (hasInvalidExtension(statement.path)) {
173
+ errors.push({
174
+ file: filePath,
175
+ line: statement.line,
176
+ importPath: statement.path,
177
+ fullLine: statement.fullLine,
178
+ type: "invalid-extension"
179
+ });
180
+ } else if (!hasValidExtension(statement.path)) {
181
+ errors.push({
182
+ file: filePath,
183
+ line: statement.line,
184
+ importPath: statement.path,
185
+ fullLine: statement.fullLine,
186
+ type: "missing-extension"
187
+ });
188
+ }
189
+ }
190
+ });
191
+ } catch (error) {
192
+ console.error(`Error reading file ${filePath}: ${error.message}`);
193
+ }
194
+
195
+ return errors;
196
+ }
197
+
198
+ /**
199
+ * Main validation function
200
+ */
201
+ function validateImports() {
202
+ console.log("🔍 Validating relative imports in src/ directory...\n");
203
+
204
+ // Find all TypeScript/TSX files in src directory
205
+ const files = findFiles(SRC_DIR, FILE_EXTENSIONS);
206
+
207
+ if (files.length === 0) {
208
+ console.log("⚠️ No TypeScript files found in src/ directory");
209
+ process.exit(0);
210
+ }
211
+
212
+ console.log(`📁 Scanning ${files.length} files...\n`);
213
+
214
+ let totalErrors = 0;
215
+ const errorsByFile = new Map();
216
+
217
+ // Validate each file
218
+ files.forEach(file => {
219
+ const errors = validateFile(file);
220
+ if (errors.length > 0) {
221
+ errorsByFile.set(file, errors);
222
+ totalErrors += errors.length;
223
+ }
224
+ });
225
+
226
+ // Report results
227
+ if (totalErrors === 0) {
228
+ console.log("✅ All relative imports have valid extensions!");
229
+ process.exit(0);
230
+ } else {
231
+ const missingExtensionErrors = [];
232
+ const invalidExtensionErrors = [];
233
+
234
+ errorsByFile.forEach(errors => {
235
+ errors.forEach(error => {
236
+ if (error.type === "missing-extension") {
237
+ missingExtensionErrors.push(error);
238
+ } else if (error.type === "invalid-extension") {
239
+ invalidExtensionErrors.push(error);
240
+ }
241
+ });
242
+ });
243
+
244
+ if (missingExtensionErrors.length > 0) {
245
+ console.log(
246
+ `❌ Found ${missingExtensionErrors.length} relative import(s) without extensions:\n`
247
+ );
248
+
249
+ const missingByFile = new Map();
250
+ missingExtensionErrors.forEach(error => {
251
+ if (!missingByFile.has(error.file)) {
252
+ missingByFile.set(error.file, []);
253
+ }
254
+ missingByFile.get(error.file).push(error);
255
+ });
256
+
257
+ missingByFile.forEach((errors, file) => {
258
+ const relativePath = file.replace(process.cwd(), "").replace(/^\//, "");
259
+ console.log(`📄 ${relativePath}:`);
260
+
261
+ errors.forEach(error => {
262
+ console.log(` Line ${error.line}: ${error.importPath}`);
263
+ console.log(` ${error.fullLine}`);
264
+ console.log(
265
+ ` ${"".padStart(error.fullLine.indexOf(error.importPath), " ")}${"".padStart(error.importPath.length, "^")}`
266
+ );
267
+ });
268
+ console.log("");
269
+ });
270
+ }
271
+
272
+ if (invalidExtensionErrors.length > 0) {
273
+ console.log(
274
+ `❌ Found ${invalidExtensionErrors.length} relative import(s) with invalid extensions:\n`
275
+ );
276
+
277
+ const invalidByFile = new Map();
278
+ invalidExtensionErrors.forEach(error => {
279
+ if (!invalidByFile.has(error.file)) {
280
+ invalidByFile.set(error.file, []);
281
+ }
282
+ invalidByFile.get(error.file).push(error);
283
+ });
284
+
285
+ invalidByFile.forEach((errors, file) => {
286
+ const relativePath = file.replace(process.cwd(), "").replace(/^\//, "");
287
+ console.log(`📄 ${relativePath}:`);
288
+
289
+ errors.forEach(error => {
290
+ console.log(` Line ${error.line}: ${error.importPath}`);
291
+ console.log(` ${error.fullLine}`);
292
+ console.log(
293
+ ` ${"".padStart(error.fullLine.indexOf(error.importPath), " ")}${"".padStart(error.importPath.length, "^")}`
294
+ );
295
+ });
296
+ console.log("");
297
+ });
298
+ }
299
+
300
+ console.log("💡 Tips:");
301
+ if (missingExtensionErrors.length > 0) {
302
+ console.log(' - Add file extensions to relative imports (e.g., "./file" → "./file.ts")');
303
+ }
304
+ if (invalidExtensionErrors.length > 0) {
305
+ console.log(" - Replace .js/.jsx with .ts/.tsx in TypeScript files");
306
+ }
307
+ console.log(" - This is required by Node.js ESM modules");
308
+ console.log(" - Valid extensions for TypeScript files: " + VALID_EXTENSIONS.join(", "));
309
+ console.log(" - Invalid extensions for TypeScript files: " + INVALID_EXTENSIONS.join(", "));
310
+
311
+ process.exit(1);
312
+ }
313
+ }
314
+
315
+ // Run the validation
316
+ validateImports();
@@ -0,0 +1,34 @@
1
+ // @refresh skip
2
+ import App from "solid-start:app";
3
+ import type { JSX } from "solid-js";
4
+ import { ErrorBoundary } from "../shared/ErrorBoundary.tsx";
5
+
6
+ function Dummy(props: { children: JSX.Element }) {
7
+ return props.children;
8
+ }
9
+
10
+ /**
11
+ *
12
+ * Read more: https://docs.solidjs.com/solid-start/reference/client/start-client
13
+ */
14
+ export function StartClient() {
15
+ return (
16
+ <Dummy>
17
+ <Dummy>
18
+ <ErrorBoundary>
19
+ <App />
20
+ </ErrorBoundary>
21
+ </Dummy>
22
+ </Dummy>
23
+ );
24
+ }
25
+
26
+ export function StartClientTanstack() {
27
+ return (
28
+ <Dummy>
29
+ <ErrorBoundary>
30
+ <App />
31
+ </ErrorBoundary>
32
+ </Dummy>
33
+ );
34
+ }
@@ -0,0 +1,2 @@
1
+ export { mount } from "./mount.ts";
2
+ export { StartClient, StartClientTanstack } from "./StartClient.tsx";
@@ -0,0 +1,114 @@
1
+ import type { JSX } from "solid-js";
2
+ import { createStore } from "solid-js/store";
3
+ import {
4
+ createComponent,
5
+ getHydrationKey,
6
+ getOwner,
7
+ hydrate,
8
+ type MountableElement
9
+ } from "solid-js/web";
10
+
11
+ /**
12
+ *
13
+ * Read more: https://docs.solidjs.com/solid-start/reference/client/mount
14
+ */
15
+ export function mount(fn: () => JSX.Element, el: MountableElement) {
16
+ if (import.meta.env.START_ISLANDS) {
17
+ const map = new WeakMap();
18
+ async function mountIsland(el: HTMLElement) {
19
+ if (el.dataset.css) {
20
+ let css = JSON.parse(el.dataset.css);
21
+ for (let href of css) {
22
+ if (!document.querySelector(`link[href="${href}"]`)) {
23
+ let link = document.createElement("link");
24
+ link.rel = "stylesheet";
25
+ link.href = href;
26
+ document.head.appendChild(link);
27
+ }
28
+ }
29
+ }
30
+
31
+ let mod = await import(
32
+ /* @vite-ignore */
33
+ import.meta.env.MANIFEST["client"]!.chunks[el.dataset.id!.split("#")[0] as string]!.output
34
+ .path
35
+ );
36
+ if (!mod || !el.dataset.hk) return;
37
+
38
+ let Component = mod[el.dataset.id!.split("#")[1] as string];
39
+ let hk = el.dataset.hk;
40
+ // _$DEBUG("hydrating island", el.dataset.island, hk.slice(0, hk.length - 1) + `1-`, el);
41
+
42
+ let props = createStore({
43
+ ...JSON.parse(el.dataset.props!),
44
+ get children() {
45
+ const p = el.getElementsByTagName("solid-children");
46
+ getHydrationKey();
47
+ [...p].forEach(a => {
48
+ (a as any).__$owner = getOwner();
49
+ });
50
+ return;
51
+ }
52
+ });
53
+
54
+ map.set(el, props);
55
+
56
+ hydrate(() => createComponent(Component, props[0]), el, {
57
+ renderId: hk.slice(0, hk.length - 1) + `${1 + Number(el.dataset.offset)}-`,
58
+ owner: lookupOwner(el)
59
+ });
60
+
61
+ delete el.dataset.hk;
62
+ el.dataset.hkk = hk;
63
+ }
64
+
65
+ let queue: HTMLElement[] = [];
66
+ let queued = false;
67
+ function runTaskQueue(info: any) {
68
+ while (info.timeRemaining() > 0 && queue.length) {
69
+ mountIsland(queue.shift()!);
70
+ }
71
+ if (queue.length) {
72
+ requestIdleCallback(runTaskQueue);
73
+ } else queued = false;
74
+ }
75
+
76
+ const hydrateIslands = () => {
77
+ const islands: NodeListOf<HTMLElement> = document.querySelectorAll("solid-island[data-hk]");
78
+ const assets = new Set<string>();
79
+ islands.forEach((el: HTMLElement) => el.dataset.id && assets.add(el.dataset.id));
80
+ Promise.all(
81
+ [...assets].map(
82
+ asset =>
83
+ import(
84
+ /* @vite-ignore */ import.meta.env.MANIFEST["client"]!.chunks[
85
+ asset.split("#")[0] as string
86
+ ]!.output.path
87
+ )
88
+ )
89
+ )
90
+ .then(() => {
91
+ islands.forEach((el: HTMLElement) => {
92
+ if (el.dataset.when === "idle" && "requestIdleCallback" in window) {
93
+ if (!queued) {
94
+ queued = true;
95
+ requestIdleCallback(runTaskQueue);
96
+ }
97
+ queue.push(el);
98
+ } else mountIsland(el as HTMLElement);
99
+ });
100
+ })
101
+ .catch(e => console.error(e));
102
+ };
103
+
104
+ function lookupOwner(el: HTMLElement) {
105
+ const parent = el.closest("solid-children");
106
+ return parent && (parent as any).__$owner;
107
+ }
108
+
109
+ hydrateIslands();
110
+
111
+ return;
112
+ }
113
+ return hydrate(fn, el);
114
+ }
@@ -0,0 +1,9 @@
1
+ // @refresh skip
2
+ import type { JSX } from "solid-js";
3
+ import { render, type MountableElement } from "solid-js/web";
4
+
5
+ export function mount(fn: () => JSX.Element, el: MountableElement) {
6
+ render(fn, el);
7
+ }
8
+
9
+ export { StartClient } from "../StartClient.tsx";
@@ -0,0 +1,19 @@
1
+ export const DEFAULT_EXTENSIONS = ["js", "jsx", "ts", "tsx"];
2
+
3
+ export const CLIENT_BASE_PATH = "_build";
4
+
5
+ export const VIRTUAL_MODULES = {
6
+ clientViteManifest: "solid-start:client-vite-manifest",
7
+ getClientManifest: "solid-start:get-client-manifest",
8
+ getManifest: "solid-start:get-manifest",
9
+ middleware: "solid-start:middleware",
10
+ serverFnManifest: "solidstart:server-fn-manifest",
11
+ clientEntry: "solid-start:client-entry",
12
+ serverEntry: "solid-start:server-entry",
13
+ app: "solid-start:app"
14
+ } as const;
15
+
16
+ export const VITE_ENVIRONMENTS = {
17
+ client: "client",
18
+ server: "ssr"
19
+ }
@@ -0,0 +1,149 @@
1
+ import { NodeRequest, sendNodeResponse } from "srvx/node";
2
+ import {
3
+ type Connect,
4
+ isRunnableDevEnvironment,
5
+ type PluginOption,
6
+ type ViteDevServer,
7
+ } from "vite";
8
+ import { VITE_ENVIRONMENTS } from "./constants.ts";
9
+
10
+ export function devServer(): Array<PluginOption> {
11
+ return [
12
+ {
13
+ name: "solid-start-dev-server",
14
+ configureServer(viteDevServer) {
15
+ (globalThis as any).VITE_DEV_SERVER = viteDevServer;
16
+ return async () => {
17
+ if (viteDevServer.config.server.middlewareMode) return
18
+
19
+ const serverEnv =
20
+ viteDevServer.environments[VITE_ENVIRONMENTS.server];
21
+
22
+ if (!serverEnv) throw new Error("Server environment not found");
23
+ if (
24
+ // do not check via `isFetchableDevEnvironment` since nitro does implement the `FetchableDevEnvironment` interface but not via inheritance (which this helper checks)
25
+ "dispatchFetch" in serverEnv
26
+ )
27
+ return;
28
+ // another plugin is controlling the dev server
29
+ if (!isRunnableDevEnvironment(serverEnv)) {
30
+ return;
31
+ }
32
+
33
+ globalThis.USING_SOLID_START_DEV_SERVER = true;
34
+
35
+ removeHtmlMiddlewares(viteDevServer);
36
+
37
+ viteDevServer.middlewares.use(async (req, res) => {
38
+ if (req.originalUrl) {
39
+ req.url = req.originalUrl;
40
+ }
41
+ const webReq = new NodeRequest({ req, res });
42
+
43
+ try {
44
+ const serverEntry: {
45
+ default: { fetch: (req: Request) => Promise<Response> };
46
+ } = await serverEnv.runner.import("./src/entry-server.tsx");
47
+
48
+ const webRes = await serverEntry.default.fetch(webReq);
49
+
50
+ return sendNodeResponse(res, webRes);
51
+ } catch (e: unknown) {
52
+ console.error(e);
53
+ viteDevServer.ssrFixStacktrace(e as Error);
54
+
55
+ if (
56
+ webReq.headers.get("content-type")?.includes("application/json")
57
+ ) {
58
+ return sendNodeResponse(
59
+ res,
60
+ Response.json(
61
+ {
62
+ status: 500,
63
+ error: "Internal Server Error",
64
+ message:
65
+ "An unexpected error occurred. Please try again later.",
66
+ timestamp: new Date().toISOString(),
67
+ },
68
+ {
69
+ status: 500,
70
+ headers: {
71
+ "Content-Type": "application/json",
72
+ },
73
+ },
74
+ ),
75
+ );
76
+ }
77
+
78
+ return sendNodeResponse(
79
+ res,
80
+ new Response(
81
+ `
82
+ <!DOCTYPE html>
83
+ <html lang="en">
84
+ <head>
85
+ <meta charset="UTF-8" />
86
+ <title>Error</title>
87
+ <script type="module">
88
+ import { ErrorOverlay } from '/@vite/client'
89
+ document.body.appendChild(new ErrorOverlay(${JSON.stringify(
90
+ prepareError(req, e),
91
+ ).replace(/</g, "\\u003c")}))
92
+ </script>
93
+ </head>
94
+ <body>
95
+ </body>
96
+ </html>
97
+ `,
98
+ {
99
+ status: 500,
100
+ headers: { "Content-Type": "text/html" },
101
+ },
102
+ ),
103
+ );
104
+ }
105
+ });
106
+ };
107
+ },
108
+ },
109
+ ];
110
+ }
111
+
112
+ /**
113
+ * Removes Vite internal middleware
114
+ *
115
+ * @param server
116
+ */
117
+ function removeHtmlMiddlewares(server: ViteDevServer) {
118
+ const html_middlewares = [
119
+ "viteIndexHtmlMiddleware",
120
+ "vite404Middleware",
121
+ "viteSpaFallbackMiddleware",
122
+ ];
123
+ for (let i = server.middlewares.stack.length - 1; i > 0; i--) {
124
+ if (
125
+ html_middlewares.includes(
126
+ // @ts-expect-error
127
+ server.middlewares.stack[i].handle.name,
128
+ )
129
+ ) {
130
+ server.middlewares.stack.splice(i, 1);
131
+ }
132
+ }
133
+ }
134
+
135
+ /**
136
+ * Formats error for SSR message in error overlay
137
+ * @param req
138
+ * @param error
139
+ * @returns
140
+ */
141
+ function prepareError(req: Connect.IncomingMessage, error: unknown) {
142
+ const e = error as Error;
143
+ return {
144
+ message: `An error occured while server rendering ${req.url}:\n\n\t${
145
+ typeof e === "string" ? e : e.message
146
+ } `,
147
+ stack: typeof e === "string" ? "" : e.stack,
148
+ };
149
+ }