filesystem-routing 0.1.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/LICENSE +21 -0
- package/README.md +317 -0
- package/dist/analyze.d.ts +16 -0
- package/dist/analyze.js +29 -0
- package/dist/convention.d.ts +45 -0
- package/dist/convention.js +118 -0
- package/dist/flat.d.ts +16 -0
- package/dist/flat.js +102 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +5 -0
- package/dist/manifest.d.ts +46 -0
- package/dist/manifest.js +12 -0
- package/dist/router.d.ts +54 -0
- package/dist/router.js +128 -0
- package/dist/tree.d.ts +26 -0
- package/dist/tree.js +29 -0
- package/dist/vite/constants.d.ts +8 -0
- package/dist/vite/constants.js +8 -0
- package/dist/vite/debounce.d.ts +4 -0
- package/dist/vite/debounce.js +10 -0
- package/dist/vite/fs-watcher.d.ts +5 -0
- package/dist/vite/fs-watcher.js +69 -0
- package/dist/vite/index.d.ts +69 -0
- package/dist/vite/index.js +215 -0
- package/dist/vite/tree-shake.d.ts +2 -0
- package/dist/vite/tree-shake.js +448 -0
- package/dist/vite/types.d.ts +10 -0
- package/dist/vite/types.js +123 -0
- package/package.json +84 -0
- package/types.d.ts +58 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { analyzeModule, getExportName, getLocalExportName } from "./analyze.js";
|
|
2
|
+
export { BaseFileSystemRouter, cleanPath, glob, normalizePath } from "./router.js";
|
|
3
|
+
export { HTTP_METHODS, PageFileSystemRouter, routePathFromFile } from "./convention.js";
|
|
4
|
+
export { FlatFileSystemRouter, flatRoutePathFromFile } from "./flat.js";
|
|
5
|
+
export { buildRouteTree, stripRouteGroups } from "./tree.js";
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The neutral route manifest.
|
|
3
|
+
*
|
|
4
|
+
* A file-system router produces a flat list of `RouteManifestEntry` objects.
|
|
5
|
+
* The manifest is deliberately router-agnostic: it records paths, params,
|
|
6
|
+
* module refs and export info, but says nothing about how a router turns
|
|
7
|
+
* those into its own route definitions. Each router ships a small emission
|
|
8
|
+
* adapter for that (e.g. `@solidjs/router/fs` emits `RouteDefinition`s),
|
|
9
|
+
* and each bundler ships a delivery adapter (e.g. `filesystem-routing/vite`
|
|
10
|
+
* serializes the manifest into a virtual module).
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* A reference to a subset of a route module's exports.
|
|
14
|
+
*
|
|
15
|
+
* Delivery adapters materialize refs into code. The key the ref is stored
|
|
16
|
+
* under decides how:
|
|
17
|
+
* - keys prefixed `$` become lazy refs: `{ src, import: () => import(...) }`
|
|
18
|
+
* - keys prefixed `$$` become eager refs: `{ require: () => ({ ...exports }) }`
|
|
19
|
+
*/
|
|
20
|
+
export interface ModuleRef {
|
|
21
|
+
/** Absolute path of the source module. */
|
|
22
|
+
src: string;
|
|
23
|
+
/** The named exports (or `"default"`) this ref selects from the module. */
|
|
24
|
+
pick: string[];
|
|
25
|
+
}
|
|
26
|
+
export interface RouteManifestEntry {
|
|
27
|
+
/**
|
|
28
|
+
* The route path in the neutral pattern language proven by SolidStart:
|
|
29
|
+
* `:param`, `:param?` (optional) and `*rest` (catch-all) segments.
|
|
30
|
+
* Group segments (`(name)`) are retained; emission adapters decide how
|
|
31
|
+
* to nest and strip them.
|
|
32
|
+
*/
|
|
33
|
+
path: string;
|
|
34
|
+
/** `true` when the module renders a page (has a default export). */
|
|
35
|
+
page?: boolean;
|
|
36
|
+
/** Lazy ref to the page component module. */
|
|
37
|
+
$component?: ModuleRef;
|
|
38
|
+
/** Eager ref to the route config (`route` export), when present. */
|
|
39
|
+
$$route?: ModuleRef;
|
|
40
|
+
/**
|
|
41
|
+
* Additional refs and metadata added by convention extensions, e.g. a
|
|
42
|
+
* server convention may add `$GET`/`$POST` handler refs. Keys prefixed
|
|
43
|
+
* `$`/`$$` are treated as lazy/eager module refs by delivery adapters.
|
|
44
|
+
*/
|
|
45
|
+
[key: string]: unknown;
|
|
46
|
+
}
|
package/dist/manifest.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The neutral route manifest.
|
|
3
|
+
*
|
|
4
|
+
* A file-system router produces a flat list of `RouteManifestEntry` objects.
|
|
5
|
+
* The manifest is deliberately router-agnostic: it records paths, params,
|
|
6
|
+
* module refs and export info, but says nothing about how a router turns
|
|
7
|
+
* those into its own route definitions. Each router ships a small emission
|
|
8
|
+
* adapter for that (e.g. `@solidjs/router/fs` emits `RouteDefinition`s),
|
|
9
|
+
* and each bundler ships a delivery adapter (e.g. `filesystem-routing/vite`
|
|
10
|
+
* serializes the manifest into a virtual module).
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
package/dist/router.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { RouteManifestEntry } from "./manifest.ts";
|
|
2
|
+
export declare const glob: (path: string) => string[];
|
|
3
|
+
/** Normalize a file path to posix separators (bundler-agnostic). */
|
|
4
|
+
export declare function normalizePath(path: string): string;
|
|
5
|
+
export interface FileSystemRouterConfig {
|
|
6
|
+
/** Absolute path of the route directory to scan. */
|
|
7
|
+
dir: string;
|
|
8
|
+
/** File extensions (without the dot) that participate in routing. */
|
|
9
|
+
extensions: string[];
|
|
10
|
+
/**
|
|
11
|
+
* Pluggable filename convention: maps a route file (relative to `dir`,
|
|
12
|
+
* extension stripped, e.g. `/blog/[id]`) to a route path in the neutral
|
|
13
|
+
* pattern language, or `undefined` to skip the file. When omitted, the
|
|
14
|
+
* router's own `toPath` implementation is used.
|
|
15
|
+
*/
|
|
16
|
+
toPath?: (routeFile: string, config: FileSystemRouterConfig) => string | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* Pluggable module convention: maps a source file to a manifest entry,
|
|
19
|
+
* or `undefined` to skip the file. When omitted, the router's own
|
|
20
|
+
* `toRoute` implementation is used.
|
|
21
|
+
*/
|
|
22
|
+
toRoute?: (src: string, router: BaseFileSystemRouter) => RouteManifestEntry | undefined;
|
|
23
|
+
}
|
|
24
|
+
type RouterEvent = CustomEvent<{
|
|
25
|
+
route: string;
|
|
26
|
+
type: "update" | "remove" | "add";
|
|
27
|
+
}>;
|
|
28
|
+
/** Strips the route dir prefix and the file extension from a source path. */
|
|
29
|
+
export declare function cleanPath(src: string, config: FileSystemRouterConfig): string;
|
|
30
|
+
/**
|
|
31
|
+
* Bundler-agnostic file-system router: scans a directory into a flat, neutral
|
|
32
|
+
* route manifest and keeps it up to date as files are added, changed and
|
|
33
|
+
* removed. Delivery adapters (e.g. the Vite plugin) subscribe to `reload`
|
|
34
|
+
* events; emission adapters consume the manifest.
|
|
35
|
+
*/
|
|
36
|
+
export declare class BaseFileSystemRouter extends EventTarget {
|
|
37
|
+
routes: RouteManifestEntry[];
|
|
38
|
+
config: FileSystemRouterConfig;
|
|
39
|
+
constructor(config: FileSystemRouterConfig);
|
|
40
|
+
glob(): string;
|
|
41
|
+
buildRoutes(): Promise<RouteManifestEntry[]>;
|
|
42
|
+
isRoute(src: string): boolean;
|
|
43
|
+
toPath(src: string): string | undefined;
|
|
44
|
+
toRoute(src: string): RouteManifestEntry | undefined;
|
|
45
|
+
_addRoute(route: RouteManifestEntry): boolean;
|
|
46
|
+
addRoute(src: string): Promise<void>;
|
|
47
|
+
reload(route: string, type: "update" | "remove" | "add"): void;
|
|
48
|
+
updateRoute(src_: string): Promise<void>;
|
|
49
|
+
removeRoute(src: string): void;
|
|
50
|
+
on(type: string, cb: (evt: RouterEvent) => void): () => void;
|
|
51
|
+
buildRoutesPromise?: Promise<RouteManifestEntry[]>;
|
|
52
|
+
getRoutes(): Promise<RouteManifestEntry[]>;
|
|
53
|
+
}
|
|
54
|
+
export {};
|
package/dist/router.js
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import fg from "fast-glob";
|
|
2
|
+
import micromatch from "micromatch";
|
|
3
|
+
import { posix, sep } from "node:path";
|
|
4
|
+
export const glob = (path) => fg.sync(path, { absolute: true });
|
|
5
|
+
/** Normalize a file path to posix separators (bundler-agnostic). */
|
|
6
|
+
export function normalizePath(path) {
|
|
7
|
+
return sep === "\\" ? path.replace(/\\/g, "/") : path;
|
|
8
|
+
}
|
|
9
|
+
/** Strips the route dir prefix and the file extension from a source path. */
|
|
10
|
+
export function cleanPath(src, config) {
|
|
11
|
+
return src
|
|
12
|
+
.slice(config.dir.length)
|
|
13
|
+
.replace(new RegExp(`\.(${(config.extensions ?? []).join("|")})$`), "");
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Bundler-agnostic file-system router: scans a directory into a flat, neutral
|
|
17
|
+
* route manifest and keeps it up to date as files are added, changed and
|
|
18
|
+
* removed. Delivery adapters (e.g. the Vite plugin) subscribe to `reload`
|
|
19
|
+
* events; emission adapters consume the manifest.
|
|
20
|
+
*/
|
|
21
|
+
export class BaseFileSystemRouter extends EventTarget {
|
|
22
|
+
routes;
|
|
23
|
+
config;
|
|
24
|
+
constructor(config) {
|
|
25
|
+
super();
|
|
26
|
+
this.routes = [];
|
|
27
|
+
this.config = config;
|
|
28
|
+
}
|
|
29
|
+
glob() {
|
|
30
|
+
const extensions = this.config.extensions;
|
|
31
|
+
// a single-entry brace pattern like `.{tsx}` is treated as a literal
|
|
32
|
+
const suffix = extensions.length === 1 ? `.${extensions[0]}` : `.{${extensions.join(",")}}`;
|
|
33
|
+
return posix.join(fg.convertPathToPattern(this.config.dir), "**/*") + suffix;
|
|
34
|
+
}
|
|
35
|
+
async buildRoutes() {
|
|
36
|
+
for (const src of glob(this.glob())) {
|
|
37
|
+
await this.addRoute(src);
|
|
38
|
+
}
|
|
39
|
+
return this.routes;
|
|
40
|
+
}
|
|
41
|
+
isRoute(src) {
|
|
42
|
+
return Boolean(micromatch(src, this.glob())?.length);
|
|
43
|
+
}
|
|
44
|
+
toPath(src) {
|
|
45
|
+
if (this.config.toPath)
|
|
46
|
+
return this.config.toPath(cleanPath(src, this.config), this.config);
|
|
47
|
+
throw new Error("Not implemented");
|
|
48
|
+
}
|
|
49
|
+
toRoute(src) {
|
|
50
|
+
if (this.config.toRoute)
|
|
51
|
+
return this.config.toRoute(src, this);
|
|
52
|
+
throw new Error("Not implemented");
|
|
53
|
+
}
|
|
54
|
+
_addRoute(route) {
|
|
55
|
+
const idx = this.routes.findIndex(r => r.path === route.path);
|
|
56
|
+
if (idx >= 0)
|
|
57
|
+
this.routes.splice(idx, 1);
|
|
58
|
+
this.routes.push(route);
|
|
59
|
+
return idx >= 0;
|
|
60
|
+
}
|
|
61
|
+
async addRoute(src) {
|
|
62
|
+
src = normalizePath(src);
|
|
63
|
+
if (this.isRoute(src)) {
|
|
64
|
+
try {
|
|
65
|
+
const route = this.toRoute(src);
|
|
66
|
+
if (route) {
|
|
67
|
+
this._addRoute(route);
|
|
68
|
+
this.reload(route.path, "add");
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch (e) {
|
|
72
|
+
console.error(e);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
reload(route, type) {
|
|
77
|
+
this.dispatchEvent(new CustomEvent("reload", {
|
|
78
|
+
detail: {
|
|
79
|
+
route,
|
|
80
|
+
type
|
|
81
|
+
}
|
|
82
|
+
}));
|
|
83
|
+
}
|
|
84
|
+
async updateRoute(src_) {
|
|
85
|
+
const src = normalizePath(src_);
|
|
86
|
+
if (this.isRoute(src)) {
|
|
87
|
+
try {
|
|
88
|
+
const route = this.toRoute(src);
|
|
89
|
+
if (route) {
|
|
90
|
+
const updated = this._addRoute(route);
|
|
91
|
+
this.reload(route.path, updated ? "update" : "add");
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
this.removeRoute(src_);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
catch (e) {
|
|
98
|
+
console.error(e);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
removeRoute(src) {
|
|
103
|
+
src = normalizePath(src);
|
|
104
|
+
if (this.isRoute(src)) {
|
|
105
|
+
const path = this.toPath(src);
|
|
106
|
+
if (path === undefined) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const idx = this.routes.findIndex(r => r.path === path);
|
|
110
|
+
if (idx === -1)
|
|
111
|
+
return;
|
|
112
|
+
this.routes.splice(idx, 1);
|
|
113
|
+
this.reload(path, "remove");
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
on(type, cb) {
|
|
117
|
+
this.addEventListener(type, cb);
|
|
118
|
+
return () => this.removeEventListener(type, cb);
|
|
119
|
+
}
|
|
120
|
+
buildRoutesPromise;
|
|
121
|
+
async getRoutes() {
|
|
122
|
+
if (!this.buildRoutesPromise) {
|
|
123
|
+
this.buildRoutesPromise = this.buildRoutes();
|
|
124
|
+
}
|
|
125
|
+
await this.buildRoutesPromise;
|
|
126
|
+
return this.routes;
|
|
127
|
+
}
|
|
128
|
+
}
|
package/dist/tree.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { RouteManifestEntry } from "./manifest.ts";
|
|
2
|
+
/**
|
|
3
|
+
* Nesting and group-stripping for the neutral route manifest.
|
|
4
|
+
*
|
|
5
|
+
* This module is deliberately free of Node and bundler imports: delivery
|
|
6
|
+
* adapters run it at build time (the Vite adapter serializes the resulting
|
|
7
|
+
* tree into the virtual module), and runtime consumers that receive only a
|
|
8
|
+
* flat manifest can run it themselves.
|
|
9
|
+
*/
|
|
10
|
+
export interface RouteTreeEntry extends RouteManifestEntry {
|
|
11
|
+
/** The manifest path this node was nested under, group segments included. */
|
|
12
|
+
id: string;
|
|
13
|
+
children?: RouteTreeEntry[];
|
|
14
|
+
}
|
|
15
|
+
/** Removes `(group)` segments from a route path: `/(app)/home` → `/home`. */
|
|
16
|
+
export declare function stripRouteGroups(path: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Nests a flat manifest by path prefix and strips `(group)` segments, so
|
|
19
|
+
* `/(app)/dashboard` renders at `/dashboard` inside the `/(app)` layout.
|
|
20
|
+
*
|
|
21
|
+
* Nested entries keep the path *relative to their parent*, which is what
|
|
22
|
+
* nested routers expect. Pass only the entries that participate in the tree
|
|
23
|
+
* (typically `entries.filter(entry => entry.page)`); the input is not
|
|
24
|
+
* mutated.
|
|
25
|
+
*/
|
|
26
|
+
export declare function buildRouteTree(entries: readonly RouteManifestEntry[]): RouteTreeEntry[];
|
package/dist/tree.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** Removes `(group)` segments from a route path: `/(app)/home` → `/home`. */
|
|
2
|
+
export function stripRouteGroups(path) {
|
|
3
|
+
return path.replace(/\([^)/]+\)/g, "").replace(/\/+/g, "/");
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Nests a flat manifest by path prefix and strips `(group)` segments, so
|
|
7
|
+
* `/(app)/dashboard` renders at `/dashboard` inside the `/(app)` layout.
|
|
8
|
+
*
|
|
9
|
+
* Nested entries keep the path *relative to their parent*, which is what
|
|
10
|
+
* nested routers expect. Pass only the entries that participate in the tree
|
|
11
|
+
* (typically `entries.filter(entry => entry.page)`); the input is not
|
|
12
|
+
* mutated.
|
|
13
|
+
*/
|
|
14
|
+
export function buildRouteTree(entries) {
|
|
15
|
+
function processRoute(routes, route, id) {
|
|
16
|
+
const parentRoute = routes.find(o => id.startsWith(o.id + "/"));
|
|
17
|
+
if (!parentRoute) {
|
|
18
|
+
routes.push({ ...route, id, path: stripRouteGroups(id) });
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
processRoute(parentRoute.children || (parentRoute.children = []), route, id.slice(parentRoute.id.length));
|
|
22
|
+
}
|
|
23
|
+
return [...entries]
|
|
24
|
+
.sort((a, b) => a.path.length - b.path.length)
|
|
25
|
+
.reduce((routes, route) => {
|
|
26
|
+
processRoute(routes, route, route.path);
|
|
27
|
+
return routes;
|
|
28
|
+
}, []);
|
|
29
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The virtual module that serves the serialized route manifest.
|
|
3
|
+
*
|
|
4
|
+
* `virtual:` is Vite's convention for plugin-served modules, and the name is
|
|
5
|
+
* not tied to any router. Override it with the plugin's `moduleId` option.
|
|
6
|
+
*/
|
|
7
|
+
export declare const moduleId = "virtual:file-routes";
|
|
8
|
+
export declare const DEFAULT_EXTENSIONS: string[];
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The virtual module that serves the serialized route manifest.
|
|
3
|
+
*
|
|
4
|
+
* `virtual:` is Vite's convention for plugin-served modules, and the name is
|
|
5
|
+
* not tied to any router. Override it with the plugin's `moduleId` option.
|
|
6
|
+
*/
|
|
7
|
+
export const moduleId = "virtual:file-routes";
|
|
8
|
+
export const DEFAULT_EXTENSIONS = ["js", "jsx", "ts", "tsx"];
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { PluginOption } from "vite";
|
|
2
|
+
import type { BaseFileSystemRouter } from "../router.ts";
|
|
3
|
+
export declare const fileSystemWatcher: (getRouter: (environment: string) => BaseFileSystemRouter | undefined, moduleId: string,
|
|
4
|
+
/** Runs on every route change, before the module is invalidated. */
|
|
5
|
+
onReload?: () => void | Promise<void>) => PluginOption;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { debounce } from "./debounce.js";
|
|
2
|
+
function setupWatcher(watcher, routes) {
|
|
3
|
+
watcher.on("unlink", path => routes.removeRoute(path));
|
|
4
|
+
watcher.on("add", path => routes.addRoute(path));
|
|
5
|
+
watcher.on("change", path => routes.updateRoute(path));
|
|
6
|
+
}
|
|
7
|
+
function createRoutesReloader(server, routes, environment, moduleId, onReload) {
|
|
8
|
+
const devEnv = server.environments[environment];
|
|
9
|
+
if (!devEnv?.moduleGraph)
|
|
10
|
+
return;
|
|
11
|
+
/**
|
|
12
|
+
* Debounce catches multiple route changes in a row
|
|
13
|
+
* Short timeout for inexpensive invalidations
|
|
14
|
+
*/
|
|
15
|
+
const invalidateModule = debounce((mod) => {
|
|
16
|
+
devEnv.moduleGraph.invalidateModule(mod);
|
|
17
|
+
}, 0);
|
|
18
|
+
/**
|
|
19
|
+
* Long debounce timeout for expensive reloads
|
|
20
|
+
*/
|
|
21
|
+
const reloadModule = debounce((mod) => {
|
|
22
|
+
devEnv.reloadModule(mod);
|
|
23
|
+
}, 200);
|
|
24
|
+
return routes.on("reload", function handleRoutesReload(evt) {
|
|
25
|
+
void onReload?.();
|
|
26
|
+
const mod = devEnv.moduleGraph.getModuleById(moduleId);
|
|
27
|
+
if (!mod) {
|
|
28
|
+
devEnv.hot.send({ type: "full-reload" });
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (evt.detail.type !== "update") {
|
|
32
|
+
// Adding or removing a route changes the manifest itself, and marking
|
|
33
|
+
// it invalid is not enough to replace it: whoever evaluated the module
|
|
34
|
+
// holds their own copy — the browser, or a server-side module runner
|
|
35
|
+
// like the one nitro serves SSR from — and only a reload displaces it.
|
|
36
|
+
// An `update` needs no reload: the entries are unchanged, and the route
|
|
37
|
+
// module's own HMR covers its contents.
|
|
38
|
+
reloadModule(mod);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
invalidateModule(mod);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
export const fileSystemWatcher = (getRouter, moduleId,
|
|
46
|
+
/** Runs on every route change, before the module is invalidated. */
|
|
47
|
+
onReload) => {
|
|
48
|
+
const plugin = {
|
|
49
|
+
name: "filesystem-routing:watcher",
|
|
50
|
+
async configureServer(server) {
|
|
51
|
+
const watched = new Set();
|
|
52
|
+
for (const environment of Object.keys(server.environments)) {
|
|
53
|
+
const router = getRouter(environment);
|
|
54
|
+
if (!router)
|
|
55
|
+
continue;
|
|
56
|
+
if (!watched.has(router)) {
|
|
57
|
+
watched.add(router);
|
|
58
|
+
setupWatcher(server.watcher, router);
|
|
59
|
+
}
|
|
60
|
+
// Build the manifest before listening for reloads, so the initial
|
|
61
|
+
// scan's `add` events don't invalidate the module mid-page-load.
|
|
62
|
+
router
|
|
63
|
+
.getRoutes()
|
|
64
|
+
.then(() => createRoutesReloader(server, router, environment, moduleId, onReload));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
return plugin;
|
|
69
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { PluginOption } from "vite";
|
|
2
|
+
import { type PageFileSystemRouterConfig } from "../convention.ts";
|
|
3
|
+
import { BaseFileSystemRouter } from "../router.ts";
|
|
4
|
+
import { DEFAULT_EXTENSIONS, moduleId } from "./constants.ts";
|
|
5
|
+
export { DEFAULT_EXTENSIONS, moduleId };
|
|
6
|
+
export { treeShake } from "./tree-shake.ts";
|
|
7
|
+
export { fileSystemWatcher } from "./fs-watcher.ts";
|
|
8
|
+
export interface FileRoutesOptions extends Pick<PageFileSystemRouterConfig, "components" | "httpMethods" | "toPath" | "toRoute"> {
|
|
9
|
+
/** Route directory, relative to the Vite root. Defaults to `src/routes`. */
|
|
10
|
+
dir?: string;
|
|
11
|
+
/** File extensions that participate in routing. Defaults to js/jsx/ts/tsx. */
|
|
12
|
+
extensions?: string[];
|
|
13
|
+
/**
|
|
14
|
+
* A custom file-system router (scanning + convention) used for every Vite
|
|
15
|
+
* environment. Defaults to a `PageFileSystemRouter` over `dir`, configured
|
|
16
|
+
* with the convention options above.
|
|
17
|
+
*/
|
|
18
|
+
router?: BaseFileSystemRouter;
|
|
19
|
+
/**
|
|
20
|
+
* Per-environment file-system routers, keyed by Vite environment name.
|
|
21
|
+
* Frameworks (e.g. SolidStart) use this to serve different conventions to
|
|
22
|
+
* client and server environments. Falls back to `router` for environments
|
|
23
|
+
* not listed.
|
|
24
|
+
*/
|
|
25
|
+
routers?: Record<string, BaseFileSystemRouter>;
|
|
26
|
+
/** The id the route manifest is served from. Defaults to `virtual:file-routes`. */
|
|
27
|
+
moduleId?: string;
|
|
28
|
+
/**
|
|
29
|
+
* Vite environments whose build should take every route module as an
|
|
30
|
+
* entry, so routes are code-split into their own chunks. Frameworks pass
|
|
31
|
+
* their browser environment's name; the inputs are added to whatever the
|
|
32
|
+
* framework already configures.
|
|
33
|
+
*/
|
|
34
|
+
buildInputs?: string | string[];
|
|
35
|
+
/**
|
|
36
|
+
* Packages that import the virtual module and must therefore stay out of
|
|
37
|
+
* esbuild's dependency prebundling, which cannot resolve it. Emission
|
|
38
|
+
* adapters are expected to take the manifest as an argument instead of
|
|
39
|
+
* importing the virtual module (so app source holds the only import, which
|
|
40
|
+
* prebundling never touches), making this an escape hatch for packages
|
|
41
|
+
* that import it anyway. Defaults to `[]`.
|
|
42
|
+
*/
|
|
43
|
+
optimizeDepsExclude?: string[];
|
|
44
|
+
/**
|
|
45
|
+
* Write a declaration for the virtual module typing the manifest as a
|
|
46
|
+
* literal tuple, and keep it in step with the route directory. Routers
|
|
47
|
+
* that derive types from their route table need this: a runtime array
|
|
48
|
+
* tells them nothing, so path-derived types silently degrade without it.
|
|
49
|
+
*
|
|
50
|
+
* `true` writes `file-routes.d.ts` next to the Vite root; pass a path to
|
|
51
|
+
* put it elsewhere. The generated file is self-contained — reference it
|
|
52
|
+
* *instead of* `filesystem-routing/types`, never both.
|
|
53
|
+
*/
|
|
54
|
+
types?: boolean | string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The Vite delivery adapter for `filesystem-routing`.
|
|
58
|
+
*
|
|
59
|
+
* Serializes the neutral route manifest into the virtual module — module refs
|
|
60
|
+
* become code-split dynamic imports (`$`-prefixed keys) or eagerly required
|
|
61
|
+
* static imports (`$$`-prefixed keys) — and keeps it hot as route files are
|
|
62
|
+
* added, changed and removed.
|
|
63
|
+
*
|
|
64
|
+
* The module serves two views of the same entries: the default export is the
|
|
65
|
+
* flat manifest, and `pageRoutes` is the page entries nested by path with
|
|
66
|
+
* `(group)` segments stripped, so emission adapters don't each reimplement
|
|
67
|
+
* the tree.
|
|
68
|
+
*/
|
|
69
|
+
export declare function fileRoutes(options?: FileRoutesOptions): PluginOption[];
|