web/vite.changelog.ts
Rama main · réplica de lectura del repositorio original.
// The What's new notes as a Vite plugin (vite.config.ts): CHANGELOG.md, read at build time.
import { existsSync, readFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import type { Plugin } from 'vite';
import { RELEASE_VERSION, releaseSection, releaseVersions, unreleasedSection } from './src/whatsnew/changelog.ts';
/**
* The What's new dialog's notes: the repository's CHANGELOG.md, read at build time (docker/web.Dockerfile copies it
* next to web/). `virtual:mdmesh-changelog` holds the versions with a section, and loads the sections themselves as
* a chunk of their own (`virtual:mdmesh-changelog/notes`), cut by release/changelog-section.sh's rules
* (src/whatsnew/changelog.ts). Unreleased is in dev builds only (`vite`, and tests). Types: src/whatsnew/virtual.d.ts.
* A production build fails without CHANGELOG.md; a dev server or test run only warns. `file` is for tests.
*/
export function changelogNotes(
appVersion: string | undefined,
file = fileURLToPath(new URL('../CHANGELOG.md', import.meta.url)),
): Plugin {
const INDEX = 'virtual:mdmesh-changelog';
const NOTES = 'virtual:mdmesh-changelog/notes';
let dev = true;
return {
name: 'mdmesh-changelog',
configResolved(config) {
dev = !config.isProduction;
},
resolveId(id) {
return id === INDEX || id === NOTES ? `\0${id}` : null;
},
load(id) {
if (id !== `\0${INDEX}` && id !== `\0${NOTES}`) return null;
let text = '';
if (existsSync(file)) {
this.addWatchFile(file);
text = readFileSync(file, 'utf8');
} else if (!dev) {
// A release image without its notes would show What's new to no one, silently: refuse to build it.
this.error(`${file} not found: a production build needs it for What's new (docker/web.Dockerfile copies it next to web/)`);
} else {
this.warn(`${file} not found: the console runs without What's new notes`);
}
const versions = releaseVersions(text);
const unreleased = dev ? unreleasedSection(text) : null;
if (id === `\0${INDEX}`) {
const v = appVersion?.replace(/^v/, '');
if (!dev && v && RELEASE_VERSION.test(v) && !versions.includes(v)) {
this.warn(`CHANGELOG.md has no section for VITE_APP_VERSION ${v}: What's new shows nothing for it`);
}
return [
`export const versions = ${JSON.stringify(versions)};`,
`export const hasUnreleased = ${unreleased !== null};`,
`export const load = () => import(${JSON.stringify(NOTES)});`,
].join('\n');
}
const sections = Object.fromEntries(versions.map((v) => [v, releaseSection(text, v)]));
return `export const sections = ${JSON.stringify(sections)};\nexport const unreleased = ${JSON.stringify(unreleased)};`;
},
};
}