summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--.changeset/shaggy-moons-judge.md5
-rw-r--r--examples/deno/package.json2
-rw-r--r--examples/deno/src/pages/index.astro2
-rw-r--r--packages/integrations/deno/package.json1
-rw-r--r--packages/integrations/deno/src/__deno_imports.ts10
-rw-r--r--packages/integrations/deno/src/index.ts39
-rw-r--r--packages/integrations/deno/src/server.ts34
-rw-r--r--packages/integrations/deno/test/basics.test.ts23
-rw-r--r--packages/integrations/deno/test/fixtures/basics/src/pages/prerender.astro9
9 files changed, 116 insertions, 9 deletions
diff --git a/.changeset/shaggy-moons-judge.md b/.changeset/shaggy-moons-judge.md
new file mode 100644
index 000000000..f23e08334
--- /dev/null
+++ b/.changeset/shaggy-moons-judge.md
@@ -0,0 +1,5 @@
+---
+'@astrojs/deno': patch
+---
+
+Fix prerendered page behavior
diff --git a/examples/deno/package.json b/examples/deno/package.json
index 8841cba73..9d9ac114b 100644
--- a/examples/deno/package.json
+++ b/examples/deno/package.json
@@ -6,7 +6,7 @@
"dev": "astro dev",
"start": "astro dev",
"build": "astro build",
- "preview": "deno run --allow-net --allow-read ./dist/server/entry.mjs",
+ "preview": "deno run --allow-net --allow-read --allow-env ./dist/server/entry.mjs",
"astro": "astro"
},
"dependencies": {
diff --git a/examples/deno/src/pages/index.astro b/examples/deno/src/pages/index.astro
index 19e358c77..0399a7534 100644
--- a/examples/deno/src/pages/index.astro
+++ b/examples/deno/src/pages/index.astro
@@ -1,5 +1,7 @@
---
import Layout from '../components/Layout.astro';
+
+export const prerender = true;
---
<Layout title="Welcome to Astro (on Deno).">
diff --git a/packages/integrations/deno/package.json b/packages/integrations/deno/package.json
index 56804afec..dc6b4ae46 100644
--- a/packages/integrations/deno/package.json
+++ b/packages/integrations/deno/package.json
@@ -20,6 +20,7 @@
"exports": {
".": "./dist/index.js",
"./server.js": "./dist/server.js",
+ "./__deno_imports.js": "./dist/__deno_imports.js",
"./package.json": "./package.json"
},
"scripts": {
diff --git a/packages/integrations/deno/src/__deno_imports.ts b/packages/integrations/deno/src/__deno_imports.ts
new file mode 100644
index 000000000..2775f1a5b
--- /dev/null
+++ b/packages/integrations/deno/src/__deno_imports.ts
@@ -0,0 +1,10 @@
+// This file is a shim for any Deno-specific imports!
+// It will be replaced in the final Deno build.
+//
+// This allows us to prerender pages in Node.
+export class Server {
+ listenAndServe() {}
+}
+
+export function serveFile() {}
+export function fromFileUrl() {}
diff --git a/packages/integrations/deno/src/index.ts b/packages/integrations/deno/src/index.ts
index 11f5adebf..fcfda5dc3 100644
--- a/packages/integrations/deno/src/index.ts
+++ b/packages/integrations/deno/src/index.ts
@@ -20,6 +20,16 @@ const SHIM = `globalThis.process = {
env: Deno.env.toObject(),
};`;
+const DENO_VERSION = `0.177.0`
+
+// We shim deno-specific imports so we can run the code in Node
+// to prerender pages. In the final Deno build, this import is
+// replaced with the Deno-specific contents listed below.
+const DENO_IMPORTS_SHIM = `@astrojs/deno/__deno_imports.js`;
+const DENO_IMPORTS = `export { Server } from "https://deno.land/std@${DENO_VERSION}/http/server.ts"
+export { serveFile } from 'https://deno.land/std@${DENO_VERSION}/http/file_server.ts';
+export { fromFileUrl } from "https://deno.land/std@${DENO_VERSION}/path/mod.ts";`
+
export function getAdapter(args?: Options): AstroAdapter {
return {
name: '@astrojs/deno',
@@ -29,6 +39,18 @@ export function getAdapter(args?: Options): AstroAdapter {
};
}
+const denoImportsShimPlugin = {
+ name: '@astrojs/deno:shim',
+ setup(build: esbuild.PluginBuild) {
+ build.onLoad({ filter: /__deno_imports\.js$/ }, async (args) => {
+ return {
+ contents: DENO_IMPORTS,
+ loader: 'js',
+ }
+ })
+ },
+}
+
export default function createIntegration(args?: Options): AstroIntegration {
let _buildConfig: BuildConfig;
let _vite: any;
@@ -49,8 +71,11 @@ export default function createIntegration(args?: Options): AstroIntegration {
'astro:build:setup': ({ vite, target }) => {
if (target === 'server') {
_vite = vite;
- vite.resolve = vite.resolve || {};
- vite.resolve.alias = vite.resolve.alias || {};
+ vite.resolve = vite.resolve ?? {};
+ vite.resolve.alias = vite.resolve.alias ?? {};
+ vite.build = vite.build ?? {};
+ vite.build.rollupOptions = vite.build.rollupOptions ?? {};
+ vite.build.rollupOptions.external = vite.build.rollupOptions.external ?? [];
const aliases = [{ find: 'react-dom/server', replacement: 'react-dom/server.browser' }];
@@ -61,10 +86,15 @@ export default function createIntegration(args?: Options): AstroIntegration {
(vite.resolve.alias as Record<string, string>)[alias.find] = alias.replacement;
}
}
-
vite.ssr = {
noExternal: true,
};
+
+ if (Array.isArray(vite.build.rollupOptions.external)) {
+ vite.build.rollupOptions.external.push(DENO_IMPORTS_SHIM);
+ } else if (typeof vite.build.rollupOptions.external !== 'function') {
+ vite.build.rollupOptions.external = [vite.build.rollupOptions.external, DENO_IMPORTS_SHIM]
+ }
}
},
'astro:build:done': async () => {
@@ -80,6 +110,9 @@ export default function createIntegration(args?: Options): AstroIntegration {
format: 'esm',
bundle: true,
external: ['@astrojs/markdown-remark'],
+ plugins: [
+ denoImportsShimPlugin
+ ],
banner: {
js: SHIM,
},
diff --git a/packages/integrations/deno/src/server.ts b/packages/integrations/deno/src/server.ts
index e7a6c8747..8979a96d0 100644
--- a/packages/integrations/deno/src/server.ts
+++ b/packages/integrations/deno/src/server.ts
@@ -3,9 +3,7 @@ import type { SSRManifest } from 'astro';
import { App } from 'astro/app';
// @ts-ignore
-import { Server } from 'https://deno.land/std@0.167.0/http/server.ts';
-// @ts-ignore
-import { fetch } from 'https://deno.land/x/file_fetch/mod.ts';
+import { Server, serveFile, fromFileUrl } from '@astrojs/deno/__deno_imports.js';
interface Options {
port?: number;
@@ -16,6 +14,17 @@ interface Options {
let _server: Server | undefined = undefined;
let _startPromise: Promise<void> | undefined = undefined;
+async function* getPrerenderedFiles(clientRoot: URL): AsyncGenerator<URL> {
+ // @ts-ignore
+ for await (const ent of Deno.readDir(clientRoot)) {
+ if (ent.isDirectory) {
+ yield* getPrerenderedFiles(new URL(`./${ent.name}/`, clientRoot))
+ } else if (ent.name.endsWith('.html')) {
+ yield new URL(`./${ent.name}`, clientRoot)
+ }
+ }
+}
+
export function start(manifest: SSRManifest, options: Options) {
if (options.start === false) {
return;
@@ -40,7 +49,24 @@ export function start(manifest: SSRManifest, options: Options) {
// try to fetch a static file instead
const url = new URL(request.url);
const localPath = new URL('./' + app.removeBase(url.pathname), clientRoot);
- const fileResp = await fetch(localPath.toString());
+
+ let fileResp = await serveFile(request, fromFileUrl(localPath));
+
+ // Attempt to serve `index.html` if 404
+ if (fileResp.status == 404) {
+ let fallback;
+ for await (const file of getPrerenderedFiles(clientRoot)) {
+ const pathname = file.pathname.replace(/\/(index)?\.html$/, '');
+ if (localPath.pathname.endsWith(pathname)) {
+ fallback = file;
+ break;
+ }
+ }
+ if (fallback) {
+ fileResp = await serveFile(request, fromFileUrl(fallback));
+ }
+ }
+
// If the static file can't be found
if (fileResp.status == 404) {
diff --git a/packages/integrations/deno/test/basics.test.ts b/packages/integrations/deno/test/basics.test.ts
index d1f8907cb..ea81042b2 100644
--- a/packages/integrations/deno/test/basics.test.ts
+++ b/packages/integrations/deno/test/basics.test.ts
@@ -68,7 +68,7 @@ Deno.test({
resp = await fetch(new URL(href!, baseUrl));
assertEquals(resp.status, 200);
const ct = resp.headers.get('content-type');
- assertEquals(ct, 'text/css');
+ assertEquals(ct, 'text/css; charset=UTF-8');
await resp.body!.cancel();
});
},
@@ -143,3 +143,24 @@ Deno.test({
sanitizeResources: false,
sanitizeOps: false,
});
+
+
+Deno.test({
+ name: 'perendering',
+ permissions: defaultTestPermissions,
+ async fn() {
+ await startApp(async (baseUrl: URL) => {
+ const resp = await fetch(new URL('/prerender', baseUrl));
+ assertEquals(resp.status, 200);
+
+ const html = await resp.text();
+ assert(html);
+
+ const doc = new DOMParser().parseFromString(html, `text/html`);
+ const h1 = doc!.querySelector('h1');
+ assertEquals(h1!.innerText, 'test');
+ });
+ },
+ sanitizeResources: false,
+ sanitizeOps: false,
+});
diff --git a/packages/integrations/deno/test/fixtures/basics/src/pages/prerender.astro b/packages/integrations/deno/test/fixtures/basics/src/pages/prerender.astro
new file mode 100644
index 000000000..d19d3e6f9
--- /dev/null
+++ b/packages/integrations/deno/test/fixtures/basics/src/pages/prerender.astro
@@ -0,0 +1,9 @@
+---
+export const prerender = true;
+---
+
+<html>
+ <body>
+ <h1>test</h1>
+ </body>
+</html>