diff --git a/CHANGELOG.md b/CHANGELOG.md index bc52411..4e461d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,17 @@ All notable changes to this project are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.0.0-prerelease.7] - 2026-11-09 + +### Fixed + +- **`.md` fences render in `astro dev`.** On a `.md` page with no React island, + the fence script failed with `@vitejs/plugin-react can't detect preamble`, + because @astrojs/react installs React's fast-refresh preamble only on pages + with an island. The script now imports `@vitejs/plugin-react/preamble` before + the diagram code when no preamble is installed. Builds were unaffected; the + module is empty outside dev. + ## [1.0.0-prerelease.6] - 2026-11-09 ### Added diff --git a/docs/wiki/Troubleshooting.md b/docs/wiki/Troubleshooting.md index ed6309e..d377131 100644 --- a/docs/wiki/Troubleshooting.md +++ b/docs/wiki/Troubleshooting.md @@ -132,6 +132,10 @@ component). If it never mounts: and a page script containing `[data-astroc4-fence]`. 3. A page rendered outside Astro's pipeline (raw HTML, a custom renderer) does not get the injected script. +4. In `astro dev` on `1.0.0-prerelease.6`, the console shows + `@vitejs/plugin-react can't detect preamble`: @astrojs/react installs React's + fast-refresh preamble only on pages with an island. Upgrade to + `1.0.0-prerelease.7`, whose script installs it first. Builds are unaffected. ## Build fails: `Several LikeC4 projects exist (…); pass project="…"` diff --git a/package.json b/package.json index 412b902..b2b5f1b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@purview-dev/astroc4", - "version": "1.0.0-prerelease.6", + "version": "1.0.0-prerelease.7", "description": "Interactive LikeC4 architecture diagrams for Astro and Starlight: , ```likec4 fences, and LikeC4 syntax highlighting derived from the live Langium grammar.", "license": "MIT", "author": { diff --git a/src/__tests__/integration.test.ts b/src/__tests__/integration.test.ts index c6b80a9..d878c08 100644 --- a/src/__tests__/integration.test.ts +++ b/src/__tests__/integration.test.ts @@ -89,6 +89,26 @@ describe('likec4Integration', () => { expect(injectScript).toHaveBeenCalledWith('page', expect.stringContaining(`import('${PACKAGE_NAME}/components/md-fences')`)); }); + // In dev, @astrojs/react installs the fast-refresh preamble only on pages with an + // island, and a .md page has none: React components then throw "can't detect preamble". + it('installs the React preamble before it loads the .md fence components', async () => { + const injectScript = vi.fn(); + + await likec4Integration().hooks['astro:config:setup']!({ + command: 'dev', + config: { root: pathToFileURL(process.cwd()), vite: {}, integrations: [] }, + updateConfig: vi.fn(), + injectScript, + logger: stubLogger(), + } as never); + + const script: string = injectScript.mock.calls.find(([stage]) => stage === 'page')![1]; + const preamble = script.indexOf(`import('@vitejs/plugin-react/preamble')`); + + expect(preamble).toBeGreaterThan(-1); + expect(preamble).toBeLessThan(script.indexOf(`import('${PACKAGE_NAME}/components/md-fences')`)); + }); + it('registers the fence transform with the site Markdown processor', async () => { const { updateConfig } = await setup(); diff --git a/src/integration.ts b/src/integration.ts index 8fe62ba..3eb26e6 100644 --- a/src/integration.ts +++ b/src/integration.ts @@ -42,11 +42,18 @@ const OPTIMIZED_DEPENDENCIES = ['react/compiler-runtime']; /** * Mounts the fences of .md pages. Injected into every page, so React and LikeC4 * are only `import()`ed on a page that has a placeholder. + * + * In dev, @astrojs/react installs React's fast-refresh preamble only on pages with + * an island, and a .md page has none, so the script installs it first. Outside dev, + * @vitejs/plugin-react serves the preamble module empty. */ const MD_FENCES_SCRIPT = [ `const mountLikeC4Fences = () => {`, ` if (!document.querySelector('[data-astroc4-fence]:not([data-astroc4-mounted])')) return;`, - ` import('${PACKAGE_NAME}/components/md-fences').then((module) => module.mountFences());`, + ` const preamble = window.$RefreshReg$ ? Promise.resolve() : import('@vitejs/plugin-react/preamble');`, + ` preamble`, + ` .then(() => import('${PACKAGE_NAME}/components/md-fences'))`, + ` .then((module) => module.mountFences());`, `};`, `if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', mountLikeC4Fences);`, `else mountLikeC4Fences();`,