Next.js: Solicitud de función: soporte de ruta base

Creado en 21 ago. 2018  ·  73Comentarios  ·  Fuente: vercel/next.js

Solicitud de función

¿Su solicitud de función está relacionada con un problema? Por favor describa.

Las zonas múltiples es una gran característica que permite ejecutar múltiples aplicaciones next.js en el mismo dominio, pero no permite definir una ruta base que será aceptada por todas las partes de next.js. Dado que no podemos utilizar aplicaciones de espacio de nombres en este momento, no es posible tener los mismos nombres para las páginas en varias aplicaciones.

Describe la solución que te gustaría

Quiero poder configurar un basepath en el archivo next.config.js. Gracias a esta configuración, todas las partes de next.js (enrutador, enlace, activos estáticos, etc.) conocerán la ruta base y automáticamente generarán y coincidirán con las rutas correctas.

Describe las alternativas que has considerado

Una alternativa es anidar todas las páginas deseadas en una carpeta que coincida con la ruta base. Esto resuelve solo un pequeño problema con el enrutamiento y es bastante feo porque la mayoría de mis rutas base no son rutas de un nivel.
La segunda alternativa es configurar un proxy de manera que la ruta base se elimine automáticamente antes de que la solicitud llegue a una aplicación next.js y también implementar un componente de enlace personalizado que agrega automáticamente la ruta base a todos los enlaces. Simplemente no quiero mantener una bifurcación personalizada de next.js. No tiene sentido en mi opinión.

Contexto adicional

La solución assetPrefix nos permite definir un prefijo diferente para cada aplicación. Pero por lo que sé, solo funciona con diferentes hosts.

ejemplo con zonas

module.exports = {
  assetPrefix: NOW_URL ? `https://${alias}` : 'http://localhost:4000'
}

Si le agrego una ruta base, todo falla

module.exports = {
  assetPrefix: NOW_URL ? `https://${alias}/account` : 'http://localhost:4000/account'
}

screen shot 2018-08-21 at 10 47 08

En mi opinión deberíamos dividirlo en 2 variables:

module.exports = {
  assetPrefix: NOW_URL ? `https://${alias}` : 'http://localhost:4000',
  basepath: '/account'
}

Asuntos relacionados

story needs investigation

Comentario más útil

Cualquier actualización sobre esto ... el año pasado por esta época me encontré con este problema. Ahora, un año después, estoy trabajando en una nueva aplicación y tengo que hacer las mismas soluciones que hice el año pasado ... algo alarmante para una reacción fw 'lista para producción'. Los caminos base deben ser una característica básica.

No estoy seguro de lo que esperas al publicar esto.

Mi equipo (5 personas) está trabajando en Next.js a tiempo completo, y estamos trabajando en muchas funciones al mismo tiempo. En el último año hemos trabajado en estos:

Hacer que las aplicaciones Next.js (nuevas y existentes) sean significativamente más pequeñas, más rápidas y más escalables.

Si desea expresar su "voto a favor" para una función, puede hacerlo. use la función 👍 en el hilo inicial.

Definitivamente estoy basePath acuerdo en que

Aquí está el PR: https://github.com/zeit/next.js/pull/9872

No dude en comunicarse con [email protected] si desea contribuir financieramente para hacer realidad esta función.

Todos 73 comentarios

cc @jxnblk

cc @alexindigo @DullReferenceException

Me encantaría recibir tus comentarios 👍

Después de jugar con el código, me di cuenta de que sería mucho más fácil dividir assetPrefix en varias partes:

module.exports = {
  host: NOW_URL ? `https://${alias}` : 'http://localhost:3000',
  basePath: '/account',
}

Aún podemos mantener la variable assetPrefix internamente, pero el usuario debe definir con mayor precisión lo que necesita.

Para la parte de activos, está realmente bien proporcionar estas dos variables juntas.
Para el enrutamiento, etc., los necesitamos por separado.
O tal vez incluso podamos proporcionarlo juntos en un archivo de configuración y luego dividirlo en la base de código next.js. En este caso, me temo que assetPrefix no es el nombre correcto.

Como efecto secundario, esto también conduce a menos cambios de código.
Es bastante obvio si comparas esos dos RP:
https://github.com/panter/next.js/pull/2 (dividido)
https://github.com/panter/next.js/pull/1 (pasar ambos)

En mi opinión, deberían estar separados, la razón de esto es que no se rompe y es más flexible mantener assetPrefix y tener basePath separado.

Entonces, ¿es assetPrefix el nombre correcto? Ambas variables son en realidad un prefijo, ¿verdad?

assetPrefix es para activos, por ejemplo: los paquetes de páginas. basePath será para el enrutador.

La forma en que debería funcionar es:

  • si assetPrefix está definido, use assetPrefix para cargar paquetes, no toque el enrutador (comportamiento actual)
  • Si se proporcionan assetPrefix y basePath use assetPrefix para cargar paquetes, agregue basePath al enrutador
  • si assetPrefix no está definido y basePath , use basePath para cargar paquetes y agregue basePath al enrutador
  • si no se define assetPrefix ni basePath no hacemos nada diferente (comportamiento actual cuando no se proporciona assetPrefix )

cc @alexindigo @DullReferenceException @ 3rd-Eden

¿Podría darnos su opinión sobre la propuesta anterior: https://github.com/zeit/next.js/issues/4998#issuecomment -414978297

@tomaswitek No estoy seguro de qué es exactamente lo que no funcionó para usted con el actual assetPrefix , este es el prefijo de activo que estamos usando en producción: "assetPrefix":"https://static.trulia-cdn.com/javascript" y funciona como se esperaba.

Y, en general, estamos usando múltiples zonas (las llamamos islas) en el mismo dominio y nunca se nos ocurrió "basePathing" cada isla, ya que complicaría la interoperabilidad entre las islas. Permítanme desarrollar un poco más sobre tat:

Entonces, tenemos dos islas A y B , y la idea principal es la transparencia para los usuarios que navegan de isla en isla como parte de su experiencia de un sitio web. Entonces debería haber vínculos entre las islas. Luego está la preocupación por la implementación frente a la preocupación por la aplicación.

  1. Preocupación por la implementación frente a la preocupación por la aplicación: la aplicación no tiene idea de dónde podría implementarse, solo sabe cómo manejar las solicitudes http entrantes; ha establecido rutas a las que puede responder.
    Cuando se implementa en algún lugar, podrían ser dominios diferentes, puertos diferentes y, sí, teóricamente, podría ser una ruta base diferente, que se hará transparente para la aplicación a través de proxy u otros medios.

  2. Enlaces cruzados entre las islas: para mantener el espíritu de las islas como entidades desplegables separadas, no debería haber ninguna fuga de conocimiento de implementación interna entre las diferentes islas.
    Entonces, la mejor manera para que las islas hagan referencia a las páginas entre sí es que exporten las rutas disponibles para que otras islas las consuman (_y en el mundo nextjs parece que los componentes personalizados <IslandALink> serían los preferidos camino_).
    Hasta ahora todo es sencillo: todas las islas asumen que comparten el mismo dominio y tienen su conjunto de rutas absolutas ( /path1 , path2 , etc.). De esa manera, la segunda isla importa esa lista de rutas y confía en que sea estable. Al mismo tiempo, es un requisito bastante mínimo que cada isla mantenga sus rutas compatibles con versiones anteriores (lo cual es bueno en la web de todos modos) :)

Cuando agregamos basePath específica de implementación, aumentamos automáticamente la complejidad de todo el sistema: ¿debería cada isla conocer (y tal vez dictar) su propia ruta base de implementación? Entonces, ¿en qué se diferencia de la forma en que funcionan las cosas actualmente? ¿O debería la isla A ser independiente de su ruta de implementación? Entonces, ¿cómo la isla B encontrará la isla A desplegada, ya que solo sabe lo que la isla A sabe de sí misma? ¿O tendrías que suministrar basePath para todas las islas desplegadas a todas las demás islas? Y con la forma moderna de implementar cosas, significa volver a implementar todas las islas cuando necesite agregar una nueva.

¿O cómo imaginó esa parte de la historia?

Gracias.

^ fue escrito antes del café de la mañana, así que avíseme si necesita una explicación más coherente de alguna parte. :)

En primer lugar, gracias a todos por tomarse el tiempo de revisar mi problema.

@timneutkensassetPrefix tiene prioridad sobre basePath , eso es exactamente lo que hemos discutido al principio. Después de ver cuántos archivos tenía que cambiar, pensé que la segunda forma sería más limpia. Pero volveré a la primera solución. Mantengamoslo totalmente separado, no hay problema en absoluto. Estaba pensando en voz alta.

@alexindigo Thx por su respuesta detallada. Déjame intentar responder tus preguntas 😏

No estoy seguro de qué es exactamente lo que no funcionó para usted con assetPrefix actual

Tengo dos problemas aquí:

  1. No puedo trabajar con varios dominios ni subdominios en el proyecto actual. (Restricciones de dominio y sin certificado SSL comodín)
  2. La implementación actual de assetPrefix en un solo dominio requiere más ajustes en el enrutamiento de proxy, archivos estáticos, etc. Podríamos reducir estos ajustes introduciendo basePath . No frenará nada y no aumentará la complejidad porque no tiene que proporcionar los basePath como @timneutkens ya mencionado.

la aplicación no tiene idea de dónde se podría implementar

¡Tenemos el mismo objetivo aquí, por supuesto! Estamos definiendo assetPrefixes dinámicamente en la solución actual que tenemos. Se proporciona a través de encabezados de solicitud por proxy.

Entonces, ¿en qué se diferencia de la forma en que funcionan las cosas actualmente?

El enrutador conocerá contextPath y reducirá la cantidad de código personalizado.

¿Debería cada isla saber (y tal vez dictar) su propia ruta base de implementación? ¿O debería la isla A ser independiente de su ruta de implementación?

No tiene por qué serlo. El desarrollador debería tener libertad aquí. Debería ser posible proporcionar basePath dinámicamente de la misma manera que assetPrefix.

Entonces, ¿cómo la isla B encontrará la isla A desplegada, ya que solo sabe lo que la isla A sabe de sí misma? ¿O tendrías que suministrar basePath para todas las islas desplegadas a todas las demás islas? Y con la forma moderna de implementar cosas, significa volver a implementar todas las islas cuando necesite agregar una nueva.

Quizás también podría agregar basePath en la exportación de rutas. No lo sé. No estoy diciendo que la variable basePath sea importante para cada caso de uso. Parece que no es la mejor solución para ti. Pero eso está totalmente bien. La cuestión es que todavía puedes usar solo assetPrefix y nada cambiará para tus islas. De todos modos, parece que tienes tu propia ruta. Los enlaces cruzados entre zonas ni siquiera son importantes para nuestro proyecto, nuestras zonas son realmente independientes y aisladas unas de otras.

Y con la forma moderna de implementar cosas, significa volver a implementar todas las islas cuando necesite agregar una nueva.

No veo una razón por la cual. Incluso puedo imaginar que algunas zonas tienen basePaths y otras no. Y tal vez algunas aplicaciones usen la configuración basePath incluso sin configuración de múltiples zonas.

@alexindigo, ¿ podría proporcionarnos dos URL reales de la isla, que se procesan con next.js para que pueda verlo en acción? Intenté encontrar uno, pero no pude encontrar una página en su dominio con _next solicitudes 😄
¿Todas sus islas tienen la misma configuración?
"assetPrefix":"https://static.trulia-cdn.com/javascript"

@tomaswitek

No puedo trabajar con varios dominios ni subdominios en el proyecto actual. (Restricciones de dominio y sin certificado SSL comodín)

¿Entonces no usa CDN en el sentido clásico, sino que confía en que los activos se obtengan directamente de cada aplicación? Veo.

La implementación actual de assetPrefix en un solo dominio requiere más ajustes en el enrutamiento de proxy, archivos estáticos, etc. Podríamos reducir estos ajustes introduciendo basePath. No frenará nada y no aumentará la complejidad porque no tiene que proporcionar la ruta base como ya se mencionó @timneutkens .

Por cierto, no fue "no, no agregue esa característica" :) Fue más como - "Probablemente podamos pensar en este enfoque de manera más integral" :)

No tiene por qué serlo. El desarrollador debería tener libertad aquí. Debería ser posible proporcionar basePath dinámicamente de la misma manera que assetPrefix.

Si. Sin embargo, solo funciona cuando no hay enlaces entre las islas. Y parece que este es su caso de uso. Al mismo tiempo, me cuesta entender qué las convierte en islas en lugar de ser simplemente un montón de aplicaciones independientes, ¿si son 100% independientes? :)

Quizás también podría agregar basePath en la exportación de rutas.

No veo cómo se podría hacer (fácilmente), ya que la exportación de rutas se realiza en el momento de la compilación y basePath se define en el momento de la implementación, y podría haber más de una implementación del mismo artefacto de código (etapa, preprod, prod, prueba env, etc.).


¿Todas sus islas tienen la misma configuración?
"assetPrefix": " https://static.trulia-cdn.com/javascript "

Sí, todas las islas comparten sus activos, ya que a continuación se realiza el hash de contenido, no solo no es un problema, sino que en realidad es muy beneficioso. (Extraemos activos construidos de cada artefacto y publicamos en CDN en el momento de la implementación).

Y de esa manera solo tenemos solicitudes "html regulares" a nuestros servidores de aplicaciones, por eso no veré ninguna ruta "_next" en trulia.com

En cuanto a los ejemplos de islas:

Nuestra nueva isla fresca - Página de vecindarios - https://www.trulia.com/n/ca/san-francisco/pacific-heights/81571 (y puede encontrar más de ellos aquí: http: //www.trulia. com / vecindarios)
Esta isla es responsable de todas las rutas /n/* .

Y otra isla es nuestra página de inicio de sesión, https://login.trulia.com/login, parece un dominio diferente, pero en realidad no lo es, se ve así por diferentes razones, pero técnicamente es la misma implementación. :)
Y esta isla maneja URL como /login , /signup .

Avísame si tienes más preguntas.

@alexindigo muchas gracias por tus ejemplos.
Tengo algunas preguntas después de analizar los ejemplos 😄

Todavía realiza la renderización del servidor para cada isla, pero intenta extraer la mayor cantidad de activos posibles en una CDN común, ¿verdad?

¿Puede describir un poco más qué sucede exactamente cuando se llama https://www.trulia.com/n/ca/san-francisco/pacific-heights/81571 ? ¿Su proxy sabe que /n significa descripción general del vecindario y lo reenvía a la isla correcta? ¿Afecta de alguna manera a la solicitud antes de que llegue a la isla?

¿Utiliza el enrutamiento integrado desde el interior de una isla o tiene una solución personalizada?
Quería comprobar la ruta dentro de su isla. Desafortunadamente, Neighborhood overview tiene una navegación más o menos modal sin cambiar la URL. En Login parece haber una solución completamente personalizada.

Espero responder a todas tus preguntas en este comentario 😏

Por cierto, no fue "no, no agregue esa característica" :) Fue más como - "Probablemente podamos pensar en este enfoque de manera más integral" :)

Claro, sería genial encontrar una solución en la que no tenga que tocar next.js 😏

Si. Sin embargo, solo funciona cuando no hay enlaces entre las islas. Y parece que este es su caso de uso. Al mismo tiempo, me cuesta entender qué las convierte en islas en lugar de ser simplemente un montón de aplicaciones independientes, ¿si son 100% independientes? :)

Nunca escribí ni dije que busco una solución "isla". Acabo de tener una conversación con @timneutkens donde describí mi problema y la respuesta de Tim fue básicamente next.js no admite rutas base. Y después de buscar en Google un poco, me di cuenta de que no soy el único que lo busca. Entonces pensé que podía contribuir un poco. Luego, Tim te hizo un ping para que me dieras un comentario y estoy muy agradecido por tus comentarios.

No veo cómo se podría hacer (fácilmente), ya que la exportación de rutas se realiza en el momento de la compilación y basePath se define en el momento de la implementación, y podría haber más de una implementación del mismo artefacto de código (etapa, preprod, prod, prueba env, etc.).

Bueno, si desea exportar rutas en el momento de la compilación y hacerlas disponibles para otras islas, entonces la única forma sencilla es probablemente codificar la ruta base en la configuración. Entiendo tu punto. Por otro lado, ¿es realmente un gran problema? Aún podría implementar la aplicación en diferentes dominios y puertos y podría usar la misma basePath para cada env.

Buenos días @tomaswitek :)

Mi experiencia con la funcionalidad "basePath", que es muy engañosa en su complejidad, y generalmente es mejor implementar ese tipo de cosas sin apresurarse con un problema específico,
pero mirándolo desde múltiples ángulos. Similar a cómo abordaría la fusión profunda: describa múltiples casos de uso y vea cómo (y si) todos caen bajo un mismo paraguas. Dado que tener características incompatibles entre las versiones (incluso las principales) del marco es muy molesto :)

Aún podría implementar la aplicación en diferentes dominios y puertos y podría usar la misma basePath para cada env.

Parece que estaría bien con la solución donde esa "basePath" es parte de su código de enrutamiento, algo que mencionó al principio, como una subcarpeta dentro del directorio pages (por cierto, ese enfoque indicaría a los desarrolladores elegidos basePath bastante bien). Pero lo único que lo detuvo es que la ruta interna de nextjs para los activos _next no es configurable.

Y eso suena como un problema más limitado que podemos resolver con menos efectos secundarios a largo plazo.

Y podría llevarnos aún más lejos, como si pudiéramos configurar assetPath por activo (por ejemplo, con el mapa next.config de algún tipo), nos permitirá tener activos compartidos entre las aplicaciones, lo que mejorará el rendimiento y otras cosas.

Y hay relaciones públicas abiertas para esa función. ;) / cc @timneutkens parece que es hora de volver con ese cachorro. :)

Si no va a agregar esto pronto, ¿podríamos agregar un servidor.js basado en expreso de ejemplo al archivo Léame que hace esto y funciona? Probé algunos que han estado flotando en estos problemas, pero no pude hacer que funcionen. Gracias.

Hola @ccarse , tengo una bifurcación de trabajo que ya usamos en producción: https://github.com/panter/next.js/pull/2
También estoy dispuesto a invertir tiempo para abrir un PR para esta función.
@timneutkens @alexindigo ¿hay alguna otra forma de resolver este problema?
Si no necesitamos una configuración basePath , ¿puede darnos un ejemplo mínimo usando assetPath ?

Mi empresa también se enfrenta a esto.

Lentamente, estamos asumiendo el control de una aplicación heredada, sección por sección, y reemplazándola con Next.js.

Como ejemplo simplificado:

| URL | Aplicación |
| --- | --- |
| example.com | legado |
| example.com/shop | siguiente |
| example.com/search | legado |
| example.com/members | siguiente |

Eso significa que queremos que todo tenga un prefijo dentro de cada aplicación Next.js ... páginas, rutas, activos, etc.

Es también digno de mención que no estamos usando ahora, así que no podemos tomar ventaja de now.json enrutamiento. Tenemos nuestro propio equilibrador de carga frente a todo el dominio y luego enruta el tráfico según la subruta.

También estamos usando un servidor personalizado (hapi), por lo que sería bueno si pudiéramos aprovechar lo que se crea aquí dentro de un servidor personalizado también.

Tal vez haya alguna combinación de configuraciones now.config.json o algún uso de micro-proxy que podamos usar para lograr lo mismo, pero aún no hemos descubierto la combinación correcta.

Creo que nos encontramos con el mismo problema con varias aplicaciones Next.js exportadas estáticamente alojadas en Now v2.

| URL | Aplicación |
| - | - |
| example.com | siguiente |
| example.com/dashboard | siguiente |

Como era de esperar, la aplicación raíz funciona bien. Sin embargo, las cosas salen mal en el segundo. Actualmente estamos envolviendo next/link que, combinado con assetPrefix , resuelve la mayor parte del problema:

export default ({ children, href, ...rest }) => (
      <Link href={process.env.NODE_ENV === "production" ? `/dashboard${href}` : href} {...rest}>
        {children}
      </Link>
);

Sin embargo, esto rompe prefetch porque luego intenta buscar archivos .js en la URL incorrecta:

Nuestra solución actual es deshabilitar prefetch , que no es lo ideal.

¿Cuál es el estado de esto?

También buscando una actualización sobre esto, por favor.

@timneutkens Estoy dispuesto a invertir tiempo para abrir un PR si la comunidad está interesada. Ya estamos usando una solución (https://github.com/panter/next.js/pull/1) en producción y estamos muy contentos con ella.

También necesitamos una solución para esto

Pronto presentaremos una nueva API que hará que esta propuesta quede obsoleta.

También afectado por esto. Necesita ejecutar el próximo proyecto en una ruta de subdirectorio. Esperando la función oficial. ¿Existe una ETA?

API

¿Asi que, como va todo? :RE

No envíe spam al hilo y use la función 👍 de GitHub en el problema en sí.

@timneutkens ¿Puede proporcionar más información? ¿Cuál es la API que hará que esto sea obsoleto? ¿Qué consideras "pronto"? Gracias.

Esto puede no estar exactamente relacionado con las multizona, pero puede ayudar ...

Resolví algo similar a esto creando un servidor personalizado y usando middleware proxy

por ejemplo: @Zertz
Tenga en cuenta: aún necesita resolver el problema del enlace: nuevamente, lo resolví creando un componente de enlace y pasando el prefijo a la aplicación a través de la configuración y, si existe un prefijo, use eso o no use nada, lo mismo para las imágenes estáticas.

const proxy = require('http-proxy-middleware');

app.setAssetPrefix('/dashboard');

  // Express custom server
  // Proxy so it works with prefix and without...
  // So if asset prefix is set then it still works
  const server = express();
  server.use(
    proxy('/dashboard', {
      target: 'http://localhost:3000', 
      changeOrigin: true,
      pathRewrite: {
        [`^/dashboard`]: '',
      },
    }),
  );

La propuesta que estaba mencionando es la # 7329

La propuesta que estaba mencionando es la # 7329

@timneutkens
¿Puede proporcionar más detalles sobre cómo el gancho propuesto resolverá nuestros problemas de ruta base?
¿Y qué pasa con los redireccionamientos del enrutador como Router.push('/about') , esto también será reemplazado por un gancho?

Gracias por tu tiempo 😏

La api del enrutador también cambiaría, ya que necesitaría un componente para conectarse. En ese momento, puede utilizar rutas relativas para la propia URL.

¿Alguna actualización sobre cuándo podemos obtener una solución o al menos una solución alternativa para esto?

Utilice 👍 en el problema inicial en lugar de publicar cualquier actualización.

@ MMT-LD Su solución funciona para mí, pero ahora, con cada clic de enlace o evento de inserción de enrutador, la página se vuelve a cargar ☹️

¡ Probé la solución de
También podría solucionar el problema prefetch copiando archivos de salida en las rutas precargadas.
https://github.com/fand/MDMT/blob/master/scripts/copy-preload.js

... es un truco sucio, pero de todos modos funciona working

@nicholasbraun

Ahora, en cada clic de enlace o evento de inserción de enrutador, la página se recarga ☹️

Tuve este problema, pero lo solucioné usando el parámetro 'como' en el enlace, por lo que el enlace apunta al archivo interno, pero el 'como' es relativo a la ruta
p.ej:
<Link href={"/${item.link}"} as={"./${item.link}"}>

@nicholasbraun

Su solución funciona para mí, pero ahora con cada clic de enlace o evento de inserción de enrutador, la página se vuelve a cargar ☹️

Esto es algo de lo que quise decir. Esto es de memoria ... pero estoy seguro de que no puede obtener lo que necesita a continuación.

// WithConfig component
import getConfig from 'next/config';

const { publicRuntimeConfig } = getConfig();

const WithConfig = ({ children }) =>
  children && children({ config: publicRuntimeConfig });

export default WithConfig;
// Extended Link component

 import React from 'react';
import PropTypes from 'prop-types';
import Link from 'next/link';
import { WithConfig } from '../WithConfig';
/* 
    <Link> component has two main props:
    href: the path inside pages directory + query string. e.g. /page/querystring?id=1
    as: the path that will be rendered in the browser URL bar. e.g. /page/querystring/1

*/

const NextLink = ({
  browserHref,
  pagesHref,
  whatever,
}) => {
  return (
    <WithConfig>
      {({ config: { pathPrefix } = {} }) => (
        <Link
          as={pathPrefix ? `${pathPrefix}${browserHref}` : browserHref}
          href={pagesHref}
          passHref
        >
          <a>{whatever}</a> // this bit is up to you - children or whatever
        </Link>
      )}
    </WithConfig>
  );
};

NextLink.propTypes = {
  browserHref: PropTypes.string.isRequired,
  pagesHref: PropTypes.string,
};

NextLink.defaultProps = {
  pagesHref: undefined,
};

export default NextLink;

Uso:

import NextLink from '../NextLink'

<NextLink browserHref={`/page/1`} pagesHref={`/page?querystring=1`} whatever='I'm the link' />

Buena suerte: smiley:

Dado que el useLink RFC ahora se ha rechazado (# 7329) y tener el soporte de basePath nos ayudaría mucho, ¿el proyecto Next.js está feliz de aceptar que los RP lo implementen? Estoy dispuesto a hacerlo.

Al observar esta implementación de @tomaswitek , parece que va en la dirección correcta, y lo más importante es que el enrutador sea consciente de basePath . ¿Hay otras cosas no obvias que dificultarían el soporte de basePath ?

En general, creo que el diseño es claro, solo una única variable de configuración:

module.exports = {
  basePath: '/demo'
}

Las interacciones con assetPrefix están bien definidas aquí: https://github.com/zeit/next.js/issues/4998#issuecomment -414978297.


ACTUALIZACIÓN : También estaba pensando si sería posible implementar esto creando un enrutador personalizado y de alguna manera intercambiando el predeterminado, pero no parece ser posible, Next.js codifica su enrutador, vea, por ejemplo, aquí . También soy escéptico de que "sólo" reemplazar el enrutador sería suficiente; la función probablemente deba ser compatible con Next.js en su conjunto.

Este problema existe desde 2017, ¿hay alguna solución? ¿O una respuesta oficial a nuestra solicitud basePath?

Entonces, después de intentar que esto funcione con la combinación de assetPrefix y un componente <Link> como se sugiere en, por ejemplo, https://github.com/zeit/next.js/issues/4998#issuecomment -464345554 o https://github.com/zeit/next.js/issues/4998#issuecomment -521189412, no creo que se pueda hacer, desafortunadamente.

Definir assetPrefix fue relativamente sencillo, algo como esto en next.config.js :

const assetPrefix = process.env.DEPLOYMENT_BUILD ? '/subdir' : '';

module.exports = {
  assetPrefix,
  env: {
    ASSET_PREFIX: assetPrefix,
  },
}

El siguiente paso es un componente Link . La primera idea, dada por ejemplo en https://github.com/zeit/next.js/issues/4998#issuecomment -464345554, es prefijar href así (simplificado):

export default ({ children, href, ...rest }) => (
  <Link href={`${process.env.ASSET_PREFIX}${href}`} {...rest}>
    {children}
  </Link>
);

Como informaron otros en este hilo, esto rompe la búsqueda previa ya que las solicitudes son repentinamente a / subdir /_next/static/.../pages/ subdir /example.js - el otro "subdir" no debería estar allí. Pero con nuestro componente Link , estamos configurando href en /subdir/example , por lo que no es de extrañar que Next.js solicite un paquete de la página pages/subdir/example.js .

Entonces, está bien, la búsqueda previa problemática no suena como el fin del mundo (aunque la UX es bastante fea), pero en nuestra aplicación, las cosas empeoran a medida que usamos el enrutamiento dinámico de Next.js 9. Para eso, necesitamos configurar as correctamente para que la evolución del componente Link vea así:

export default ({ children, href, as, ...rest }) => (
  <Link 
    href={`${process.env.ASSET_PREFIX}${href}`}
    as={`${process.env.ASSET_PREFIX}${as}`}
    {...rest}
  >
    {children}
  </Link>
);

El uso es:

<CustomLink href='/post/[id]' as='/post/1'>...</CustomLink>

que se convierte en:

<Link href='/subdir/post/[id]' as='/subdir/post/1'>...</Link>

y eso no funcionó para mí cuando se implementó en Now, tratando de navegar a https://deployment-id.now.sh/subdir/post/1 lead to 404. No estoy completamente seguro de por qué, tal vez también sea un problema con @now/next builder ( ACTUALIZACIÓN : se debe a https://github.com/zeit/next.js/pull/8426#issuecomment-522801831) pero, en última instancia, estamos confundiendo el enrutador de Next.js cuando pedimos /subdir/post/[id] componente cuando no existe tal archivo en el disco.

Hay otro ejemplo en este hilo, https://github.com/zeit/next.js/issues/4998#issuecomment -521189412, que tiene el prefijo solo como , no href, así (simplificado):

export default ({ children, href, as, ...rest }) => (
  <Link href={href} as={`${process.env.ASSET_PREFIX}${as}`} {...rest}>
    {children}
  </Link>
);

pero eso arrojará este error en el navegador:

El <Link> de as es incompatible con el href . Esto no es válido.

Es un problema informado en https://github.com/zeit/next.js/issues/7488.

Después de todo esto, no creo que haya una solución hasta que se admita algo como basePath , con lo que estaría feliz de ayudar.

@borekb También estoy listo para ayudar como mencioné un par de veces antes. Todas las soluciones que vi hasta ahora resuelven solo una parte del problema. Ahora mismo estamos usando una bifurcación de next.js en producción que implementa basePath.

Pronto presentaremos una nueva API que hará que esta propuesta quede obsoleta.

@tim ¿ https://github.com/zeit/next.js/issues/7329

Por cierto. mañana será exactamente un año en que abrí este número 🎉

Una idea relativamente descabellada es tener páginas en algo como src/pages y luego vincularlas simbólicamente a la ubicación adecuada. Por ejemplo:

  • Para implementar en myapp.example.com , enlazaría src/pages a pages
  • Para implementar en example.com/myapp , enlazaría src/pages a pages/myapp

En combinación con el componente <Link> y assetPrefix , _podría_ funcionar pero no soy lo suficientemente valiente para probarlo 😄.

¿Alguna actualización con eso?

¿Algún progreso en el soporte de basePath ? :)

@nicholasbraun

Ahora, en cada clic de enlace o evento de inserción de enrutador, la página se vuelve a cargar frowning_face

Tuve este problema, pero lo solucioné usando el parámetro 'como' en el enlace, por lo que el enlace apunta al archivo interno, pero el 'como' es relativo a la ruta
p.ej:
<Link href={"/${item.link}"} as={"./${item.link}"}>

¡Salvaste mi día! :)))

estoy haciendo lo mismo con Router.push(`/route`, `${process.env.BASE_PATH}route`);

@nicholasbraun

Ahora, en cada clic de enlace o evento de inserción de enrutador, la página se recarga ☹️

Tuve este problema, pero lo solucioné usando el parámetro 'como' en el enlace, por lo que el enlace apunta al archivo interno, pero el 'como' es relativo a la ruta
p.ej:
<Link href={"/${item.link}"} as={"./${item.link}"}>

Esta solución no funciona con el siguiente enrutamiento basado en 9 archivos. /route/[id] , ${process.env.BASE_PATH}/route${id} arroja este error

Este comentario explica muy bien el problema.

Aunque he visto a algunas personas discutir cómo las soluciones aquí rompen la búsqueda previa. Para nosotros hay otro tema más importante.

Con next9, usar un assetPrefix en su href hace que next _siempre_ realice una ruta de servidor. He creado un repositorio de reproducción en este número que demuestra que está sucediendo.

Básicamente, esto rompe nuestra caché de cliente Apollo, ya que se vuelve a crear en cada ruta.

Creo que la implementación está comparando la página subyacente href sin un assetPrefix, con las siguientes rutas href (que incluye un assetPrefix), lo que da como resultado una ruta profunda.

por ejemplo, si está en href /prefix/page (la página subyacente es solo /page ) y su próxima ruta href es /prefix/page/[id] (porque sin el prefijo será 404) esta es una ruta completamente diferente y no es posible una ruta poco profunda.

Buscando soluciones alternativas en el momento con rutas exprés

Cuando se usa componente con href props que es basePath, la captación previa no funciona.
PLZ admite basePath y prefetch, será increíble

Realmente podría usar esto. Estoy ejecutando varias aplicaciones desde una única fuente de servidor y cada una se ha separado en su propio web/appX/{next project files} . Sería genial tener más control sobre basePath. He descubierto una solución alternativa por ahora, pero no es muy bonita.

la exportación estática también necesita basePath 😊

parece trabajo exitoso 👏

{
  experimental:{
    basePath: '/some/dir',
  }
}

Desafortunadamente, esta es una limitación bastante mala para nosotros :(

Tenemos todas las aplicaciones detrás de un proxy inverso, por lo que las rutas deben tener un prefijo (en el siguiente ejemplo, este es el prefijo /auction-results )

Ya usamos el prefijo assetPrefix , y esto permite que las aplicaciones se ejecuten correctamente para las solicitudes del lado del servidor.
Por ejemplo: mydomain.com/auction-results/ funciona bien usando algún enrutamiento expreso como este:

router.get(`/${appPrefix}/`, (req, res) => {
  nextApp.render(req, res, '/national', req.params);
});

Pero cuando intentamos hacer navegación del lado del cliente a través de next/link , por ejemplo:

Donde /auction-results es el prefijo de la aplicación y /national es la página en ~pages/national

<Link href="/national" as="/auction-results/">
  <a>Goto National Page</a>
</Link>

Esto no hace nada (clic fantasma)

Tener enlaces de actualización de página completa no es lo ideal.

Si hay alguna forma en que pueda ayudar con esto, me encantaría

Cualquier actualización sobre esto ... el año pasado por esta época me encontré con este problema. Ahora, un año después, estoy trabajando en una nueva aplicación y tengo que hacer las mismas soluciones que hice el año pasado ... algo alarmante para una reacción fw 'lista para producción'. Los caminos base deben ser una característica básica.

Cualquier actualización sobre esto ... el año pasado por esta época me encontré con este problema. Ahora, un año después, estoy trabajando en una nueva aplicación y tengo que hacer las mismas soluciones que hice el año pasado ... algo alarmante para una reacción fw 'lista para producción'. Los caminos base deben ser una característica básica.

No estoy seguro de lo que esperas al publicar esto.

Mi equipo (5 personas) está trabajando en Next.js a tiempo completo, y estamos trabajando en muchas funciones al mismo tiempo. En el último año hemos trabajado en estos:

Hacer que las aplicaciones Next.js (nuevas y existentes) sean significativamente más pequeñas, más rápidas y más escalables.

Si desea expresar su "voto a favor" para una función, puede hacerlo. use la función 👍 en el hilo inicial.

Definitivamente estoy basePath acuerdo en que

Aquí está el PR: https://github.com/zeit/next.js/pull/9872

No dude en comunicarse con [email protected] si desea contribuir financieramente para hacer realidad esta función.

¿Cuál es el estado de esto? realmente dependemos de esto: /

El soporte de

cf. # 9872

@martpie ya lo vi, pero para. mi caso basePath no es solo uno, puede ser múltiples basesPath, ya que servimos nuestra aplicación a través de diferentes "URL" y configurar basePath durante el tiempo de compilación no es una opción (aunque tiene para admitir una serie de rutas en lugar de una sola cadena)

@timneutkens Gracias por la actualización. ¿Sería tan amable de darnos otra actualización? Esta es para nosotros una característica clave y necesitamos saber ...

  1. ¿Será solo para empresas (su referencia a las ventas de la empresa de contacto causó cierta irritación)?

  2. Parece estar en la hoja de ruta, según el PR, no se eliminará nuevamente; ¿Puede dar alguna indicación de si es seguro construir alrededor de esta función ahora sin recibir sorpresas en los próximos meses, como una versión de código abierto paralizada y otra con soporte completo después de que negociamos semanas con algunos vendedores al azar sobre precios arbitrarios?

Entiendo que ustedes trabajan en muchas funciones y todos tienen sus prioridades, pero incluso las configuraciones más pequeñas necesitan proxy Next, ejecutar múltiples instancias y darle un basePath dedicado por servicio. Antes de que comencemos a construir múltiples servicios en Next, necesitamos saber qué tan probable es y pronto esta función estará disponible como código abierto completo. De lo contrario, sería demasiado arriesgado invertir más tiempo en Next.

Gracias por su comprensión y esperando sus comentarios.

FWIW, ahora lo tengo funcionando y para otros que conducen por:

Pon esto en tu next.config.js :

module.exports = {
  experimental: {
    basePath: '/custom',
  },
}

Luego, necesitaba reiniciar el servidor y configurar correctamente el middleware de mi servidor web:

Capturo todas las solicitudes a través de una ruta personalizada, por ejemplo. app.use('/custom', (req, res...) => { ... y luego (lo cual fue importante) necesito enviar un proxy a la URL del sistema donde se está ejecutando Next (por lo tanto, la dirección interna de la orquestación de su contenedor y nuevamente con la ruta respectiva si usa http-proxy => eg. ... target: 'http://next:3000/custom ), por lo que no solo el host sin la ruta personalizada. Si usa http-proxy-middleware no lo necesita.

Se siente bastante bien, espero que esta función no necesite ninguna licencia EE. Si su equipo necesita ayuda para madurar esta función, háganoslo saber, ¡tal vez podamos ayudarlo!

Editar: Intenté esto también con el modo de producción de Next y parece que también funciona.

@timneutkens Gracias por la actualización. ¿Sería tan amable de darnos otra actualización? Esta es para nosotros una característica clave y necesitamos saber ...

  1. ¿Será solo para empresas (su referencia a las ventas de la empresa de contacto causó cierta irritación)?
  2. Parece estar en la hoja de ruta, según el PR, no se eliminará nuevamente; ¿Puede dar alguna indicación de si es seguro construir alrededor de esta función ahora sin recibir sorpresas en los próximos meses, como una versión de código abierto paralizada y otra con soporte completo después de que negociamos semanas con algunos vendedores al azar sobre precios arbitrarios?

Entiendo que ustedes trabajan en muchas funciones y todos tienen sus prioridades, pero incluso las configuraciones más pequeñas necesitan proxy Next, ejecutar múltiples instancias y darle un basePath dedicado por servicio. Antes de que comencemos a construir múltiples servicios en Next, necesitamos saber qué tan probable es y pronto esta función estará disponible como código abierto completo. De lo contrario, sería demasiado arriesgado invertir más tiempo en Next.

Gracias por su comprensión y esperando sus comentarios.

@ pe-s Creo que estás malinterpretando mi publicación.

No existe una "versión empresarial de Next.js" a partir de ahora. Me refería a las numerosas ocasiones en las que empresas externas se acercaron a pagar por consultoría para desarrollar funciones como esta en un período de tiempo más corto. Por ejemplo, el soporte de zonas se creó en colaboración con Trulia.

Esta característica aún se está trabajando y está en la hoja de ruta. Todas las funciones en las que se está trabajando son de código abierto, como dije, no hay una versión empresarial de Next.js. Tenemos múltiples prioridades de trabajo de alto impacto en la hoja de ruta, aunque por eso me referí a contactar a [email protected] si necesita esta función lo antes posible / para discutir el soporte empresarial para Next.js.

@timneutkens tx por su respuesta rápida y genial! Entonces, podemos ir con todo :)
¡Mantener el buen trabajo!

El soporte de ruta base está disponible en next@canary este momento, ya no es experimental. Pronto estará en el canal estable.

Llego bastante tarde para esto, pero ¿consideró usar HTML real

El soporte de ruta base está disponible en next@canary este momento, ya no es experimental. Pronto estará en el canal estable.

@timneutkens , gracias por esta adición. ¿Sabes cuándo se lanzará oficialmente el soporte no experimental de basePath?

Además, cuando configuro basePath, los activos (ubicados en la carpeta pública) se envían a la URL adecuada como se esperaba. Pero, cuando los hago referencia en mi código, entonces tengo que agregar la ruta base al src manualmente, porque de lo contrario todavía se hará referencia a ellos desde la ruta normal. ¿Es este el uso esperado de basePath? También intenté usar assetPrefix, pero no tuve ningún efecto en mi código que yo pudiera decir.

Ejemplo :

  1. usando next v9.4.5-canary.24
  2. basePath establecido en /alerts en next.config.js:
const basePath = '/alerts';
module.exports = {
  basePath: basePath,
  env: {
    BASE_PATH: basePath,
  },
};
  1. activo ubicado en public/images/example.png
  2. ejemplo de uso de activo en el componente de reacción:
const ExampleImage = () => (
  <img src={`${process.env.BASE_PATH}/images/example.png`} />
);

En mis pruebas, no actualiza las URL de activos.

Instalé el último canario:
npm install [email protected]

next.config.js

const isProd = process.env.NODE_ENV === 'production';

module.exports = {
  basePath: isProd ? '/example' : ''
}

Todas las páginas y enlaces se cargan correctamente:
http: // localhost : 3000 / example / posts / pre-rendering
http: // localhost : 3000 / example / posts / ssg-ssr
http: // localhost : 3000 / example / posts / pre-rendering

Pero las imágenes, favicons, etc.no están mapeados:
http: // localhost : 3000 / favicon.ico 404
http: // localhost : 3000 / images / profile.jpg 404

¿Alguien probó esto? También intenté usar assetPrefix, pero tampoco funcionó.

Además, estoy confundido, ¿por qué no usar la funcionalidad del navegador integrado para esto?
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base

Gracias por investigar esto también por su parte @kmturley . Me alegra saber que no soy solo yo.
@timneutkens , ¿deberíamos reabrir este problema / crear un nuevo problema para este error?

Tienes que prefijar las imágenes manualmente. Puede obtener el basePath usando

const {basePath} = useRouter()

https://nextjs.org/docs/api-reference/next.config.js/cdn-support-with-asset-prefix

Next.js usará automáticamente su prefijo en los scripts que carga, pero esto no tiene ningún efecto en la carpeta pública;

Ahora, me doy cuenta de que hay varias formas de vincular archivos en / public. por ejemplo, <img/> <link/> ...
¿Es por eso que tenemos que especificar manualmente la ruta base para cada uno?

Si hubiera un componente como el siguiente disponible, creo que ahorraría tiempo y reduciría las confusiones para mucha gente.

<WithinBasePath>
  {/* automatically fixes the path with basePath */}
  <img src="/logo.png" />
</WithinBasePath>

Realmente no creo que esto sea apropiado, pero esto es lo que quise decir.

// src/components/WithinBasePath/index.tsx

import React from "react"
import path from "path"
import { useRouter } from "next/router"
interface Props {}

const WithinBasePath: React.FC<Props> = (props) => {
  const { basePath } = useRouter()
  const children = [props.children].flatMap((c) => c) as React.ReactElement[]
  return (
    <>
      {children.map((child, key) => {
        let newChild = null

        switch (child.type) {
          case "img":
            newChild = React.createElement(child.type, {
              ...child.props,
              src: path.join(basePath, child.props.src),
              key,
            })
            break
          case "link":
            newChild = React.createElement(child.type, {
              ...child.props,
              href: path.join(basePath, child.props.href),
              key,
            })
            break
          default:
            newChild = React.createElement(child.type, {
              ...child.props,
              key,
            })
        }
        return newChild
      })}
    </>
  )
}
export default WithinBasePath

// pages/test.tsx

import React from "react"
import WithinBasePath from "@src/components/WithinBasePath"
interface Props {}

const test: React.FC<Props> = (props) => {
  return (
    <WithinBasePath>
      <img src="/123.jpg" />
      <link href="/abc.jpg" />
      <div>other element</div>
    </WithinBasePath>
  )
}
export default test

Para aquellos que intentan usar const {basePath} = useRouter() que es un gancho, para trabajar con clases y componentes y obtener este error:

Advertencia de llamada de gancho no válida

https://reactjs.org/warnings/invalid-hook-call-warning.html

Puede hacerlo funcionar usando:

import { withRouter, Router } from 'next/router'

class Example extends Component<{router: Router}, {router: Router}> {
  constructor(props) {
    super(props)
    this.state = {
      router: props.router
    }
  }
  render() {
    return (
      <Layout home>
        <Head><title>Example title</title></Head>
        <img src={`${this.state.router.basePath}/images/creators.jpg`} />
      </Layout>
    )
  }
}
export default withRouter(Example)

Si desea usar basePath con markdown, parece que necesita buscar y reemplazar en la cadena:

const content = this.state.doc.content.replace('/docs', `${this.state.router.basePath}/docs`);
return (
<Layout>
  <Container docs={this.state.allDocs}>
    <h1>{this.state.doc.title}</h1>
    <div
      className={markdownStyles['markdown']}
      dangerouslySetInnerHTML={{ __html: content }}
    />
  </Container>
</Layout>
)

Tienes que prefijar las imágenes manualmente. Puede obtener el basePath usando

const {basePath} = useRouter()

Sin embargo, esta solución no tiene en cuenta las imágenes importadas en un archivo css o scss. ¿Tiene una solución sobre cómo establecer la ruta base al importar un activo desde un archivo css o scss?
Con esta solución tendremos que asegurarnos de que todas las imágenes se importen a través de una etiqueta img, estilo en línea o en la etiqueta de estilo. No es ideal, porque dividirá sus estilos para implementarlos en varios lugares.

@peetjvv Aquí hay una solución subóptima para usar activos con basePaths prefijados en CSS. Cree, importe y agregue un componente <CSSVariables> en _app.tsx , que inyecta un elemento <style> global en línea que contiene variables CSS, que luego puede usar en todas sus hojas de estilo.

Por ejemplo, en la apertura de <body> construir e inyectar variables:

<style>
:root {
      --asset-url: url("${basePath}/img/asset.png");
}
</style>

Para obtener esa basePath utilizo el enfoque de withRouter .
Así es como podría verse ese componente:

import { withRouter, Router } from "next/router";
import { Component } from "react";

export interface IProps {
  router: Router;
}

class CSSVariables extends Component<IProps> {
  render() {
    const basePath = this.props.router.basePath;
    const prefixedPath = (path) => `${basePath}${path}`;
    const cssString = (value) => `\"${value}\"`;
    const cssURL = (value) => `url(${value})`;
    const cssVariable = (key, value) => `--${key}: ${value};`;
    const cssVariables = (variables) => Object.entries(variables)
      .map((entry) => cssVariable(entry[0], entry[1]))
      .join("\n");
    const cssRootVariables = (variables) => `:root {
      ${cssVariables(variables)}
    }`;

    const variables = {
      "asset-url": cssURL(
        cssString(prefixedPath("/img/asset.png"))
      ),
    };

    return (
      <style
        dangerouslySetInnerHTML={{
          __html: cssRootVariables(variables),
        }}
      />
    );
  }
}

export default withRouter(CSSVariables);
¿Fue útil esta página
0 / 5 - 0 calificaciones