Resolución

El documento beyond-resolution/1 y el import map que todo origen responde en /resolution.json y /importmap.json, que asignan cada especificador público a una URL relativa al origen, con ámbitos para versiones que conviven.

  • Disponibilidad: Experimental
  • Evidencia: Ejecución reproducida
  • Referencia

Qué es

Un documento beyond-resolution/1 indica qué URL entrega cada especificador público, para un target y un formato. Todos los valores son relativos al origen: una ruta canónica más la consulta canónica. Por eso un mismo documento funciona en un origen de desarrollo y en uno publicado, y un consumidor antepone el origen con el que fue configurado.

JSON
{
  "protocol": "beyond-resolution/1",
  "release": "r-42",
  "target": "browser",
  "format": "esm",
  "imports": {
    "@example/app": "/m/@example/[email protected]/modules/~root?target=browser&format=esm&env=production&min=true&sourcemap=external&types=false&css=false"
  },
  "scopes": {
    "/m/@example/[email protected]/": {
      "library/main": "/m/[email protected]/modules/main?target=browser&format=esm&env=production&min=true&sourcemap=external&types=false&css=false"
    }
  }
}

Miembros

Miembro Obligatorio Regla
protocol Sí beyond-resolution/1
release No El release al que pertenece el documento. Es opaco para el contrato. La salida de desarrollo no tiene ninguno.
target Sí browser o node
format Sí esm, cjs o system
imports Sí URL relativa al origen por especificador público
scopes Sí Para cada prefijo de ámbito, los imports que reemplazan a imports para los importadores que están bajo él. Puede estar vacío.

Reglas

  • Un especificador es un módulo público y se compara de forma exacta. No hay asignaciones por prefijo. Se resuelve a una ruta de módulo, o a una ruta de estilo solo cuando el especificador termina en .css (selección de salida). Un especificador sin .css nunca se resuelve a una hoja de estilos.
  • Un valor se acepta solo cuando el códec compartido lo lee y lo vuelve a escribir sin cambios: la ruta canónica (sin el alias /m/npm/), la consulta canónica, y el target y el format del documento. Se rechaza un esquema, un host, un fragmento o una consulta ausente.
  • Un ámbito es una ruta relativa al origen bajo /m/. Un ámbito que termina en / coincide con todos los importadores que están bajo él; cualquier otro ámbito coincide con una sola ruta. Gana el ámbito más largo que contiene el especificador, y en caso contrario responde imports.
  • Un documento que incumple una regla se rechaza con RESOLUTION_INVALID. Es un error del códec del lado del cliente; no es uno de los códigos de error HTTP de las rutas de entrega.

Los ámbitos son la forma en que conviven dos versiones de un paquete en una aplicación: los módulos de @example/legacy del ejemplo conservan [email protected] mientras todos los demás reciben la versión de imports.

Las rutas

Todo origen del contrato responde la resolución que sirve, en dos formas:

Text
GET <base>/resolution.json[?target=<browser|node>&format=<esm|cjs|system>]    beyond-resolution/1, application/json
GET <base>/importmap.json[?target=<browser|node>&format=<esm|cjs|system>]     import map, application/importmap+json
  • target y format van juntos, o ninguno: sin ellos el servicio responde su documento predeterminado. Cualquier otra opción, una repetida, un valor inválido o solo una de las dos es 400 OPTION_INVALID.
  • importmap.json es la misma resolución como import map estándar, cuyas direcciones y claves de ámbito son todas relativas al documento (./m/…). Un consumidor que carga el mapa desde su URL lo resuelve en el origen que lo sirvió, prefijo de ruta incluido: Deno con --import-map=<base>/importmap.json?…, y SystemJS con <script type="systemjs-importmap" src="…">. Una página que incluye el mapa en línea resuelve las direcciones respecto de sí misma, así que necesita direcciones absolutas: resolution.importmap(origin).
  • Las respuestas llevan un ETag fuerte, responden If-None-Match con 304 y puede leerlas una página de otro origen, como todo recurso del contrato.
Servidor de desarrollo CDN
Dónde El origen del servicio La base de un release, /_r/<release number>, y en el host de una aplicación el alias del release vinculado. El origen de entrega compartido no tiene ninguno (404 NOT_FOUND).
Qué Se calcula a partir del workspace en cada solicitud, no-store. Para navegadores lista además los paquetes instalados y las hojas de estilos a las que llegan las compilaciones; el documento de Node lista solo los módulos del workspace. Los documentos almacenados cuando se preparó el release, uno por target y formato, con la política de caché del release. Nunca cambian.
Sin consulta El documento de módulos ES para Node El documento del target predeterminado
Un target o formato que no tiene 400 OPTION_UNSUPPORTED (format=cjs) 404 OUTPUT_NOT_AVAILABLE, nunca una compilación

Cómo usarlo

La herramienta de verificación de este sitio ejecuta este ejemplo contra el códec compartido:

JavaScriptresolve.mjs
// Read a beyond-resolution/1 document with the shared codec. Its values are
// origin-relative, so the same document serves any base origin.
import { Resolution } from '@beyond-js/artifact-api';

const query = 'target=browser&format=esm&env=production&min=true&sourcemap=external&types=false&css=false';

const resolution = new Resolution({
	protocol: 'beyond-resolution/1',
	release: 'r-42',
	target: 'browser',
	format: 'esm',
	imports: {
		'@example/app': `/m/@example/[email protected]/modules/~root?${query}`,
		'library/main': `/m/[email protected]/modules/main?${query}`,
		// Only a specifier that ends with ".css" resolves to a stylesheet
		'@example/app/theme.css': `/m/@example/[email protected]/styles/theme?${query}`
	},
	scopes: {
		// Modules of @example/legacy keep the version of "library" they were tested with
		'/m/@example/[email protected]/': { 'library/main': `/m/[email protected]/modules/main?${query}` }
	}
});

const importer = '/m/@example/[email protected]/modules/widget';

console.log(resolution.resolve('library/main'));
console.log(resolution.resolve('library/main', importer));
console.log(resolution.url('https://cdn.example', '@example/app'));
console.log(resolution.resolve('@example/app/theme.css'));

// Absolute addresses, for a map inlined in a page of another origin
console.log(JSON.stringify(resolution.importmap('http://localhost:8080'), null, 2));
// Addresses relative to the document, as a service answers /importmap.json
console.log(JSON.stringify(resolution.importmap(), null, 2));
Llamada Resultado
new Resolution(values), Resolution.parse(text) Valida el documento; lanza RESOLUTION_INVALID
resolve(specifier, importer?) La URL relativa al origen, o undefined. El importador es una URL o una ruta relativa al origen.
url(origin, specifier, importer?) La URL absoluta en un servicio
importmap(origin) { imports, scopes } con URL absolutas, para un mapa en línea en una página
importmap() { imports, scopes } relativo a un documento en la base (./m/…), que es lo que responde /importmap.json
serialize() El documento con un orden de claves estable, para que resoluciones iguales se serialicen igual

ResolutionRequest.parse(pathname, query) lee una solicitud de cualquiera de las dos rutas e indica qué target y qué formato selecciona, para un servicio que las implementa.

Un release nunca vuelve a resolver

Un release lleva su resolución. La API de administración informa su ubicación como urls.resolution del release, como una URL relativa al origen, y el cierre de backend de un target incluye la resolución congelada de ese target. La resolución de un release nunca cambia: la promoción y la reversión eligen un release, no lo vuelven a resolver.

Cada entorno consume estos documentos a su manera; consulta Estrategias por entorno.