Paquetes y módulos públicos
Cómo publica un módulo un paquete en un proyecto creado a partir de la plantilla beyond-web, cómo agregar un módulo público y un paquete hermano cuyo import bare se conserva, y cómo comprobar cada cambio.
- Disponibilidad: Experimental
- Evidencia: Ejecución registrada
- Guía práctica
Antes de empezar
Necesitas un proyecto creado a partir de la plantilla beyond-web 0.1.0 y su servidor de desarrollo en ejecución: consulta La plantilla del proyecto. Las palabras que se usan aquí están definidas en Desarrollar con Beyond.
Cómo publica un módulo un paquete
{
"name": "@project/app",
"version": "0.1.0",
"private": true,
"description": "The web application of this project",
"exports": {
"./main": "./main/index.ts"
},
"dependencies": {},
"beyond": {
"modules": ".",
"bundler": "ts"
},
"bundlers": {
"ts": "@beyond-js/packages/bundlers/ts"
}
}| Miembro | Significado |
|---|---|
name, version |
El paquete y su versión exacta. Las direcciones de los módulos siempre llevan esta versión, así que cuando la cambias la dirección cambia con ella |
exports |
Los módulos públicos. Una entrada cuyo destino es un punto de entrada de código fuente publica un módulo: "./main": "./main/index.ts" publica @project/app/main. Lo que ese archivo de entrada exporta, y solo eso, es la API pública del módulo |
dependencies |
Cada paquete que este importa por especificador bare. Un módulo del mismo paquete no necesita declaración |
beyond.modules |
El directorio del paquete en el que se buscan los archivos module.json. . es el propio paquete |
beyond.bundler |
El bundler predeterminado del paquete, que se aplica a cada módulo que no selecciona uno: ts |
bundlers |
El registro de bundlers: de dónde viene cada nombre de bundler. ts es @beyond-js/packages/bundlers/ts |
Un module.json junto al punto de entrada es opcional y agrega la especificación del módulo. En la plantilla declara dónde se ejecuta el módulo:
{
"platforms": ["web"]
}platforms es ["web"] para navegadores y ["node", "web"] para ambos. Un módulo solicitado para una plataforma que no declara falla con CONDITIONAL_NOT_FOUND.
Autores de paquetes, bundlers y procesadores
Para autoría Beyond con TypeScript y funciones específicas del módulo, comienza con module.json: declara el módulo y configura su compilación. No necesitas duplicarlo en los exports del paquete. Los auxiliares del módulo siguen siendo privados. Los exports del paquete son una vía alternativa asociada al empaquetado JavaScript estándar; también se aceptan destinos de código TypeScript. La plantilla combina ambas formas, pero no es obligatorio.
En la implementación actual, beyond.modules indica dónde descubrir los manifiestos. Un manifiesto deriva su subruta del directorio o define subpath; bundler selecciona una implementación registrada y, si falta, se usa beyond.bundler. Un módulo declarado sólo por manifiesto que use el bundler ts actual define entry, relativo a su directorio, por ejemplo index.ts. Su identidad pública combina el nombre del paquete y la subruta. Esta vía se observó en el código; no es un tutorial adicional ejecutado.
Los artefactos compilados y su mapa de imports son distintos de las declaraciones de autoría. El escritor de distribuciones lista las salidas en beyond-distribution.json; no reescribe automáticamente los exports del paquete.
Un autor de bundlers puede implementar directamente el contrato de módulo y condicional, o usar el SDK opcional @beyond-js/packages/sdk para componer procesadores reutilizables. Un autor de procesadores implementa transformaciones usadas por esos bundlers. Ni crear un paquete ni implementar un bundler exige una capa separada de packager.
Agregar un módulo público con las declaraciones combinadas de la plantilla
- Crea un directorio en el paquete, por ejemplo
packages/app/settings/, con un punto de entradaindex.tsy unmodule.jsoncomo{ "platforms": ["web"] }. - Agrégalo a los
exportsdepackages/app/package.json:"./settings": "./settings/index.ts". - Exporta su API pública desde
index.ts. Deja los auxiliares en otros archivos del directorio e impórtalos con rutas relativas. - Impórtalo desde otros módulos como
@project/app/settings.
Agregar un paquete hermano con un import bare conservado
Esta es la forma de compartir código entre paquetes. El ejemplo agrega @project/shared con un módulo text que la aplicación importa.
- Crea
packages/shared/package.json:
{
"name": "@project/shared",
"version": "0.1.0",
"private": true,
"exports": { "./text": "./text/index.ts" },
"dependencies": {},
"beyond": { "modules": ".", "bundler": "ts" },
"bundlers": { "ts": "@beyond-js/packages/bundlers/ts" }
}- Crea
packages/shared/text/module.jsoncon{ "platforms": ["web"] }, y el punto de entradapackages/shared/text/index.ts:
export const greeting = (name: string): string => `Hello from shared, ${name}`;- Registra el paquete en
beyond.json:
{
"packages": ["packages/app", "packages/shared"]
}- Declara la dependencia en
packages/app/package.json. Laversiondel paquete del workspace debe satisfacer el rango que declares:
{
"name": "@project/app",
"version": "0.1.0",
"private": true,
"description": "The web application of this project",
"exports": {
"./main": "./main/index.ts"
},
"dependencies": {
"@project/shared": "0.1.0"
},
"beyond": {
"modules": ".",
"bundler": "ts"
},
"bundlers": {
"ts": "@beyond-js/packages/bundlers/ts"
}
}- Impórtalo por su especificador bare, por ejemplo en
packages/app/main/texts.ts:
import { greeting } from '@project/shared/text';
/**
* What the element says. The title now comes from a public module of another package, imported by its
* bare specifier.
*/
export const texts = {
title: greeting('Beyond'),
description: 'This page is the public module @project/app/main, compiled and served by Beyond Packages.',
action: 'Count',
count: (value: number): string => (value === 1 ? '1 click' : `${value} clicks`)
};Los manifiestos (beyond.json, package.json, module.json) se leen de nuevo en la siguiente solicitud al servidor de desarrollo. No lo reinicias.
Resultado esperado: <endpoint>/preview/entry.json lista @project/shared/text con "source": "environment", y el módulo compilado de la aplicación todavía contiene from '@project/shared/text'. Los dos módulos son dos artefactos; el código de uno no se copia dentro del otro.
Comprobar un cambio
Cada comprobación prueba una sola cosa. Una compilación exitosa no prueba el renderizado.
# <endpoint> is the address the development server printed when it started.
# It compiles, and every module has an address: "diagnostics" is []
curl -s <endpoint>/preview/entry.json
# Every public module of the workspace builds: each one is "valid", or lists its diagnostics
curl -s <endpoint>/state
# The boundary is preserved: the compiled module keeps from '<bare specifier>' for other public modules
curl -s "<endpoint>/m/@project/[email protected]/modules/main?target=browser&format=esm&env=development&min=false&sourcemap=none&types=false&css=false"Luego carga <endpoint>/preview/ en un navegador para comprobar el renderizado, los estilos y el comportamiento. Después de una edición, cárgala de nuevo: la página en ejecución no se actualiza en su lugar.
Reglas que mantienen el límite
- Nunca importes cruzando el límite de un módulo con una ruta relativa. Usa el especificador público.
- Nunca agregues una entrada de
exportspara un archivo interno solo para que funcione un import. Decide primero si es API pública. - El bundler
tsde la plantilla selecciona fuentes.ts/.tsxy no emite código de ejecución para.d.ts. Mantén las pruebas fuera de esas entradas hasta que se admita su exclusión; la selección de fuentes depende del bundler. - No llames
modulea un directorio interno:./modulese resolvería al manifiestomodule.json. - Los módulos para navegador no deben importar módulos integrados de Node.
- No escribas en
.beyond/y no lo agregues al control de versiones. Contiene la selección de desarrollo, que cambia solo cuando alguien lo pide.
Cuando la compilación se niega
| Código | Significado | Qué hacer |
|---|---|---|
DEPENDENCY_NOT_DECLARED |
Un paquete se importa por especificador bare y no está en las dependencies del paquete que lo importa |
Decláralo |
DEPENDENCY_INCOMPATIBLE |
La version del paquete del workspace no satisface el rango declarado |
Corrige el rango o la versión |
CONDITIONAL_NOT_FOUND |
El módulo se solicitó para una plataforma que su module.json no declara |
Agrega la plataforma a platforms, si el módulo de verdad se ejecuta allí |
PREVIEW_BUILTIN |
Un módulo para navegador importa un módulo integrado de Node | Quita el import |
PREVIEW_CDN_UNSET |
El servidor se inició sin BEYOND_CDN_ORIGIN |
Inícialo de nuevo con la variable definida. No lo esquives |
PREVIEW_VERSION_UNRESOLVED |
Un paquete de fuera del workspace no tiene una versión exacta instalada o declarada | Declara la versión exacta |
Límites
- Un paquete del workspace que no está seleccionado para desarrollo se solicita al CDN en la versión de su
package.json, así que tiene que haberse publicado allí. Hasta que alguien selecciona, todos los paquetes del workspace están en desarrollo. - La plantilla, versión 0.1.0, no declara ningún widget ni ninguna hoja de estilos: su elemento está construido con estándares web, consulta el elemento y sus estilos. El bundler que selecciona sí compila ambos: consulta Crear un widget Beyond y Estilos.
- Publicar un paquete y hacer un release de una aplicación son operaciones distintas, con sus propias herramientas y permisos, y el proyecto no tiene ningún comando para ninguna de las dos. Las guías del CDN describen cómo publicar fuentes de Beyond en npm.
Siguiente acción
Mira cómo se direcciona por HTTP el módulo compilado: URL e identidades.