Next.js: [RFC] Routes dynamiques

Créé le 19 juin 2019  ·  90Commentaires  ·  Source: vercel/next.js

Routes dynamiques

Contexte

Le routage dynamique (également connu sous le nom de slugs d'URL ou URL Pretty / Clean) est une fonctionnalité demandée depuis longtemps de Next.js.

Les solutions actuelles impliquent de placer un proxy L7 , un serveur personnalisé ou un middleware utilisateur devant votre application. Aucune de ces solutions n'offre une expérience développeur suffisamment _ergonomique_.

De plus, les utilisateurs qui recherchent un serveur personnalisé se désengagent par inadvertance des fonctionnalités avancées au niveau du cadre, telles que les fonctions sans serveur par page.

Buts

  1. Tirer parti de la convention pour fournir une prise en charge d'URL Slug sur laquelle il est facile de raisonner
  2. Couvrir la majorité des cas d'utilisation observés à l'état sauvage
  3. Élimine le besoin d'un serveur personnalisé pour prendre en charge /blog/:post
  4. Validez les transitions d'itinéraire <Link /> lorsque cela est possible
  5. Évitez une implémentation qui nécessite un manifeste d'itinéraire
  6. Les itinéraires doivent être exprimables via le système de fichiers

Proposition

Next.js doit prendre en charge les paramètres d'URL nommés qui correspondent à un segment d'URL entier . Ces routes seraient exprimées via le système de fichiers:

  1. Un nom de fichier ou un nom de répertoire entouré de [] serait considéré comme un paramètre nommé
  2. Les segments de route explicites seraient prioritaires sur les segments dynamiques, mis en correspondance de gauche à droite
  3. Les paramètres d'itinéraire seraient obligatoires , jamais facultatifs
  4. Les paramètres d'itinéraire seront fusionnés dans l'objet query (accessible depuis getInitialProps ou router via withRouter ) - ces paramètres ne peuvent pas être remplacés par un paramètre de requête

Pour vous aider à comprendre cette proposition, examinons l'arborescence de fichiers suivante:

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

Next.js produirait les routes suivantes, enregistrées dans l'ordre suivant:

;[
  { 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' },
]

Exemples d'utilisation

Ces exemples supposent tous une page avec le nom pages/blog/[id].js fichier

Accéder à la page avec <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>

L'exemple ci-dessus passera à la page /blog/[id].js et fournira l'objet query suivant au _Router_:

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

Lecture des paramètres nommés depuis _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

Remarque: vous pouvez également utiliser withRouter .

Lecture des paramètres nommés dans 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

Mises en garde

Les paramètres d'itinéraire facultatifs ne peuvent pas être exprimés via le système de fichiers.

Vous pouvez émuler un paramètre d'itinéraire facultatif en créant une page de stub qui exporte la version du paramètre (ou vice versa). Cela augmente la visibilité des routes de votre application lors de l'inspection du système de fichiers.

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

Les paramètres nommés ne peuvent pas apparaître au milieu d'un nom d'itinéraire.

Cela signifie qu'une page nommée blog-[id].js serait interprétée _littéralement_ et ne correspondrait pas à /blog-1 . Vous pouvez soit restructurer votre page pour qu'elle devienne /blog/[id].js ou transformer l'ensemble du segment d'URL en un paramètre nommé et gérer la suppression de blog- dans le code de votre application.

Alternatives

Indiquez les slugs d'URL avec le symbole _insert here_ au lieu de []

Il y a très peu de symboles disponibles pour représenter un paramètre nommé sur le système de fichiers. Malheureusement, le moyen le plus reconnu de définir un paramètre nommé ( :name ) n'est pas un nom de fichier valide .

Lors de l'étude de l'état de la technique, les symboles les plus couramment utilisés pour désigner un paramètre étaient _ , $ et [] .

Nous avons exclu _ car _ est généralement indicatif d'une route interne qui n'est pas publiquement routable (par exemple _app , _document , /_src , /_logs ).
Nous avons également exclu $ car il s'agit d'un sigil en bash pour l'expansion des paramètres.

Tirez parti de path-to-regexp pour une assistance complète

La plupart des symboles requis pour exprimer l'expression régulière ne sont

Dans le futur, nous pourrons autoriser path-to-regexp routes définies dans next.config.js ou similaire. Ceci est actuellement hors de portée de cette proposition.

Exploration future

Paramètres fourre-tout

À l'avenir, nous pourrions envisager d'ajouter des paramètres fourre-tout. Avec ce que nous savons jusqu'à présent, ces paramètres doivent être à la fin de l'URL et utiliseraient potentiellement % pour désigner une route fourre-tout (par exemple pages/website-builder/[customerName]/%.tsx ).

Commentaire le plus utile

Sondage : Pour exprimer votre intérêt pour les paramètres optionnels , veuillez réagir avec un "+1" à ce commentaire.

Remarque : les paramètres facultatifs sont déjà possibles avec cette RFC, ils n'ont tout simplement pas de syntaxe explicite (voir la section Avertissements ).

Tous les 90 commentaires

Sondage : Pour exprimer votre intérêt pour les paramètres optionnels , veuillez réagir avec un "+1" à ce commentaire.

Remarque : les paramètres facultatifs sont déjà possibles avec cette RFC, ils n'ont tout simplement pas de syntaxe explicite (voir la section Avertissements ).

Sondage : Pour exprimer votre intérêt pour les paramètres fourre-tout , veuillez réagir avec un "+1" à ce commentaire.

Remarque : veuillez partager votre cas d'utilisation des paramètres fourre-tout dans ce fil! Nous aimerions mieux comprendre l'espace-problème.

réservé 3

Sur ricardo.ch, nous utilisons un préfixe de locale pour chaque route, ce qui rend le routage un peu plus complexe.

Exemple d'itinéraires valides:

  • / - page d'accueil avec paramètres régionaux détectés automatiquement
  • /:locale - page d'accueil avec paramètres régionaux forcés
  • /:locale/search - page de recherche
  • /:locale/article/:id - page de l'article

Pensez-vous que de tels paramètres de préfixe pourraient être pris en charge?

Pour le moment, nous utilisons https://www.npmjs.com/package/next-routes

Autre chose: pour la page de l'article, nous supportons également un slug avant l'id comme /de/article/example-article-123 où l'id serait 123. Cela se fait via une expression régulière assez complexe en utilisant next-routes et je ne voyez comment cela pourrait être exprimé avec une API de système de fichiers.

@ValentinH les routes fournies sont toutes possibles en utilisant l'API du système de fichiers - compte tenu de vos routes fournies:

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

nous supportons également un slug avant l'id comme / de / article / example-article-123 où l'id serait 123

Ce cas d'utilisation est traité ci-dessus:

Les paramètres nommés ne peuvent pas apparaître au milieu d'un nom d'itinéraire.

Cela signifie qu'une page nommée blog-$id.js serait interprétée littéralement et ne correspondrait pas à /blog-1 . Vous pouvez soit restructurer vos pages pour qu'elles deviennent /blog/$id.js ou transformer l'ensemble du segment d'URL en un paramètre nommé et gérer la suppression de blog- dans le code de votre application.

Cette solution ne répond-elle pas à vos besoins? Nous aimerions en savoir plus sur vos besoins spécifiques.

Merci beaucoup pour la réponse.

Je n'ai pas pensé à utiliser $locale/index.js fois comme dossier et fichier, c'est vraiment chouette!

En ce qui concerne le "paramètre nommé au milieu", je l'ai négligé car je pensais que le fait que le slug soit dynamique était différent. Cependant, vous avez tout à fait raison et cela est abordé dans le paragraphe que vous avez mentionné. Striping le slug dans le code de l'application sera la voie à suivre 🙂

Est-ce que quelque chose comme ça (analyser les paramètres des .files / .folders cachés) serait 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

ou laissez le $ pour qu'on puisse trouver leurs fichiers: D mais toujours utiliser le dossier $ pour indiquer un paramètre?

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

J'avais l'habitude d'avoir ce cas d'utilisation pour les paramètres facultatifs dans une application qui fonctionnait avec les packages npm. Ceux-ci pourraient éventuellement avoir une portée. Il existe des itinéraires comme:

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

Donc, fondamentalement, le paramètre scope est facultatif, mais ce n'est également qu'une portée quand il commence par @ .
Donc /packages/express/dependencies et /packages/@babel/core ont le même nombre de segments, mais dans un cas c'est /dependencies de express et dans l'autre c'est /index sur @babel/core .

En fin de compte, il a été résolu en react-router avec les routes suivantes:

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

Je ne suis pas sûr de voir une solution pour ce cas d'utilisation dans cette RFC.

En ce qui concerne les cas d'utilisation fourre-tout, je pense à tout lien profond dans des données imbriquées récursivement, comme les structures de dossiers, les arborescences, les treemaps.

Mes 2 cents: les signes dollar dans les noms de fichiers sont une mauvaise idée car ils sont utilisés par les coquilles comme sceau. Vous allez dérouter les gens qui essaient d'exécuter rm $root.js . Les soulignés semblent être une alternative décente.

Plus largement: comme beaucoup de gens, j'ai essayé de tirer parti du système de fichiers comme solution à cela dans le passé. En fin de compte, je pense que le système de fichiers n'offrira jamais l'expressivité totale que vous recherchez. Par exemple, les routeurs déclaratifs vous permettent généralement de spécifier un modèle de validation pour un paramètre dynamique. Dans ce cas, une partie du schéma réside sur le système de fichiers et une autre partie dans le code. La séparation des préoccupations est une bonne chose, mais dans ce cas, c'est une limitation technique plus que toute autre chose.

Comme @ValentinH, nous utilisons la

Devrions-nous utiliser /page.ts et /page/$locale/page.ts?

Comme nous pouvons utiliser une locale «par défaut» ou une locale prédéfinie (paramètres utilisateur), dans ces cas, nous n'utilisons pas le paramètre $ locale.

Mais nous avons plus de cas d'utilisation: / car / search / $ optional-filter-1 / $ optional-filter-2 / $ optional-filter-3

Où option-filtre-1: couleur-rouge, filtre-facultatif-2: marque-ford, etc ...

Et pour les paramètres optionnels, quelque chose comme / $ required-param / et / $$ optional-param /?

Génial que cela arrive sur la feuille de route!

Je dois cependant soutenir @timdp . Lorsque vous ne pouvez même pas touch $file cela entraînera beaucoup de confusion. Vous devez vous rappeler de vous échapper à chaque interaction. touch \$file; vim $file ouvrira vim sans fichier (car $ file n'est pas une variable définie).
De même, la complétion des tabulations dans un shell listera toutes les variables, ce qui apporte encore une fois de la confusion.

Je propose deux alternatives qui, selon moi, donnent les bonnes associations et devraient fonctionner en coquille:

  • = Il peut être lu comme page is a customer pour =customer . Vous pouvez même le tordre mentalement pour être un deux-points juste étiré, ressemblant ainsi à la forme la plus courante pour les paramètres nommés.
  • @ car il se lit aussi assez bien. a customer pour @customer

Une autre option serait d'utiliser des accolades (à moins qu'il ne s'agisse de caractères réservés sur certains systèmes de fichiers). Cette syntaxe de paramètre est également de "l'art antérieur" et est utilisée par de nombreux autres routeurs:

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

Cela permettrait d'avoir des paramètres au milieu du segment de route et plusieurs paramètres par segment car il est clair où le paramètre commence et où il se termine, par exemple /product-{productId}-{productColor} .

Tellement excité que des routes dynamiques arrivent sur Next.js!

En ce qui concerne la syntaxe des paramètres nommés, c'est quelque chose qui a été discuté sur Spectrum: https://spectrum.chat/next-js/general/rfc-move-parameterized-routing-to-the-file-system~ce289c5e-ff66 -4a5b-8e49-08548adfa9c7. Cela pourrait valoir la peine de l'utiliser comme entrée pour la discussion ici. Personnellement, j'aime la façon dont Sapper le fait en utilisant [brackets] . C'est également quelque chose que Nuxt va implémenter dans la version 3. Avoir différents frameworks utilisent le même format pour les routes basées sur des systèmes de fichiers dynamiques semble être une bonne chose.

En ce qui concerne l'utilisation de <Link /> , je pense que les développeurs oublieront facilement de définir les attributs href et as . Je comprends qu'il n'est pas possible de "fusionner" ces derniers dans l'attribut href car cela introduirait un changement de rupture, mais j'ai l'impression que cela pourrait être résolu d'une manière plus élégante.

Les accolades sont malheureusement utilisées par Bash pour regrouper les commandes.

Je suis d'accord avec @ stephan281094 concernant l'utilisation de <Link /> , ce sera source d'erreurs.

Le routage dynamique est une fonctionnalité extrêmement utile, donc c'est vraiment génial que vous les ayez examinés et que vous ayez trouvé une solution, d'énormes accessoires!

Sur ce sujet, les routes génériques seraient également un ajout intéressant à la proposition. Vous avez mentionné les paramètres fourre-tout comme quelque chose à étudier à l'avenir, mais cela ne couvre pas les cas où vous pourriez vouloir faire quelque chose comme /category/* , qui pourrait avoir N nombre de niveaux, et vous voulez tous les pour rendre la page category .

Est-il possible d'utiliser : toute sécurité? Si tel est le cas, ce serait mon vote, car tout le monde connaît déjà cette convention d'express.

En raison du conflit entre $ et les variables shell, je m'y oppose personnellement fortement.

Est-il possible d'utiliser : toute sécurité? Si tel est le cas, ce serait mon vote, car tout le monde connaît déjà cette convention d'express.

Apparemment, : est un caractère interdit dans Windows, donc ce n'est probablement pas sûr. Utiliser _ n'est pas non plus idéal, car les traits de soulignement peuvent être utilisés dans les URL. La raison pour laquelle je pense que [brackets] est une bonne solution, c'est parce que c'est plus à l'épreuve du temps. Si Next.js veut prendre en charge des routes comme post-12345 à l'avenir, en utilisant cette syntaxe, cela peut être fait sans introduire de changement de rupture.

Donc, une liste de caractères à éviter serait:

  • Conflits avec les systèmes de fichiers: : , * , " , < , > , |
  • Conflits avec les variables shell: $
  • Conflits avec l'expansion des accolades bash { , }

Rien d'autre?

Cela n'éliminerait pas notre besoin d'avoir un fichier d'itinéraire centralisé pour plusieurs raisons:

  • Nous avons un plan du site généré automatiquement, et le système de fichiers seul ne suffit pas à le définir.
  • Nous avons utilisé des routes nommées et les "pages" de destination sont déterminées par des données, plutôt que par quelque chose qui est connaissable au moment de la construction. La logique pour déterminer quelle page charger en fonction du nom et des paramètres est régie par la configuration de la route.

Nous générons également notre dossier de pages pour ces raisons:

  • Nous utilisons Relay, ce qui signifie que les modules impliquant GraphQL doivent porter un nom unique. Pour cette raison, nous ne pouvons souvent pas avoir les noms de segments de route identiques aux noms de modules. index.js n'est certainement pas unique, et je vois des endroits où nous aurions plusieurs segments communs comme edit .
  • Nous préférons co-localiser des composants spécifiques à une page en tant que frères des modules de page eux-mêmes, ce que Next.js ne permet pas dans le dossier pages.

Notre modèle consiste essentiellement à utiliser notre configuration de route centralisée pour générer notre dossier de pages, qui contient des fichiers qui ne font rien de plus que d'importer / exporter des modules ailleurs dans la base de code.

À cette fin, je me concentre davantage sur la question de savoir si cette proposition peut fonctionner simplement comme un format de sortie amélioré pour notre processus de génération de page existant, afin que nous puissions au moins profiter de ne pas avoir besoin d'un serveur personnalisé.

J'ai passé en revue certains de mes cas d'utilisation ailleurs: https://gist.github.com/AndrewIngram/8d4c4ccd9bd10415a375caacade9f5ca

La principale chose que je ne vois pas est la prise en charge des paramètres implicites qui ne sont pas exprimés dans le système de fichiers, par exemple les remplacements d'URL.

Disons que nous avons une URL comme celle-ci:

/some-vanity-url/

Où, dans les termes actuels de Next.js, nous voudrions qu'il mappe à une page de produit avec un certain nombre de paramètres de requête, par exemple Product.js?id=foo&language=en .

De même, sur notre site Web, la plupart des «sites» de pays sont définis par un segment de premier niveau, par exemple es ou ie , mais le site gb est monté sans ce segment. Cela signifie que toutes les pages gb ont un paramètre implicite country , alors que pour tous les autres pays, il est explicite.

L'autre inconvénient, c'est que parce que dans notre cas, la même 'page' peut exister à plusieurs points de montage dans l'architecture URL, nous allons nous retrouver avec un plus grand nombre de bundles (c'est-à-dire plusieurs points d'entrée en double) que nous en fait besoin en pratique.

Dans l'ensemble, cette proposition semble bien fonctionner pour la plupart des cas d'utilisation courants, mais elle n'élimine pas le besoin d'une configuration d'itinéraire ou d'un serveur personnalisé dans _tous_ les cas. Mais en supposant que cela ne remplace pas ma capacité à utiliser le framework comme je le fais aujourd'hui, je n'ai aucune objection réelle à ce que ce soit l'API happy-path préférée.

Je soutiens la suggestion {id} . Cela permet plusieurs paramètres et je pense que cela a l'air beaucoup mieux. Il s'adapte également mieux à React.

Je suis en faveur du caractère file/&param.js . Pris directement à partir d'urls et il ne semble pas qu'il soit en conflit avec les systèmes de fichiers ou bash.

J'utiliserais _ et autoriserais peut-être un remplacement dans le next.config.js pour ceux qui ont vraiment besoin de quelque chose de différent.

Appréciez le travail à ce sujet. Je le voulais depuis un moment! ❤️

Incroyable! 🎉🎉🎉

Mon seul problème ici est que Link besoin des paramètres href et as .

Je crois que nous pourrions simplement écrire <Link to="blog/123" /> : puisque Nextjs connaît déjà toutes les routes basées sur les fichiers dans le dossier pages, il pourrait facilement le traduire en "/blog/$id" .

Donc, une liste de caractères à éviter serait:

& est un opérateur de contrôle dans bash qui exécute le côté gauche de l'argument dans un sous-shell async. Texte clair: open pages/&customer exécuterait open pages/ en arrière-plan et la commande customer dans le shell de premier plan.

Cela a l'air vraiment cool.

Il semble que cela créera un nombre important de répertoires de fichiers uniques (comme /blog/$id dans l'exemple d'origine). Cela devient encore plus fastidieux si vous voulez deux paramètres de route de fin (ie /git/compare/$hash1/$hash2 ).

Je n'aime pas non plus que le nom de fichier pour afficher un article de blog soit $id.js . Le nommer blog.js serait beaucoup plus descriptif.

Peut-être combiner avec un décorateur @customRoute ?

// 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

Cela semble également fournir une solution plus propre pour les paramètres fourre-tout proposés.

Les décorateurs ne peuvent pas être appliqués aux fonctions (peut-être que cela a changé depuis la dernière lecture?) Et la proposition est probablement loin de toute façon

Eh bien, supposons que vous suiviez cette voie, vous le feriez probablement de la manière dont AMP est configuré maintenant:

// /pages/blog.js
export const config = {
  amp: true,
  dynamicRoute: true // adds a [blog] property to the query object
  // dynamicRoute: /\d+/ // could even support regex if you want
};

Cependant, je pense que des choses comme celles-ci peuvent être ajoutées plus tard si cela semble utile à un moment donné. Je pense que je préfère voir un support de base pour commencer, comme décrit dans la RFC. Obtenez une réelle utilisation avec cela, puis affinez où cela se brise. Je pense aussi que les seuls caractères à prendre en compte pour éviter sont ceux du système de fichiers. Ce sont les vrais bloqueurs de la création de cette fonctionnalité.

Veillez à utiliser un personnage compatible avec les solutions sans serveur! (Sur Aws, certains personnages peuvent causer des problèmes)

Exporter un objet de configuration avec une clé de composant est quelque chose que je ne déteste pas.

Vous pouvez également simplement utiliser un HOC

function BlogPost(props) {
    return <div />
}

export default withCustomRoute(BlogPost, "/blog/:id")

Et si nous ajoutions un champ statique à la page (comme getInitialProps)?

// pages/blog.js
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>
}

// By default it would be as it is now
BlogPost.route = '/blog/:id';

export default BlogPost

@ dmytro-lymarenko Que se passe-t-il lorsque vous accédez à /blog dans le navigateur? Un 404?

Parce que cela doit être déterminé au moment de la compilation, je suppose que vous auriez besoin de quelque chose qui est statiquement analysable. un HOC ou une propriété statique ne le serait pas.

vous auriez besoin de quelque chose qui est statiquement analysable. un HOC ou une propriété statique ne serait pas

Chaque exemple de propriété statique donné jusqu'à présent serait statiquement analysable (bien que vous puissiez certainement casser les choses facilement). Nous pourrions simplement insister pour que vous exportiez votre fonction et que vous définissiez la propriété route dessus d'une manière statiquement analysable. Le runtime peut vérifier les propriétés de route définies lors de l'exécution mais qui n'ont pas été interceptées par notre analyseur statique et émettre un avertissement / générer une erreur.

Que se passe-t-il lorsque vous accédez à / blog dans le navigateur? Un 404?

@kingdaro - OMI, oui. Si vous souhaitez utiliser à la fois les chemins /blog et /blog/:blogId , vous utilisez un répertoire. Vous surchargez ce chemin, la structure du répertoire est donc justifiée.

pages/
├── blog/
│ ├── $id.js
│ └── index.js

Eh bien, supposons que vous suiviez cette voie, vous le feriez probablement de la manière dont AMP est configuré maintenant:

// /pages/blog.js
export const config = {
  amp: true,
  dynamicRoute: true // adds a [blog] property to the query object
  // dynamicRoute: /\d+/ // could even support regex if you want
};

Cependant, je pense que des choses comme celles-ci peuvent être ajoutées plus tard si cela semble utile à un moment donné. Je pense que je préfère voir un support de base pour commencer, comme décrit dans la RFC. Obtenez une réelle utilisation avec cela, puis affinez où cela se brise. Je pense aussi que les seuls caractères à prendre en compte pour éviter sont ceux du système de fichiers. Ce sont les vrais bloqueurs de la création de cette fonctionnalité.

Je pense que l'utilisation de config est une mauvaise idée car vous devez parcourir plusieurs fichiers pour voir ce qui est réellement dynamique. Si vous le définissez dans le système de fichiers, vous pouvez le voir du premier coup d'œil.

Je me demande si plusieurs solutions de routage standard devraient être envisagées.

Le routage simple basé sur des fichiers est un excellent argument de vente pour les nouveaux utilisateurs de Next / React, ou pour tous ceux qui souhaitent rapidement mettre en place une application simple, mais cela peut être plutôt limitant. Et il me semble qu'essayer de faire un routage dynamique dans ce modèle pourrait ruiner cette simplicité et conduire à une complexité inutile, tout cela au nom de garder tout basé sur des fichiers.

Après avoir lu cette discussion et réfléchi à ma propre utilisation de Next.js, je pense qu'un support de première classe pour un système de routage alternatif (supplémentaire) pourrait être le meilleur moyen de résoudre ce problème.

J'aime certaines idées originales de ce fil (comme la proposition d'utiliser des décorateurs), mais ces idées ont certainement leurs propres problèmes. J'espère que nous pourrons trouver quelque chose de génial 👍

Exporter un objet de configuration avec une clé de composant est quelque chose que je ne déteste pas.

Vous pouvez également simplement utiliser un HOC

function BlogPost(props) {
    return <div />
}

export default withCustomRoute(BlogPost, "/blog/:id")

C'est plutôt cool, mais je me demande si les informations d'itinéraire sont réparties sur de nombreux fichiers comme
cela pourrait devenir difficile à gérer.

Ma pensée originale en proposant une configuration locale (dans le fichier) par rapport à une configuration globale ( route.js ), a été d'aborder les scénarios spécifiques mentionnés dans mon premier commentaire (fichiers profondément imbriqués qui sont le seul fichier dans leur répertoire, noms de fichiers non sémantiques et paramètres fourre-tout).

Si elle est utilisée strictement dans ces contextes, c'est beaucoup moins déroutant, car l'URL mappe directement sur le système de fichiers, et seuls les paramètres "supplémentaires" sont adressés par la configuration locale.

Cela dit, je ne suis pas sûr que j'essaierais même d'empêcher les utilisateurs de le faire comme ils le souhaitent. Nous pouvons assez imprimer la table de routage calculée sur la console, ou même l'enregistrer dans un fichier prédéterminé. Cela devrait être suffisant pour faciliter le dépannage des itinéraires

@merelinguist Je ne crois pas que = soit interdit dans Windows comme vous l'avez écrit dans le tableau récapitulatif. Vous faites un lien vers la façon dont : est interdit, mais selon les documents de dénomination des fichiers Microsoft Windows, le caractère égal est autorisé.

Je porte déjà des routes dynamiques dans un projet que j'utilise en production (j'espère pouvoir le faire vivre cette semaine).

Question spécifique cependant, la nouvelle fonctionnalité de l'API Next @ Canary prendra-t-elle également en charge le routage dynamique?

{ path: '/api/:customer', page: '/api/$customer/index.js' }

Je viens de l'essayer avec [email protected] et j'obtiens un 404 introuvable, donc je suppose qu'il n'est pas encore là. Il semble juste qu'il soit logique que ces deux fonctionnalités (API + routes dynamiques) aient la parité sur le routage des URL.

@remy ce n'est pas encore implémenté c'est sur ma liste pour le faire bientôt

Nous devons également prendre en compte non seulement les systèmes Windows et Linux, mais aussi d'autres:
https://en.wikipedia.org/wiki/Filename#Comparison_of_filename_limitations

Je souhaite ajouter plus d'informations sur ma proposition:

Et si nous ajoutions un champ statique à la page (comme getInitialProps)?

// pages/blog.js
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>
}

// By default it would be as it is now
BlogPost.route = '/blog/:id';

export default BlogPost
  1. Le développeur ne peut pas utiliser la variable d'exécution pour cette propriété d'itinéraire
const route = `/blog/${somethingElse}`;
BlogPost.route = route; // is not allowed
  1. Lorsque nous construisons un manifeste de page avec ce RFC actuel (où le dossier contient un caractère pour l'identifier est dynamique), je ne vois pas la différence si nous construisons ce manifeste de page en lisant le fichier et trouvons la propriété de route statique sur la page. De la même manière que lingui fonctionne: ils ne permettent pas à id pour Trans d'être dynamique
<Trans id="msg.docs" /* id can only be static string */>
   Read the <a href="https://lingui.js.org">documentation</a>
   for more info.
 </Trans>

En passant par la liste des préfixes déjà listés - je me demande s'il y a une bonne raison _pas_ d'utiliser un préfixe de symbole @ ?

Je doute que cela ait de la valeur, mais vous obtenez la parité avec Nuxt - ce qui signifie que quelqu'un qui passe de l'un ou de l'autre saura immédiatement comment cela fonctionne.

Sinon, quelqu'un a-t-il pensé à faire du préfixe une option utilisateur? Cela rend plus difficile pour les gens de comprendre un projet à partir d'un autre, mais cela signifie que si je le voulais, je pourrais créer le préfixe query__{...} ou quelque chose comme ça.

Juste une pensée.

À la suite de la suggestion de

@ scf4 J'avais une bibliothèque qui est un PoC, qui utilise la configuration de now.json routes pour faire un routage universel avec nextjs aussi ici

J'espère que l'équipe Zeit ouvrira également l'analyseur de routes sur la bibliothèque côté client.

En regardant Nuxt, je pense que _id.js n'est pas trop mal. Oui, nous utilisons déjà _app et _document.js comme vous l'avez mentionné et ce n'est pas publiquement routable. Mais une route dynamique peut également être considérée comme non routable car il s'agit d'un modèle pour de nombreuses pages

Comment cela serait-il géré pour les exportations de sites statiques?

(Peu importe celui-ci)

Je pense également qu'il serait utile que Next.js imprime les routes générées dans un seul fichier (peut-être masqué par défaut). À tout le moins, cela servirait de référence utile aux personnes travaillant sur un projet, mais cela pourrait également ouvrir la porte à un routage dynamique puissant plus tard.

Par exemple, s'il utilise ce fichier pour la gestion des itinéraires au moment de l'exécution, il serait très facile pour les utilisateurs d'ajouter / modifier des itinéraires (par exemple, pour la correspondance de modèles complexes) sans perdre les avantages de l'API basée sur le système de fichiers.

Cela créerait quelques défis concernant la façon de suivre les itinéraires qui ont été modifiés manuellement, mais s'ils sont résolus, je pense que ce serait de loin la meilleure solution.

@ scf4 Next.js a déjà la capacité de faire des routes complexes en utilisant l'option de serveur personnalisé. Ce que vous proposez est réalisé dans presque la même quantité de code avec des outils déjà disponibles.

Ah ouais, c'est juste.

Je pense qu'avoir un seul fichier de routes qui peut être édité est de toute façon une bien meilleure option!

J'ai écrit quelques réflexions sur le routage avec le système de fichiers , mais je peux résumer mes résultats ici:

  • [param] semble le plus sûr (et est utilisé par Sapper).
  • : est familier aux utilisateurs d'Express, mais j'aurais pu _serter_ j'ai eu des problèmes sur Windows FS.
  • $ et {param} sont utilisés pour l'expansion des variables et des accolades dans les shells, donc cela peut être plus problématique dans la CLI.
  • _ _pourrait_ fonctionner, mais c'est trop courant comme indicateur "privé".

J'ai personnellement eu de meilleures expériences avec les fichiers de liste blanche pour les routes ( /^index\. ) par rapport à une liste noire ( /^_/ ), mais ce serait un problème de compatibilité descendante avec /pages .

Avec les discussions récentes pour prendre en charge les routes API (# 7297), cela pourrait être l'occasion de prendre en charge /api et /pages sous une nouvelle maison de /routes .

Cependant, _et c'est un "cependant" fort _, ​​l'écosystème Next.js est suffisamment grand pour justifier des ajouts de fonctionnalités _incrémentaux_, par opposition à un "hé, si nous devions recommencer, nous le ferions de cette manière".

Les crochets ( [example] ) sont utilisés par zsh pour la correspondance de motifs, donc cela ne serait pas viable non plus.

Voir des exemples dans Génération de noms de

Les crochets [] sont utilisés par zsh pour la correspondance de motifs, donc cela ne serait pas viable non plus.

On dirait qu'ils viennent de le faire sur https://github.com/zeit/next.js/pull/7623

Merci pour l'information. J'ai aussi publié un commentaire là-dedans.

J'ai essayé [id] et l'utiliser simplement dans les chemins est pénible (par exemple cd \[id\]/view.js ). Il me semble que les doubles traits __id soulignement cd __id/view.js ) fonctionnent tout aussi bien et peuvent être distingués (albite peut-être encore légèrement déroutant) des fichiers / dossiers internes (par exemple _app.js ).

@AaronDDM utilisez-vous zsh ? Vous n'avez pas besoin d'échapper à [ ou ] dans bash.

Ouais, cela arrive aussi pour moi avec zsh - super ennuyeux d'interagir avec ces répertoires.

$ mkdir [asdf]
zsh: no matches found: [asdf]
$ mkdir \[asdf\]
$ cd [asdf]
zsh: no matches found: [asdf]
$ cd \[asdf\]

Et puisque zsh deviendra le shell par défaut dans macOS Catalina , peut-être que quelque chose devrait être fait à ce sujet après tout ...

d'accord avec __id.js

Hm, je n'aime vraiment pas le __ , ça ne me va pas.

@merelinguist em, Jest utilise __tests__ pour le dossier de test par défaut, je pense que __ sens dans certains cas.

@YUFENGWANG Peut-être, mais je préférerais un seul caractère si possible. En fin de compte, je pense que la meilleure solution serait:

  1. Par défaut sensible et multiplateforme, comme =
  2. Option dans next.config.js pour personnaliser le caractère de route spécial qui est utilisé
  3. Documentation sur quels personnages posent problème dans quelles situations

D'accord avec un seul caractère mais je préférerais avoir une configuration zéro. et je suppose que beaucoup de gens passeront par tous les problèmes même si vous les décrivez dans une documentation

Notez également que = est réservé par zsh. À partir de la documentation :

Si un mot commence par un '=' sans guillemets et que l'option EQUALS est définie, le reste du mot est considéré comme le nom d'une commande. Si une commande existe sous ce nom, le mot est remplacé par le chemin complet de la commande.

Juste une idée; qu'en est-il de l'utilisation d'un suffixe? Par exemple [email protected] , ou similaire pourrait suffire. Cela peut résoudre le problème d'avoir à s'échapper et à travailler sur des shells et des systèmes de fichiers tant que le caractère est valide.

Ceux-ci fonctionnent dans zsh et bash sans avoir besoin de s'échapper, jusqu'à présent:

[email protected]
example~.js
example=.js

Ooh. Pas un suffixe mais un moyen de désigner les paramètres d'URL de fin.

Donc [email protected] devient blog/:id .

compare@[email protected] devient compare/:a/:b .

Cela pourrait résoudre les répertoires de fichiers uniques profondément imbriqués auxquels je m'opposais ci-dessus et conserver l'ensemble du système de fichiers de définition de routage basé.

Cela n'a pas l'air aussi sophistiqué, mais que diriez-vous de quelque chose du genre:

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

un préfixe _var_ Quel type d'essaie d'imiter les déclarations de variables JS. Ou faut-il que ce soit une chose super courte, un personnage?

Que diriez-vous du caractère ~ ?

Comme /blogs/~id .

Utiliser ~ comme préfixe n'est pas non plus viable, car il est utilisé pour s'étendre vers le dossier de base dans les shells compatibles POSIX.

Tout caractère qui ne correspond pas à [0-9a-zA-Z-._] (regex) ne peut pas être considéré comme sûr comme préfixe dans les systèmes d'exploitation, les shells et les systèmes de fichiers.

Certains personnages ne sont pas non plus sûrs en ligne. Voir la documentation de zsh

Je pense également que nous ne devrions pas nous efforcer de savoir si cela a l'air sophistiqué, mais plutôt d'être intuitif, lisible et facile à communiquer.

  • l'utilisation de parenthèses pour [params].js semble plus élégante et largement utilisée. (sapeur, nuxt v3?).
  • préfixe de soulignement pages/_helper.js généralement pour une fonction privée et peut-être que cela ne devrait pas être rendu. cela nous permet de créer des composants d'aide dans le dossier pages

à mon humble avis: cela ressemble à une solution temporaire au plus grand problème. Bien qu'avoir des routes basées sur la structure de fichiers soit très agréable au départ, cela ne s'adapte pas bien lorsque vous avez des centaines de routes, de paramètres, etc. Avoir un fichier de configuration de routes (peut-être avoir un fichier routes.js dans chaque répertoire) est une meilleure solution à long terme. Je suis personnellement attiré par nextjs en raison des fonctionnalités prêtes à l'emploi (SSR, vitesse, etc.) qu'il fournit, et non de la facilité de création de routes à partir de fichiers.

@mmahalwy vous avez frappé le clou sur la tête.

Next.js génère déjà une configuration de routes (basée sur le système de fichiers). Je crois que rendre cette configuration plus explicite et / ou permettre à l'utilisateur de "l'éjecter" s'il le souhaite serait la solution la plus transparente ici

@mmahalwy @ scf4 FWIW, une justification significative pour les routes du système de fichiers est de supprimer le besoin d'avoir un fichier centralisé. En fait, on pourrait facilement affirmer que l'intégralité de l'API de Next.js pour les liens et le routage est conçue autour de cette contrainte.

Le problème avec une configuration d'itinéraire est que vous finissez par devoir l'expédier au client, ce qui peut signifier un paquet de codes assez lourd si vous avez des itinéraires numérotés de centaines à des milliers.

Cependant, il existe de nombreux cas d'utilisation courants qui (pour autant que j'ai pu le dire, après avoir discuté de ce problème avec @timneutkens à plusieurs reprises au cours des derniers mois) ne peuvent pas vraiment être résolus sans une configuration centralisée. J'en ai énuméré certains dans mon commentaire précédent, mais il y en a d'autres.

Le plus simple est d'avoir un blog basé sur un CMS où les auteurs peuvent créer des liens vers des pages du site. Ils créeront simplement des liens avec une ancienne URL simple, sans savoir quel est le module de page sous-jacent. Avec une configuration de route centralisée, il est assez facile d'inverser la correspondance d'une URL et de déterminer quelle page charger (ma propre bibliothèque, le résolveur de route suivant est conçu pour prendre en charge ces cas d'utilisation, et tous les autres que j'ai proposés) .

Je ne vois pas comment je peux faire en sorte que le site sur lequel je travaille fonctionne sans configuration de route, donc je me concentre simplement sur la recherche de moyens de garder la configuration de route dans les tolérances de taille de fichier. Pour d'autres personnes, le routage du système de fichiers peut être plus que suffisant. Je ne pense pas que le routage soit un problème où il existe une solution unique qui résout tout, il s'agit d'équilibrer les compromis.

Donc, comme je l'ai mentionné précédemment, en ce qui concerne cette proposition, cela semble bien tant qu'elle est vendue comme résolvant entièrement le problème de routage, car ce serait un peu trompeur :)

@AndrewIngram Je comprends d'où vous venez mais cette limitation limite le pouvoir de nextjs. Nextjs offre tellement de choses hors de la boîte qu'il devrait être une évidence pour tout nouveau projet ou entreprise de l'utiliser. Cependant, le défi est que c'est une opinion difficile sur le routage qui le rend inéquitable à l'avenir (et en tant que grande entreprise, vous envisagez toujours la stratégie de sortie si les projets perdent de l'intérêt ou de la maintenance).

@mmahalwy Je pense que vous avez mal compris mon point. Je suis d'accord avec vous, je ne pense pas que le routage du système de fichiers soit suffisant pour appeler le problème de routage résolu, et je serais déçu s'il était présenté comme tel. Je pense que cela offre une amélioration pour un ensemble particulier de cas d'utilisation, mais je pense également qu'il devrait également y avoir une sorte de format de manifeste d'itinéraire pour ceux qui souhaitent opter pour un ensemble différent de compromis (par exemple, vous et moi) .

Pour ceux qui souhaitent une configuration de routage centralisée ou avancée, n'est-elle pas bien gérée en utilisant le serveur personnalisé et / ou des packages externes? Qu'espérez-vous être ajouté ici?

Tout cela semble hors sujet de cette RFC. Je ne pense pas que quiconque, y compris l'OP, ait suggéré que ce soit la solution ultime pour le routage. Cela améliore simplement le routage basé sur le système de fichiers.

J'utilise les routes dynamiques pour un mini projet depuis quelques semaines (en utilisant $ bien que je note qu'il est déplacé vers [param] 3 jours dans le repo canary, mais de toute façon).

J'ai _just_ commencé à utiliser getRequestHandler et je pense que cela ne prend pas en charge le routage dynamique côté serveur.

Est-ce un bug, intentionnel (c'est-à-dire un changement de getRequestHandler ), autre chose, ou l'utilisation de getRequestHandler désactive complètement le routage dynamique (ce qui aurait du sens maintenant j'y pense…) ?

Pour ceux qui souhaitent une configuration de routage centralisée ou avancée, n'est-elle pas bien gérée en utilisant le serveur personnalisé et / ou des packages externes? Qu'espérez-vous être ajouté ici?

L'un des objectifs ici est d'éviter d'avoir à créer un serveur personnalisé, ne serait-ce que pour le rendre plus facile à utiliser avec des services comme Now (qui nécessite actuellement que toutes les routes dynamiques fassent partie de sa configuration).

Tout cela semble hors sujet de cette RFC. Je ne pense pas que quiconque, y compris l'OP, ait suggéré que ce soit la solution ultime pour le routage. Cela améliore simplement le routage basé sur le système de fichiers.

Il y a en fait un contexte supplémentaire ici. Cette proposition a été longue à venir, et sur la base de nombreuses discussions que j'ai vues à ce sujet (y compris celles avec lesquelles j'ai été directement impliqué), cela a été dans une certaine mesure mis en avant comme supprimant la nécessité d'utiliser ces itinéraires bibliothèques de gestion comme next-routes et la mienne. Je ne pense pas que ce soit hors sujet de mettre en évidence les cas d'utilisation qui ne sont pas remplis par cette RFC. Certains d'entre eux pourraient vraisemblablement être satisfaits par des modifications de la proposition, d'autres non. Mais de toute façon, il est sûrement utile de sensibiliser aux limites de ce qui est proposé?

FWIW, nous utilisons des routes basées sur FS de style [param] sur Pinterest (mais pas Next). Il est vraiment bien mis à l'échelle jusqu'à présent. La plus grande critique est que Jest interprète [] comme des paires d'expressions rationnelles, il peut donc être difficile de cibler des tests pour les gestionnaires param-ful.

@chrislloyd Quelles sont vos expériences en matière de création et de gestion de fichiers à l'aide de ce format pour les chemins / fichiers dans différents environnements, étant donné que tout le monde utilise zsh ou un outil qui les interprète différemment?

Vu que [] utilise pour la correspondance de motifs dans zsh (et, comme vous le dites avec Jest), vous devrez échapper à ces chemins. Ce n'est pas vraiment un problème si vous le savez, mais étant donné qu'il devrait être utilisable et compris par les débutants, je doute que ce soit le bon format pour aller avec.

J'ai une idée sur l'utilisation de ! comme paramètre requis, comme /pages/id!.js et ? pour un paramètre facultatif, comme dans /pages/posts/id?.js .

Il n'a aucun problème avec le préfixe comme dans les discussions ci-dessus, et il est familier sur la façon dont ! représente les paramètres requis, et ? représente les paramètres facultatifs.

Windows n'autorise pas les points d'interrogation dans les noms de fichiers, et les deux? et ! ont une signification particulière dans Bash.

API routes

@remy getRequestHandler devrait gérer le routage dynamique - je viens de confirmer localement qu'il le fait. Pourriez-vous s'il vous plaît déposer un bug / problème séparé avec les étapes de reproduction afin que nous puissions enquêter? :prier:

Salut à tous! Merci pour la réponse incroyable à cette RFC.

Cette RFC a été implémentée et publiée comme stable dans Next.js 9.
Vous pouvez en savoir plus à ce sujet dans l'article de blog .

Nous allons publier une nouvelle RFC à l'avenir pour répondre à tous les commentaires avancés donnés ici. Nous publierons une mise à jour ici lorsqu'elle sera disponible.

Cette page vous a été utile?
0 / 5 - 0 notes