Salidas, estilos y recursos

Las cuatro familias de recursos de una versión de paquete (módulos, estilos, mapas y recursos estáticos), cómo un import selecciona el JavaScript o la hoja de estilos de un módulo público, la hoja de estilos compartida de un paquete y cómo se anuncian los recursos complementarios.

  • Disponibilidad: Experimental
  • Evidencia: Leído del código fuente
  • Referencia

Cuatro familias bajo una misma identidad

Cada versión de un paquete tiene cuatro familias hermanas. Comparten el prefijo de identidad, de modo que un registro, un paquete, una versión o una subruta nunca es válido en una familia e inválido en otra.

Familia Ruta Tipo de medio Opciones
Módulo /m/[<registry>/]<package>@<version>/modules/<subpath> application/javascript
Estilo /m/[<registry>/]<package>@<version>/styles/<subpath> text/css
Mapa /m/[<registry>/]<package>@<version>/maps/<subpath> application/json (source map, revisión 3)
Recurso estático /m/[<registry>/]<package>@<version>/assets/<path> El tipo de medio del archivo No

El segmento de familia es el que sigue a <package>@<version>. Un registro o una subruta de módulo que casualmente se llame styles o assets se lee como antes.

Módulos

Una respuesta correcta de módulo contiene JavaScript, un ETag fuerte y el Cache-Control del servicio. Consulta Caché y releases para ambos encabezados.

Una solicitud devuelve un módulo público. El CDN nunca fusiona módulos públicos en un solo archivo ni divide uno en varios: el módulo público es la unidad de entrega, y sus imports de otros módulos públicos siguen siendo referencias simples que la resolución asigna a URL.

Estilos

Text
/m/@example/app@1.0.0/styles/core/router?target=browser&format=esm

Un estilo se direcciona con la subruta de un módulo público, ~root incluido. Es la hoja de estilos de ese módulo o bien un módulo de estilo, que es un módulo público cuya salida es CSS. Acepta las mismas opciones que la solicitud del módulo, con la misma validación.

Los estilos forman parte del cierre alcanzable de una aplicación. La preparación los rastrea como elementos de sus módulos. Una hoja de estilos nunca se descarta ni se inyecta en el JavaScript: es una salida separada, que enlaza o adopta quien entrega el módulo.

Un url() en una hoja de estilos, o un import de un archivo estático desde el código fuente, se escribe como ../assets/<path in the package>, relativo a donde este contrato sirve el módulo o su hoja de estilos. Por eso una misma salida funciona en cualquier origen.

Seleccionar una salida

Un módulo público puede tener varias salidas. El código fuente elige una con su especificador de import:

Especificador Selecciona
pkg/sub El JavaScript del módulo público ./sub. Es el predeterminado de todo import.
pkg/sub.css La hoja de estilos de ./sub: el módulo de estilo, o la hoja de estilos que produce el módulo. Cuando el paquete publica una subruta literal ./sub.css, como hacen los paquetes npm que exportan archivos CSS, se selecciona esa subruta.
pkg/sub.js, pkg/sub.mjs El JavaScript de ./sub.js cuando el paquete lo publica, y si no el de ./sub
Cualquier otra extensión Nada especial: forma parte de la subruta

La regla se comprueba cuando se compila o analiza el módulo que importa, y una selección incorrecta falla ahí, nunca en la entrega:

Diagnóstico Cuándo
OUTPUT_NOT_FOUND Un módulo que solo es una hoja de estilos importado sin .css (el mensaje nombra el especificador que hay que escribir), o .css de un módulo que no produce hoja de estilos
OUTPUT_AMBIGUOUS El especificador nombra dos módulos públicos distintos, como una subruta literal ./sub.css y un módulo ./sub con su propia hoja de estilos. No se adivina nada.
STYLE_BINDING_UNSUPPORTED Se pidió un valor a una hoja de estilos: import sheet from 'pkg/sub.css', un import con nombre de ella, o with { type: 'css' }

Una hoja de estilos seleccionada es una relación de estilo, no un import de código. Se quita del JavaScript compilado, import 'pkg/sub.css' no carga el código de ./sub, y el inventario de la preparación la lista como el elemento style de su módulo. Un documento de resolución asigna un especificador a una dirección /styles/ solo cuando el especificador termina en .css.

Quién aplica una hoja de estilos

Nada aplica CSS por una extensión: ni un navegador, ni SystemJS, ni un host de Node o de Deno lo hacen. Quien entrega el módulo aplica sus hojas de estilos de forma explícita:

  • Un documento enlaza las hojas de estilos de los módulos que carga fuera de cualquier widget. El shell de una aplicación publicada enlaza las inmediatas en su cabecera y las diferidas cuando el punto de entrada ya cargó.
  • Un widget adopta, dentro de su propia shadow root, su hoja de estilos y las de los módulos públicos que importa, mediante el registro de estilos del runtime. Un widget anidado tiene su propia raíz. Consulta Widgets y frameworks de vista.
  • Node.js y Deno no cargan ninguna hoja de estilos.

La hoja de estilos compartida de un paquete

Un paquete puede publicar una hoja de estilos que comparten todos sus widgets: el módulo de estilo ./global. Publicarlo es toda la declaración; no hay otra marca.

  • Cada módulo widget de ese paquete depende de ella de forma implícita: preparar un solo widget prepara también la hoja.
  • Cada widget la adopta dentro de su propia raíz, antes de sus propias hojas, y un widget de otro paquete no lo hace.
  • Un paquete sin ./global no produce ninguna solicitud de ella.
  • En un servidor de desarrollo, una actualización de la hoja la reemplaza en cada widget de ese paquete y en ningún otro; una hoja rota conserva la última válida.

Esto es distinto de seleccionar una hoja de estilos con .css: los widgets de su propio paquete adoptan la hoja compartida, mientras que .css selecciona la hoja de estilos de cualquier módulo público que nombres.

Source maps

Text
/m/@example/app@1.0.0/maps/core/router?target=browser&format=esm

Un mapa es el source map externo del JavaScript que seleccionan las mismas opciones. Solicítalo con las opciones del módulo al que pertenece.

Un mapa generado nunca nombra una ruta de la máquina que lo compiló. Cada entrada de sources se escribe bajo una raíz virtual, beyond://<package>@<version>/<path in the package>, para el código y las hojas de estilos en ambos formatos; lo que se generó para la unidad se nombra bajo ~generated/. Las salidas son reproducibles: el repositorio de Packages registra que las mismas fuentes, extraídas en dos directorios distintos, producen salidas, mapas y digests idénticos byte por byte. Los mapas de desarrollo son la excepción y conservan nombres relativos al directorio del módulo.

Que existan mapas para un release depende de un ajuste de la aplicación, sourcemaps:

Valor Efecto
restricted (predeterminado) Los mapas se conservan y se sirven solo a un miembro: 401 sin acceso y 403 para un invitado. El encabezado SourceMap se envía solo a quien se le serviría el mapa.
public Los mapas se exponen junto con el release
none No se conservan mapas; el release se prepara con sourcemap=none

Promover un release que expone mapas públicos exige una confirmación explícita. Consulta Releases, promoción y reversión.

Recursos estáticos

Text
/m/@example/app@1.0.0/assets/images/logo.png

Un recurso estático pertenece al paquete, no a uno de sus módulos. Su ruta es el archivo dentro del paquete, con sus barras y su extensión.

  • Un paquete declara recursos en un manifiesto de módulo (assets, relativo al directorio del módulo) o en su package.json (beyond.assets). Un archivo al que hace referencia un url() o un import del código fuente también se incluye en el inventario de un release. Un archivo que simplemente existe en el paquete no es un recurso, y un recurso que el servicio no tiene es 404 OUTPUT_NOT_AVAILABLE.
  • Una solicitud de recurso no acepta opciones. Cualquier consulta es 400 OPTION_INVALID.
  • Los segmentos vacíos, los segmentos . y .., las barras codificadas, las barras invertidas y los caracteres de control son 400 IDENTITY_INVALID, de modo que un recurso tiene una sola ruta y una solicitud nunca sale del paquete.

Cómo se anuncian los recursos complementarios

Un servicio anuncia un recurso complementario solo cuando la solicitud lo pide y el servicio lo sirve:

  • Con css=true, la respuesta de un módulo agrega un encabezado Link hacia su hoja de estilos.
  • Con types=true, la respuesta de un módulo agrega un encabezado Link hacia sus declaraciones, en un servicio que las produce.
  • La respuesta de una hoja de estilos puede llevar un encabezado SourceMap que apunta a su mapa externo.

Un servicio que no puede servir el recurso complementario rechaza la opción con OPTION_UNSUPPORTED en lugar de anunciar un recurso que no tiene. Nunca construyas la URL de un recurso complementario adivinándola: usa el encabezado o el inventario del release.

En código

JavaScript
import { ResourcePath } from '@beyond-js/artifact-api';

const style = ResourcePath.parse('/m/@example/app@1.0.0/styles/core/router');
style.kind; // 'style'
style.media; // 'text/css'
style.options(query); // the same Options as the module request

const asset = ResourcePath.parse('/m/@example/app@1.0.0/assets/images/logo.png');
asset.path; // 'images/logo.png'
asset.options(query); // undefined; any query throws OPTION_INVALID

ResourcePath.format({ kind: 'map', identity: style.identity }); // '/m/@example/app@1.0.0/maps/core/router'