You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
senzapaura_es/vite.config.ts

189 lines
6.5 KiB

import { sep } from 'node:path';
import { mdsvex } from 'mdsvex';
import remarkBreaks from 'remark-breaks';
import { defineConfig } from 'vitest/config';
import { playwright } from '@vitest/browser-playwright';
import adapter from '@sveltejs/adapter-node';
import { sveltekit } from '@sveltejs/kit/vite';
import type { PreprocessorGroup } from 'svelte/compiler';
import { conExtracto } from './src/lib/content/extracto.ts';
import { ancla } from './src/lib/content/anclas.ts';
/**
* Dos aplicaciones, un repositorio.
*
* `APP=panel` compila la administración; sin esa variable, la web pública. Cada
* una tiene su carpeta de rutas, sus hooks y su carpeta de salida, así que **el
* servidor público no lleva dentro ni una línea del panel**: no es que la
* esconda, es que ahí no existe. Cada una se sirve en su dominio y en su
* proceso, como los archivos en `m.senzapaura.es`.
*
* Comparten `src/lib`, que es donde están el esquema, las consultas y el
* acceso. Con dos repositorios habría que mantener las migraciones por
* duplicado, y el día que se desincronizaran nadie se enteraría hasta que el
* panel guardara en una columna que ya no existe.
*/
const esPanel = process.env.APP === 'panel';
/**
* Escribe en el frontmatter de cada cancion los primeros versos de su letra.
*
* Tiene que correr ANTES que mdsvex: despues, el cuerpo ya es un componente
* compilado y el texto ha dejado de ser texto. Con esto, las tarjetas pueden
* ensenar unos versos sin que nadie mantenga a mano un campo de resumen.
*/
const inyectarExtracto: PreprocessorGroup = {
name: 'extracto-de-cancion',
markup({ content, filename }) {
// En Windows los nombres llegan con barras invertidas.
if (!filename?.split(sep).join('/').includes('/src/content/canciones/')) return;
const conFragmento = conExtracto(content);
return conFragmento === content ? undefined : { code: conFragmento };
}
};
/**
* Pone un `id` a cada encabezado de nivel 2 del Markdown.
*
* Hace falta para que el indice lateral de los textos largos pueda enlazar a
* sus apartados. Se escribe a mano en vez de traer `rehype-slug` porque son
* quince lineas, y porque el ancla tiene que salir de la misma funcion que usa
* el cargador al construir el indice: con dos implementaciones parecidas, un
* dia dejan de coincidir.
*/
type NodoHast = {
type: string;
tagName?: string;
value?: string;
properties?: Record<string, unknown>;
children?: NodoHast[];
};
function textoDe(nodo: NodoHast): string {
if (nodo.type === 'text') return nodo.value ?? '';
return (nodo.children ?? []).map(textoDe).join('');
}
function anclasEnEncabezados() {
return (arbol: NodoHast) => {
const recorrer = (nodo: NodoHast) => {
if (nodo.tagName === 'h2') {
nodo.properties = { ...nodo.properties, id: ancla(textoDe(nodo)) };
}
for (const hijo of nodo.children ?? []) recorrer(hijo);
};
recorrer(arbol);
};
}
/**
* mdsvex 0.12 emite `<script context="module">` para exportar el frontmatter,
* sintaxis que Svelte 5 marca como obsoleta. El aviso apunta a los .md de
* contenido, donde no hay nada que corregir, y sale uno por archivo en cada
* compilacion.
*
* Se corrige la salida en lugar de silenciar el aviso: `sveltekit()` ignora
* `onwarn` cuando la configuracion viaja en el propio vite.config.ts.
*/
const corregirScriptDeMdsvex: PreprocessorGroup = {
name: 'mdsvex-script-module',
markup({ content, filename }) {
if (!filename?.endsWith('.md') && !filename?.endsWith('.svx')) return;
if (!content.includes('<script context="module">')) return;
return {
code: content.replaceAll('<script context="module">', '<script module>')
};
}
};
export default defineConfig({
plugins: [
sveltekit({
compilerOptions: {
// Force runes mode for the project, except for libraries. Can be removed in svelte 6.
runes: ({ filename }) =>
filename.split(/[/\\]/).includes('node_modules') ? undefined : true
},
/*
* Lo único que distingue a las dos aplicaciones: de dónde salen las
* rutas, qué hooks corren y dónde se escribe el resultado. Los `.svelte-kit`
* también van separados, porque ahí dentro está el manifiesto de rutas
* y con uno compartido cada build borraría el del otro.
*/
files: esPanel
? { routes: 'src/panel/rutas', hooks: { server: 'src/panel/hooks.server' } }
: undefined,
outDir: esPanel ? '.svelte-kit-panel' : '.svelte-kit',
adapter: adapter({ out: esPanel ? 'build-panel' : 'build' }),
paths: {
/*
* Rutas absolutas para los recursos —`/_app/…`— en vez de las
* relativas que SvelteKit usa por defecto.
*
* Hace falta por la página de espera: su HTML se sirve en la
* dirección que pidió quien llega, no en `/proximamente`. Con rutas
* relativas, un visitante en `/musica/baladas-romanticas` pedía sus
* hojas de estilo en `/musica/_app/…` y no encontraba ninguna.
*
* No se pierde nada: las relativas sirven para poder mover el sitio a
* un subdirectorio sin reconstruir, y este vive en la raíz de su
* dominio.
*/
relative: false
},
preprocess: [
inyectarExtracto,
mdsvex({
extensions: ['.svx', '.md'],
// Sin remark-breaks, Markdown junta los versos de una letra en un
// unico parrafo: en una cancion el salto de linea es contenido.
// mdsvex declara los plugins con una version antigua de los tipos de
// unified, incompatible con la de remark-breaks 4. En ejecucion
// encajan; lo que choca es solo la firma.
// @ts-expect-error tipos de unified desalineados entre mdsvex y remark-breaks
remarkPlugins: [remarkBreaks],
rehypePlugins: [anclasEnEncabezados]
}),
corregirScriptDeMdsvex
],
extensions: ['.svelte', '.svx', '.md'],
typescript: {
config: (config) => {
config.include.push('../drizzle.config.ts');
}
}
})
],
test: {
expect: { requireAssertions: true },
projects: [
{
extends: './vite.config.ts',
test: {
name: 'client',
browser: {
enabled: true,
provider: playwright(),
instances: [{ browser: 'chromium', headless: true }]
},
include: ['src/**/*.svelte.{test,spec}.{js,ts}'],
exclude: ['src/lib/server/**']
}
},
{
extends: './vite.config.ts',
test: {
name: 'server',
environment: 'node',
// Tambien las herramientas de `scripts/`: colocan archivos de audio
// segun una convencion de nombres, y equivocarla no da ningun error.
include: ['src/**/*.{test,spec}.{js,ts}', 'scripts/**/*.spec.mjs'],
exclude: ['src/**/*.svelte.{test,spec}.{js,ts}']
}
}
]
}
});

Powered by TurnKey Linux.