remix-flat-routes
Advanced tools
Comparing version 0.4.4 to 0.4.5
@@ -47,6 +47,7 @@ var __create = Object.create; | ||
let file = `app/${baseDir}/${routeFile}`; | ||
if (ignoredFilePatterns.some((pattern) => (0, import_minimatch.default)(file, pattern))) { | ||
let absoluteFile = path.resolve(file); | ||
if (ignoredFilePatterns.some((pattern) => (0, import_minimatch.default)(absoluteFile, pattern, { dot: true }))) { | ||
return; | ||
} | ||
const routeInfo = getRouteInfo(baseDir, routeFile, options.basePath); | ||
const routeInfo = getRouteInfo(baseDir, routeFile, options.basePath, options.paramPrefixChar); | ||
if (!routeInfo) | ||
@@ -102,3 +103,5 @@ return; | ||
getRoutes(parentMap, child.name, route); | ||
const path2 = child.path.substring(parentRoute.routeInfo.path.length + 1); | ||
let path2 = child.path.substring(parentRoute.routeInfo.path.length); | ||
if (path2.startsWith("/")) | ||
path2 = path2.substring(1); | ||
route(path2, child.file, { index: child.index }); | ||
@@ -110,4 +113,7 @@ } | ||
} | ||
function getRouteInfo(baseDir, routeFile, basePath) { | ||
function getRouteInfo(baseDir, routeFile, basePath, paramsPrefixChar) { | ||
let url = basePath != null ? basePath : ""; | ||
if (url.startsWith("/")) { | ||
url = url.substring(1); | ||
} | ||
let ext = path.extname(routeFile); | ||
@@ -130,3 +136,3 @@ if (![".js", ".jsx", ".ts", ".tsx", ".md", ".mdx"].includes(ext)) { | ||
let routeSegment = routeSegments[i]; | ||
url = appendPathSegment(url, routeSegment); | ||
url = appendPathSegment(url, routeSegment, paramsPrefixChar); | ||
} | ||
@@ -140,3 +146,3 @@ return { | ||
} | ||
function appendPathSegment(url, segment) { | ||
function appendPathSegment(url, segment, paramsPrefixChar = "$") { | ||
if (segment) { | ||
@@ -152,6 +158,8 @@ if (["index", "_index"].some((name) => segment === name)) { | ||
} | ||
if (segment.startsWith("$")) { | ||
segment = segment === "$" ? "*" : `:${segment.substring(1)}`; | ||
if (segment.startsWith(paramsPrefixChar)) { | ||
segment = segment === paramsPrefixChar ? "*" : `:${segment.substring(1)}`; | ||
} | ||
url += "/" + segment; | ||
if (url) | ||
url += "/"; | ||
url += segment; | ||
} | ||
@@ -158,0 +166,0 @@ return url; |
{ | ||
"name": "remix-flat-routes", | ||
"version": "0.4.4", | ||
"version": "0.4.5", | ||
"description": "Package for generating routes using flat convention", | ||
@@ -20,3 +20,3 @@ "main": "dist/index.js", | ||
"contributors:generate": "all-contributors generate", | ||
"prepublish": "npm run build", | ||
"prepare": "npm run typecheck && npm run build", | ||
"typecheck": "tsc -b", | ||
@@ -23,0 +23,0 @@ "migrate": "rm -rf ./app/flat-files ./app/flat-folders && npm run build && node ./dist/cli.js" |
167
README.md
@@ -5,7 +5,7 @@ # Remix Flat Routes | ||
[![All Contributors](https://img.shields.io/badge/all_contributors-3-orange.svg?style=flat-square)](#contributors-) | ||
[![All Contributors](https://img.shields.io/badge/all_contributors-5-orange.svg?style=flat-square)](#contributors-) | ||
<!-- ALL-CONTRIBUTORS-BADGE:END --> | ||
This package enables you to define your routes using the flat-routes convention. This is based on the [gist](https://gist.github.com/ryanflorence/0dcc52c2332c2f6e1b52925195f87baf) by Ryan Florence | ||
This package enables you to define your routes using the `flat-routes` convention. This is based on the [gist](https://gist.github.com/ryanflorence/0dcc52c2332c2f6e1b52925195f87baf) by Ryan Florence | ||
@@ -24,2 +24,6 @@ ## π Installation | ||
const { flatRoutes } = require('remix-flat-routes') | ||
/** | ||
* @type {import("@remix-run/dev").AppConfig} | ||
*/ | ||
module.exports = { | ||
@@ -32,2 +36,3 @@ // ignore all files in routes folder to prevent | ||
basePath: '/', // optional base path (defaults to /) | ||
paramPrefixChar: '$', // optional specify param prefix | ||
ignoredRouteFiles: [], // same as remix config | ||
@@ -39,30 +44,26 @@ }) | ||
NOTE: `baseDir` should be relative to the `app` folder. If you want to | ||
use the `routes` folder, you will need to update the `ignoredRouteFiles` | ||
property to ignore **all** files: `**/*` | ||
### API | ||
## π Migrating Existing Routes | ||
```ts | ||
function flatRoutes( | ||
baseDir: string, | ||
defineRoutes: DefineRoutesFunction, | ||
options: FlatRoutesOptions, | ||
) | ||
You can now migrate your existing routes to the new flat-routes convention. Simply run: | ||
type FlatRoutesOptions = { | ||
basePath?: string // optional base path (default is '/') | ||
paramPrefixChar?: string // optional param prefix (default is '$') | ||
ignoredRouteFiles?: string[] // optional files to ingore as routes (same as Remix config option) | ||
visitFiles?: VisitFilesFunction // optional visitor (useful for tests to provide files without file system) | ||
} | ||
``` | ||
```bash | ||
npx migrate-flat-routes <sourceDir> <targetDir> [options] | ||
NOTE: `baseDir` should be relative to the `app` folder. If you want to use the `routes` folder, you will need to update the `ignoredRouteFiles` property to ignore **all** files: `**/*` | ||
Example: | ||
npx migrate-flat-routes ./app/routes ./app/flatroutes --convention=flat-folders | ||
## π¨ Flat Routes Convention | ||
NOTE: | ||
sourceDir and targetDir are relative to project root | ||
### Example (flat-files) | ||
Options: | ||
--convention=<convention> | ||
The convention to use when migrating. | ||
flat-files - Migrates all files to a flat directory structure. | ||
flat-folders - Migrates all files to a flat directory structure, but | ||
creates folders for each route. | ||
``` | ||
## π¨ Flat Routes Convention | ||
``` | ||
routes/ | ||
@@ -135,24 +136,50 @@ _auth.forgot-password.tsx | ||
## Nested Layouts | ||
### Default match | ||
By default, `flat-routes` will nest the current route into the parent layout that has the longest matching prefix. | ||
Given the layout route `app.calendar.tsx`, the following routes will be nested under `app.calendar.tsx` since **`app.calendar`** is the longest matching prefix. | ||
- `app.calendar.index.tsx` | ||
- `app.calendar.$day.tsx` | ||
### Override match | ||
Sometimes you want to use a parent layout that is higher up in the route hierarchy. With the default Remix convention, you would use dot (`.`) notation instead of nested folders. With `flat-routes`, since routes files always use dots, there is a different convention to specify which layout to nest under. | ||
Let's say you have an `app.tsx` layout, and you have a route that you don't want to share with the layout, but instead want to match with `root.tsx`. To override the default parent match, append a trailing underscore (`_`) to the segment that is the immediate child of the route you want to nest under. | ||
`app_.projects.$id.roadmap.tsx` will nest under `root` since there are no matching routes: | ||
- β `app_.projects.$id.tsx` | ||
- β `app_.projects.tsx` | ||
- β `app_.tsx` | ||
- β `root.tsx` | ||
## Conventions | ||
| filename | convention | behavior | | ||
| ----------------------- | ---------------------- | ------------------------------- | | ||
| `privacy.jsx` | filename | normal route | | ||
| `pages.tos.jsx` | dot with no layout | normal route, "." -> "/" | | ||
| `about.jsx` | filename with children | parent layout route | | ||
| `about.contact.jsx` | dot | child route of layout | | ||
| `about.index.jsx` | index filename | index route of layout | | ||
| `about_.company.jsx` | trailing underscore | url segment, no layout | | ||
| `_auth.jsx` | leading underscore | layout nesting, no url segment | | ||
| `_auth.login.jsx` | leading underscore | child of pathless layout route | | ||
| `users.$userId.jsx` | leading $ | URL param | | ||
| `docs.$.jsx` | bare $ | splat route | | ||
| `dashboard.route.jsx` | route suffix | optional, ignored completely | | ||
| `_layout.jsx` | explict layout file | optional, same as parent folder | | ||
| `_route.jsx` | explict route file | optional, same as parent folder | | ||
| `investors/[index].jsx` | brackets | escapes conventional characters | | ||
| filename | convention | behavior | | ||
| ------------------------------- | ---------------------- | ------------------------------- | | ||
| `privacy.jsx` | filename | normal route | | ||
| `pages.tos.jsx` | dot with no layout | normal route, `.` -> `/` | | ||
| `about.jsx` | filename with children | parent layout route | | ||
| `about.contact.jsx` | dot | child route of layout | | ||
| `about.index.jsx` | index filename | index route of layout | | ||
| `about._index.jsx` | alias of index.tsx | index route of layout\* | | ||
| `about_.company.jsx` | trailing underscore | url segment, no layout | | ||
| `app_.projects.$id.roadmap.tsx` | trailing underscore | change default parent layout | | ||
| `_auth.jsx` | leading underscore | layout nesting, no url segment | | ||
| `_auth.login.jsx` | leading underscore | child of pathless layout route | | ||
| `users.$userId.jsx` | leading $ | URL param | | ||
| `docs.$.jsx` | bare $ | splat route | | ||
| `dashboard.route.jsx` | route suffix | optional, ignored completely | | ||
| `investors/[index].jsx` | brackets | escapes conventional characters | | ||
> NOTE: The underscore prefix for the index route is optional but helps sort the file to the top of the directory listing. | ||
## Justification | ||
- **Make it easier to see the routes your app has defined** - just pop open "routes/" and they are all right there. Since file systems typically sort folders first, when you have dozens of routes it's hard to see which folders have layouts and which don't today. Now all related routes are sorted together. | ||
- **Make it easier to see the routes your app has defined** - just pop open "routes/" and they are all right there. Since file systems typically sort folders first, when you have dozens of routes it's hard to see today which folders have layouts and which don't. Now all related routes are sorted together. | ||
@@ -165,8 +192,13 @@ - **Decrease refactor/redesign friction** - while code editors are pretty good at fixing up imports when you move files around, and Remix has the `"~"` import alias, it's just generally easier to refactor a code base that doesn't have a bunch of nested folders. Remix will no longer force this. | ||
- **Colocation** - while the example is exclusively files, they are really just "import paths". So you could make a folder for a route instead and the `index` file will be imported, allowing all of a route's modules to live along side each other. | ||
## Colocation | ||
For example, these routes: | ||
While the example is exclusively files, they are really just "import paths". So you could make a folder for a route instead and the `index` file will be imported, allowing all of a route's modules to live alongside each other. This is the _flat-folders_ convention, as opposed to the _flat-files_ convention detailed above. | ||
### Example (flat-folders) | ||
``` | ||
routes/ | ||
_auth.forgot-password.tsx | ||
_auth.login.tsx | ||
_auth.tsx | ||
_landing.about.tsx | ||
@@ -176,2 +208,3 @@ _landing.index.tsx | ||
app.projects.tsx | ||
app.projects.$id.tsx | ||
app.tsx | ||
@@ -181,10 +214,12 @@ app_.projects.$id.roadmap.tsx | ||
Could be folders holding their own modules inside: | ||
Each route becomes a folder with the route name minus the file extension. The route file then is named _index.tsx_. | ||
So _app.projects.tsx_ becomes _app.projects/index.tsx_ | ||
``` | ||
routes/ | ||
_auth/ | ||
_layout.tsx <- explicit layout file (same as _auth.tsx) | ||
index.tsx x <- route file (same as _auth.tsx) | ||
_auth.forgot-password/ | ||
_route.tsx <- explicit route file (same as _auth.forgot-password.tsx) | ||
index.tsx <- route file (same as _auth.forgot-password.tsx) | ||
_auth.login/ | ||
@@ -213,3 +248,3 @@ index.tsx <- route files (same as _auth.login.tsx) | ||
app.projects/ | ||
_layout.tsx <- explicit layout file (sames as app.projects.tsx) | ||
index.tsx <- layout file (sames as app.projects.tsx) | ||
project-card.tsx | ||
@@ -219,8 +254,40 @@ get-projects.server.tsx | ||
app.projects.$id/ | ||
_route.tsx <- explicit route file (sames as app.projects.$id.tsx) | ||
index.tsx <- route file (sames as app.projects.$id.tsx) | ||
``` | ||
### Aliases | ||
Since the route file is now named _index.tsx_ and you can colocate additional files in the same route folder, the _index.tsx_ file may get lost in the list of files. You can also use the following aliases for _index.tsx_. The underscore prefix will sort the file to the top of the directory listing. | ||
- `_index.tsx` | ||
- `_layout.tsx` | ||
- `_route.tsx` | ||
> NOTE: The _\_layout.tsx_ and _\_route.tsx_ files are simply more explicit about their role. They work the same as _index.tsx_. | ||
As with flat files, an index route (not to be confused with index route _file_), can also use the underscore prefix. The route `_landing.index` can be saved as `_landing.index/index.tsx` or `_landing._index/_index.tsx`. | ||
This is a bit more opinionated, but I think it's ultimately what most developers would prefer. Each route becomes its own "mini app" with all of its dependencies together. With the `ignoredRouteFiles` option it's completely unclear which files are routes and which aren't. | ||
## π Migrating Existing Routes | ||
You can now migrate your existing routes to the new `flat-routes` convention. Simply run: | ||
```bash | ||
npx migrate-flat-routes <sourceDir> <targetDir> [options] | ||
Example: | ||
npx migrate-flat-routes ./app/routes ./app/flatroutes --convention=flat-folders | ||
NOTE: | ||
sourceDir and targetDir are relative to project root | ||
Options: | ||
--convention=<convention> | ||
The convention to use when migrating. | ||
flat-files - Migrates all files to a flat directory structure. | ||
flat-folders - Migrates all files to a flat directory structure, but | ||
creates folders for each route. | ||
``` | ||
This is a bit more opinionated, but I think it's ultimately what most developers would prefer. Each route becomes its own "mini app" with all of it's dependencies together. With the `ignoredRouteFiles` option it's completely unclear which files are routes and which aren't. | ||
## π Contributors | ||
@@ -238,2 +305,4 @@ | ||
<td align="center"><a href="https://blp.is/"><img src="https://avatars.githubusercontent.com/u/967145?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Brandon Pittman</b></sub></a><br /><a href="https://github.com/kiliman/remix-mount-routes/commits?author=brandonpittman" title="Documentation">π</a> <a href="https://github.com/kiliman/remix-mount-routes/commits?author=brandonpittman" title="Code">π»</a></td> | ||
<td align="center"><a href="https://github.com/machour"><img src="https://avatars.githubusercontent.com/u/304450?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mehdi Achour</b></sub></a><br /><a href="https://github.com/kiliman/remix-mount-routes/commits?author=machour" title="Documentation">π</a></td> | ||
<td align="center"><a href="https://github.com/falegh"><img src="https://avatars.githubusercontent.com/u/49175237?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Fidel GonzΓ‘lez</b></sub></a><br /><a href="https://github.com/kiliman/remix-mount-routes/commits?author=falegh" title="Documentation">π</a></td> | ||
</tr> | ||
@@ -240,0 +309,0 @@ </table> |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
31074
377
306