diff --git a/packages/astro/src/container/index.ts b/packages/astro/src/container/index.ts
index acacdf22b8d3..dddd6b09e09e 100644
--- a/packages/astro/src/container/index.ts
+++ b/packages/astro/src/container/index.ts
@@ -164,7 +164,6 @@ function createManifest(
clientScriptHashes: manifest?.clientScriptHashes ?? [],
clientStyleHashes: manifest?.clientStyleHashes ?? [],
shouldInjectCspMetaTags: manifest?.shouldInjectCspMetaTags ?? false,
- astroIslandHashes: manifest?.astroIslandHashes ?? {},
};
}
@@ -253,7 +252,6 @@ type AstroContainerManifest = Pick<
| 'clientScriptHashes'
| 'clientStyleHashes'
| 'shouldInjectCspMetaTags'
- | 'astroIslandHashes'
>;
type AstroContainerConstructor = {
diff --git a/packages/astro/src/core/app/types.ts b/packages/astro/src/core/app/types.ts
index 62211ea1f937..18f926eb37f0 100644
--- a/packages/astro/src/core/app/types.ts
+++ b/packages/astro/src/core/app/types.ts
@@ -92,7 +92,6 @@ export type SSRManifest = {
* When enabled, Astro tracks the hashes of script and styles, and eventually it will render the `` tag
*/
shouldInjectCspMetaTags: boolean;
- astroIslandHashes: Record;
};
export type SSRActions = {
diff --git a/packages/astro/src/core/astro-islands-hashes.ts b/packages/astro/src/core/astro-islands-hashes.ts
deleted file mode 100644
index 56f4ad6fbffe..000000000000
--- a/packages/astro/src/core/astro-islands-hashes.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-// This file is code-generated, please don't change it manually
-export const ASTRO_ISLAND_HASHES = {
- "astro-island": "p9VbHs/ClkQc+x63XdUjvCAgeWxA4ZGvpebJtMn9jbs=",
- "idle": "BF0290pkb3jxQsE7z00xR8Imp8X34FLC88L0lkMnrGw=",
- "load": "QzWFZi+FLIx23tnm9SBU4aEgx4x8DsuASP07mfqol/c=",
- "media": "0chmwFk0zaA528yFfGV7J9ppIpdfTPPULncDF3WG7Zs=",
- "only": "eIXWvAmxkr251LJZkjniEK5LcPF3NkapbJepohwYRIc=",
- "visible": "Q2BPg90ZMplYY+FSdApNErhpWafg2hcRRbndmvxuL/Q=",
- "astro-island-styles": "s81ZcLcyAa7P/Jh5M5hUxYthTGwW+iZY3e6aHrQ8H9E="
-};
\ No newline at end of file
diff --git a/packages/astro/src/core/base-pipeline.ts b/packages/astro/src/core/base-pipeline.ts
index 7e3174a48c46..d239a4a2fae2 100644
--- a/packages/astro/src/core/base-pipeline.ts
+++ b/packages/astro/src/core/base-pipeline.ts
@@ -13,6 +13,7 @@ import type {
} from '../types/public/internal.js';
import { createOriginCheckMiddleware } from './app/middlewares.js';
import type { SSRActions } from './app/types.js';
+import { createCSPMiddleware } from './csp/middleware.js';
import { ActionNotFoundError } from './errors/errors-data.js';
import { AstroError } from './errors/index.js';
import type { Logger } from './logger/core.js';
@@ -20,7 +21,6 @@ import { NOOP_MIDDLEWARE_FN } from './middleware/noop-middleware.js';
import { sequence } from './middleware/sequence.js';
import { RouteCache } from './render/route-cache.js';
import { createDefaultRoutes } from './routing/default.js';
-import { createCSPMiddleware } from './csp/middleware.js';
/**
* The `Pipeline` represents the static parts of rendering that do not change between requests.
diff --git a/packages/astro/src/core/build/generate.ts b/packages/astro/src/core/build/generate.ts
index f6170516b36a..b143fc06a3fd 100644
--- a/packages/astro/src/core/build/generate.ts
+++ b/packages/astro/src/core/build/generate.ts
@@ -9,7 +9,6 @@ import {
getStaticImageList,
prepareAssetsGenerationEnv,
} from '../../assets/build/generate.js';
-import { type BuildInternals, hasPrerenderedPages } from './internal.js';
import {
isRelativePath,
joinPaths,
@@ -29,6 +28,7 @@ import type {
SSRLoadedRenderer,
} from '../../types/public/internal.js';
import type { SSRActions, SSRManifest, SSRManifestI18n } from '../app/types.js';
+import { shouldTrackCspHashes, trackScriptHashes, trackStyleHashes } from '../csp/common.js';
import { NoPrerenderedRoutesWithDomains } from '../errors/errors-data.js';
import { AstroError, AstroErrorData } from '../errors/index.js';
import { NOOP_MIDDLEWARE_FN } from '../middleware/noop-middleware.js';
@@ -41,6 +41,7 @@ import { matchRoute } from '../routing/match.js';
import { stringifyParams } from '../routing/params.js';
import { getOutputFilename } from '../util.js';
import { getOutFile, getOutFolder } from './common.js';
+import { type BuildInternals, hasPrerenderedPages } from './internal.js';
import { cssOrder, mergeInlineCss } from './internal.js';
import { BuildPipeline } from './pipeline.js';
import type {
@@ -50,8 +51,6 @@ import type {
StylesheetAsset,
} from './types.js';
import { getTimeStat, shouldAppendForwardSlash } from './util.js';
-import { shouldTrackCspHashes, trackScriptHashes, trackStyleHashes } from '../csp/common.js';
-import { ASTRO_ISLAND_HASHES } from '../astro-islands-hashes.js';
export async function generatePages(options: StaticBuildOptions, internals: BuildInternals) {
const generatePagesTimer = performance.now();
@@ -70,7 +69,7 @@ export async function generatePages(options: StaticBuildOptions, internals: Buil
const actions: SSRActions = internals.astroActionsEntryPoint
? await import(internals.astroActionsEntryPoint.toString()).then((mod) => mod)
: NOOP_ACTIONS_MOD;
- manifest = createBuildManifest(
+ manifest = await createBuildManifest(
options.settings,
internals,
renderers.renderers as SSRLoadedRenderer[],
@@ -604,22 +603,22 @@ function getPrettyRouteName(route: RouteData): string {
*
* Renderers needs to be pulled out from the page module emitted during the build.
*/
-function createBuildManifest(
+async function createBuildManifest(
settings: AstroSettings,
internals: BuildInternals,
renderers: SSRLoadedRenderer[],
middleware: MiddlewareHandler,
actions: SSRActions,
key: Promise,
-): SSRManifest {
+): Promise {
let i18nManifest: SSRManifestI18n | undefined = undefined;
let clientStyleHashes: string[] = [];
let clientScriptHashes: string[] = [];
if (shouldTrackCspHashes(settings.config)) {
- clientScriptHashes = trackScriptHashes(internals, settings);
- clientStyleHashes = trackStyleHashes(internals);
+ clientScriptHashes = await trackScriptHashes(internals, settings);
+ clientStyleHashes = await trackStyleHashes(internals, settings);
}
if (settings.config.i18n) {
@@ -668,6 +667,5 @@ function createBuildManifest(
clientStyleHashes,
clientScriptHashes,
shouldInjectCspMetaTags: shouldTrackCspHashes(settings.config),
- astroIslandHashes: ASTRO_ISLAND_HASHES,
};
}
diff --git a/packages/astro/src/core/build/internal.ts b/packages/astro/src/core/build/internal.ts
index a726480b8cef..5f303596b620 100644
--- a/packages/astro/src/core/build/internal.ts
+++ b/packages/astro/src/core/build/internal.ts
@@ -80,6 +80,10 @@ export interface BuildInternals {
// A list of all static files created during the build. Used for SSR.
staticFiles: Set;
+
+ // A list of all statics chunks and assets that are built in the client
+ clientChunksAndAssets: Set;
+
// The SSR entry chunk. Kept in internals to share between ssr/client build steps
ssrEntryChunk?: Rollup.OutputChunk;
// The SSR manifest entry chunk.
@@ -121,6 +125,7 @@ export function createBuildInternals(): BuildInternals {
prerenderOnlyChunks: [],
astroActionsEntryPoint: undefined,
middlewareEntryPoint: undefined,
+ clientChunksAndAssets: new Set(),
};
}
diff --git a/packages/astro/src/core/build/plugins/plugin-internals.ts b/packages/astro/src/core/build/plugins/plugin-internals.ts
index 2d4dfc3603f3..6bef4414b3a5 100644
--- a/packages/astro/src/core/build/plugins/plugin-internals.ts
+++ b/packages/astro/src/core/build/plugins/plugin-internals.ts
@@ -40,7 +40,9 @@ function vitePluginInternals(input: Set, internals: BuildInternals): Vit
);
}
await Promise.all(promises);
- for (const [, chunk] of Object.entries(bundle)) {
+ for (const [_, chunk] of Object.entries(bundle)) {
+ internals.clientChunksAndAssets.add(chunk.fileName);
+
if (chunk.type === 'chunk' && chunk.facadeModuleId) {
const specifiers = mapping.get(chunk.facadeModuleId) || new Set([chunk.facadeModuleId]);
for (const specifier of specifiers) {
diff --git a/packages/astro/src/core/build/plugins/plugin-manifest.ts b/packages/astro/src/core/build/plugins/plugin-manifest.ts
index 015e79ff20d0..75fb1b466c0a 100644
--- a/packages/astro/src/core/build/plugins/plugin-manifest.ts
+++ b/packages/astro/src/core/build/plugins/plugin-manifest.ts
@@ -12,6 +12,7 @@ import type {
SerializedRouteInfo,
SerializedSSRManifest,
} from '../../app/types.js';
+import { shouldTrackCspHashes, trackScriptHashes, trackStyleHashes } from '../../csp/common.js';
import { encodeKey } from '../../encryption.js';
import { fileExtension, joinPaths, prependForwardSlash } from '../../path.js';
import { DEFAULT_COMPONENTS } from '../../routing/default.js';
@@ -23,8 +24,6 @@ import { type BuildInternals, cssOrder, mergeInlineCss } from '../internal.js';
import type { AstroBuildPlugin } from '../plugin.js';
import type { StaticBuildOptions } from '../types.js';
import { makePageDataKey } from './util.js';
-import { shouldTrackCspHashes, trackScriptHashes, trackStyleHashes } from '../../csp/common.js';
-import { ASTRO_ISLAND_HASHES } from '../../astro-islands-hashes.js';
const manifestReplace = '@@ASTRO_MANIFEST_REPLACE@@';
const replaceExp = new RegExp(`['"]${manifestReplace}['"]`, 'g');
@@ -143,7 +142,7 @@ async function createManifest(
const staticFiles = internals.staticFiles;
const encodedKey = await encodeKey(await buildOpts.key);
- return buildManifest(buildOpts, internals, Array.from(staticFiles), encodedKey);
+ return await buildManifest(buildOpts, internals, Array.from(staticFiles), encodedKey);
}
/**
@@ -157,12 +156,12 @@ function injectManifest(manifest: SerializedSSRManifest, chunk: Readonly {
const { settings } = opts;
const routes: SerializedRouteInfo[] = [];
@@ -281,8 +280,8 @@ function buildManifest(
let clientStyleHashes: string[] = [];
if (shouldTrackCspHashes(settings.config)) {
- clientScriptHashes = trackScriptHashes(internals, opts.settings);
- clientStyleHashes = trackStyleHashes(internals);
+ clientScriptHashes = await trackScriptHashes(internals, opts.settings);
+ clientStyleHashes = await trackStyleHashes(internals, opts.settings);
}
return {
@@ -317,6 +316,5 @@ function buildManifest(
shouldInjectCspMetaTags: shouldTrackCspHashes(opts.settings.config),
clientStyleHashes,
clientScriptHashes,
- astroIslandHashes: ASTRO_ISLAND_HASHES,
};
}
diff --git a/packages/astro/src/core/build/plugins/plugin-ssr.ts b/packages/astro/src/core/build/plugins/plugin-ssr.ts
index 649bdc39ebec..60bf63ef2289 100644
--- a/packages/astro/src/core/build/plugins/plugin-ssr.ts
+++ b/packages/astro/src/core/build/plugins/plugin-ssr.ts
@@ -113,7 +113,6 @@ function vitePluginSSR(
internals.staticFiles.add(chunk.fileName);
}
}
-
for (const [, chunk] of Object.entries(bundle)) {
if (chunk.type === 'asset') {
continue;
diff --git a/packages/astro/src/core/csp/common.ts b/packages/astro/src/core/csp/common.ts
index 74c7c2f67652..d1ed301f7432 100644
--- a/packages/astro/src/core/csp/common.ts
+++ b/packages/astro/src/core/csp/common.ts
@@ -1,42 +1,82 @@
+import { readFileSync } from 'node:fs';
+import { fileURLToPath } from 'node:url';
+import { ISLAND_STYLES } from '../../runtime/server/astro-island-styles.js';
+import astroIslandPrebuiltDev from '../../runtime/server/astro-island.prebuilt-dev.js';
+import astroIslandPrebuilt from '../../runtime/server/astro-island.prebuilt.js';
+import type { AstroSettings } from '../../types/astro.js';
import type { AstroConfig } from '../../types/public/index.js';
import type { BuildInternals } from '../build/internal.js';
-import crypto from 'node:crypto';
-import type { AstroSettings } from '../../types/astro.js';
+import { generateDigest } from '../encryption.js';
export function shouldTrackCspHashes(config: AstroConfig): boolean {
return config.experimental?.csp === true;
}
-export function trackStyleHashes(internals: BuildInternals): string[] {
+export async function trackStyleHashes(
+ internals: BuildInternals,
+ settings: AstroSettings,
+): Promise {
const clientStyleHashes: string[] = [];
for (const [_, page] of internals.pagesByViteID.entries()) {
for (const style of page.styles) {
if (style.sheet.type === 'inline') {
- clientStyleHashes.push(generateHash(style.sheet.content));
+ clientStyleHashes.push(await generateDigest(style.sheet.content));
}
}
}
+ for (const clientAsset in internals.clientChunksAndAssets) {
+ const contents = readFileSync(
+ fileURLToPath(new URL(clientAsset, settings.config.build.client)),
+ 'utf-8',
+ );
+ if (clientAsset.endsWith('.css') || clientAsset.endsWith('.css')) {
+ clientStyleHashes.push(await generateDigest(contents));
+ }
+ }
+
+ if (settings.renderers.length > 0) {
+ clientStyleHashes.push(await generateDigest(ISLAND_STYLES));
+ }
+
return clientStyleHashes;
}
-export function trackScriptHashes(internals: BuildInternals, settings: AstroSettings): string[] {
+export async function trackScriptHashes(
+ internals: BuildInternals,
+ settings: AstroSettings,
+): Promise {
const clientScriptHashes: string[] = [];
for (const script of internals.inlinedScripts.values()) {
- clientScriptHashes.push(generateHash(script));
+ clientScriptHashes.push(await generateDigest(script));
+ }
+
+ for (const directiveContent of Array.from(settings.clientDirectives.values())) {
+ clientScriptHashes.push(await generateDigest(directiveContent));
+ }
+
+ for (const clientAsset in internals.clientChunksAndAssets) {
+ const contents = readFileSync(
+ fileURLToPath(new URL(clientAsset, settings.config.build.client)),
+ 'utf-8',
+ );
+ if (clientAsset.endsWith('.js') || clientAsset.endsWith('.mjs')) {
+ clientScriptHashes.push(await generateDigest(contents));
+ }
}
for (const script of settings.scripts) {
const { content, stage } = script;
if (stage === 'head-inline' || stage === 'before-hydration') {
- clientScriptHashes.push(generateHash(content));
+ clientScriptHashes.push(await generateDigest(content));
}
}
- return clientScriptHashes;
-}
+ if (settings.renderers.length > 0) {
+ clientScriptHashes.push(await generateDigest(astroIslandPrebuilt));
+ clientScriptHashes.push(await generateDigest(astroIslandPrebuiltDev));
+ }
-function generateHash(content: string): string {
- return crypto.createHash('sha256').update(content).digest('base64');
+ return clientScriptHashes;
}
diff --git a/packages/astro/src/core/encryption.ts b/packages/astro/src/core/encryption.ts
index 5f72e7367f16..e3668ab5d865 100644
--- a/packages/astro/src/core/encryption.ts
+++ b/packages/astro/src/core/encryption.ts
@@ -109,3 +109,13 @@ export async function decryptString(key: CryptoKey, encoded: string) {
const decryptedString = decoder.decode(decryptedBuffer);
return decryptedString;
}
+
+/**
+ * Generates an SHA-256 digest of the given string.
+ * @param {string} data The string to hash.
+ */
+export async function generateDigest(data: string): Promise {
+ const hashBuffer = await crypto.subtle.digest('SHA-256', encoder.encode(data));
+
+ return encodeBase64(new Uint8Array(hashBuffer));
+}
diff --git a/packages/astro/src/core/render-context.ts b/packages/astro/src/core/render-context.ts
index 81610f42635a..b877b4c859fe 100644
--- a/packages/astro/src/core/render-context.ts
+++ b/packages/astro/src/core/render-context.ts
@@ -465,7 +465,6 @@ export class RenderContext {
shouldInjectCspMetaTags: manifest.shouldInjectCspMetaTags,
clientScriptHashes: manifest.clientScriptHashes,
clientStyleHashes: manifest.clientStyleHashes,
- astroIslandHashes: manifest.astroIslandHashes,
};
return result;
diff --git a/packages/astro/src/runtime/server/astro-island-styles.ts b/packages/astro/src/runtime/server/astro-island-styles.ts
index ca816c9204b9..422f6bbc49f4 100644
--- a/packages/astro/src/runtime/server/astro-island-styles.ts
+++ b/packages/astro/src/runtime/server/astro-island-styles.ts
@@ -1,2 +1 @@
-export const ISLAND_STYLES =
- '';
+export const ISLAND_STYLES = 'astro-island,astro-slot,astro-static-slot{display:contents}';
diff --git a/packages/astro/src/runtime/server/render/common.ts b/packages/astro/src/runtime/server/render/common.ts
index de70c6127e82..5c765d6b2b35 100644
--- a/packages/astro/src/runtime/server/render/common.ts
+++ b/packages/astro/src/runtime/server/render/common.ts
@@ -1,4 +1,3 @@
-import type { RenderInstruction } from './instruction.js';
import type { SSRResult } from '../../../types/public/internal.js';
import type { HTMLBytes, HTMLString } from '../escape.js';
import { markHTMLString } from '../escape.js';
@@ -8,6 +7,7 @@ import {
getPrescripts,
} from '../scripts.js';
import { renderAllHeadContent } from './head.js';
+import type { RenderInstruction } from './instruction.js';
import { isRenderInstruction } from './instruction.js';
import { renderServerIslandRuntime } from './server-islands.js';
import { type SlotString, isSlotString } from './slot.js';
diff --git a/packages/astro/src/runtime/server/render/csp.ts b/packages/astro/src/runtime/server/render/csp.ts
index 143bf0746b9a..2a148c35006b 100644
--- a/packages/astro/src/runtime/server/render/csp.ts
+++ b/packages/astro/src/runtime/server/render/csp.ts
@@ -12,16 +12,6 @@ export function renderCspContent(result: SSRResult): string {
finalStyleHashes.add(`'sha256-${styleHash}'`);
}
- if (result.renderers.length > 0) {
- for (const [ name, hash ] of Object.entries(result.astroIslandHashes)) {
- if (name === 'astro-island-styles') {
- finalStyleHashes.add(`'sha256-${hash}'`);
- } else {
- finalScriptHashes.add(`'sha256-${hash}'`);
- }
- }
- }
-
const scriptSrc = `style-src 'self' ${Array.from(finalStyleHashes).join(' ')};`;
const styleSrc = `script-src 'self' ${Array.from(finalScriptHashes).join(' ')};`;
return `${scriptSrc} ${styleSrc}`;
diff --git a/packages/astro/src/runtime/server/render/head.ts b/packages/astro/src/runtime/server/render/head.ts
index 7989cb7acb5d..3af8be5a87b6 100644
--- a/packages/astro/src/runtime/server/render/head.ts
+++ b/packages/astro/src/runtime/server/render/head.ts
@@ -1,9 +1,9 @@
import type { SSRResult } from '../../../types/public/internal.js';
import { markHTMLString } from '../escape.js';
+import { renderCspContent } from './csp.js';
import type { MaybeRenderHeadInstruction, RenderHeadInstruction } from './instruction.js';
import { createRenderInstruction } from './instruction.js';
import { renderElement } from './util.js';
-import { renderCspContent } from './csp.js';
// Filter out duplicate elements in our set
const uniqueElements = (item: any, index: number, all: any[]) => {
diff --git a/packages/astro/src/runtime/server/scripts.ts b/packages/astro/src/runtime/server/scripts.ts
index e77947de9168..fa87fcd631ca 100644
--- a/packages/astro/src/runtime/server/scripts.ts
+++ b/packages/astro/src/runtime/server/scripts.ts
@@ -1,7 +1,7 @@
import type { SSRResult } from '../../types/public/internal.js';
+import { ISLAND_STYLES } from './astro-island-styles.js';
import islandScriptDev from './astro-island.prebuilt-dev.js';
import islandScript from './astro-island.prebuilt.js';
-import { ISLAND_STYLES } from './astro-island-styles.js';
export function determineIfNeedsHydrationScript(result: SSRResult): boolean {
if (result._metadata.hasHydrationScript) {
@@ -36,7 +36,7 @@ export function getPrescripts(result: SSRResult, type: PrescriptType, directive:
// deps to be loaded immediately.
switch (type) {
case 'both':
- return `${ISLAND_STYLES}`;
case 'directive':
diff --git a/packages/astro/src/types/public/internal.ts b/packages/astro/src/types/public/internal.ts
index 50d202389a5d..73e1502c99a6 100644
--- a/packages/astro/src/types/public/internal.ts
+++ b/packages/astro/src/types/public/internal.ts
@@ -1,13 +1,13 @@
// TODO: Should the types here really be public?
import type { ErrorPayload as ViteErrorPayload } from 'vite';
+import type { SSRManifest } from '../../core/app/types.js';
import type { AstroCookies } from '../../core/cookies/cookies.js';
import type { AstroComponentInstance } from '../../runtime/server/index.js';
import type { Params } from './common.js';
import type { AstroConfig, RedirectConfig } from './config.js';
import type { AstroGlobal, AstroGlobalPartial } from './context.js';
import type { AstroRenderer } from './integrations.js';
-import type { SSRManifest } from '../../core/app/types.js';
export type { SSRManifest } from '../../core/app/types.js';
@@ -253,7 +253,6 @@ export interface SSRResult {
shouldInjectCspMetaTags: boolean;
clientScriptHashes: SSRManifest['clientScriptHashes'];
clientStyleHashes: SSRManifest['clientStyleHashes'];
- astroIslandHashes: SSRManifest['astroIslandHashes'];
}
/**
diff --git a/packages/astro/src/vite-plugin-astro-server/plugin.ts b/packages/astro/src/vite-plugin-astro-server/plugin.ts
index e43e45dd71af..567afee158f2 100644
--- a/packages/astro/src/vite-plugin-astro-server/plugin.ts
+++ b/packages/astro/src/vite-plugin-astro-server/plugin.ts
@@ -5,6 +5,7 @@ import { fileURLToPath } from 'node:url';
import type * as vite from 'vite';
import { normalizePath } from 'vite';
import type { SSRManifest, SSRManifestI18n } from '../core/app/types.js';
+import { shouldTrackCspHashes } from '../core/csp/common.js';
import { warnMissingAdapter } from '../core/dev/adapter-validation.js';
import { createKey, getEnvironmentKey, hasEnvironmentKey } from '../core/encryption.js';
import { getViteErrorPayload } from '../core/errors/dev/index.js';
@@ -25,8 +26,6 @@ import { DevPipeline } from './pipeline.js';
import { handleRequest } from './request.js';
import { setRouteError } from './server-state.js';
import { trailingSlashMiddleware } from './trailing-slash.js';
-import { ASTRO_ISLAND_HASHES } from '../core/astro-islands-hashes.js';
-import { shouldTrackCspHashes } from '../core/csp/common.js';
interface AstroPluginOptions {
settings: AstroSettings;
@@ -211,6 +210,5 @@ export function createDevelopmentManifest(settings: AstroSettings): SSRManifest
clientScriptHashes: [],
clientStyleHashes: [],
shouldInjectCspMetaTags: shouldTrackCspHashes(settings.config),
- astroIslandHashes: ASTRO_ISLAND_HASHES,
};
}
diff --git a/packages/astro/test/astro-dynamic.test.js b/packages/astro/test/astro-dynamic.test.js
index 47344bf0ea97..0af25560e3c8 100644
--- a/packages/astro/test/astro-dynamic.test.js
+++ b/packages/astro/test/astro-dynamic.test.js
@@ -17,7 +17,7 @@ describe('Dynamic components', () => {
const html = await fixture.readFile('/index.html');
const $ = cheerio.load(html);
- assert.equal($('script').length, 1);
+ assert.equal($('script').length, 2, "to have directive and astro island script");
});
it('Loads pages using client:media hydrator', async () => {
@@ -25,7 +25,7 @@ describe('Dynamic components', () => {
const $ = cheerio.load(html);
// test 1: static value rendered
- assert.equal($('script').length, 1);
+ assert.equal($('script').length, 2, "to have directive and astro island script");
});
it('Loads pages using client:only hydrator', async () => {
@@ -56,7 +56,7 @@ describe('Dynamic components subpath', () => {
const html = await fixture.readFile('/index.html');
const $ = cheerio.load(html);
- assert.equal($('script').length, 1);
+ assert.equal($('script').length, 2);
});
it('Loads pages using client:media hydrator', async () => {
@@ -64,7 +64,7 @@ describe('Dynamic components subpath', () => {
const $ = cheerio.load(html);
// test 1: static value rendered
- assert.equal($('script').length, 1);
+ assert.equal($('script').length, 2, "to have directive and astro island script");
});
it('Loads pages using client:only hydrator', async () => {
diff --git a/packages/astro/test/astro-slot-with-client.test.js b/packages/astro/test/astro-slot-with-client.test.js
index 8f34b8fc9158..cf762a9db051 100644
--- a/packages/astro/test/astro-slot-with-client.test.js
+++ b/packages/astro/test/astro-slot-with-client.test.js
@@ -15,7 +15,7 @@ describe('Slots with client: directives', () => {
it('Tags of dynamic tags works', async () => {
const html = await fixture.readFile('/index.html');
const $ = cheerio.load(html);
- assert.equal($('script').length, 1);
+ assert.equal($('script').length, 2);
});
it('Astro slot tags are kept', async () => {
diff --git a/packages/astro/test/astro-slots-nested.test.js b/packages/astro/test/astro-slots-nested.test.js
index 3d04b00e27ba..7ab56249c32e 100644
--- a/packages/astro/test/astro-slots-nested.test.js
+++ b/packages/astro/test/astro-slots-nested.test.js
@@ -15,7 +15,7 @@ describe('Nested Slots', () => {
it('Hidden nested slots see their hydration scripts hoisted', async () => {
const html = await fixture.readFile('/hidden-nested/index.html');
const $ = cheerio.load(html);
- assert.equal($('script').length, 1, 'script rendered');
+ assert.equal($('script').length, 2, 'script rendered');
const scriptInTemplate = $($('template')[0].children[0]).find('script');
assert.equal(scriptInTemplate.length, 0, 'script defined outside of the inner template');
});
@@ -23,7 +23,7 @@ describe('Nested Slots', () => {
it('Slots rendered via Astro.slots.render have the hydration script', async () => {
const html = await fixture.readFile('/component-slot/index.html');
const $ = cheerio.load(html);
- assert.equal($('script').length, 1, 'script rendered');
+ assert.equal($('script').length, 2, 'script rendered');
});
describe('Client components nested inside server-only framework components', () => {
diff --git a/packages/astro/test/csp.test.js b/packages/astro/test/csp.test.js
index fc5703c0a016..6671483dceed 100644
--- a/packages/astro/test/csp.test.js
+++ b/packages/astro/test/csp.test.js
@@ -1,8 +1,8 @@
-import { before, describe, it } from 'node:test';
-import { loadFixture } from './test-utils.js';
-import testAdapter from './test-adapter.js';
import assert from 'node:assert/strict';
+import { before, describe, it } from 'node:test';
import * as cheerio from 'cheerio';
+import testAdapter from './test-adapter.js';
+import { loadFixture } from './test-utils.js';
describe('CSP', () => {
let app;
@@ -39,24 +39,7 @@ describe('CSP', () => {
`Should have a CSP meta tag for ${hash}`,
);
}
-
- let [, astroStyleHash] = Object.entries(manifest.astroIslandHashes).find(
- ([name, _]) => name === 'astro-island-styles',
- );
- astroStyleHash = `sha256-${astroStyleHash}`;
-
- let [, astroIsland] = Object.entries(manifest.astroIslandHashes).find(([name, _]) => name === 'astro-island');
- astroIsland = `sha256-${astroIsland}`;
-
- assert.ok(
- meta.attr('content').includes(astroStyleHash),
- `Should have a CSP meta tag for ${astroStyleHash}`,
- );
-
- assert.ok(
- meta.attr('content').includes(astroIsland),
- `Should have a CSP meta tag for ${astroIsland}`,
- );
+
} else {
assert.fail('Should have the manifest');
}
diff --git a/packages/astro/test/hydration-race.test.js b/packages/astro/test/hydration-race.test.js
index 00837fdd9bc3..1916c20d06ad 100644
--- a/packages/astro/test/hydration-race.test.js
+++ b/packages/astro/test/hydration-race.test.js
@@ -25,7 +25,7 @@ describe('Hydration script ordering', async () => {
// Sanity check that we're only rendering them once.
assert.equal($('style').length, 1, 'hydration style added once');
- assert.equal($('script').length, 1, 'only one hydration script needed');
+ assert.equal($('script').length, 2, 'only 2 hydration scripts needed');
});
it('Hydration script included when inside dynamic slot', async () => {
@@ -35,7 +35,7 @@ describe('Hydration script ordering', async () => {
// First, let's make sure all islands rendered
assert.equal($('astro-island').length, 1);
- // There should be 1 script
- assert.equal($('script').length, 1);
+ // There should be 2 scripts: directive and astro island
+ assert.equal($('script').length, 2);
});
});
diff --git a/scripts/cmd/prebuild.js b/scripts/cmd/prebuild.js
index 4b26aa529bd5..68a3a4f91386 100644
--- a/scripts/cmd/prebuild.js
+++ b/scripts/cmd/prebuild.js
@@ -4,14 +4,11 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
import esbuild from 'esbuild';
import { red } from 'kleur/colors';
import { glob } from 'tinyglobby';
-import crypto from 'node:crypto';
function escapeTemplateLiterals(str) {
return str.replace(/\`/g, '\\`').replace(/\$\{/g, '\\${');
}
-const ASTRO_ISLAND_STYLE_REGEX = /'([^']*)'/;
-
export default async function prebuild(...args) {
let buildToString = args.indexOf('--to-string');
if (buildToString !== -1) {
@@ -43,8 +40,6 @@ export default async function prebuild(...args) {
return outURL;
}
- const hashes = new Map();
-
async function prebuildFile(filepath) {
let tscode = await fs.promises.readFile(filepath, 'utf-8');
// If we're bundling a client directive, modify the code to match `packages/astro/src/core/client-directive/build.ts`.
@@ -114,35 +109,9 @@ export default async function prebuild(...args) {
export default \`${generatedCode}\`;`;
const url = getPrebuildURL(filepath, result.dev);
await fs.promises.writeFile(url, mod, 'utf-8');
- const hash = crypto.createHash('sha256').update(code).digest('base64');
- const basename = path.basename(filepath);
- hashes.set(basename.slice(0, basename.indexOf('.')), hash);
}
}
for (const entrypoint of entryPoints) {
await prebuildFile(entrypoint);
}
-
- const fileContent = await fs.promises.readFile(
- new URL('../../packages/astro/src/runtime/server/astro-island-styles.ts', import.meta.url),
- 'utf-8',
- );
- const styleContent = fileContent.match(ASTRO_ISLAND_STYLE_REGEX)[1];
- hashes.set(
- 'astro-island-styles',
- crypto.createHash('sha256').update(styleContent).digest('base64'),
- );
-
- const entries = JSON.stringify(Object.fromEntries(hashes.entries()), null, 2);
- const content = `// This file is code-generated, please don't change it manually
-export const ASTRO_ISLAND_HASHES = ${entries};`;
- await fs.promises.writeFile(
- path.join(
- fileURLToPath(import.meta.url),
- '../../../packages/astro/src/core',
- 'astro-islands-hashes.ts',
- ),
- content,
- 'utf-8',
- );
}