Replies: 2 comments 3 replies
-
@pcattori since you're working on the new way to define routes, I wrote about my ideas here, hope it's useful for the team. |
Beta Was this translation helpful? Give feedback.
-
@sergiodxa glad that some of your proposals made it to RR7 FTR, I'd like to make you notice of a need that our open source CMS community (Plone) has right now, while we are planning to migrate from RR5 to full RR7 (framework) mode. I left my proposal in here: The summary is that in RR5 you were able to do:
We need splat routes with fixed suffixes. We would love to share our use case and discuss about it and how to achieve the challenges that we have ahead with the Remix/RR team. Thanks! |
Beta Was this translation helpful? Give feedback.
-
Proposal
Improve the way routes are defined using code instead of a file convention.
Background
Many people has issues with Remix's file convention since v2, but the reality is that there's always going to be someone who doesn't like the default conventions.
And while Remix has always allowed apps to customize the routes completely, it's not that clear and simple to do so.
Use Case
API/Examples
My proposal is to do something similar to what Rails
config/routes.rb
file does, here's an example:Let's define what's happening here.
This line is loading at a certain route another application, in this case it comes from a package.
This one, is creating a namespace (which adds an URL segment) and defining a root route, and two resources routes.
This one defines that the root (/) of the namespace will redirect to
/admin/users
These two define a resource (route), this defines
/admin/users
and/admin/posts
, and all the CRUD routes for them, soGET /admin/users
=>UsersController#index
GET /admin/users/new
=>UsersController#new
POST /admin/users
=>UsersController#create
GET /admin/users/:id
=>UsersController#show
GET /admin/users/:id/edit
=>UsersController#edit
PATCH /admin/users/:id
=>UsersController#update
PUT /admin/users/:id
=>UsersController#update
DELETE /admin/users/:id
=>UsersController#destroy
Each different CRUD goes to the same controller on different methods.
This is drawing (loading) routes from another file, is similar to
mount
but for local routes, it's useful to split largeroutes.rb
files.Finally this;
Is similar to the ones inside the admin namespace, a resource can be nested inside another resource so here we have
/users
,/users/posts
and/posts/:id
, theonly
option is used to limit what actions are defined. And theroot to: "home#index"
is making/
uses theHomeController#index
.I think Remix can adopt a similar approach, adapted to what Remix already supports and it's features.
In Remix case, there's no concept of resources like Rails, instead it focus on routes, so we can have a
route
function here. Sincenamespace
is used in TS, we can usescope
instead, anddraw
can be replaced byextend
.File Convention
Like Remix, Rails has a file convention that the routes.rb uses to know where to look up for the controller, so when we do
resources :users
it goes toapp/controllers/users_controller.rb
, and if we define that resource inside the admin namespace it will goes toapp/controllers/admin/users_controller.rb
.The same way, Remix could keep a simpler convention on how to find the route file, for example, the
route("users"
) can try to find the file onapp/routes/users.tsx
orapp/routes/users.ts
(and JSX or JS). Similarly a route can be a folder with a route.tsx file inside, for exampleapp/routes/users/route.tsx
.For the
scope("admin")
, the routes defined inside can be defined onapp/routes/admin/users.tsx
orapp/routes/admin/users/route.tsx
For parameterized routes, like
route("posts/:postId")
, the file can beapp/routes/posts.$postId.tsx
orapp/routes/posts.$postId/route.tsx
.This means
scope
use folders, and/
uses.
to replace the/
on the file name.Customizing the Route File
If the app wants to organize files in another way, or maybe the reuse a file in two routes, the
route
function could accept and optional second argument with the file path, for example.This would look for
app/routes/users._index.tsx
instead ofapp/routes/users.tsx
, but still define/users
as the route.Also note that the file extension is omited, so Remix should look up for the file using the extensions it supports in the order
tsx
,ts
,jsx
, orjs
.Nested Routes
One of the main features of Remix is nested routes, here a route can have children routes, for example:
In this case, the first route will look up for
app/routes/users.$userId.tsx
and the nested route will look up forapp/routes/users.$userId/posts.tsx
.The
/
in the route path is replaced with.
in the file name, but the nested route uses/
.Nested Routes with Custom Files
The
route
function second argument can be either a string with the file path, or a callback for the children routes, if you want to do both, the callback could become a third argument.Here the first route has a custom file on
app/routes/users/$userId.tsx
but the nested route will use the defaultapp/routes/users.$userId/posts.tsx
.Route Constraints (#7111)
If the Route Constraints proposal is also accepted, this can be used to define those constraints right here, for example:
The second argument of
route
can be either a string for a file path, a function for nested routes, or an object with options for more advanced features, in this case thefile
becomes an option and there's aconstraints
option too.Here we define a constraint on the first route that
articleId
must be a number, and on the second route we don't define any constraints. This way a like/123
will match the first route, but/abc
will match the second one.Multi Tenancy
Right now, building a multi tenant app in Remix would mean you either have many
if
in your loader, action and component, or you have two separate Remix apps, one for the tenants and another for the app itself. Eg. one app handling company.com with landings, blog, payments, etc. and another one for tenant.company.com which has the app the tenants use.Using constraints it's possible to define a scope that will be used as a subdomain, for example:
This can be useful to create multi tenant apps, where a group of routes will only work if the app has a subdomain, other routes will be ignored when the app has no subdomain.
Custom Routes Folder
The default folder for routes is still
app/routes
, but it can be changed using thescope
function, for example we could move our admin routes somewhere else like this:This
base
option defines the folder insideapp
, in this case the valueadmin
will point toapp/admin
. Then any route inside thisscope
will look for files insideapp/admin
instead ofapp/routes
, this way we can have multiple route folders when organizing our code.Another thing is that because this is a scope it stills adds
/admin
, but because we changed the base, routes inside will not need to go toapp/admin/admin/users.tsx
butapp/admin/users.tsx
directly.Custom Folder without URL Segments
If we want to set a custom folder for a group of routes, without adding a URL segment, we could use another
base
function.With this, any route defined inside the
base
will lookup files onapp/admin
but the URL will not have/admin
as a prefix. This can be useful for grouping routes outside the routes folder without changing the URL, another e.g. could be to add debug routes in development.This way, in development, we can access
/email
and/cache
to debug emails and cache, and those routes files will live inapp/debug/email.tsx
andapp/debug/cache.tsx
.Splitting Routes
If the route file grows to be too large, it could be possible to split it into multiple files and combine them in
app/routes.ts
. This can be useful to group routes together, for example:The
extend
function receives a routes manifest (the output ofdefineRoutes
) and can use it to extend the routes. This way we can split the routes into multiple files and combine them in the mainapp/routes.ts
.Additionally, routes defined below a
extend
call can overwrite the extended configuration. Similarly, a route defined above anextend
call can be overwritten by the extended configuration. So the order here matters.Package Routes
The same feature used to split routes, can be used by packages to provide routes, for example:
This
remix-auth/routes
could export adefineRoutes
output, and can point the route files tonode_modules/remix-auth/routes
for example. This way developers could create an ecosystem of packages that provides routes ready to use.Redirects & Rewrites
It could be possible to define redirects in the routes file too, for example:
This would redirect
/old
to/new
.Similarly rewrites could be defined like this:
Now if the user goes to
/old
it will see the content of/new
, while the URL will still be/old
.Splat Routes
Sometimes, you want to define a route to be used when the URL doesn't match any valid route, a splat or catch-all route. This could be defined with a wildcard in the
route
.It wildcard could be applied to a subroute too.
In this case, going to
/something
will not match any route, but/parent/something/here
will do.It could also include a segment prefix.
In this case,
/admin/anything/here/not/matter/the/nesting
will match thenot-found
route.Following the convention, just using
route("*")
should lookup for the fileapp/routes/$.tsx
.Final API
To summarize, the final API would be something like this:
Beta Was this translation helpful? Give feedback.
All reactions