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.
{
"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.cssnunca 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 eltargety elformatdel 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 respondeimports. - 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:
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+jsontargetyformatvan 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 es400 OPTION_INVALID.importmap.jsones 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
ETagfuerte, respondenIf-None-Matchcon304y 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:
// 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.