summaryrefslogtreecommitdiff
path: root/packages/integrations/cloudflare/src/index.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/integrations/cloudflare/src/index.ts')
-rw-r--r--packages/integrations/cloudflare/src/index.ts75
1 files changed, 74 insertions, 1 deletions
diff --git a/packages/integrations/cloudflare/src/index.ts b/packages/integrations/cloudflare/src/index.ts
index deed35655..d7a68c3e4 100644
--- a/packages/integrations/cloudflare/src/index.ts
+++ b/packages/integrations/cloudflare/src/index.ts
@@ -1,7 +1,7 @@
import type { AstroConfig, AstroIntegration, RouteData } from 'astro';
import { createReadStream } from 'node:fs';
-import { appendFile, rename, stat } from 'node:fs/promises';
+import { appendFile, rename, stat, unlink } from 'node:fs/promises';
import { createInterface } from 'node:readline/promises';
import {
appendForwardSlash,
@@ -13,6 +13,7 @@ import { AstroError } from 'astro/errors';
import { getPlatformProxy } from 'wrangler';
import { createRoutesFile, getParts } from './utils/generate-routes-json.js';
import { setImageConfig } from './utils/image-config.js';
+import { NonServerChunkDetector } from './utils/non-server-chunk-detector.js';
import { wasmModuleLoader } from './utils/wasm-module-loader.js';
export type { Runtime } from './entrypoints/server.js';
@@ -64,6 +65,13 @@ export type Options = {
export default function createIntegration(args?: Options): AstroIntegration {
let _config: AstroConfig;
+ // Initialize the unused chunk analyzer as a shared state between hooks.
+ // The analyzer is used on earlier hooks to collect information about used hooks on a Vite plugin
+ // and then later after the full build to clean up unused chunks, so it has to be shared between them.
+ const chunkAnalyzer = new NonServerChunkDetector();
+
+ const prerenderImports: string[][] = [];
+
return {
name: '@astrojs/cloudflare',
hooks: {
@@ -84,6 +92,63 @@ export default function createIntegration(args?: Options): AstroIntegration {
wasmModuleLoader({
disabled: !args?.wasmModuleImports,
}),
+ chunkAnalyzer.getPlugin(),
+ {
+ name: 'dynamic-imports-analyzer',
+ enforce: 'post',
+ generateBundle(_, bundle) {
+ // Find all pages (ignore the ssr entrypoint) which are prerendered based on the dynamic imports of the prerender chunk
+ for (const chunk of Object.values(bundle)) {
+ if (chunk.type !== 'chunk') continue;
+
+ const isPrerendered = chunk.dynamicImports.some(
+ (entry) =>
+ entry.includes('prerender') && chunk.name !== '_@astrojs-ssr-virtual-entry'
+ );
+ if (isPrerendered) {
+ prerenderImports.push([chunk.facadeModuleId ?? '', chunk.fileName]);
+ }
+ }
+
+ const entryChunk = bundle['index.js'];
+ if (
+ entryChunk &&
+ entryChunk.type === 'chunk' &&
+ entryChunk.name === '_@astrojs-ssr-virtual-entry'
+ ) {
+ // Update dynamicImports information, so that there are no imports listed which we remove later
+ entryChunk.dynamicImports = entryChunk.dynamicImports.filter(
+ (entry) => !prerenderImports.map((e) => e[1]).includes(entry)
+ );
+
+ // Clean the ssr entry file from prerendered imporst, since Astro adds them, which it shouldn't. But this is a current limitation in core, because the prerender meta info gets added later in the chain
+ for (const page of prerenderImports) {
+ // Find the dynamic import inside of the ssr entry file, which get generated by Astro: https://github.com/withastro/astro/blob/08cdd0919d3249a762822e4bba9e0c5d3966916c/packages/astro/src/core/build/plugins/plugin-ssr.ts#L56
+ const importRegex = new RegExp(
+ `^const (_page\\d) = \\(\\) => import\\('.\\/${page[1]}'\\);$\\n`,
+ 'gm'
+ );
+
+ let pageId: string | undefined;
+ const matches = entryChunk.code.matchAll(importRegex);
+ for (const match of matches) {
+ if (match[1]) {
+ pageId = match[1];
+ }
+ }
+ const pageSource = page[0].split(':')[1].replace('@_@', '.');
+ entryChunk.code = entryChunk.code.replace(importRegex, '');
+ if (pageId) {
+ // Find the page in the pageMap of the ssr entry file, which get generated by Astro: https://github.com/withastro/astro/blob/08cdd0919d3249a762822e4bba9e0c5d3966916c/packages/astro/src/core/build/plugins/plugin-ssr.ts#L65
+ const arrayRegex = new RegExp(`\\["${pageSource}", ?${pageId}\\],?`, 'gm');
+ entryChunk.code = entryChunk.code.replace(arrayRegex, '');
+ }
+ }
+ } else {
+ // We don't want to handle this case, since it will always occur for the client build.
+ }
+ },
+ },
],
},
image: setImageConfig(args?.imageService ?? 'DEFAULT', config.image, command, logger),
@@ -303,6 +368,14 @@ export default function createIntegration(args?: Options): AstroIntegration {
logger.error('Failed to write _redirects file');
}
}
+
+ // Get chunks from the bundle that are not needed on the server and delete them
+ // Those modules are build only for prerendering routes.
+ const chunksToDelete = chunkAnalyzer.getNonServerChunks();
+ for (const chunk of chunksToDelete) {
+ // Chunks are located on `./_worker.js` directory inside of the output directory
+ await unlink(new URL(`./_worker.js/${chunk}`, _config.outDir));
+ }
},
},
};