@troyio/vite-file-router 0.3.0 → 0.3.2

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 (3) hide show
  1. package/README.md +23 -0
  2. package/dist/index.js +18 -8
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -108,6 +108,12 @@ Catch-all segments such as `[...slug]` become `*`. Parenthesized directories
108
108
  are route groups; they organize files and can have their own page, layout,
109
109
  loading files, loaders, and actions, but their names do not add a URL segment.
110
110
 
111
+ Directories whose names start with an underscore, such as `_components` or
112
+ `_utils`, are private folders. The plugin skips them and everything nested
113
+ inside them, so you can colocate components, hooks, and helpers next to the
114
+ routes that use them without creating routes. A `_components/page.tsx` file is
115
+ never routed.
116
+
111
117
  ### Layouts
112
118
 
113
119
  The plugin adapts React Router's matched child route to a `children` prop. A
@@ -178,6 +184,23 @@ when a descendant URL matches. An action runs only when its route is selected
178
184
  as the submission target; a parent action does not automatically handle
179
185
  submissions targeting child routes.
180
186
 
187
+ A loader module may also export `shouldRevalidate(args)` to control the route's
188
+ React Router `shouldRevalidate` option. It receives the same arguments as
189
+ `shouldRevalidate` and must synchronously return a boolean:
190
+
191
+ ```ts
192
+ import type { LoaderFunctionArgs, ShouldRevalidateFunctionArgs } from "react-router";
193
+
194
+ export function shouldRevalidate({ nextUrl, defaultShouldRevalidate }: ShouldRevalidateFunctionArgs) {
195
+ if (nextUrl.searchParams.get("refresh") === "never") return false;
196
+ return defaultShouldRevalidate;
197
+ }
198
+
199
+ export async function loader({ request }: LoaderFunctionArgs) {
200
+ return getDashboardData(request);
201
+ }
202
+ ```
203
+
181
204
  Use a loader to redirect users who should not enter a protected route subtree.
182
205
  For example, `src/pages/dashboard/loader.ts` can guard `/dashboard` and all of
183
206
  its nested pages:
package/dist/index.js CHANGED
@@ -53,6 +53,7 @@ function scan(directory, conventions = DEFAULT_CONVENTIONS) {
53
53
  for (const entry of entries) {
54
54
  const file = path.join(directory, entry.name);
55
55
  if (entry.isDirectory()) {
56
+ if (entry.name.startsWith("_")) continue;
56
57
  node.children.push(scan(file, conventions));
57
58
  continue;
58
59
  }
@@ -132,9 +133,19 @@ function generateImport(file, projectRoot) {
132
133
  Component: (await import(${JSON.stringify(getImportPath(file, projectRoot))})).default
133
134
  })`;
134
135
  }
135
- function generateRouteLazy(node, projectRoot, includeLayout) {
136
+ function generateRouteLazy(node, projectRoot, includeLayout, includeLoader) {
136
137
  const properties = [];
137
138
  if (includeLayout && node.layout) properties.push(`Component: withOutlet((await import(${JSON.stringify(getImportPath(node.layout, projectRoot))})).default)`);
139
+ if (includeLoader && node.loader) return `async () => {
140
+ const loaderModule = await import(${JSON.stringify(getImportPath(node.loader, projectRoot))});
141
+ return {
142
+ loader: loaderModule.loader,
143
+ ...(typeof loaderModule.shouldRevalidate === "function"
144
+ ? { shouldRevalidate: loaderModule.shouldRevalidate }
145
+ : {}),
146
+ ${properties.join(",\n ")}
147
+ };
148
+ }`;
138
149
  return `async () => ({ ${properties.join(", ")} })`;
139
150
  }
140
151
  function generateLazyComponent(file, projectRoot) {
@@ -143,8 +154,8 @@ function generateLazyComponent(file, projectRoot) {
143
154
  function generateLazyLayout(file, projectRoot) {
144
155
  return `lazy(() => import(${JSON.stringify(getImportPath(file, projectRoot))}).then(({ default: Layout }) => ({ default: withOutlet(Layout) })))`;
145
156
  }
146
- function generateDataHandler(file, kind, projectRoot) {
147
- return `async (args) => (await import(${JSON.stringify(getImportPath(file, projectRoot))})).${kind}(args)`;
157
+ function generateDataHandler(file, projectRoot) {
158
+ return `async (args) => (await import(${JSON.stringify(getImportPath(file, projectRoot))})).action(args)`;
148
159
  }
149
160
  function getRouteId(directory, projectRoot) {
150
161
  return `file-route:${path.relative(projectRoot, directory).split(path.sep).join("/") || "."}`;
@@ -159,8 +170,7 @@ function generateNode(node, root, context, inheritedBoundary) {
159
170
  context.hasErrorBoundaries = true;
160
171
  route.ErrorBoundary = `createErrorBoundary(${generateLazyComponent(node.error, context.projectRoot)})`;
161
172
  }
162
- if (node.loader) route.loader = generateDataHandler(node.loader, "loader", context.projectRoot);
163
- if (node.action) route.action = generateDataHandler(node.action, "action", context.projectRoot);
173
+ if (node.action) route.action = generateDataHandler(node.action, context.projectRoot);
164
174
  let loadingComponent;
165
175
  if (node.loading) {
166
176
  loadingComponent = genSafeVariableName(`Loading${context.nextLoadingId++}`);
@@ -173,17 +183,17 @@ function generateNode(node, root, context, inheritedBoundary) {
173
183
  } else if (node.layout) {
174
184
  if (hasBoundary) route.Component = generateLazyLayout(node.layout, context.projectRoot);
175
185
  }
176
- if (node.layout && !hasBoundary) route.lazy = generateRouteLazy(node, context.projectRoot, true);
186
+ if (node.layout && !hasBoundary || node.loader) route.lazy = generateRouteLazy(node, context.projectRoot, Boolean(node.layout && !hasBoundary), Boolean(node.loader));
177
187
  const children = [];
178
188
  if (node.page) {
179
189
  const page = hasBoundary ? {
180
190
  index: "true",
181
191
  Component: generateLazyComponent(node.page, context.projectRoot),
182
- ...node.action ? { action: generateDataHandler(node.action, "action", context.projectRoot) } : {}
192
+ ...node.action ? { action: generateDataHandler(node.action, context.projectRoot) } : {}
183
193
  } : {
184
194
  index: "true",
185
195
  lazy: generateImport(node.page, context.projectRoot),
186
- ...node.action ? { action: generateDataHandler(node.action, "action", context.projectRoot) } : {}
196
+ ...node.action ? { action: generateDataHandler(node.action, context.projectRoot) } : {}
187
197
  };
188
198
  children.push(genObjectFromRaw(page));
189
199
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@troyio/vite-file-router",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "File-system routing plugin for Vite",
5
5
  "type": "module",
6
6
  "private": false,