Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC] Dynamic Routes #7607

Closed
Timer opened this issue Jun 19, 2019 · 90 comments
Closed

[RFC] Dynamic Routes #7607

Timer opened this issue Jun 19, 2019 · 90 comments

Comments

@Timer
Copy link
Member

Timer commented Jun 19, 2019

Dynamic Routes

Background

Dynamic routing (also known as URL Slugs or Pretty/Clean URLs) has been a long-time requested feature of Next.js.

Current solutions involve placing a L7 proxy, custom server, or user-land middleware in-front of your application. None of these solutions offer a sufficiently ergonomic developer experience.

Additionally, users reaching for a custom server inadvertently opt-out of advanced framework-level features like per-page serverless functions.

Goals

  1. Leverage convention to provide URL Slug support that is easy to reason about
  2. Cover a majority of use-cases observed in the wild
  3. Eliminate the need of a custom server to support /blog/:post
  4. Validate <Link /> route transitions when possible
  5. Avoid an implementation that requires a route manifest
  6. Routes must be expressible through the filesystem

Proposal

Next.js should support named URL parameters that match an entire URL segment. These routes would be expressed via the filesystem:

  1. A filename or directory name that is wrapped with [] would be considered a named parameter
  2. Explicit route segments would take priority over dynamic segments, matched from left-to-right
  3. Route parameters would be required, never optional
  4. Route parameters will be merged into the query object (accessible from getInitialProps or router via withRouter) — these parameters can not be overridden by a query parameter

To help understand this proposal, let's examine the following file tree:

pages/
├── [root].js
├── blog/
│ └── [id].js
├── customers/
│ ├── [customer]/
│ │ ├── [post].js
│ │ ├── index.js
│ │ └── profile.js
│ ├── index.js
│ └── new.js
├── index.js
└── terms.js

Next.js would produce the following routes, registered in the following order:

;[
  { path: '/', page: '/index.js' },
  { path: '/blog/:id', page: '/blog/[id].js' },
  { path: '/customers', page: '/customers/index.js' },
  { path: '/customers/new', page: '/customers/new.js' },
  { path: '/customers/:customer', page: '/customers/[customer]/index.js' },
  {
    path: '/customers/:customer/profile',
    page: '/customers/[customer]/profile.js',
  },
  { path: '/customers/:customer/:post', page: '/customers/[customer]/[post].js' },
  { path: '/terms', page: '/terms.js' },
  { path: '/:root', page: '/[root].js' },
]

Usage Examples

These examples all assume a page with the filename pages/blog/[id].js:

Navigating to the Page with <Link />

<Link href="/blog/[id]" as="/blog/how-to-use-dynamic-routes">
  <a>
    Next.js: Dynamic Routing{' '}
    <span role="img" aria-label="Party Popper">
      🎉
    </span>
  </a>
</Link>

The above example will transition to the /blog/[id].js page and provide the following query object to the Router:

{
  id: 'how-to-use-dynamic-routes'
}

Reading Named Parameters from Router

import { useRouter } from 'next/router'

function BlogPost() {
  const router = useRouter()
  // `blogId` will be `'how-to-use-dynamic-routes'` when rendering
  // `/blog/how-to-use-dynamic-routes`
  const blogId = router.query.id
  return <main>This is blog post {blogId}.</main>
}

export default BlogPost

Note: you can also use withRouter.

Reading Named Parameters in getInitialProps

function BlogPost({ blogText }) {
  return <main>{blogText}</main>
}

BlogPost.getInitialProps = async function({ query }) {
  // `blogId` will be `'how-to-use-dynamic-routes'` when rendering
  // `/blog/how-to-use-dynamic-routes`
  const blogId = query.id

  const { text } = await fetch(
    '/api/blog/content?id=' + encodeURIComponent(blogId)
  ).then(res => res.json())

  return { blogText: text }
}

export default BlogPost

Caveats

Optional route parameters are not expressible through the filesystem.

You can emulate an optional route parameter by creating a stub page that exports the parameter version (or vice versa). This increases the visibility of your application's routes when inspecting the filesystem.

// pages/blog/comments.js
// (the optional version of `pages/blog/[id]/comments.js`)
export { default } from './[id]/comments.js'

Named parameters cannot appear in the middle of a route name.

This means a page named blog-[id].js would be interpreted literally and not matched by /blog-1. You can either restructure your page to be /blog/[id].js or turn the entire URL Segment into a named parameter and handle stripping blog- in your application's code.

Alternatives

Denote URL Slugs with insert symbol here instead of []

There are very few symbols available for use to represent a named parameter on the filesystem. Unfortunately, the most recognized way of defining a named parameter (:name) is not a valid filename.

While surveying prior art, the most common symbols used to denote a parameter were _, $ and [].

We ruled out _ because _ is typically indicative of an internal route that is not publicly routable (e.g. _app, _document, /_src, /_logs).
We also ruled out $ because it is a sigil in bash for parameter expansion.

Leverage path-to-regexp for comprehensive support

Most of the symbols required to express regex are not valid filenames. Additionally, complex regexes are sensitive to route ordering for prioritization. The filesystem cannot express order nor contain regex symbols.

In the future, we may allow path-to-regexp routes defined in next.config.js or similar. This is currently out of scope for this proposal.

Future Exploration

Catch-All Parameters

In the future, we may consider adding catch-all parameters. With what we know thus far, these parameters must be at the end of the URL and would potentially use % to denote a catch-all route (e.g. pages/website-builder/[customerName]/%.tsx).

@Timer
Copy link
Member Author

Timer commented Jun 19, 2019

Poll: To express interest in optional parameters, please react with a "+1" this comment.

Note: Optional parameters are already possible with this RFC, they just do not have an explicit syntax (see Caveats section).

@Timer
Copy link
Member Author

Timer commented Jun 19, 2019

Poll: To express interest in catch-all parameters, please react with a "+1" this comment.

Note: Please share your use case for catch-all parameters in this thread! We'd love to understand the problem-space more.

@Timer

This comment has been minimized.

@Timer Timer added the RFC label Jun 19, 2019
@ValentinH
Copy link
Contributor

On ricardo.ch, we use a locale prefix for each route which make routing a bit more complex.

Example of valid routes:

  • / - homepage with auto-detected locale
  • /:locale - homepage with forced locale
  • /:locale/search - search page
  • /:locale/article/:id - article page

Do your think such prefix parameters could be supported?

At the moment, we use https://www.npmjs.com/package/next-routes

Another thing: for the article page, we also support a slug before the id like /de/article/example-article-123 where the id would be 123. This is done via a quite complex regex using next-routes and I don't see how this could be expressed with a file-system API.

@Timer
Copy link
Member Author

Timer commented Jun 19, 2019

@ValentinH the provided routes are all possible using the filesystem API -- given your provided routes:

  • / => pages/index.js
  • /:locale => pages/$locale/index.js
  • /:locale/search => pages/$locale/search.js
  • /:locale/article/:id => pages/$locale/article/$id.js

we also support a slug before the id like /de/article/example-article-123 where the id would be 123

This use case is addressed above:

Named parameters cannot appear in the middle of a route name.

This means a page named blog-$id.js would be interpreted literally and not matched by /blog-1. You can either restructure your pages to be /blog/$id.js or turn the entire URL Segment into a named parameter and handle stripping blog- in your application's code.

Does this solution not meet your needs? We'd love to learn more about your specific requirements.

@ValentinH
Copy link
Contributor

ValentinH commented Jun 19, 2019

Thanks a lot for the answer.

I didn't thought about using $locale/index.js both as a folder and a file, this is really neat!

Regarding the "named parameter in middle", I overlooked it because I thought having the slug being dynamic was different. However, you are completely right and this is addressed by the paragraph you mentioned. Striping the slug in the application code will be the way to go 🙂

@jpstrikesback
Copy link

jpstrikesback commented Jun 19, 2019

Would something like this (parse params from .hidden .files/.folders) be possible?

pages/
├── .root.js
├── blog/
│ ├── .id/
│ │ ├── index.js
│ │ └── comments.js <-- optional?
├── customers/
│ ├── .customer/
│ │ ├── .post/
│ │ │ └── index.js
│ │ ├── index.js
│ │ └── profile.js
│ ├── index.js
│ └── new.js
├── index.js
└── terms.js

or leave the $ so one could find their files :D but always use $folder to indicate a param?

pages/
├── $root.js
├── blog/
│ ├── $id/
│ │ ├── index.js
│ │ └── comments.js <-- optional?
├── customers/
│ ├── $customer/
│ │ ├── $post/
│ │ │ └── index.js
│ │ ├── index.js
│ │ └── profile.js
│ ├── index.js
│ └── new.js
├── index.js
└── terms.js

@Janpot
Copy link
Contributor

Janpot commented Jun 19, 2019

I used to have this use-case for optional parameters in an app that worked with npm packages. These could optionally have a scope. There are routes like:

  • /packages/express
  • /packages/express/dependencies
  • /packages/@babel/core
  • /packages/@babel/core/dependencies

So basically, the scope parameter is optional, but it's also only a scope when it starts with @.
So /packages/express/dependencies and /packages/@babel/core have the same amount of segments, but in one case it's /dependencies of express and in the other it's /index of @babel/core.

In the end it was solved in react-router with the following routes:

<Switch>
  <Route path={`/packages/`} exact component={PackagesOverview} />
  <Route path={`/packages/:name(@[^/]+/[^/]+)`} component={PackageView} />
  <Route path={`/packages/:name`} component={PackageView} />
</Switch>

I'm not sure I see a solution for this use-case in this RFC.

As for catch-all use cases, I'm thinking any deep linking into recursively nested data, like folder structures, treeviews, treemaps.

@timdp
Copy link

timdp commented Jun 19, 2019

My 2 cents: dollar signs in filenames are a bad idea because they're used by shells as a sigil. You're going to confuse people trying to run rm $root.js. Underscores seem like a decent alternative.

More broadly: like many people, I've tried to leverage the file system as a solution to this in the past. Ultimately, I think the file system is never going to offer the full expressiveness you're looking for. For example, declarative routers usually let you specify a validation pattern for a dynamic parameter. In that case, part of the schema lives on the file system, and another part in the code. Separation of concerns is a good thing, but in this case, it's a technical limitation more than anything else.

@amesas
Copy link

amesas commented Jun 19, 2019

Like @ValentinH we use the $locale var, but it's optional.

Should we use /page.ts and /page/$locale/page.ts?

Because we can use a "default" locale or a predefined locale ( user settings ), in those cases we don't use the $locale param.

But we have more use cases: /car/search/$optional-filter-1/$optional-filter-2/$optional-filter-3

Where optional-filter-1: color-red, optional-filter-2: brand-ford, etc...

And for optional params, something like /$required-param/ and /$$optional-param/?

@nervetattoo
Copy link

Awesome that this is coming up on the roadmap!

I have to chime in supporting @timdp though. When you can't even touch $file this will lead to a lot of confusion. You need to remember escaping at every interaction. touch \$file; vim $file will open vim without a file (because $file isn't a defined variable).
Likewise tab completion in a shell will list all variables, once again bringing confusion.

I'm proposing two alternatives that I feel gives the right associations and should work in shells:

  • = It can be read as page is a customer for =customer. You can even contort it mentally to be a colon just stretched out, thus resembling the most common form for named parameters.
  • @ as it also reads somewhat well. a customer for @customer

@pfyod
Copy link

pfyod commented Jun 19, 2019

Another option would be to use curly braces (unless they are reserved characters on some file systems). This parameter syntax is also "prior art" and is used by many other routers:

pages/
├── {root}.js
├── blog/
│ └── {id}.js
├── customers/
│ ├── {customer}/
│ │ ├── {post}.js
│ │ ├── index.js
│ │ └── profile.js
│ ├── index.js
│ └── new.js
├── index.js
└── terms.js

This would allow to have parameters in the middle of the route segment and multiple parameters per segment as it's clear where the parameter starts and where it ends, e.g. /product-{productId}-{productColor}.

@stephan281094
Copy link

So excited that dynamic routes is coming to Next.js!

Regarding the syntax for named parameters, this is something that has been discussed on Spectrum: https://spectrum.chat/next-js/general/rfc-move-parameterized-routing-to-the-file-system~ce289c5e-ff66-4a5b-8e49-08548adfa9c7. It might be worth using that as input for the discussion here. Personally, I like how Sapper is doing it using [brackets]. This is also something Nuxt is going to implement in version 3. Having different frameworks use the same format for dynamic filesystem-based routes sounds like a good thing.

Regarding the usage of <Link />, I think developers will easily forget to set both the href and as attributes. I get that it's not possible to "merge" these into the href attribute because it'd introduce a breaking change, but I feel like it could be solved in a more elegant way.

@timdp
Copy link

timdp commented Jun 19, 2019

Curly braces are unfortunately used by Bash to group commands.

@ValentinH
Copy link
Contributor

I agree with @stephan281094 regarding usage of <Link />, it will be source of mistakes.

@Deevian
Copy link

Deevian commented Jun 19, 2019

Dynamic routing is an extremely useful feature, so it's really awesome you guys have looked into it and came up with a solution, huge props!

While on this topic, wildcard routes would also be a worthy addition to the proposal. You did mention catch-all parameters as something to investigate in the future, but it doesn't cover cases where you might want to do something like /category/*, which could have N number of levels, and you want all of them to render the category page.

@rauchg
Copy link
Member

rauchg commented Jun 19, 2019

Is it possible to use : safely ? If so, that'd be my vote, because everyone is already familiar with that convention from express.

@rauchg
Copy link
Member

rauchg commented Jun 19, 2019

Due to $ conflicting with shell variables, I personally strongly oppose it.

@stephan281094
Copy link

Is it possible to use : safely ? If so, that'd be my vote, because everyone is already familiar with that convention from express.

Apparently : is a prohibited character in Windows, so it's probably not safe. Going with _ isn't ideal either, since underscores can be used in URLs. The reason I think [brackets] are a nice solution, is because it's more future proof. If Next.js wants to support routes like post-12345 in the future, using this syntax it can be done without introducing a breaking change.

@Janpot
Copy link
Contributor

Janpot commented Jun 19, 2019

So a list of characters to avoid would be:

  • Conflicts with file systems: :, *, ", <, >, |
  • Conflicts with shell variables: $
  • Conflicts with bash brace expansion {, }

Anything else?

@AndrewIngram
Copy link

This wouldn't eliminate our need to have a centralised route file for a couple of reasons:

  • We have an automatically generated sitemap, and the filesystem alone isn't sufficient to define it.
  • We used named routes and destination "pages" are determined by data, rather than something that's knowable at build time. The logic for figuring out what page to load based on name and params is driven by the route config.

We also generate our pages folder for these reasons:

  • We use Relay, and this means modules involving GraphQL need to be uniquely named. For that reason we can't often can't have the route segment names be the same as the module names. index.js definitely isn't unique, and I see places where we'd have multiple common segments like edit.
  • We prefer co-locating one-off page-specific components as siblings of the page modules themselves, which Next.js doesn't permit within the pages folder.

Essentially our pattern is to use our centralised route configuration to generate our pages folder, which contains files which do nothing more than import/export modules from elsewhere in the codebase.

To that end, my focus is more on whether this proposal can work simply as an enhanced output format for our existing page generation process, so that we can at least get the benefit of not needing a custom server.

I've gone over some of my use cases elsewhere: https://gist.github.com/AndrewIngram/8d4c4ccd9bd10415a375caacade9f5ca

The main thing i'm not seeing is supporting implicit parameters that aren't expressed in the file-system, for example URL overrides.

Let's say we have a URL like this:

/some-vanity-url/

Where in current Next.js terms, we'd want it to map to a product page with a number of query parameters, e.g Product.js?id=foo&language=en.

Similarly, on our website most countries "sites" are scoped by a top-level segment eg es or ie, but the gb site is mounted without that segment. This means all the gb pages have an implicit country parameter, whilst for all other countries it's explicit.

The other downside, is that because in our case, the same 'page' can exist at multiple mount points in the URL architecture, we're going to end up with a greater number of bundles (i.e. several duplicate entry points) than we actually need in practice.

On the whole this proposal seems like it's going to work well for most common use cases, but it doesn't obviate the need for a route config or custom server in all cases. But assuming this doesn't replace my ability to use the framework the way I do today, I don't have any real objection to this being the preferred happy-path API.

@scf4
Copy link

scf4 commented Jun 19, 2019

I support the {id} suggestion. It allows for multiple params and I think it looks a lot better. It also fits better with React.

@pkrawc
Copy link
Contributor

pkrawc commented Jun 19, 2019

I'm in favor of the file/&param.js character. Taken directly from urls and it doesn't look like it conflicts with files systems or bash.

@poeticninja
Copy link

I would use _ and maybe allow for an override in the next.config.js for those who reallllly need something different.

Appreciate the work on this. Been wanting it for a while! ❤️

@doguh
Copy link

doguh commented Jun 19, 2019

Amazing! 🎉🎉🎉

My only issue here is that Link needs both href and as params.

I believe we could just write <Link to="blog/123" /> : since Nextjs already knows all the routes based on files in the pages folder, it could easily translate it into "/blog/$id".

@nervetattoo
Copy link

So a list of characters to avoid would be:

& is a control operator in bash that runs the left side of the argument in an async subshell. Plaintext: open pages/&customer would run open pages/ in the background and the command customer in the foreground shell.

@jamestalmage
Copy link

jamestalmage commented Jun 19, 2019

This looks really cool.

It does seem like this will create a significant number of single file directories (like /blog/$id in the original example). This gets even more cumbersome if you want two trailing route parameters (i.e. /git/compare/$hash1/$hash2).

I also don't love that the filename for rending a blog post would be $id.js. Having it named blog.js would be much more descriptive.

Perhaps combine with a @customRoute decorator?

// pages/blog.js
import {useRouter, @customRoute} from 'next/router'

@customRoute('/blog/:id')
function BlogPost() {
  const router = useRouter()
  // `blogId` will be `'how-to-use-dynamic-routes'` when rendering
  // `/blog/how-to-use-dynamic-routes`
  const blogId = router.query.id
  return <main>This is blog post {blogId}.</main>
}

export default BlogPost

This seems to provide a cleaner solution for the proposed catch-all parameters as well.

@itsMapleLeaf
Copy link

Decorators can't be applied to functions (maybe this changed since I last read it?) and the proposal is probably a long way away anyway

@yufengwang
Copy link
Contributor

@merelinguist em, Jest use __tests__ for default test folder, I think __ make sense in some case.

@merelinguist
Copy link
Contributor

@yufengwang Perhaps, but I’d prefer a single character if possible. Ultimately, I think the best solution would be:

  1. Sensible, cross-platform default, like =
  2. Option in next.config.js to customise the special route character which is used
  3. Documentation on which characters are problematic in which situations

@nataliyakarat
Copy link
Contributor

Agreed with a single character but I'd prefer to have a zero configuration. and my guess is that many people will go through all issues even if you describe them in a documentation

@fnky
Copy link

fnky commented Jun 22, 2019

Note also = is reserved by zsh. From the docs:

If a word begins with an unquoted ‘=’ and the EQUALS option is set, the remainder of the word is taken as the name of a command. If a command exists by that name, the word is replaced by the full pathname of the command.

@fnky
Copy link

fnky commented Jun 22, 2019

Just an idea; what about using a suffix? For example example@.js, or the like could suffice. This may solve the issue with having to escape and work across shells and file systems as long as the character is valid.

These work in zsh and bash without the need to escape, so far:

example@.js
example~.js
example=.js

@jamestalmage
Copy link

Ooh. Not a suffix but a way to denote trailing URL params.

So blog@id.js becomes blog/:id.

compare@a@b.js becomes compare/:a/:b.

This could solve the deeply nested single file directories I was objecting to above, and keep the entire routing definition file system based.

@Janpot
Copy link
Contributor

Janpot commented Jun 23, 2019

It doesn't look as fancy, but how about something along the lines of:

/blogs/_var_blog-id/index.js
/blogs/_var_blog-id.js

a prefix _var_ Which kind of tries to mimic JS variable declarations. Or does it have to be a super short, one character thing?

@revskill10
Copy link
Contributor

How about ~ character ?

Like /blogs/~id.

@fnky
Copy link

fnky commented Jun 23, 2019

Using ~ as a prefix is also not viable, as it is used to expand to the home folder in POSIX-compliant shells.

Any character that doesn't match [0-9a-zA-Z-._] (regex) cannot be considered safe as a prefix across operating systems, shells and file systems.

Some characters aren't safe inline, either. See zsh's docs about substitutions

@fnky
Copy link

fnky commented Jun 23, 2019

Also I think we shouldn't strive for whether it looks fancy, but rather be intuitive, readable and easy to communicate.

@damaera
Copy link

damaera commented Jun 24, 2019

  • using brackets for [params].js seem more elegant and widely used. (sapper, nuxt v3?).
  • underscore prefix pages/_helper.js usually for a private function and maybe this should be not rendered. this allows us to create helper components within the pages folder

@mmahalwy
Copy link

imho: this feels like a temporary solution to the greater problem. While having routes based on file structure is very nice to have to begin with, it doesn't scale well when you have hundreds of routes, params, etc. Having a routes config file (maybe have a routes.js file in each directory) is a better long term solution. I am personally drawn to nextjs because of the features out-of-the-box (SSR, speed, etc) it provides, not the ease of creating routes from files.

@scf4
Copy link

scf4 commented Jun 24, 2019

@mmahalwy you hit the nail on the head.

Next.js already generates a routes config (based on the filesystem). I believe that making this config more explicit and/or allowing the user to "eject" it if they wish would be the most seamless solution here

@AndrewIngram
Copy link

@mmahalwy @scf4 FWIW, a significant justification for filesystem routes is to remove the need to have a centralised file. In fact, one could easily argue that the entirety of Next.js's API for links and routing is designed around this constraint.

The problem with a route config is that you end up having to ship it to the client, which can mean quite a hefty code bundle if you have routes numbering from hundreds to thousands.

However, there are quite a few common use cases that (as far as I've been able to tell, from discussing this issue with @timneutkens numerous times over the past few months) can't really be solved without a centralised config. I listed some of them in my earlier comment, but there are more.

The simplest one is having a CMS-driven blog where authors can create links to pages on the site. They'll just be creating links with a plain old URL, with no knowledge of what the underlying page module is. With a centralised route config, it's pretty easy to reverse match a URL and work out which page to load (my own library, next-route-resolver is designed to support this use cases, and all the others i've come up with).

I don't see how I can make the site I'm working on work without a route config, so my focus has just been on finding ways to keep the route config within filesize tolerances. For other people, filesystem routing may be more than sufficient. I don't think routing is a problem where there's a single solution that solves everything, it's all about balancing trade-offs.

So as I mentioned before, as far as this proposal is concerned, it seems fine as long as it's sold as solving the routing problem entirely, because that would be a little misleading :)

@mmahalwy
Copy link

@AndrewIngram I understand where you are coming from but this limitation is limiting the power that nextjs has. Nextjs offers so much out of the box that it should be a no-brainer for any new project or company to use it. The challenge though is it's hard opinion on routing that make it unejectable in the future (and as a large company, you're always considering the exit strategy should projects lose interest or maintenance).

@AndrewIngram
Copy link

AndrewIngram commented Jun 24, 2019

@mmahalwy I think you misunderstood my point. I'm in agreement with you, I don't think file-system routing is sufficient to call the routing problem solved, and would be disappointed if it was presented as such. I do think it offers an improvement for a particular set of use cases, but I also think there should also be some kind of route manifest format for those willing to opt-in to a different set of trade-offs (e.g. you and me).

@jamestalmage
Copy link

For those wishing for a centralized or advanced routing config, isn't it well handled by using the custom server and/or external packages? What are you hoping gets added here?

It all seems off topic from this RFC. I don't think anyone, including the OP, has suggested this is the end-all solution for routing. This just improves on the filesystem based routing.

@remy
Copy link
Contributor

remy commented Jun 24, 2019

I've been using the dynamic routes for a mini project for the last few weeks (using $ though I note that it's moved to [param] 3 days ago in the canary repo, but anyway).

I just started using getRequestHandler and I think it's not picking up the dynamic routing on the server side.

Is that a bug, or intentional (i.e. some change to getRequestHandler), something else, or does using getRequestHandler completely turn off the dynamic routing (which would make sense now I think about it…)?

@AndrewIngram
Copy link

For those wishing for a centralized or advanced routing config, isn't it well handled by using the custom server and/or external packages? What are you hoping gets added here?

One of the goals here is to avoid the need to create a custom server, if only to make it easier to use with services like Now (which currently requires all the dynamic routes to be part of its config).

It all seems off topic from this RFC. I don't think anyone, including the OP, has suggested this is the end-all solution for routing. This just improves on the filesystem based routing.

There actually is some additional context here. This proposal has been a long time coming, and based on many of the discussions i've seen related to it (including ones i've been directly involved with), this was being hyped to some degree as removing the need for using these route management libraries like next-routes and my own. I don't think it's off-topic to highlight the use cases which aren't fulfilled by this RFC. Some of them might conceivably be fulfilled by some changes to the proposal, others might not. But either way, surely it's valuable to raise awareness of the limits of what's being proposed?

@chrislloyd
Copy link
Contributor

FWIW we use [param] style FS-based routes at Pinterest (though not Next). It's scaled really well so far. The biggest criticism is that Jest interprets [] as regexp pairs so it can be difficult to target tests for param-ful handlers.

@fnky
Copy link

fnky commented Jun 25, 2019

@chrislloyd What are your experiences with creating and managing files using this format for paths/files in different environments, considering anyone is using zsh, or a tool that interprets these differently?

Seen as the [] is using for pattern matching in zsh (and, as you say with Jest) you will need to escape these paths. This isn't much of a problem if you know this, but given that it should be usable and understood by beginners, I have doubts that this is the right format to go with.

@revskill10
Copy link
Contributor

I have an idea on using ! as required parameter, like /pages/id!.js and ? for optional parameter, like in /pages/posts/id?.js .

It doesn't have any issue with prefix like above discussions, and it's familiar on how ! represents required params, and ? represents optional parameters.

@timdp
Copy link

timdp commented Jun 27, 2019

Windows doesn't allow question marks in file names, and both ? and ! have a special meaning in Bash.

@huv1k
Copy link
Contributor

huv1k commented Jun 28, 2019

API routes now supports dynamic params #7629 🚀

@Timer
Copy link
Member Author

Timer commented Jul 2, 2019

@remy getRequestHandler is expected to handle dynamic routing -- I just confirmed locally it does. Could you please file a separate bug/issue with reproduction steps so we can investigate? 🙏

@Timer
Copy link
Member Author

Timer commented Jul 8, 2019

Hi everyone! Thanks for the incredible response to this RFC.

This RFC has been implemented and released as stable in Next.js 9.
You can read more about it in the blog post.

We're going to publish a new RFC in the future to address all the advanced feedback given here. We'll post an update here when it's available.

@Timer Timer closed this as completed Jul 8, 2019
@vercel vercel locked as resolved and limited conversation to collaborators Jul 8, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests