From eb9ca3f3e15974b66159c59bd10e590d8ccc4d16 Mon Sep 17 00:00:00 2001 From: Tate Date: Wed, 22 Jan 2025 11:40:47 +1300 Subject: [PATCH 1/7] Add support for astro 5 --- CHANGELOG.md | 5 ++ .../engines/astro-engine/lib/builder.js | 70 ++++++++++++++----- .../astro-engine/lib/modules/actions.js | 51 ++++++++++++++ .../astro-engine/lib/modules/assets.js | 27 +++++++ .../lib/modules/client-router.astro | 3 + .../astro-engine/lib/modules/content.js | 5 ++ .../engines/astro-engine/lib/modules/i18n.js | 54 ++++++++++++++ .../astro-engine/lib/modules/middleware.js | 35 ++++++++++ .../astro-engine/lib/modules/transitions.js | 45 ++++++++++++ .../engines/astro-engine/package.json | 2 +- 10 files changed, 278 insertions(+), 19 deletions(-) create mode 100644 javascript-modules/engines/astro-engine/lib/modules/actions.js create mode 100644 javascript-modules/engines/astro-engine/lib/modules/client-router.astro create mode 100644 javascript-modules/engines/astro-engine/lib/modules/i18n.js create mode 100644 javascript-modules/engines/astro-engine/lib/modules/middleware.js create mode 100644 javascript-modules/engines/astro-engine/lib/modules/transitions.js diff --git a/CHANGELOG.md b/CHANGELOG.md index d6b9c37e..b4d8f413 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,11 @@ ## Unreleased +* Added support for Astro 5. +* Added support for `astro:env` and public environment variables in Astro components. +* Added support for the `getImage` function in Astro components. +* Added fallbacks for the `astro:actions`, `astro:i18n`, `astro middleware`, and `astro:transitions` virtual modules. + ## v3.12.0 (October 28, 2024) * Added a `--disable-bindings` flag to the `@bookshop/generate` command. diff --git a/javascript-modules/engines/astro-engine/lib/builder.js b/javascript-modules/engines/astro-engine/lib/builder.js index f696db34..3c92f5c5 100644 --- a/javascript-modules/engines/astro-engine/lib/builder.js +++ b/javascript-modules/engines/astro-engine/lib/builder.js @@ -13,6 +13,15 @@ const { transform: bookshopTransform } = AstroPluginVite({ __removeClientDirectives: true, }); +const getEnvironmentDefines = () => { + return Object.entries(process.env ?? {}).reduce((acc, [key, value]) => { + if(key.startsWith("PUBLIC_")){ + acc[`import.meta.env.${key}`] = JSON.stringify(value); + } + return acc; + }, {}) +} + export const buildPlugins = [ sassPlugin({ filter: /\.module\.(s[ac]ss|css)$/, @@ -83,7 +92,13 @@ export const buildPlugins = [ build.onResolve({ filter: /^astro:.*$/ }, async (args) => { const type = args.path.replace("astro:", ""); - if (type !== "content" && type !== "assets") { + if (type === "env/client" || type === "env"){ + return { path: 'env', namespace: 'virtual' }; + } + if (type === "transitions/client" || type === "transitions"){ + return { path: join(dir, "modules", "transitions.js").replace("file:", "") }; + } + if (!["content", "assets", "i18n", "actions", "middleware"].includes(type)) { console.error( `Error: The 'astro:${type}' module is not supported inside Bookshop components.` ); @@ -118,6 +133,35 @@ export const buildPlugins = [ } }); + build.onLoad({ filter: /^env$/, namespace: 'virtual' }, async (args) => { + let contents = ""; + Object.entries(astroConfig?.env?.schema ?? {}).forEach(([key, schema]) => { + if(schema.context !== "client" || schema.access !== "public"){ + return; + } + + try{ + switch(schema.type){ + case "boolean": + contents += `export const ${key} = ${!!process.env[key]};\n` + break; + case "number": + contents += `export const ${key} = ${Number(process.env[key])};\n` + break; + default: + contents += `export const ${key} = ${JSON.stringify(process.env[key] ?? "")};\n` + } + } catch(e){ + //Error intentionally ignored + } + }); + contents += "export const getSecret = () => console.warn(\"[Bookshop] getSecret is not supported in Bookshop. Please use an editing fallback instead.\");" + return { + contents, + loader: "js", + }; + }); + build.onLoad({ filter: /\.astro$/, namespace: "style" }, async (args) => { let text = await fs.promises.readFile(args.path, "utf8"); let transformed = await transform(text, { @@ -155,9 +199,9 @@ export const buildPlugins = [ loader: "ts", target: "esnext", sourcemap: false, - define: { ENV_BOOKSHOP_LIVE: "true" }, + define: { ...getEnvironmentDefines(), ENV_BOOKSHOP_LIVE: "true"}, }); - let result = await bookshopTransform( + let result = bookshopTransform( jsResult.code, args.path.replace(process.cwd(), "") ); @@ -189,10 +233,10 @@ export const buildPlugins = [ jsxFragment: "__React.Fragment", target: "esnext", sourcemap: false, - define: { ENV_BOOKSHOP_LIVE: "true" }, + define: { ...getEnvironmentDefines(), ENV_BOOKSHOP_LIVE: "true" }, }); - let result = await bookshopTransform( + let result = bookshopTransform( jsResult.code, args.path.replace(process.cwd(), "") ); @@ -218,26 +262,16 @@ export const buildPlugins = [ loader: "ts", target: "esnext", sourcemap: false, - define: { ENV_BOOKSHOP_LIVE: "true" }, + define: { ...getEnvironmentDefines(), ENV_BOOKSHOP_LIVE: "true" }, }); - let result = await bookshopTransform( - jsResult.code, - args.path.replace(process.cwd(), "") - ); - - if (!result) { - console.warn("Bookshop transform failed:", args.path); - result = jsResult; - } - let importTransform = (await resolveConfig({}, "build")).plugins.find( ({ name }) => name === "vite:import-glob" ).transform; - let viteResult = await importTransform(result.code, args.path); + let viteResult = await importTransform(jsResult.code, args.path); return { - contents: viteResult?.code ?? result.code, + contents: viteResult?.code ?? jsResult.code, loader: "js", }; }); diff --git a/javascript-modules/engines/astro-engine/lib/modules/actions.js b/javascript-modules/engines/astro-engine/lib/modules/actions.js new file mode 100644 index 00000000..f89ea33a --- /dev/null +++ b/javascript-modules/engines/astro-engine/lib/modules/actions.js @@ -0,0 +1,51 @@ +export const actions = new Proxy({}, { + get() { + console.warn("[Bookshop] actions is not supported in Bookshop. Please use an editing fallback instead."); + return () => {}; + } +}); + +export const defineAction = () => { + console.warn("[Bookshop] defineAction is not supported in Bookshop. Please use an editing fallback instead."); + return { + handler: () => {}, + input: null + }; +}; + +export const isInputError = (error) => { + console.warn("[Bookshop] isInputError is not supported in Bookshop. Please use an editing fallback instead."); + return false; +}; + +export const isActionError = (error) => { + console.warn("[Bookshop] isActionError is not supported in Bookshop. Please use an editing fallback instead."); + return false; +}; + +export class ActionError extends Error { + constructor(code, message) { + super(message); + console.warn("[Bookshop] ActionError is not supported in Bookshop. Please use an editing fallback instead."); + this.code = code; + } +} + +export const getActionContext = (context) => { + console.warn("[Bookshop] getActionContext is not supported in Bookshop. Please use an editing fallback instead."); + return { + action: undefined, + setActionResult: () => {}, + serializeActionResult: () => ({}) + }; +}; + +export const deserializeActionResult = (result) => { + console.warn("[Bookshop] deserializeActionResult is not supported in Bookshop. Please use an editing fallback instead."); + return {}; +}; + +export const getActionPath = (action) => { + console.warn("[Bookshop] getActionPath is not supported in Bookshop. Please use an editing fallback instead."); + return ''; +}; diff --git a/javascript-modules/engines/astro-engine/lib/modules/assets.js b/javascript-modules/engines/astro-engine/lib/modules/assets.js index 12fce2e0..3d8c24b5 100644 --- a/javascript-modules/engines/astro-engine/lib/modules/assets.js +++ b/javascript-modules/engines/astro-engine/lib/modules/assets.js @@ -3,3 +3,30 @@ import PictureInternal from './picture.astro'; export const Image = ImageInternal; export const Picture = PictureInternal; + +export const getImage = async (options) => { + const resolvedSrc = + typeof options.src === "object" && "then" in options.src + ? (await options.src).default ?? (await options.src) + : options.src; + return { + rawOptions: { + src: { + src: resolvedSrc, + }, + }, + options: { + src: { + src: resolvedSrc, + }, + }, + src: resolvedSrc, + srcSet: { values: [] }, + attributes: { } + } +} + +export const inferRemoteSize = async () => { + console.warn("[Bookshop] inferRemoteSize is not supported in Bookshop. Please use an editing fallback instead."); + return {}; +} diff --git a/javascript-modules/engines/astro-engine/lib/modules/client-router.astro b/javascript-modules/engines/astro-engine/lib/modules/client-router.astro new file mode 100644 index 00000000..bbb35286 --- /dev/null +++ b/javascript-modules/engines/astro-engine/lib/modules/client-router.astro @@ -0,0 +1,3 @@ +--- +console.warn("[Bookshop] view transitions are not supported in Bookshop. Please use an editing fallback instead."); +--- diff --git a/javascript-modules/engines/astro-engine/lib/modules/content.js b/javascript-modules/engines/astro-engine/lib/modules/content.js index 7a8053fe..4a15f0be 100644 --- a/javascript-modules/engines/astro-engine/lib/modules/content.js +++ b/javascript-modules/engines/astro-engine/lib/modules/content.js @@ -43,3 +43,8 @@ export const getEntries = (entries) => { export const getEntryBySlug = (collection, slug) => { return getEntry({ collection, slug }); }; + +export const render = async () => ({ Content: () => "Content is not available when live editing", headings: [], remarkPluginFrontmatter: {} }); + +export const defineCollection = () => console.warn("[Bookshop] defineCollection is not supported in Bookshop. Make sure you're not importing your config in a component file by mistake."); +export const reference = () => console.warn("[Bookshop] reference is not supported in Bookshop. Make sure you're not importing your config in a component file by mistake."); diff --git a/javascript-modules/engines/astro-engine/lib/modules/i18n.js b/javascript-modules/engines/astro-engine/lib/modules/i18n.js new file mode 100644 index 00000000..bf168ae6 --- /dev/null +++ b/javascript-modules/engines/astro-engine/lib/modules/i18n.js @@ -0,0 +1,54 @@ +export const getRelativeLocaleUrl = (locale, path, options) => { + console.warn("[Bookshop] i18n routing is not supported in Bookshop. Please use an editing fallback instead."); + return ''; +}; + +export const getAbsoluteLocaleUrl = (locale, path, options) => { + console.warn("[Bookshop] i18n routing is not supported in Bookshop. Please use an editing fallback instead."); + return ''; +}; + +export const getRelativeLocaleUrlList = (path, options) => { + console.warn("[Bookshop] i18n routing is not supported in Bookshop. Please use an editing fallback instead."); + return []; +}; + +export const getAbsoluteLocaleUrlList = (path, options) => { + console.warn("[Bookshop] i18n routing is not supported in Bookshop. Please use an editing fallback instead."); + return []; +}; + +export const getPathByLocale = (locale) => { + console.warn("[Bookshop] i18n routing is not supported in Bookshop. Please use an editing fallback instead."); + return ''; +}; + +export const getLocaleByPath = (path) => { + console.warn("[Bookshop] i18n routing is not supported in Bookshop. Please use an editing fallback instead."); + return ''; +}; + +export const redirectToDefaultLocale = (context, statusCode) => { + console.warn("[Bookshop] i18n routing is not supported in Bookshop. Please use an editing fallback instead."); + return Promise.resolve(new Response()); +}; + +export const redirectToFallback = (context, response) => { + console.warn("[Bookshop] i18n routing is not supported in Bookshop. Please use an editing fallback instead."); + return Promise.resolve(new Response()); +}; + +export const notFound = (context, response) => { + console.warn("[Bookshop] i18n routing is not supported in Bookshop. Please use an editing fallback instead."); + return Promise.resolve(new Response()); +}; + +export const middleware = (options) => { + console.warn("[Bookshop] i18n routing is not supported in Bookshop. Please use an editing fallback instead."); + return () => {}; +}; + +export const requestHasLocale = (context) => { + console.warn("[Bookshop] i18n routing is not supported in Bookshop. Please use an editing fallback instead."); + return false; +}; diff --git a/javascript-modules/engines/astro-engine/lib/modules/middleware.js b/javascript-modules/engines/astro-engine/lib/modules/middleware.js new file mode 100644 index 00000000..0066b6a8 --- /dev/null +++ b/javascript-modules/engines/astro-engine/lib/modules/middleware.js @@ -0,0 +1,35 @@ +export const sequence = (...handlers) => { + console.warn("[Bookshop] middleware is not supported in Bookshop. Please use an editing fallback instead."); + return () => {}; +}; + +export const defineMiddleware = (fn) => { + console.warn("[Bookshop] middleware is not supported in Bookshop. Please use an editing fallback instead."); + return () => {}; +}; + +export const createContext = (context) => { + console.warn("[Bookshop] middleware is not supported in Bookshop. Please use an editing fallback instead."); + return {}; +}; + +export const trySerializeLocals = (value) => { + console.warn("[Bookshop] middleware is not supported in Bookshop. Please use an editing fallback instead."); + return ''; +}; + +// transitions.js +export const ClientRouter = () => { + console.warn("[Bookshop] view transitions are not supported in Bookshop. Please use an editing fallback instead."); + return null; +}; + +export const fade = (opts) => { + console.warn("[Bookshop] view transitions are not supported in Bookshop. Please use an editing fallback instead."); + return {}; +}; + +export const slide = (opts) => { + console.warn("[Bookshop] view transitions are not supported in Bookshop. Please use an editing fallback instead."); + return {}; +}; diff --git a/javascript-modules/engines/astro-engine/lib/modules/transitions.js b/javascript-modules/engines/astro-engine/lib/modules/transitions.js new file mode 100644 index 00000000..0ca07b26 --- /dev/null +++ b/javascript-modules/engines/astro-engine/lib/modules/transitions.js @@ -0,0 +1,45 @@ +import ClientRouterInternal from './client-router.astro'; + +export const ClientRouter = ClientRouterInternal; + +export const fade = (opts) => { + console.warn("[Bookshop] view transitions are not supported in Bookshop. Please use an editing fallback instead."); + return {}; +}; + +export const slide = (opts) => { + console.warn("[Bookshop] view transitions are not supported in Bookshop. Please use an editing fallback instead."); + return {}; +}; + +export const navigate = (href, options) => { + console.warn("[Bookshop] view transitions are not supported in Bookshop. Please use an editing fallback instead."); +}; + +export const supportsViewTransitions = false; + +export const transitionEnabledOnThisPage = false; + +export const getFallback = () => { + console.warn("[Bookshop] view transitions are not supported in Bookshop. Please use an editing fallback instead."); + return 'none'; +}; + +export const swapFunctions = { + deselectScripts: () => { + console.warn("[Bookshop] view transitions are not supported in Bookshop. Please use an editing fallback instead."); + }, + swapRootAttributes: () => { + console.warn("[Bookshop] view transitions are not supported in Bookshop. Please use an editing fallback instead."); + }, + swapHeadElements: () => { + console.warn("[Bookshop] view transitions are not supported in Bookshop. Please use an editing fallback instead."); + }, + saveFocus: () => { + console.warn("[Bookshop] view transitions are not supported in Bookshop. Please use an editing fallback instead."); + return () => {}; + }, + swapBodyElement: () => { + console.warn("[Bookshop] view transitions are not supported in Bookshop. Please use an editing fallback instead."); + } +}; diff --git a/javascript-modules/engines/astro-engine/package.json b/javascript-modules/engines/astro-engine/package.json index 76512425..886debd8 100644 --- a/javascript-modules/engines/astro-engine/package.json +++ b/javascript-modules/engines/astro-engine/package.json @@ -41,7 +41,7 @@ "vite": "^4.2.1" }, "peerDependencies": { - "astro": "^2.0.0 || ^3.0.0 || ^4.0.0", + "astro": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0", "react": "^17.0.2 || ^18.0.0", "react-dom": "^17.0.2 || ^18.0.0" }, From 534095cb9afee068233fa3256d4528c0424cbcd4 Mon Sep 17 00:00:00 2001 From: Tate Date: Wed, 22 Jan 2025 11:44:26 +1300 Subject: [PATCH 2/7] Remove extra exports from middleware --- .../astro-engine/lib/modules/middleware.js | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/javascript-modules/engines/astro-engine/lib/modules/middleware.js b/javascript-modules/engines/astro-engine/lib/modules/middleware.js index 0066b6a8..d62405b1 100644 --- a/javascript-modules/engines/astro-engine/lib/modules/middleware.js +++ b/javascript-modules/engines/astro-engine/lib/modules/middleware.js @@ -17,19 +17,3 @@ export const trySerializeLocals = (value) => { console.warn("[Bookshop] middleware is not supported in Bookshop. Please use an editing fallback instead."); return ''; }; - -// transitions.js -export const ClientRouter = () => { - console.warn("[Bookshop] view transitions are not supported in Bookshop. Please use an editing fallback instead."); - return null; -}; - -export const fade = (opts) => { - console.warn("[Bookshop] view transitions are not supported in Bookshop. Please use an editing fallback instead."); - return {}; -}; - -export const slide = (opts) => { - console.warn("[Bookshop] view transitions are not supported in Bookshop. Please use an editing fallback instead."); - return {}; -}; From 12c91ccd739e16c9f23047e5249738c2fe2a4540 Mon Sep 17 00:00:00 2001 From: Tate Date: Wed, 22 Jan 2025 11:48:14 +1300 Subject: [PATCH 3/7] Regenerate yarn.lock --- javascript-modules/yarn.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript-modules/yarn.lock b/javascript-modules/yarn.lock index 98e37b5c..f21a88db 100644 --- a/javascript-modules/yarn.lock +++ b/javascript-modules/yarn.lock @@ -575,7 +575,7 @@ __metadata: postcss-modules: ^6.0.0 vite: ^4.2.1 peerDependencies: - astro: ^2.0.0 || ^3.0.0 || ^4.0.0 + astro: ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 react: ^17.0.2 || ^18.0.0 react-dom: ^17.0.2 || ^18.0.0 languageName: unknown From ea4feca446c81c4c478c544162242f4facc5513c Mon Sep 17 00:00:00 2001 From: Liam Bigelow <40188355+bglw@users.noreply.github.com> Date: Wed, 22 Jan 2025 14:02:40 +1300 Subject: [PATCH 4/7] Update integration-test.yml --- .github/workflows/integration-test.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index 8ad97dea..24de75ba 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -40,6 +40,17 @@ jobs: uses: actions/setup-node@v2 with: node-version: 20.x + + - name: Ubuntu AppArmor fix + if: ${{ matrix.os == 'ubuntu-latest' }} + # Ubuntu >= 23 has AppArmor enabled by default, which breaks Puppeteer. + # See https://github.com/puppeteer/puppeteer/issues/12818 "No usable sandbox!" + # this is taken from the solution used in Puppeteer's own CI: https://github.com/puppeteer/puppeteer/pull/13196 + # The alternative is to pin Ubuntu 22 or to use aa-exec to disable AppArmor for commands that need Puppeteer. + # This is also suggested by Chromium https://chromium.googlesource.com/chromium/src/+/main/docs/security/apparmor-userns-restrictions.md + run: | + $echo 0 | sudo tee /proc/sys/kernel/apparmor_restrict_unprivileged_userns + shell: bash # TODO: Remove when possible (https://github.com/actions/setup-node/issues/515) - name: Windows Node fix if: ${{ matrix.os == 'windows-latest' }} From 26376e849fa08ba227a83c042cdea89ad1d13538 Mon Sep 17 00:00:00 2001 From: Liam Bigelow <40188355+bglw@users.noreply.github.com> Date: Wed, 22 Jan 2025 14:04:17 +1300 Subject: [PATCH 5/7] Update integration-test.yml --- .github/workflows/integration-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index 24de75ba..2f662f22 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -49,7 +49,7 @@ jobs: # The alternative is to pin Ubuntu 22 or to use aa-exec to disable AppArmor for commands that need Puppeteer. # This is also suggested by Chromium https://chromium.googlesource.com/chromium/src/+/main/docs/security/apparmor-userns-restrictions.md run: | - $echo 0 | sudo tee /proc/sys/kernel/apparmor_restrict_unprivileged_userns + echo 0 | sudo tee /proc/sys/kernel/apparmor_restrict_unprivileged_userns shell: bash # TODO: Remove when possible (https://github.com/actions/setup-node/issues/515) - name: Windows Node fix From 62d64c7811f69c888cde8fbd6cbc948cfa02960d Mon Sep 17 00:00:00 2001 From: Liam Bigelow <40188355+bglw@users.noreply.github.com> Date: Wed, 22 Jan 2025 14:05:46 +1300 Subject: [PATCH 6/7] Update release.yml --- .github/workflows/release.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index fc9b4715..300e4981 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -38,6 +38,16 @@ jobs: uses: actions/setup-node@v2 with: node-version: 20.x + - name: Ubuntu AppArmor fix + if: ${{ matrix.os == 'ubuntu-latest' }} + # Ubuntu >= 23 has AppArmor enabled by default, which breaks Puppeteer. + # See https://github.com/puppeteer/puppeteer/issues/12818 "No usable sandbox!" + # this is taken from the solution used in Puppeteer's own CI: https://github.com/puppeteer/puppeteer/pull/13196 + # The alternative is to pin Ubuntu 22 or to use aa-exec to disable AppArmor for commands that need Puppeteer. + # This is also suggested by Chromium https://chromium.googlesource.com/chromium/src/+/main/docs/security/apparmor-userns-restrictions.md + run: | + echo 0 | sudo tee /proc/sys/kernel/apparmor_restrict_unprivileged_userns + shell: bash # TODO: Remove when possible (https://github.com/actions/setup-node/issues/515) - name: Windows Node fix if: ${{ matrix.os == 'windows-latest' }} From 144695d5895185fa1b562ab46e2ef5846ac250d0 Mon Sep 17 00:00:00 2001 From: Tate Date: Wed, 22 Jan 2025 14:48:06 +1300 Subject: [PATCH 7/7] Better handling for server islands with editor fallbacks --- .../engines/astro-engine/lib/engine.js | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/javascript-modules/engines/astro-engine/lib/engine.js b/javascript-modules/engines/astro-engine/lib/engine.js index 852abe70..91b7ca72 100644 --- a/javascript-modules/engines/astro-engine/lib/engine.js +++ b/javascript-modules/engines/astro-engine/lib/engine.js @@ -35,7 +35,7 @@ export class Engine { this.reactRoots.push({Component, props}); return { html: `
` }; } - + const reactNode = await Component(props); return { html: renderToStaticMarkup(reactNode) }; }, @@ -118,12 +118,30 @@ export class Engine { async renderAstroComponent(target, key, props, globals) { const component = this.files?.[key]; + + let encryptionKey; + try{ + encryptionKey = window.crypto.subtle.generateKey( + { + name: "AES-GCM", + length: 256, + }, + true, + ["encrypt", "decrypt"], + ) + } catch(err){ + console.warn("[Bookshop] Could not generate a key for Astro component. This may cause issues with Astro components that use server-islands") + } + const SSRResult = { styles: new Set(), scripts: new Set(), links: new Set(), propagation: new Map(), propagators: new Map(), + serverIslandNameMap: { get: () => "Bookshop" }, + key: encryptionKey, + base: "/", extraHead: [], componentMetadata: new Map(), renderers: this.renderers, @@ -166,6 +184,9 @@ export class Engine { flushSync(() => root.render(reactNode)); }); this.reactRoots = []; + target.querySelectorAll("link, [data-island-id]").forEach((node) => { + node.remove(); + }); } async eval(str, props = [{}]) {