filesystem-routing 0.3.1 → 0.4.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.
- package/README.md +45 -0
- package/dist/analyze.d.ts +11 -0
- package/dist/analyze.js +28 -1
- package/dist/convention.d.ts +8 -0
- package/dist/convention.js +14 -7
- package/dist/flags.d.ts +11 -0
- package/dist/flags.js +11 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/manifest.d.ts +13 -0
- package/dist/router.js +1 -1
- package/dist/tree.js +1 -1
- package/dist/vite/constants.d.ts +9 -0
- package/dist/vite/constants.js +9 -0
- package/dist/vite/index.d.ts +1 -1
- package/dist/vite/index.js +23 -9
- package/dist/vite/types.js +10 -4
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -190,6 +190,50 @@ server environment's router only (SolidStart pairs it with `components:
|
|
|
190
190
|
false` in SPA mode, so the server manifest routes requests without shipping
|
|
191
191
|
page modules) — see the per-environment `routers` option below.
|
|
192
192
|
|
|
193
|
+
## Server-function pages
|
|
194
|
+
|
|
195
|
+
With `serverComponents: true`, a page whose default export begins with a
|
|
196
|
+
`"use server"` directive is a server-function page:
|
|
197
|
+
|
|
198
|
+
```tsx
|
|
199
|
+
// src/routes/stories/[id].tsx
|
|
200
|
+
export const route = { live: true }; // any config the emission adapter reads
|
|
201
|
+
|
|
202
|
+
export default async function Story({ params }) {
|
|
203
|
+
"use server";
|
|
204
|
+
const story = await db.stories.get(params.id);
|
|
205
|
+
return props => <article>{story.title}{props.children}</article>;
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
The scanner sees the directive (on an inline function declaration or
|
|
210
|
+
expression, or a top-level function the default export names — not through
|
|
211
|
+
a wrapper call or a re-export) and records two neutral facts on the entry:
|
|
212
|
+
`server: true`, and a `$component` ref marked `eager` and picking only
|
|
213
|
+
`default`. The client side of such a module is a stub, so there is no code
|
|
214
|
+
worth a chunk: the Vite adapter delivers the ref eagerly (`{ src, require }`)
|
|
215
|
+
even with code splitting on, and it is not a build input. What a
|
|
216
|
+
server-rendered page *means* — how the stub is called, cached, and mounted —
|
|
217
|
+
is the emission adapter's business; the scanner only states the fact.
|
|
218
|
+
|
|
219
|
+
Adapters that carry code only server pages need gate it on
|
|
220
|
+
`filesystem-routing/flags`:
|
|
221
|
+
|
|
222
|
+
```ts
|
|
223
|
+
import { serverRoutes } from "filesystem-routing/flags";
|
|
224
|
+
import * as server from "./server.js"; // dropped from builds with no server page
|
|
225
|
+
|
|
226
|
+
if (serverRoutes && entry.server) server.wrap(entry);
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
The package ships `flags` as a real module whose facts are all `true` — the
|
|
230
|
+
safe answer wherever no plugin hook is in the loop (dev prebundling, a
|
|
231
|
+
hand-built manifest, another bundler). In builds the Vite plugin serves the
|
|
232
|
+
scan's answer instead, folded to a literal, so a gated static import
|
|
233
|
+
tree-shakes out of every app without a server page and is an ordinary
|
|
234
|
+
static import — present at hydration — in every app with one. The option is
|
|
235
|
+
off by default; a manifest built without it is byte-identical to before.
|
|
236
|
+
|
|
193
237
|
## Custom conventions
|
|
194
238
|
|
|
195
239
|
Conventions plug in at two independent seams, so a custom scheme picks the
|
|
@@ -310,6 +354,7 @@ fileRoutes({
|
|
|
310
354
|
| --- | --- |
|
|
311
355
|
| `httpMethods` | emit `$GET`, `$POST`, … refs for uppercase handler exports; a module with handlers but no default export routes without being a page |
|
|
312
356
|
| `components` | set `false` to route without emitting `$component` refs, keeping page modules out of that environment's bundle |
|
|
357
|
+
| `serverComponents` | recognize server-function pages: a `"use server"` default export is flagged `server: true` and delivered eagerly; scan facts are served from `filesystem-routing/flags` (defaults to `false`) |
|
|
313
358
|
| `buildInputs` | environments whose build takes every code-split route module as an entry |
|
|
314
359
|
| `codeSplitting` | set `false` to deliver every module ref as an eager static import — no `lazy()` components, zero dynamic imports, one bundle — for small apps where per-chunk overhead outweighs the split (defaults to `true`; with `@solidjs/router` requires the next release, newer than `2.0.0-next.14`) |
|
|
315
360
|
| `moduleId` | the id the manifest is served from |
|
package/dist/analyze.d.ts
CHANGED
|
@@ -8,6 +8,17 @@ export type { StaticExportEntry };
|
|
|
8
8
|
* a compiler that already performs export analysis can provide it instead.
|
|
9
9
|
*/
|
|
10
10
|
export declare function analyzeModule(src: string): StaticExportEntry[];
|
|
11
|
+
export interface RouteModuleAnalysis {
|
|
12
|
+
exports: StaticExportEntry[];
|
|
13
|
+
/**
|
|
14
|
+
* The directive prologue of the default export, when it is a function
|
|
15
|
+
* declared in this module (inline, or a top-level binding it names):
|
|
16
|
+
* `"use server"` marks a page whose component runs on the server.
|
|
17
|
+
*/
|
|
18
|
+
defaultDirective?: string;
|
|
19
|
+
}
|
|
20
|
+
/** `analyzeModule` plus what the default export's function body declares. */
|
|
21
|
+
export declare function analyzeRouteModule(src: string): RouteModuleAnalysis;
|
|
11
22
|
export declare function getExportName(entry: StaticExportEntry): string;
|
|
12
23
|
/**
|
|
13
24
|
* Returns the export name only when it is backed by a same-named local
|
package/dist/analyze.js
CHANGED
|
@@ -24,6 +24,10 @@ function loadTsrxParser(src) {
|
|
|
24
24
|
* a compiler that already performs export analysis can provide it instead.
|
|
25
25
|
*/
|
|
26
26
|
export function analyzeModule(src) {
|
|
27
|
+
return analyzeRouteModule(src).exports;
|
|
28
|
+
}
|
|
29
|
+
/** `analyzeModule` plus what the default export's function body declares. */
|
|
30
|
+
export function analyzeRouteModule(src) {
|
|
27
31
|
const source = fs.readFileSync(src, "utf-8");
|
|
28
32
|
let result;
|
|
29
33
|
if (src.endsWith(".tsrx")) {
|
|
@@ -44,7 +48,30 @@ export function analyzeModule(src) {
|
|
|
44
48
|
const error = result.errors[0];
|
|
45
49
|
if (error)
|
|
46
50
|
throw new SyntaxError(`Failed to parse ${src}:\n${error.codeframe || error.message}`);
|
|
47
|
-
return
|
|
51
|
+
return {
|
|
52
|
+
exports: result.module.staticExports.flatMap(({ entries }) => entries.filter(entry => !entry.isType && entry.exportName.kind !== "None")),
|
|
53
|
+
defaultDirective: defaultDirectiveOf(result.program.body)
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function defaultDirectiveOf(body) {
|
|
57
|
+
let fn = body.find(node => node.type === "ExportDefaultDeclaration")?.declaration;
|
|
58
|
+
if (fn?.type === "Identifier") {
|
|
59
|
+
// `export default Story` — follow the name to a top-level function.
|
|
60
|
+
const name = fn.name;
|
|
61
|
+
fn = undefined;
|
|
62
|
+
for (const node of body) {
|
|
63
|
+
if (node.type === "FunctionDeclaration" && node.id?.name === name)
|
|
64
|
+
fn = node;
|
|
65
|
+
else if (node.type === "VariableDeclaration")
|
|
66
|
+
for (const d of node.declarations)
|
|
67
|
+
if (d.id?.name === name)
|
|
68
|
+
fn = d.init;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (!fn || !/Function(Declaration|Expression)$/.test(fn.type))
|
|
72
|
+
return;
|
|
73
|
+
const first = fn.body?.body?.[0];
|
|
74
|
+
return first?.type === "ExpressionStatement" ? first.directive : undefined;
|
|
48
75
|
}
|
|
49
76
|
export function getExportName(entry) {
|
|
50
77
|
return entry.exportName.name ?? "default";
|
package/dist/convention.d.ts
CHANGED
|
@@ -30,6 +30,14 @@ export interface PageFileSystemRouterConfig extends FileSystemRouterConfig {
|
|
|
30
30
|
* Pass `true` for the standard set. Defaults to `false`.
|
|
31
31
|
*/
|
|
32
32
|
httpMethods?: boolean | readonly string[];
|
|
33
|
+
/**
|
|
34
|
+
* Recognize server-function pages: a default export whose body begins with
|
|
35
|
+
* a `"use server"` directive is flagged `server: true` and its `$component`
|
|
36
|
+
* delivered eagerly — the client side of such a module is a stub, not a
|
|
37
|
+
* chunk's worth of component. What a server-rendered page means is the
|
|
38
|
+
* emission adapter's business. Defaults to `false`.
|
|
39
|
+
*/
|
|
40
|
+
serverComponents?: boolean;
|
|
33
41
|
}
|
|
34
42
|
/**
|
|
35
43
|
* The module convention proven by SolidStart: a route module is a page when
|
package/dist/convention.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { analyzeRouteModule, getExportName, getLocalExportName } from "./analyze.js";
|
|
2
2
|
import { BaseFileSystemRouter, cleanPath } from "./router.js";
|
|
3
3
|
/**
|
|
4
4
|
* The filename convention proven by SolidStart:
|
|
@@ -85,24 +85,31 @@ export class PageFileSystemRouter extends BaseFileSystemRouter {
|
|
|
85
85
|
};
|
|
86
86
|
}
|
|
87
87
|
const methods = httpMethodsOf(this.config);
|
|
88
|
-
const exports =
|
|
88
|
+
const { exports, defaultDirective } = analyzeRouteModule(src);
|
|
89
89
|
const exportNames = exports.map(getExportName);
|
|
90
90
|
const localExportNames = exports.map(getLocalExportName).filter(name => name !== undefined);
|
|
91
91
|
const hasDefault = exportNames.includes("default");
|
|
92
92
|
const hasRouteConfig = exportNames.includes("route");
|
|
93
93
|
const handlers = createHandlerRefs(src, exportNames, methods);
|
|
94
94
|
const hasHandlers = Object.keys(handlers).length > 0;
|
|
95
|
+
// A server-function page (opt-in): the client gets a stub, not a chunk's
|
|
96
|
+
// worth of component, so it is delivered eagerly and flagged for the adapter.
|
|
97
|
+
const server = this.config.serverComponents === true && hasDefault && defaultDirective === "use server";
|
|
95
98
|
if (hasDefault || hasHandlers) {
|
|
96
99
|
return {
|
|
97
100
|
page: hasDefault,
|
|
101
|
+
...(server ? { server } : {}),
|
|
98
102
|
$component: components && hasDefault
|
|
99
103
|
? {
|
|
100
104
|
src: src,
|
|
101
|
-
pick:
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
105
|
+
pick: server
|
|
106
|
+
? ["default"]
|
|
107
|
+
: [
|
|
108
|
+
...localExportNames.filter(name => name !== "route" && !methods.includes(name)),
|
|
109
|
+
"default",
|
|
110
|
+
"$css"
|
|
111
|
+
],
|
|
112
|
+
...(server ? { eager: true } : {})
|
|
106
113
|
}
|
|
107
114
|
: undefined,
|
|
108
115
|
$$route: hasRouteConfig
|
package/dist/flags.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Facts about the route scan, for emission adapters to gate static imports
|
|
3
|
+
* on. This file is the fallback: every fact is `true`, so code that reads it
|
|
4
|
+
* without the Vite plugin in the loop (dev prebundling, a hand-built
|
|
5
|
+
* manifest, another bundler) errs toward "present", never toward "broken".
|
|
6
|
+
* `filesystem-routing/vite` replaces this module in builds with the scan's
|
|
7
|
+
* actual answers, folded to literals, so an adapter's
|
|
8
|
+
* `if (serverRoutes) use(server)` drops its import when no route needs it.
|
|
9
|
+
*/
|
|
10
|
+
/** `true` when some page's component is a server function (`server: true`). */
|
|
11
|
+
export declare const serverRoutes: boolean;
|
package/dist/flags.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Facts about the route scan, for emission adapters to gate static imports
|
|
3
|
+
* on. This file is the fallback: every fact is `true`, so code that reads it
|
|
4
|
+
* without the Vite plugin in the loop (dev prebundling, a hand-built
|
|
5
|
+
* manifest, another bundler) errs toward "present", never toward "broken".
|
|
6
|
+
* `filesystem-routing/vite` replaces this module in builds with the scan's
|
|
7
|
+
* actual answers, folded to literals, so an adapter's
|
|
8
|
+
* `if (serverRoutes) use(server)` drops its import when no route needs it.
|
|
9
|
+
*/
|
|
10
|
+
/** `true` when some page's component is a server function (`server: true`). */
|
|
11
|
+
export const serverRoutes = true;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { analyzeModule, getExportName, getLocalExportName } from "./analyze.ts";
|
|
2
|
-
export type { StaticExportEntry } from "./analyze.ts";
|
|
1
|
+
export { analyzeModule, analyzeRouteModule, getExportName, getLocalExportName } from "./analyze.ts";
|
|
2
|
+
export type { RouteModuleAnalysis, StaticExportEntry } from "./analyze.ts";
|
|
3
3
|
export type { ModuleRef, RouteManifestEntry } from "./manifest.ts";
|
|
4
4
|
export { BaseFileSystemRouter, cleanPath, glob, normalizePath, type FileSystemRouterConfig } from "./router.ts";
|
|
5
5
|
export { HTTP_METHODS, PageFileSystemRouter, routePathFromFile, type PageFileSystemRouterConfig } from "./convention.ts";
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { analyzeModule, getExportName, getLocalExportName } from "./analyze.js";
|
|
1
|
+
export { analyzeModule, analyzeRouteModule, getExportName, getLocalExportName } from "./analyze.js";
|
|
2
2
|
export { BaseFileSystemRouter, cleanPath, glob, normalizePath } from "./router.js";
|
|
3
3
|
export { HTTP_METHODS, PageFileSystemRouter, routePathFromFile } from "./convention.js";
|
|
4
4
|
export { FlatFileSystemRouter, flatRoutePathFromFile } from "./flat.js";
|
package/dist/manifest.d.ts
CHANGED
|
@@ -27,6 +27,12 @@ export interface ModuleRef {
|
|
|
27
27
|
src: string;
|
|
28
28
|
/** The named exports (or `"default"`) this ref selects from the module. */
|
|
29
29
|
pick: string[];
|
|
30
|
+
/**
|
|
31
|
+
* Deliver eagerly even under code splitting. Set by a convention when the
|
|
32
|
+
* module has no client code worth a chunk — a server-function page, whose
|
|
33
|
+
* client side is a stub — so the ref is materialized `{ src, require }`.
|
|
34
|
+
*/
|
|
35
|
+
eager?: boolean;
|
|
30
36
|
}
|
|
31
37
|
export interface RouteManifestEntry {
|
|
32
38
|
/**
|
|
@@ -38,6 +44,13 @@ export interface RouteManifestEntry {
|
|
|
38
44
|
path: string;
|
|
39
45
|
/** `true` when the module renders a page (has a default export). */
|
|
40
46
|
page?: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* `true` when the page component is a server function — its default export
|
|
49
|
+
* begins with a `"use server"` directive. The convention delivers such a
|
|
50
|
+
* `$component` eagerly; what a server-rendered page means is the emission
|
|
51
|
+
* adapter's business.
|
|
52
|
+
*/
|
|
53
|
+
server?: boolean;
|
|
41
54
|
/** Lazy ref to the page component module. */
|
|
42
55
|
$component?: ModuleRef;
|
|
43
56
|
/** Eager ref to the route config (`route` export), when present. */
|
package/dist/router.js
CHANGED
|
@@ -36,7 +36,7 @@ export class BaseFileSystemRouter extends EventTarget {
|
|
|
36
36
|
return posix.join(fg.convertPathToPattern(this.config.dir), "**/*") + suffix;
|
|
37
37
|
}
|
|
38
38
|
async buildRoutes() {
|
|
39
|
-
for (const src of glob(this.glob())) {
|
|
39
|
+
for (const src of glob(this.glob()).sort()) {
|
|
40
40
|
await this.addRoute(src);
|
|
41
41
|
}
|
|
42
42
|
return this.routes;
|
package/dist/tree.js
CHANGED
|
@@ -21,7 +21,7 @@ export function buildRouteTree(entries) {
|
|
|
21
21
|
processRoute(parentRoute.children || (parentRoute.children = []), route, id.slice(parentRoute.id.length));
|
|
22
22
|
}
|
|
23
23
|
return [...entries]
|
|
24
|
-
.sort((a, b) => a.path.length - b.path.length)
|
|
24
|
+
.sort((a, b) => (a.path.length - b.path.length) || a.path.localeCompare(b.path))
|
|
25
25
|
.reduce((routes, route) => {
|
|
26
26
|
processRoute(routes, route, route.path);
|
|
27
27
|
return routes;
|
package/dist/vite/constants.d.ts
CHANGED
|
@@ -6,3 +6,12 @@
|
|
|
6
6
|
*/
|
|
7
7
|
export declare const moduleId = "virtual:file-routes";
|
|
8
8
|
export declare const DEFAULT_EXTENSIONS: string[];
|
|
9
|
+
/**
|
|
10
|
+
* The module adapters import scan facts from — `filesystem-routing/flags`.
|
|
11
|
+
* The package ships it as a real file whose facts are all `true` (the safe
|
|
12
|
+
* answer wherever no plugin hook is in the loop: dev prebundling, a custom
|
|
13
|
+
* manifest, another bundler); the Vite plugin serves the scan's answer in
|
|
14
|
+
* builds so gated code folds away.
|
|
15
|
+
*/
|
|
16
|
+
export declare const flagsId = "filesystem-routing/flags";
|
|
17
|
+
export declare const resolvedFlagsId: string;
|
package/dist/vite/constants.js
CHANGED
|
@@ -6,3 +6,12 @@
|
|
|
6
6
|
*/
|
|
7
7
|
export const moduleId = "virtual:file-routes";
|
|
8
8
|
export const DEFAULT_EXTENSIONS = ["js", "jsx", "ts", "tsx", "tsrx"];
|
|
9
|
+
/**
|
|
10
|
+
* The module adapters import scan facts from — `filesystem-routing/flags`.
|
|
11
|
+
* The package ships it as a real file whose facts are all `true` (the safe
|
|
12
|
+
* answer wherever no plugin hook is in the loop: dev prebundling, a custom
|
|
13
|
+
* manifest, another bundler); the Vite plugin serves the scan's answer in
|
|
14
|
+
* builds so gated code folds away.
|
|
15
|
+
*/
|
|
16
|
+
export const flagsId = "filesystem-routing/flags";
|
|
17
|
+
export const resolvedFlagsId = "\0" + flagsId;
|
package/dist/vite/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { DEFAULT_EXTENSIONS, moduleId } from "./constants.ts";
|
|
|
5
5
|
export { DEFAULT_EXTENSIONS, moduleId };
|
|
6
6
|
export { sanitizeChunkFileName, toPickId, treeShake } from "./tree-shake.ts";
|
|
7
7
|
export { fileSystemWatcher } from "./fs-watcher.ts";
|
|
8
|
-
export interface FileRoutesOptions extends Pick<PageFileSystemRouterConfig, "components" | "httpMethods" | "toPath" | "toRoute"> {
|
|
8
|
+
export interface FileRoutesOptions extends Pick<PageFileSystemRouterConfig, "components" | "httpMethods" | "serverComponents" | "toPath" | "toRoute"> {
|
|
9
9
|
/** Route directory, relative to the Vite root. Defaults to `src/routes`. */
|
|
10
10
|
dir?: string;
|
|
11
11
|
/** File extensions that participate in routing. Defaults to js/jsx/ts/tsx. */
|
package/dist/vite/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { dirname, relative, resolve } from "node:path";
|
|
|
3
3
|
import { PageFileSystemRouter } from "../convention.js";
|
|
4
4
|
import { normalizePath } from "../router.js";
|
|
5
5
|
import { buildRouteTree } from "../tree.js";
|
|
6
|
-
import { DEFAULT_EXTENSIONS, moduleId } from "./constants.js";
|
|
6
|
+
import { DEFAULT_EXTENSIONS, flagsId, moduleId, resolvedFlagsId } from "./constants.js";
|
|
7
7
|
import { fileSystemWatcher } from "./fs-watcher.js";
|
|
8
8
|
import { sanitizeChunkFileName, toPickId, treeShake } from "./tree-shake.js";
|
|
9
9
|
import { serializeTypes } from "./types.js";
|
|
@@ -138,6 +138,7 @@ export function fileRoutes(options = {}) {
|
|
|
138
138
|
extensions: options.extensions ?? DEFAULT_EXTENSIONS,
|
|
139
139
|
components: options.components,
|
|
140
140
|
httpMethods: options.httpMethods,
|
|
141
|
+
serverComponents: options.serverComponents,
|
|
141
142
|
toPath: options.toPath,
|
|
142
143
|
toRoute: options.toRoute
|
|
143
144
|
});
|
|
@@ -169,7 +170,7 @@ export function fileRoutes(options = {}) {
|
|
|
169
170
|
const input = [];
|
|
170
171
|
for (const route of routes) {
|
|
171
172
|
for (const [key, ref] of Object.entries(route)) {
|
|
172
|
-
if (ref && key.startsWith("$") && !key.startsWith("$$")) {
|
|
173
|
+
if (ref && key.startsWith("$") && !key.startsWith("$$") && !ref.eager) {
|
|
173
174
|
input.push(toModuleId(ref));
|
|
174
175
|
}
|
|
175
176
|
}
|
|
@@ -181,8 +182,20 @@ export function fileRoutes(options = {}) {
|
|
|
181
182
|
resolveId(source) {
|
|
182
183
|
if (source === virtualId)
|
|
183
184
|
return virtualId;
|
|
185
|
+
if (source === flagsId)
|
|
186
|
+
return resolvedFlagsId;
|
|
184
187
|
},
|
|
185
188
|
async load(loadedId) {
|
|
189
|
+
if (loadedId === resolvedFlagsId) {
|
|
190
|
+
// Facts about the scan, folded to literals so an adapter's static
|
|
191
|
+
// imports gated on them tree-shake out of a build that does not
|
|
192
|
+
// need them. In serve, always `true`: dev has no size to protect
|
|
193
|
+
// and the first server page must work without a restart.
|
|
194
|
+
const router = getRouter(this.environment.name);
|
|
195
|
+
const routes = (router && (await router.getRoutes())) ?? [];
|
|
196
|
+
const serverRoutes = this.environment.mode !== "build" || routes.some(route => route.server === true);
|
|
197
|
+
return `export const serverRoutes = ${serverRoutes};`;
|
|
198
|
+
}
|
|
186
199
|
if (loadedId !== virtualId)
|
|
187
200
|
return;
|
|
188
201
|
const root = this.environment.config.root;
|
|
@@ -216,18 +229,19 @@ export function fileRoutes(options = {}) {
|
|
|
216
229
|
}
|
|
217
230
|
else if (key.startsWith("$")) {
|
|
218
231
|
const buildId = toModuleId(value);
|
|
219
|
-
// With code splitting off
|
|
220
|
-
//
|
|
221
|
-
//
|
|
222
|
-
//
|
|
223
|
-
|
|
232
|
+
// With code splitting off — or a ref the convention marked
|
|
233
|
+
// `eager` — the ref is delivered eagerly: a namespace import
|
|
234
|
+
// (named imports would fail on the synthetic `$css` pick)
|
|
235
|
+
// behind the `require()` shape eager refs carry, plus the
|
|
236
|
+
// `src` lazy refs already expose.
|
|
237
|
+
if (!codeSplitting || value.eager) {
|
|
224
238
|
return {
|
|
225
|
-
src: relative(root, buildId),
|
|
239
|
+
src: normalizePath(relative(root, buildId)),
|
|
226
240
|
require: `_$() => (${js.addNamespaceImport(buildId)})$_`
|
|
227
241
|
};
|
|
228
242
|
}
|
|
229
243
|
return {
|
|
230
|
-
src: relative(root, buildId),
|
|
244
|
+
src: normalizePath(relative(root, buildId)),
|
|
231
245
|
build: isBuild ? `_$() => import('${buildId}')$_` : undefined,
|
|
232
246
|
import: `_$() => import('${buildId}')$_`
|
|
233
247
|
};
|
package/dist/vite/types.js
CHANGED
|
@@ -32,6 +32,8 @@ const REF_TYPES = ` /** A code-split ref: the delivery adapter emits it as a dy
|
|
|
32
32
|
export interface FileRouteEntry {
|
|
33
33
|
path: string;
|
|
34
34
|
page?: boolean;
|
|
35
|
+
/** The page component is a server function; its \`$component\` is delivered eagerly. */
|
|
36
|
+
server?: boolean;
|
|
35
37
|
$component?: FileRouteLazyRef<any> | FileRouteEagerRef<any>;
|
|
36
38
|
$$route?: FileRouteEagerRef<any>;
|
|
37
39
|
[key: string]: unknown;
|
|
@@ -72,14 +74,18 @@ function entryType(entry, indent, nested, from, codeSplitting) {
|
|
|
72
74
|
if (nested)
|
|
73
75
|
fields.push(`id: ${JSON.stringify(entry.id)}`);
|
|
74
76
|
fields.push(`page: ${entry.page ? "true" : "false"}`);
|
|
77
|
+
if (entry.server)
|
|
78
|
+
fields.push(`server: true`);
|
|
75
79
|
// A convention records refs it did not emit as present-but-undefined keys,
|
|
76
80
|
// so go by the value, not the key.
|
|
77
81
|
const refKeys = Object.keys(entry).filter(key => key.startsWith("$") && entry[key] !== undefined);
|
|
78
82
|
for (const key of refKeys) {
|
|
79
|
-
// With code splitting off, the
|
|
80
|
-
// eagerly, so the declaration
|
|
81
|
-
|
|
82
|
-
|
|
83
|
+
// With code splitting off, or a ref the convention marked `eager`, the
|
|
84
|
+
// delivery adapter materializes lazy refs eagerly, so the declaration
|
|
85
|
+
// describes them as delivered.
|
|
86
|
+
const ref = entry[key];
|
|
87
|
+
const kind = isEagerRefKey(key) || !codeSplitting || ref.eager ? "eager" : "lazy";
|
|
88
|
+
fields.push(`${key}: ${refType(ref, kind, from)}`);
|
|
83
89
|
}
|
|
84
90
|
// Reading an absent ref is how adapters branch, so keep the key present.
|
|
85
91
|
if (!refKeys.some(isLazyRefKey))
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "filesystem-routing",
|
|
3
3
|
"description": "Router-neutral file-system routing: scans a route directory into a neutral route manifest with pluggable conventions and delivery adapters",
|
|
4
4
|
"license": "MIT",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.4.0",
|
|
6
6
|
"author": "Ryan Carniato",
|
|
7
7
|
"homepage": "https://github.com/solidjs/filesystem-routing#readme",
|
|
8
8
|
"repository": {
|
|
@@ -44,6 +44,10 @@
|
|
|
44
44
|
"types": "./dist/api.d.ts",
|
|
45
45
|
"default": "./dist/api.js"
|
|
46
46
|
},
|
|
47
|
+
"./flags": {
|
|
48
|
+
"types": "./dist/flags.d.ts",
|
|
49
|
+
"default": "./dist/flags.js"
|
|
50
|
+
},
|
|
47
51
|
"./types": {
|
|
48
52
|
"types": "./types.d.ts"
|
|
49
53
|
}
|