fix(@astrojs/cloudflare): SSR split file renaming misses ts endpoints (#7568)
* fix bug, where ts files where not renamed correctly * try to make rename logic more robust * remove log * update tests * update changeset * cleanup * fix lint * debug windows tests * fix windows support * fix cloudflare directory code * use EventContext type * improve for loop * change changeset Co-authored-by: Emanuele Stoppa <my.burning@gmail.com> * change changeset Co-authored-by: Emanuele Stoppa <my.burning@gmail.com> --------- Co-authored-by: Emanuele Stoppa <my.burning@gmail.com>
This commit is contained in:
parent
1f0d0b5863
commit
6ec040761e
8 changed files with 63 additions and 33 deletions
5
.changeset/large-meals-joke.md
Normal file
5
.changeset/large-meals-joke.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'@astrojs/cloudflare': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fix a bug where asset redirects caused Cloudflare error
|
5
.changeset/sweet-bats-clap.md
Normal file
5
.changeset/sweet-bats-clap.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'@astrojs/cloudflare': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fix bug where `.ts` files are not renamed to `.js`
|
|
@ -3,7 +3,7 @@ import type { AstroAdapter, AstroConfig, AstroIntegration, RouteData } from 'ast
|
||||||
import esbuild from 'esbuild';
|
import esbuild from 'esbuild';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
import { dirname } from 'path';
|
import { sep } from 'path';
|
||||||
import glob from 'tiny-glob';
|
import glob from 'tiny-glob';
|
||||||
import { fileURLToPath, pathToFileURL } from 'url';
|
import { fileURLToPath, pathToFileURL } from 'url';
|
||||||
|
|
||||||
|
@ -21,15 +21,15 @@ interface BuildConfig {
|
||||||
export function getAdapter(isModeDirectory: boolean): AstroAdapter {
|
export function getAdapter(isModeDirectory: boolean): AstroAdapter {
|
||||||
return isModeDirectory
|
return isModeDirectory
|
||||||
? {
|
? {
|
||||||
name: '@astrojs/cloudflare',
|
name: '@astrojs/cloudflare',
|
||||||
serverEntrypoint: '@astrojs/cloudflare/server.directory.js',
|
serverEntrypoint: '@astrojs/cloudflare/server.directory.js',
|
||||||
exports: ['onRequest', 'manifest'],
|
exports: ['onRequest', 'manifest'],
|
||||||
}
|
}
|
||||||
: {
|
: {
|
||||||
name: '@astrojs/cloudflare',
|
name: '@astrojs/cloudflare',
|
||||||
serverEntrypoint: '@astrojs/cloudflare/server.advanced.js',
|
serverEntrypoint: '@astrojs/cloudflare/server.advanced.js',
|
||||||
exports: ['default'],
|
exports: ['default'],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const SHIM = `globalThis.process = {
|
const SHIM = `globalThis.process = {
|
||||||
|
@ -112,13 +112,12 @@ export default function createIntegration(args?: Options): AstroIntegration {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isModeDirectory && _buildConfig.split) {
|
if (isModeDirectory && _buildConfig.split) {
|
||||||
const entryPointsRouteData = [..._entryPoints.keys()];
|
|
||||||
const entryPointsURL = [..._entryPoints.values()];
|
const entryPointsURL = [..._entryPoints.values()];
|
||||||
const entryPaths = entryPointsURL.map((entry) => fileURLToPath(entry));
|
const entryPaths = entryPointsURL.map((entry) => fileURLToPath(entry));
|
||||||
const outputDir = fileURLToPath(new URL('.astro', _buildConfig.server));
|
const outputUrl = new URL('$astro', _buildConfig.server)
|
||||||
|
const outputDir = fileURLToPath(outputUrl);
|
||||||
|
|
||||||
// NOTE: AFAIK, esbuild keeps the order of the entryPoints array
|
await esbuild.build({
|
||||||
const { outputFiles } = await esbuild.build({
|
|
||||||
target: 'es2020',
|
target: 'es2020',
|
||||||
platform: 'browser',
|
platform: 'browser',
|
||||||
conditions: ['workerd', 'worker', 'browser'],
|
conditions: ['workerd', 'worker', 'browser'],
|
||||||
|
@ -134,28 +133,44 @@ export default function createIntegration(args?: Options): AstroIntegration {
|
||||||
logOverride: {
|
logOverride: {
|
||||||
'ignored-bare-import': 'silent',
|
'ignored-bare-import': 'silent',
|
||||||
},
|
},
|
||||||
write: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// loop through all bundled files and write them to the functions folder
|
const outputFiles: Array<string> = (
|
||||||
for (const [index, outputFile] of outputFiles.entries()) {
|
await glob(`**/*`, {
|
||||||
// we need to make sure the filename in the functions folder
|
cwd: outputDir,
|
||||||
// matches to cloudflares routing capabilities (see their docs)
|
filesOnly: true,
|
||||||
// IN: src/pages/[language]/files/[...path].astro
|
})
|
||||||
// OUT: [language]/files/[[path]].js
|
)
|
||||||
const fileName = entryPointsRouteData[index].component
|
|
||||||
.replace('src/pages/', '')
|
|
||||||
.replace('.astro', '.js')
|
|
||||||
.replace(/(\[\.\.\.)(\w+)(\])/g, (_match, _p1, p2) => {
|
|
||||||
return `[[${p2}]]`;
|
|
||||||
});
|
|
||||||
|
|
||||||
const fileUrl = new URL(fileName, functionsUrl);
|
// move the files into the functions folder
|
||||||
const newFileDir = dirname(fileURLToPath(fileUrl));
|
// & make sure the file names match Cloudflare syntax for routing
|
||||||
if (!fs.existsSync(newFileDir)) {
|
for (const outputFile of outputFiles) {
|
||||||
fs.mkdirSync(newFileDir, { recursive: true });
|
const path = outputFile.split(sep);
|
||||||
}
|
|
||||||
await fs.promises.writeFile(fileUrl, outputFile.contents);
|
const finalSegments = path.map((segment) => segment
|
||||||
|
.replace(/(\_)(\w+)(\_)/g, (_, __, prop) => {
|
||||||
|
return `[${prop}]`;
|
||||||
|
})
|
||||||
|
.replace(/(\_\-\-\-)(\w+)(\_)/g, (_, __, prop) => {
|
||||||
|
return `[[${prop}]]`;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
finalSegments[finalSegments.length - 1] = finalSegments[finalSegments.length - 1]
|
||||||
|
.replace('entry.', '')
|
||||||
|
.replace(/(.*)\.(\w+)\.(\w+)$/g, (_, fileName, __, newExt) => {
|
||||||
|
return `${fileName}.${newExt}`;
|
||||||
|
})
|
||||||
|
|
||||||
|
const finalDirPath = finalSegments.slice(0, -1).join(sep);
|
||||||
|
const finalPath = finalSegments.join(sep);
|
||||||
|
|
||||||
|
const newDirUrl = new URL(finalDirPath, functionsUrl);
|
||||||
|
await fs.promises.mkdir(newDirUrl, { recursive: true })
|
||||||
|
|
||||||
|
const oldFileUrl = new URL(`$astro/${outputFile}`, outputUrl);
|
||||||
|
const newFileUrl = new URL(finalPath, functionsUrl);
|
||||||
|
await fs.promises.rename(oldFileUrl, newFileUrl);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const entryPath = fileURLToPath(new URL(_buildConfig.serverEntry, _buildConfig.server));
|
const entryPath = fileURLToPath(new URL(_buildConfig.serverEntry, _buildConfig.server));
|
||||||
|
|
|
@ -24,7 +24,9 @@ export function createExports(manifest: SSRManifest) {
|
||||||
const { pathname } = new URL(request.url);
|
const { pathname } = new URL(request.url);
|
||||||
// static assets fallback, in case default _routes.json is not used
|
// static assets fallback, in case default _routes.json is not used
|
||||||
if (manifest.assets.has(pathname)) {
|
if (manifest.assets.has(pathname)) {
|
||||||
return next(request);
|
// we need this so the page does not error
|
||||||
|
// https://developers.cloudflare.com/pages/platform/functions/advanced-mode/#set-up-a-function
|
||||||
|
return (runtimeEnv.env as EventContext<unknown, string, unknown>['env']).ASSETS.fetch(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
let routeData = app.match(request, { matchNotFound: true });
|
let routeData = app.match(request, { matchNotFound: true });
|
||||||
|
|
|
@ -36,6 +36,9 @@ describe('Cloudflare SSR split', () => {
|
||||||
expect(await fixture.pathExists('../functions/[person]/[car].js')).to.be.true;
|
expect(await fixture.pathExists('../functions/[person]/[car].js')).to.be.true;
|
||||||
expect(await fixture.pathExists('../functions/files/[[path]].js')).to.be.true;
|
expect(await fixture.pathExists('../functions/files/[[path]].js')).to.be.true;
|
||||||
expect(await fixture.pathExists('../functions/[language]/files/[[path]].js')).to.be.true;
|
expect(await fixture.pathExists('../functions/[language]/files/[[path]].js')).to.be.true;
|
||||||
|
expect(await fixture.pathExists('../functions/trpc/[trpc].js')).to.be.true;
|
||||||
|
expect(await fixture.pathExists('../functions/javascript.js')).to.be.true;
|
||||||
|
expect(await fixture.pathExists('../functions/test.json.js')).to.be.true;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('generates pre-rendered files', async () => {
|
it('generates pre-rendered files', async () => {
|
||||||
|
|
0
packages/integrations/cloudflare/test/fixtures/split/src/pages/javascript.js
vendored
Normal file
0
packages/integrations/cloudflare/test/fixtures/split/src/pages/javascript.js
vendored
Normal file
0
packages/integrations/cloudflare/test/fixtures/split/src/pages/test.json.ts
vendored
Normal file
0
packages/integrations/cloudflare/test/fixtures/split/src/pages/test.json.ts
vendored
Normal file
0
packages/integrations/cloudflare/test/fixtures/split/src/pages/trpc/[trpc].ts
vendored
Normal file
0
packages/integrations/cloudflare/test/fixtures/split/src/pages/trpc/[trpc].ts
vendored
Normal file
Loading…
Reference in a new issue