Next.js: [RFC] Динамические маршруты

Созданный на 19 июн. 2019  ·  90Комментарии  ·  Источник: vercel/next.js

Динамические маршруты

Задний план

Динамическая маршрутизация (также известная как URL-блоки или красивые / чистые URL-адреса) - это давно запрашиваемая функция Next.js.

Текущие решения включают размещение прокси- сервера L7 , настраиваемого сервера или промежуточного программного обеспечения на уровне пользователя перед вашим приложением. Ни одно из этих решений не предлагает достаточно _эргономичный_ опыт разработчика.

Кроме того, пользователи, обращающиеся к настраиваемому серверу, непреднамеренно отказываются от расширенных функций уровня инфраструктуры, таких как постраничные бессерверные функции.

Цели

  1. Используйте соглашение для обеспечения поддержки URL Slug, о которой легко рассуждать
  2. Охватывает большинство случаев использования, наблюдаемых в дикой природе
  3. Устранение необходимости в настраиваемом сервере для поддержки /blog/:post
  4. По возможности проверяйте переходы маршрута <Link />
  5. Избегайте реализации, требующей манифеста маршрута
  6. Маршруты должны быть выражены через файловую систему

Предложение

Next.js должен поддерживать именованные параметры URL, соответствующие всему сегменту URL . Эти маршруты будут выражены через файловую систему:

  1. Имя файла или каталога, заключенное в [] , будет считаться именованным параметром.
  2. Явные сегменты маршрута будут иметь приоритет над динамическими сегментами, сопоставленными слева направо.
  3. Параметры маршрута будут обязательными , но не обязательными
  4. Параметры маршрута будут объединены в объект query (доступный из getInitialProps или router через withRouter ) - эти параметры не могут быть переопределены параметром запроса

Чтобы понять это предложение, давайте рассмотрим следующее дерево файлов:

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

Next.js будет генерировать следующие маршруты, зарегистрированные в следующем порядке:

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

Примеры использования

Все эти примеры предполагают наличие страницы с именем файла pages/blog/[id].js :

Переход на страницу с помощью <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>

В приведенном выше примере выполняется переход на страницу /blog/[id].js а в _Router_ будет предоставлен следующий объект query :

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

Чтение именованных параметров из _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

Примечание: вы также можете использовать withRouter .

Чтение именованных параметров в 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

Предостережения

Необязательные параметры маршрута не могут быть выражены через файловую систему.

Вы можете эмулировать необязательный параметр маршрута, создав страницу-заглушку, которая экспортирует версию параметра (или наоборот). Это увеличивает видимость маршрутов вашего приложения при проверке файловой системы.

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

Именованные параметры не могут появляться в середине имени маршрута.

Это означает, что страница с именем blog-[id].js будет интерпретироваться _буквально_ и не будет соответствовать /blog-1 . Вы можете реструктурировать свою страницу до /blog/[id].js или превратить весь сегмент URL в именованный параметр и обработать удаление blog- в коде вашего приложения.

Альтернативы

Обозначьте заголовки URL-адресов с помощью символа _insert_ вместо []

Для представления именованного параметра файловой системы доступно очень мало символов . К сожалению, наиболее распространенный способ определения именованного параметра ( :name ) не является допустимым именем файла .

При обзоре уровня техники наиболее распространенными символами, используемыми для обозначения параметра, были _ , $ и [] .

Мы исключили _ потому что _ обычно указывает на внутренний маршрут, который не является общедоступным (например, _app , _document , /_src , /_logs ).
Мы также исключили $ потому что это сигил в bash для расширения параметров.

Используйте path-to-regexp для комплексной поддержки

Большинство символов, необходимых для выражения регулярного выражения, не являются

В будущем мы можем разрешить path-to-regexp маршруты, определенные в next.config.js или аналогичном. В настоящее время это выходит за рамки данного предложения.

Будущее исследование

Все параметры

В будущем мы можем рассмотреть возможность добавления универсальных параметров. Насколько нам известно, эти параметры должны быть в конце URL-адреса и потенциально могут использовать % для обозначения универсального маршрута (например, pages/website-builder/[customerName]/%.tsx ).

Самый полезный комментарий

Опрос : Чтобы выразить интерес к необязательным параметрам , поставьте "+1" в этом комментарии.

Примечание . Дополнительные параметры уже возможны в этом RFC, просто у них нет явного синтаксиса (см. Раздел « Предостережения »).

Все 90 Комментарий

Опрос : Чтобы выразить интерес к необязательным параметрам , поставьте "+1" в этом комментарии.

Примечание . Дополнительные параметры уже возможны в этом RFC, просто у них нет явного синтаксиса (см. Раздел « Предостережения »).

Опрос . Чтобы выразить интерес к параметрам для всех , поставьте "+1" в этом комментарии.

Примечание . Поделитесь своим вариантом использования универсальных параметров в этой теме! Нам бы хотелось больше разобраться в проблемном пространстве.

зарезервировано 3

В ricardo.ch мы используем префикс локали для каждого маршрута, что немного усложняет маршрутизацию.

Пример действительных маршрутов:

  • / - домашняя страница с автоматически определяемой локалью
  • /:locale - домашняя страница с принудительной локалью
  • /:locale/search - страница поиска
  • /:locale/article/:id - страница статьи

Как вы думаете, могут ли поддерживаться такие параметры префикса?

На данный момент мы используем https://www.npmjs.com/package/next-routes

Еще одна вещь: для страницы статьи мы также поддерживаем slug перед идентификатором, например /de/article/example-article-123 где идентификатор будет равен 123. Это делается с помощью довольно сложного регулярного выражения с использованием next-routes а я не посмотрите, как это можно выразить с помощью API файловой системы.

@ValentinH все предоставленные маршруты возможны с использованием API файловой системы - с учетом предоставленных вами маршрутов:

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

мы также поддерживаем слаг перед идентификатором, например / de / article / example-article-123, где идентификатор будет 123

Этот вариант использования рассмотрен выше:

Именованные параметры не могут появляться в середине имени маршрута.

Это означает, что страница с именем blog-$id.js будет интерпретироваться буквально и не будет соответствовать /blog-1 . Вы можете либо реструктурировать свои страницы, чтобы они были /blog/$id.js либо превратить весь сегмент URL в именованный параметр и обработать удаление blog- в коде вашего приложения.

Это решение не соответствует вашим потребностям? Мы хотели бы узнать больше о ваших конкретных требованиях.

Большое спасибо за ответ.

Я не думал об использовании $locale/index.js одновременно как папку и как файл, это действительно здорово!

Что касается «именованного параметра посередине», я упустил его из виду, потому что думал, что динамический слаг - другое дело. Однако вы совершенно правы, и это решено в упомянутом вами абзаце. Разделение ярлыка в коде приложения будет лучшим решением

Возможно ли что-то подобное (параметры синтаксического анализа из .hidden .files / .folders)?

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

или оставьте $, чтобы можно было найти свои файлы: D, но всегда используйте папку $ для указания параметра?

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

Раньше у меня был этот вариант использования дополнительных параметров в приложении, которое работало с пакетами npm. Они могут опционально иметь прицел. Есть такие маршруты, как:

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

Таким образом, в основном параметр области действия является необязательным, но он также является областью, когда он начинается с @ .
Итак, /packages/express/dependencies и /packages/@babel/core имеют одинаковое количество сегментов, но в одном случае это /dependencies из express а в другом - /index из @babel/core .

В конце концов она была решена в react-router со следующими маршрутами:

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

Я не уверен, что вижу решение для этого варианта использования в этом RFC.

Что касается универсальных вариантов использования, я думаю о любых глубоких ссылках на рекурсивно вложенные данные, такие как структуры папок, древовидные представления, древовидные карты.

Мои 2 цента: знаки доллара в именах файлов - плохая идея, потому что они используются оболочками как сигилы. Вы запутаете людей, пытающихся запустить rm $root.js . Подчеркивание кажется достойной альтернативой.

В более широком смысле: как и многие люди, в прошлом я пытался использовать файловую систему в качестве решения этой проблемы. В конечном счете, я думаю, что файловая система никогда не сможет предложить полную выразительность, которую вы ищете. Например, декларативные маршрутизаторы обычно позволяют указать шаблон проверки для динамического параметра. В этом случае часть схемы находится в файловой системе, а другая часть - в коде. Разделение проблем - это хорошо, но в данном случае это скорее техническое ограничение, чем что-либо еще.

Как и @ValentinH, мы используем

Должны ли мы использовать /page.ts и /page/$locale/page.ts?

Поскольку мы можем использовать языковой стандарт «по умолчанию» или предопределенный языковой стандарт (пользовательские настройки), в этих случаях мы не используем параметр $ locale.

Но у нас есть и другие варианты использования: / car / search / $ optional-filter-1 / $ optional-filter-2 / $ optional-filter-3.

Где optional-filter-1: красный цвет, optional-filter-2: brand-ford и т. Д.

А для необязательных параметров что-то вроде / $ required-param / и / $$ optional-param /?

Здорово, что это приближается к дорожной карте!

Однако я должен поддержать @timdp . Когда вы не можете даже touch $file это приведет к большой путанице. Вы должны помнить, что нужно убегать при каждом взаимодействии. touch \$file; vim $file откроет vim без файла (поскольку $ file не является определенной переменной).
Точно так же завершение табуляции в оболочке перечислит все переменные, что снова внесет путаницу.

Я предлагаю две альтернативы, которые, как мне кажется, вызывают правильные ассоциации и должны работать в оболочках:

  • = Его можно читать как page is a customer для =customer . Вы даже можете мысленно исказить его, чтобы он выглядел как просто растянутое двоеточие, напоминая, таким образом, наиболее распространенную форму именованных параметров.
  • @ как он тоже неплохо читается. a customer за @customer

Другой вариант - использовать фигурные скобки (если они не являются зарезервированными символами в некоторых файловых системах). Этот синтаксис параметра также соответствует уровню техники и используется многими другими маршрутизаторами:

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

Это позволит иметь параметры в середине сегмента маршрута и несколько параметров на сегмент, поскольку ясно, где параметр начинается и где он заканчивается, например /product-{productId}-{productColor} .

Так рад, что в Next.js появятся динамические маршруты!

Что касается синтаксиса для именованных параметров, это то, что обсуждалось на Spectrum: https://spectrum.chat/next-js/general/rfc-move-parameterized-routing-to-the-file-system~ce289c5e-ff66 -4a5b-8e49-08548adfa9c7. Возможно, стоит использовать это в качестве исходных данных для обсуждения здесь. Лично мне нравится, как это делает Sapper, используя [brackets] . Это также то, что Nuxt собирается реализовать в версии 3. То, что разные фреймворки используют один и тот же формат для динамических маршрутов на основе файловой системы, звучит неплохо.

Что касается использования <Link /> , я думаю, разработчики легко забудут установить атрибуты href и as . Я понимаю, что невозможно «объединить» их в атрибут href потому что это приведет к критическому изменению, но я чувствую, что это можно решить более элегантным способом.

К сожалению, фигурные скобки используются Bash для группировки команд.

Я согласен с @ stephan281094 относительно использования <Link /> , это будет источником ошибок.

Динамическая маршрутизация - чрезвычайно полезная функция, так что это действительно здорово, что вы, ребята, изучили ее и пришли к решению, огромному реквизиту!

По этой теме, маршруты с подстановочными знаками также были бы достойным дополнением к предложению. Вы упомянули общие параметры как нечто, что необходимо изучить в будущем, но это не касается случаев, когда вы можете захотеть сделать что-то вроде /category/* , которое может иметь N уровней, и вы хотите, чтобы все их, чтобы отобразить страницу category .

Можно ли безопасно использовать : ? Если так, то это мой голос, потому что все уже знакомы с этим соглашением от Express.

Из-за того, что $ конфликтует с переменными оболочки, я лично категорически против этого.

Можно ли безопасно использовать : ? Если так, то это мой голос, потому что все уже знакомы с этим соглашением от Express.

Очевидно, : - запрещенный символ в Windows, поэтому, вероятно, это небезопасно. Использование _ тоже не идеально, поскольку в URL-адресах можно использовать подчеркивание. Причина, по которой я думаю, что [brackets] - хорошее решение, заключается в том, что это больше подходит для будущего. Если Next.js в будущем захочет поддерживать маршруты типа post-12345 , используя этот синтаксис, это можно сделать без внесения критических изменений.

Итак, список персонажей, которых следует избегать, будет:

  • Конфликты с файловыми системами: : , * , " , < , > , |
  • Конфликты с переменными оболочки: $
  • Конфликты с расширением скобок в bash { , }

Что-нибудь еще?

Это не избавит нас от необходимости иметь централизованный файл маршрутов по двум причинам:

  • У нас есть автоматически сгенерированная карта сайта, и одной файловой системы недостаточно для ее определения.
  • Мы использовали именованные маршруты, а «страницы» назначения определяются данными, а не чем-то, что можно узнать во время сборки. Логика определения того, какую страницу загружать на основе имени и параметров, определяется конфигурацией маршрута.

Мы также создаем папку наших страниц по следующим причинам:

  • Мы используем Relay, а это означает, что модули, включающие GraphQL, должны иметь уникальные имена. По этой причине мы не можем часто, чтобы имена сегментов маршрута совпадали с именами модулей. index.js определенно не уникален, и я вижу места, где у нас было бы несколько общих сегментов, например edit .
  • Мы предпочитаем размещать отдельные компоненты, специфичные для страницы, в качестве братьев и сестер самих модулей страницы, что в Next.js не разрешено в папке страниц.

По сути, наш шаблон заключается в использовании нашей централизованной конфигурации маршрута для создания нашей папки страниц, которая содержит файлы, которые не делают ничего, кроме импорта / экспорта модулей из других мест в кодовой базе.

С этой целью я больше сосредоточен на том, может ли это предложение работать просто как расширенный формат вывода для нашего существующего процесса генерации страниц, чтобы мы могли, по крайней мере, получить преимущество, так как не нужен настраиваемый сервер.

Я рассмотрел некоторые из моих вариантов использования в другом месте: https://gist.github.com/AndrewIngram/8d4c4ccd9bd10415a375caacade9f5ca

Главное, чего я не вижу, - это поддержка неявных параметров, которые не выражаются в файловой системе, например переопределения URL.

Допустим, у нас есть такой URL:

/some-vanity-url/

Там, где в текущих условиях Next.js, мы хотели бы, чтобы он отображался на странице продукта с рядом параметров запроса, например, Product.js?id=foo&language=en .

Точно так же на нашем веб-сайте большинство страновых «сайтов» ограничены сегментом верхнего уровня, например es или ie , но сайт gb монтируется без этого сегмента. Это означает, что все страницы gb имеют неявный параметр country , а для всех других стран - явный.

Другой недостаток заключается в том, что поскольку в нашем случае одна и та же «страница» может существовать в нескольких точках монтирования в архитектуре URL-адресов, мы собираемся получить большее количество пакетов (т.е. несколько повторяющихся точек входа), чем мы на самом деле необходимость на практике.

В целом это предложение, похоже, будет хорошо работать для большинства распространенных случаев использования, но оно не устраняет необходимость в конфигурации маршрута или настраиваемом сервере во всех _ всех_ случаях. Но если предположить, что это не заменяет мою способность использовать фреймворк так, как я делаю сегодня, у меня нет никаких серьезных возражений против того, чтобы это был предпочтительный API счастливого пути.

Я поддерживаю предложение {id} . Он позволяет использовать несколько параметров, и я думаю, что это выглядит намного лучше. Он также лучше подходит для React.

Я за символ file/&param.js . Взято непосредственно из URL-адресов, и не похоже, что это конфликтует с файловыми системами или bash.

Я бы использовал _ и, возможно, разрешил бы переопределение в next.config.js для тех, кому действительно нужно что-то другое.

Оцените работу над этим. Давно хотел этого! ❤️

Удивительный! 🎉🎉🎉

Моя единственная проблема здесь в том, что Link нужны как href и as params.

Я считаю, что мы могли бы просто написать <Link to="blog/123" /> : поскольку Nextjs уже знает все маршруты, основанные на файлах в папке страниц, он мог бы легко перевести их в "/blog/$id" .

Итак, список персонажей, которых следует избегать, будет:

& - это управляющий оператор в bash, который запускает левую часть аргумента в подоболочке async. Открытый текст: open pages/&customer запустит open pages/ в фоновом режиме, а команду customer в оболочке переднего плана.

Это выглядит действительно круто.

Кажется, что это создаст значительное количество одиночных файловых каталогов (например, /blog/$id в исходном примере). Это становится еще более громоздким, если вам нужны два параметра конечного маршрута (например, /git/compare/$hash1/$hash2 ).

Мне также не нравится, что имя файла для вывода сообщения в блоге будет $id.js . Если бы он назвал blog.js было бы намного более наглядно.

Может быть, в сочетании с декоратором @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

Похоже, это также обеспечивает более четкое решение для предложенных универсальных параметров.

Декораторы нельзя применять к функциям (может быть, это изменилось с тех пор, как я его последний раз читал?), И предложение, вероятно, все равно далеко.

Что ж, предположим, вы пойдете по этому пути, вы, вероятно, сделаете это так, как сейчас настроен AMP:

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

Однако я думаю, что такие вещи можно будет добавить позже, если они когда-нибудь покажутся полезными. Думаю, для начала я бы предпочел получить базовую поддержку, как описано в RFC. Получите от этого реальное применение, а затем уточните, где он ломается. Я также думаю, что единственные символы, которых следует избегать, - это символы файловой системы. Это настоящие препятствия для создания этой функции.

Пожалуйста, убедитесь, что вы используете персонажа, дружелюбного к бессерверным решениям! (На Aws есть некоторые персонажи, которые могут вызвать проблемы)

Я не ненавижу экспорт объекта конфигурации с ключом компонента.

Вы также можете просто использовать HOC

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

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

что, если мы добавим на страницу статическое поле (например, 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 Что происходит, когда вы переходите к /blog в браузере? 404?

Поскольку это необходимо определить во время компиляции, я думаю, вам понадобится что-то, что можно статически анализировать. HOC или статическое свойство не будет.

вам понадобится что-то статически анализируемое. HOC или статическое свойство не будут

Каждый пример статических свойств, приведенный до сих пор, можно было бы статически анализировать (хотя вы, безусловно, можете легко что-то сломать). Мы могли бы просто настоять на том, чтобы вы экспортировали свою функцию и установили для нее свойство маршрута статически анализируемым способом. Среда выполнения может проверять свойства маршрута, которые установлены во время выполнения, но не были обнаружены нашим статическим анализатором, и выдавать предупреждение / выдавать ошибку.

Что происходит, когда вы переходите в / blog в браузере? 404?

@kingdaro - ИМО, да. Если вы хотите использовать как пути /blog , так и пути /blog/:blogId , тогда вы используете каталог. Вы перегружаете этот путь, поэтому структура каталогов оправдана.

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

Что ж, предположим, вы пойдете по этому пути, вы, вероятно, сделаете это так, как сейчас настроен AMP:

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

Однако я думаю, что такие вещи можно будет добавить позже, если они когда-нибудь покажутся полезными. Думаю, для начала я бы предпочел получить базовую поддержку, как описано в RFC. Получите от этого реальное применение, а затем уточните, где он ломается. Я также думаю, что единственные символы, которых следует избегать, - это символы файловой системы. Это настоящие препятствия для создания этой функции.

Я думаю, что использование config - плохая идея, потому что вам нужно просмотреть несколько файлов, чтобы увидеть, что на самом деле является динамическим. Если установить его в файловой системе, это видно с первого взгляда.

Интересно, стоит ли рассматривать более одного стандартного решения для маршрутизации.

Простая маршрутизация на основе файлов - отличный аргумент для новичков в Next / React или для тех, кто хочет быстро запустить и запустить простое приложение, но это может быть довольно ограничивающим фактором. И мне кажется, что попытка втиснуть динамическую маршрутизацию в этот шаблон может разрушить эту простоту и привести к ненужной сложности, и все во имя сохранения всего файлового типа.

Прочитав это обсуждение и подумав о моем собственном использовании Next.js, я думаю, что первоклассная поддержка альтернативной (дополнительной) системы маршрутизации может быть лучшим способом решить эту проблему.

Мне нравятся некоторые нестандартные идеи в этой теме (например, предложение использовать декораторы), но у этих идей определенно есть свои проблемы. Надеюсь, мы сможем придумать что-нибудь отличное 👍

Я не ненавижу экспорт объекта конфигурации с ключом компонента.

Вы также можете просто использовать HOC

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

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

Это довольно круто, но мне интересно, разделена ли информация о маршруте между многими файлами, например
это может стать трудным для управления.

Моя первоначальная мысль, предлагая локальную конфигурацию (в файле) по сравнению с глобальной ( route.js ), заключалась в рассмотрении конкретных сценариев, упомянутых в моем первом комментарии (глубоко вложенные файлы, которые являются единственным файлом в своем каталоге, несемантические имена файлов и универсальные параметры).

Если использовать строго в этих контекстах, это гораздо менее запутанно, потому что URL-адрес отображается непосредственно в файловой системе, и только "дополнительные" параметры обрабатываются локальной конфигурацией.

Тем не менее, я не уверен, что даже попытаюсь ограничить пользователей делать это так, как они хотят. Мы можем распечатать рассчитанную таблицу маршрутизации на консоли или даже сохранить ее в какой-нибудь заранее определенный файл. Этого должно быть достаточно, чтобы помочь в поиске и устранении неисправностей.

@merelinguist Я не верю, что = запрещено в Windows, как вы написали в сводной таблице. Вы ссылаетесь на то, что : запрещено, но в соответствии с документами по

Я уже портирую с динамическими маршрутами в проекте, который использую в продакшене (надеюсь, я смогу запустить его на этой неделе).

Конкретный вопрос: будет ли новая функция API next @ canary _ также_ поддерживать динамическую маршрутизацию?

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

Я только что попробовал с [email protected] и получил 404 not found, так что подозреваю, что его еще нет. Похоже, что для этих двух функций (API + динамические маршруты) имеет смысл иметь паритет при маршрутизации URL-адресов.

@remy это еще не реализовано, это в моем списке, чтобы сделать это в ближайшее время

Также следует учитывать не только системы Windows и Linux, но и другие:
https://en.wikipedia.org/wiki/Filename#Comparison_of_filename_limitations

Я хочу добавить больше информации о своем предложении:

что, если мы добавим на страницу статическое поле (например, 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. Разработчик не может использовать переменную времени выполнения для этого свойства маршрута
const route = `/blog/${somethingElse}`;
BlogPost.route = route; // is not allowed
  1. Когда мы создаем манифест страницы с этим текущим RFC (где папка содержит какой-то символ, чтобы определить, что он динамический), я не вижу разницы, если мы создадим этот манифест страницы с чтением файла и найдем свойство статического маршрута на странице. Точно так же работает Trans быть динамическим
<Trans id="msg.docs" /* id can only be static string */>
   Read the <a href="https://lingui.js.org">documentation</a>
   for more info.
 </Trans>

Следуя списку уже перечисленных префиксов - интересно, есть ли веская причина _не_ использовать префикс символа @ ?

Я сомневаюсь, что это имеет значение, но вы получаете паритет с Nuxt - это означает, что кто-то, переходящий с одного или другого, сразу поймет, как это работает.

В качестве альтернативы, кто-нибудь думал о том, чтобы сделать префикс пользовательской опцией? Людям сложнее понять один проект из другого, но это означает, что если бы я хотел, я мог бы сделать префикс query__{...} или что-то в этом роде.

Просто мысль.

Следуя предложению @remy , почему бы не полностью открыть API, чтобы узнать, как Next анализирует маршруты из файловой системы. Предоставляя пользователям столько (или меньше) гибкости, сколько им нужно, и вдохновляя на создание надежных сторонних решений для маршрутизации.

@ scf4 У меня была библиотека, которая представляет собой PoC, которая использует конфигурацию now.json routes для универсальной маршрутизации с nextjs тоже здесь

Я надеюсь, что команда Zeit также откроет исходный код парсера маршрутов в клиентской библиотеке.

Глядя на Nuxt, я думаю, что _id.js не так уж и плох. Да, мы уже используем _app и _document.js как вы упомянули, и это не является общедоступной маршрутизацией. Но динамический маршрут также можно рассматривать как немаршрутизируемый, поскольку это шаблон для многих страниц.

Как это будет обрабатываться для экспорта статических сайтов?

(Забудь об этом)

Я также думаю, что было бы полезно, если бы Next.js выводил сгенерированные маршруты в один файл (возможно, скрытый по умолчанию). По крайней мере, он мог бы послужить полезным справочником для людей, работающих над проектом, но он также мог бы открыть дверь для некоторой мощной динамической маршрутизации позже.

То есть, если он использует этот файл для обработки маршрута во время выполнения, пользователям будет очень легко добавлять / изменять маршруты (например, для сложного сопоставления с образцом) без потери преимуществ API на основе файловой системы.

Это создало бы несколько проблем, связанных с отслеживанием маршрутов, которые были изменены вручную, но если бы они были решены, я думаю, что это было бы лучшим решением на сегодняшний день.

@ scf4 Next.js уже имеет возможность выполнять сложные маршруты с использованием настраиваемой опции сервера. То, что вы предлагаете, достигается с помощью почти такого же количества кода с уже доступными инструментами.

Ах да, достаточно честно.

Я думаю, что иметь один файл маршрутов, который можно редактировать, в любом случае будет намного лучше!

Я написал несколько мыслей о маршрутизации с файловой системой , но могу резюмировать свои выводы здесь:

  • [param] выглядит самым безопасным (и используется Sapper).
  • : знакомо пользователям Express, но я мог бы _признаться_, что у меня проблемы с Windows FS.
  • $ и {param} используются для раскрытия переменных и скобок в оболочках, поэтому это может быть более проблематичным при использовании интерфейса командной строки.
  • _ _could_ работать, но слишком часто используется как "частный" индикатор.

У меня лично был лучший опыт работы с файлами белого списка для маршрутов ( /^index\. ) по сравнению с черным списком ( /^_/ ), но это была бы проблема обратной совместимости с /pages .

В связи с недавним обсуждением поддержки маршрутов API (# 7297) это может быть возможностью для поддержки /api и /pages в новом доме /routes .

Тем не менее, _и это сильное «однако» _, экосистема Next.js достаточно велика, чтобы гарантировать _инкрементальные_ добавления функций, а не «эй, если бы нам пришлось делать это снова, мы бы сделали это _ таким_ способом».

Квадратные скобки ( [example] ) используются zsh для сопоставления с образцом, так что это тоже нецелесообразно.

См. Примеры в разделе " Генерация имени файла"

Скобки [] используются zsh для сопоставления с образцом, так что это тоже нецелесообразно.

Похоже, они только что сделали это в https://github.com/zeit/next.js/pull/7623

Спасибо за внимание. Я тоже оставил там комментарий.

Я пробовал [id] и просто использовать его в путях - это боль (например, cd \[id\]/view.js ). Мне кажется, двойное подчеркивание __id (например, cd __id/view.js ) работает так же хорошо, и его можно отличить (альбит, возможно, немного сбивает с толку) от внутренних файлов / папок (например, _app.js ).

@AaronDDM вы используете zsh ? Вам не нужно экранировать [ или ] в bash.

Да, это также происходит со мной с zsh - супер раздражает взаимодействие с этими каталогами.

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

А поскольку zsh станет оболочкой по умолчанию в macOS Catalina , возможно, все-таки с этим нужно что-то делать ...

согласен с __id.js

Хм, правда не люблю __ , просто мне не очень нравится.

@merelinguist em, Jest используйте __tests__ для тестовой папки по умолчанию, я думаю, что __ имеет смысл в некоторых случаях.

@YUFENGWANG Возможно, но я бы предпочел, если возможно, одного персонажа. В конечном счете, я думаю, что лучшим решением будет:

  1. Разумное кроссплатформенное значение по умолчанию, например =
  2. Вариант в next.config.js для настройки используемого специального символа маршрута
  3. Документация по персонажам, вызывающим проблемы, в каких ситуациях

Согласен с одним символом, но я бы предпочел нулевую конфигурацию. и я предполагаю, что многие люди решат все проблемы, даже если вы опишете их в документации.

Обратите внимание, что = зарезервировано zsh. Из документов :

Если слово начинается с символа '=' без кавычек и установлен параметр EQUALS, оставшаяся часть слова принимается как имя команды. Если существует команда с таким именем, слово заменяется полным путем к команде.

Просто идея; как насчет использования суффикса? Например, [email protected] или подобное может быть достаточно. Это может решить проблему с экранированием и работой с оболочками и файловыми системами, пока символ действителен.

Они работают в zsh и bash без необходимости выхода:

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

Ох. Не суффикс, а способ обозначить параметры конечного URL.

Итак, [email protected] становится blog/:id .

compare@[email protected] становится compare/:a/:b .

Это могло бы решить проблему с глубоко вложенными одиночными файловыми каталогами, против которых я возражал выше, и сохранить всю файловую систему определения маршрутизации на основе.

Это не выглядит таким уж фантастическим, но как насчет чего-нибудь вроде:

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

префикс _var_ Который пытается имитировать объявления переменных JS. Или он должен быть очень коротким, с одним персонажем?

Как насчет символа ~ ?

Как /blogs/~id .

Использование ~ в качестве префикса также нецелесообразно, поскольку оно используется для расширения до домашней папки в POSIX-совместимых оболочках.

Любой символ, который не соответствует [0-9a-zA-Z-._] (регулярное выражение), не может считаться безопасным в качестве префикса в операционных системах, оболочках и файловых системах.

Некоторые символы тоже небезопасны. См. Документацию zsh о

Также я думаю, что мы не должны стремиться к тому, чтобы он выглядел модно, а скорее был интуитивно понятным, читаемым и простым в общении.

  • использование скобок для [params].js кажется более элегантным и широко используемым. (сапер, nuxt v3?).
  • префикс подчеркивания pages/_helper.js обычно для частной функции, и, возможно, его не следует отображать. это позволяет нам создавать вспомогательные компоненты в папке страниц

имхо: это похоже на временное решение более серьезной проблемы. Хотя наличие маршрутов, основанных на файловой структуре, очень приятно начинать, это плохо масштабируется, когда у вас есть сотни маршрутов, параметров и т. Д. Наличие файла конфигурации маршрутов (возможно, есть файл routes.js в каждом каталоге) - лучшее долгосрочное решение. Меня лично привлекает nextjs из-за готовых функций (SSR, скорость и т. Д.), Которые он предоставляет, а не из-за простоты создания маршрутов из файлов.

@mmahalwy ты попал в

Next.js уже генерирует конфигурацию маршрутов (на основе файловой системы). Я считаю, что сделать эту конфигурацию более явной и / или разрешить пользователю «извлекать» ее, если они пожелают, было бы наиболее простым решением.

@mmahalwy @ scf4 FWIW, существенным оправданием для маршрутов файловой системы является устранение необходимости иметь централизованный файл. Фактически, можно легко утверждать, что весь API Next.js для ссылок и маршрутизации разработан с учетом этого ограничения.

Проблема с конфигурацией маршрута заключается в том, что вам приходится отправлять его клиенту, что может означать довольно большой пакет кода, если у вас есть маршруты, насчитывающие от сотен до тысяч.

Тем не менее, существует довольно много распространенных вариантов использования, которые (насколько я мог судить, из обсуждения этой проблемы с @timneutkens несколько раз за последние несколько месяцев) не могут быть решены без централизованной конфигурации. Некоторые из них я перечислил в своем предыдущем комментарии, но их гораздо больше.

Самый простой из них - это вести блог на CMS, где авторы могут создавать ссылки на страницы сайта. Они просто будут создавать ссылки с простым старым URL-адресом, не зная, что такое основной модуль страницы. С централизованной конфигурацией маршрута довольно легко выполнить обратное сопоставление URL-адреса и определить, какую страницу загружать (моя собственная библиотека, next-route-resolver предназначена для поддержки этого варианта использования и всех других, которые я придумал) .

Я не понимаю, как я могу заставить сайт, над которым я работаю, работать без конфигурации маршрута, поэтому мое внимание было сосредоточено только на поиске способов сохранить конфигурацию маршрута в пределах допусков по размеру файла. Для других маршрутизация файловой системы может быть более чем достаточной. Я не думаю, что маршрутизация - это проблема, когда есть одно решение, которое решает все, все дело в балансировании компромиссов.

Итак, как я упоминал ранее, что касается этого предложения, оно кажется прекрасным, если оно продается как полностью решающее проблему маршрутизации, потому что это будет немного вводить в заблуждение :)

@AndrewIngram Я понимаю, откуда вы пришли, но это ограничение ограничивает возможности nextjs. Nextjs предлагает так много "из коробки", что для любого нового проекта или компании использование его должно быть легким делом. Однако проблема заключается в том, что это жесткое мнение о маршрутизации, которое делает его неизбежным в будущем (и, как большая компания, вы всегда рассматриваете стратегию выхода, если проекты потеряют интерес или обслуживание).

@mmahalwy Я думаю, вы неправильно поняли мою точку зрения. Я согласен с вами, я не думаю, что маршрутизации файловой системы достаточно, чтобы назвать проблему маршрутизации решенной, и был бы разочарован, если бы она была представлена ​​как таковая. Я действительно думаю, что он предлагает улучшение для определенного набора сценариев использования, но я также думаю, что также должен быть какой-то формат манифеста маршрута для тех, кто желает выбрать другой набор компромиссов (например, вы и я) .

Для тех, кому нужна централизованная или расширенная конфигурация маршрутизации, разве она не обрабатывается с помощью настраиваемого сервера и / или внешних пакетов? Что вы надеетесь здесь добавить?

Все это кажется не по теме этого RFC. Я не думаю, что кто-то, включая OP, предположил, что это окончательное решение для маршрутизации. Это просто улучшает маршрутизацию на основе файловой системы.

Я использовал динамические маршруты для мини-проекта в течение последних нескольких недель (используя $ хотя я заметил, что он был перемещен в [param] 3 дня назад в репозитории канареек, но в любом случае).

Я _just_ начал использовать getRequestHandler и я думаю, что он не улавливает динамическую маршрутизацию на стороне сервера.

Это ошибка, или намеренная (например, какое-то изменение в getRequestHandler ), что-то еще, или использование getRequestHandler полностью отключает динамическую маршрутизацию (что имело бы смысл сейчас, я думаю об этом…) ?

Для тех, кому нужна централизованная или расширенная конфигурация маршрутизации, разве она не обрабатывается с помощью настраиваемого сервера и / или внешних пакетов? Что вы надеетесь здесь добавить?

Одна из целей здесь - избежать необходимости создавать собственный сервер, хотя бы для того, чтобы упростить его использование с такими сервисами, как Now (который в настоящее время требует, чтобы все динамические маршруты были частью его конфигурации).

Все это кажется не по теме этого RFC. Я не думаю, что кто-то, включая OP, предположил, что это окончательное решение для маршрутизации. Это просто улучшает маршрутизацию на основе файловой системы.

На самом деле здесь есть некий дополнительный контекст. Это предложение появилось давно, и, основываясь на многих обсуждениях, которые я видел, связанных с ним (включая те, в которых я принимал непосредственное участие), его до некоторой степени раздумывали как устранение необходимости использования этого маршрута библиотеки управления, такие как next-routes и моя собственная. Я не думаю, что не по теме выделять варианты использования, которые не выполняются этим RFC. Некоторые из них могут быть выполнены путем внесения некоторых изменений в предложение, другие - нет. Но в любом случае, несомненно, полезно повысить осведомленность о пределах предлагаемого?

FWIW мы используем в Pinterest маршруты на основе FS в стиле [param] (но не Next). Пока масштабируется очень хорошо. Самая большая критика заключается в том, что Jest интерпретирует [] как пары регулярных выражений, поэтому может быть сложно нацелить тесты на параметрические обработчики.

@chrislloyd Каков ваш опыт создания и управления файлами с использованием этого формата для путей / файлов в разных средах, учитывая, что кто-то использует zsh или инструмент, который интерпретирует их по-разному?

Видно, что [] используется для сопоставления с образцом в zsh (и, как вы говорите с Jest), вам нужно будет избегать этих путей. Это не большая проблема, если вы _знаете_ об этом, но, учитывая, что он должен быть пригоден для использования и понят новичками, я сомневаюсь, что это правильный формат.

У меня есть идея использовать ! качестве обязательного параметра, например /pages/id!.js и ? в качестве необязательного параметра, например, /pages/posts/id?.js .

У него нет проблем с префиксом, как в предыдущих обсуждениях, и он знаком с тем, как ! представляет обязательные параметры, а ? представляет необязательные параметры.

Windows не позволяет использовать вопросительные знаки в именах файлов, и то и другое? и ! имеют особое значение в Баше.

API routes теперь поддерживают динамические параметры # 7629 🚀

Ожидается, что @remy getRequestHandler будет обрабатывать динамическую маршрутизацию - я только что подтвердил локально, что это так. Не могли бы вы сообщить об отдельной ошибке / проблеме с инструкциями по воспроизведению, чтобы мы могли изучить их? : молиться:

Всем привет! Спасибо за прекрасный ответ на этот RFC.

Этот RFC был реализован и выпущен как стабильный в Next.js 9.
Вы можете прочитать об этом в блоге .

В будущем мы собираемся опубликовать новый RFC, чтобы учесть все представленные здесь расширенные отзывы. Мы опубликуем здесь обновление, когда оно станет доступно.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги