Skip to content

Commit 7167174

Browse files
committed
Verify generated Astro projects on Deno
Give each Deno compatibility server a reserved port and embed that port in the adapter configuration at build time. Generate npm-backed dependencies that Vite can resolve, then build generated Deno projects with local package links exposed through node_modules. #936 (comment) #936 (comment) Assisted-by: Codex:gpt-5.6-sol
1 parent a10dfc7 commit 7167174

8 files changed

Lines changed: 77 additions & 12 deletions

File tree

docs/manual/integration.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -879,7 +879,7 @@ to integrate Fedify with Astro:
879879
::: code-group
880880

881881
~~~~ sh [Deno]
882-
deno add jsr:@fedify/astro
882+
deno add npm:@fedify/astro
883883
~~~~
884884

885885
~~~~ sh [npm]
@@ -957,6 +957,10 @@ export const onRequest = sequence(
957957

958958
### For Deno users
959959

960+
Install packages that Astro loads through Vite from npm. Vite resolves these
961+
imports through *node\_modules/* rather than Deno's JSR import map;
962+
`fedify init` selects npm packages for this reason.
963+
960964
If you are using Deno, you should import `@deno/astro-adapter` in
961965
_astro.config.ts_ and use it as the adapter:
962966

packages/astro/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ export const onRequest = sequence(
7878
For Deno users
7979
--------------
8080

81+
Install `@fedify/astro` and the other packages loaded by Astro from npm. Vite
82+
resolves these imports through *node\_modules/* rather than Deno's JSR import
83+
map.
84+
8185
If you are using Deno, you should import `@deno/astro-adapter` in
8286
*astro.config.mjs* and use it as the adapter:
8387

packages/astro/compat/run.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,12 @@ async function testCompatibility(testCase: CompatibilityCase): Promise<void> {
5757
`Astro ${testCase.astro}, ${adapterName} ${testCase.adapter}, ${testCase.runtime}`;
5858
console.log(`Testing ${label}...`);
5959
const tempDir = await Deno.makeTempDir({ prefix: "fedify-astro-compat-" });
60+
const port = reservePort();
6061
try {
6162
const tarballs = await packFedifyPackages(tempDir);
6263
await Deno.writeTextFile(
6364
join(tempDir, "astro.config.mjs"),
64-
await getAstroConfig(testCase),
65+
await getAstroConfig(testCase, port),
6566
);
6667
await copy(join(compatDir, "src"), join(tempDir, "src"));
6768
await Deno.writeTextFile(
@@ -89,7 +90,7 @@ async function testCompatibility(testCase: CompatibilityCase): Promise<void> {
8990

9091
await run(["pnpm", "install", "--strict-peer-dependencies"], tempDir);
9192
await run(["pnpm", "exec", "astro", "build"], tempDir);
92-
await exerciseServer(tempDir, testCase.runtime);
93+
await exerciseServer(tempDir, testCase.runtime, port);
9394
console.log(`Passed ${label}.`);
9495
} finally {
9596
if (Deno.env.get("KEEP_ASTRO_COMPAT") == null) {
@@ -100,7 +101,10 @@ async function testCompatibility(testCase: CompatibilityCase): Promise<void> {
100101
}
101102
}
102103

103-
async function getAstroConfig(testCase: CompatibilityCase): Promise<string> {
104+
async function getAstroConfig(
105+
testCase: CompatibilityCase,
106+
port: number,
107+
): Promise<string> {
104108
if (!testCase.astro.startsWith("^7.")) {
105109
return await Deno.readTextFile(join(compatDir, "astro.config.mjs.tpl"));
106110
}
@@ -122,6 +126,16 @@ async function getAstroConfig(testCase: CompatibilityCase): Promise<string> {
122126
});
123127
const config = initializer.files?.["astro.config.ts"];
124128
if (config == null) throw new Error("Astro initializer produced no config");
129+
if (testCase.runtime === "deno") {
130+
const configured = config.replace(
131+
"adapter: deno(),",
132+
`adapter: deno({ port: ${port} }),`,
133+
);
134+
if (configured === config) {
135+
throw new Error("Could not configure the Deno compatibility test port");
136+
}
137+
return configured;
138+
}
125139
return config;
126140
}
127141

@@ -167,8 +181,8 @@ async function packFedifyPackages(
167181
async function exerciseServer(
168182
dir: string,
169183
runtime: "node" | "deno" | "bun",
184+
port: number,
170185
): Promise<void> {
171-
const port = runtime === "deno" ? 8085 : reservePort();
172186
const command = new Deno.Command(runtime, {
173187
args: runtime === "deno"
174188
? ["run", "-A", "dist/server/entry.mjs"]

packages/init/src/action/configs.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ const getLinks = <
124124
T extends Pick<InitCommandData, "kv" | "mq" | "initializer" | "dir">,
125125
>({ kv, mq, initializer, dir }: T) =>
126126
pipe(
127-
{ "@fedify/fedify": "" },
127+
{ "@fedify/fedify": "", "@fedify/vocab": "" },
128128
merge(initializer.dependencies),
129129
merge(kv.dependencies),
130130
merge(mq.dependencies),

packages/init/src/action/utils.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import $ from "@david/dax";
2+
import { readFile, writeFile } from "node:fs/promises";
23
import { join as joinPath } from "node:path";
34
import type { InitCommandData } from "../types.ts";
45

@@ -88,8 +89,24 @@ export function stringifyEnvs(object: Record<string, string>): string {
8889
* Runs `<packageManager> install` in the project directory to install all
8990
* dependencies. Logs an error message if the installation fails.
9091
*/
91-
export const installDependencies = ({ packageManager, dir }: InitCommandData) =>
92-
$`${packageManager} install`.cwd(dir).spawn();
92+
export const installDependencies = async (data: InitCommandData) => {
93+
const { packageManager, dir, testMode } = data;
94+
if (packageManager !== "deno" || !testMode) {
95+
return await $`${packageManager} install`.cwd(dir).spawn();
96+
}
97+
98+
const configPath = joinPath(dir, "deno.json");
99+
const config = JSON.parse(await readFile(configPath, "utf8"));
100+
const links = config.links;
101+
delete config.links;
102+
await writeFile(configPath, JSON.stringify(config, null, 2) + "\n");
103+
try {
104+
return await $`${packageManager} install`.cwd(dir).spawn();
105+
} finally {
106+
config.links = links;
107+
await writeFile(configPath, JSON.stringify(config, null, 2) + "\n");
108+
}
109+
};
93110

94111
/**
95112
* Runs the precommand specified in the initializer to set up the project.

packages/init/src/package.test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { access, readFile } from "node:fs/promises";
33
import { dirname, resolve } from "node:path";
44
import test from "node:test";
55
import { fileURLToPath } from "node:url";
6+
import { PACKAGE_VERSION } from "./lib.ts";
67
import astroDescription from "./webframeworks/astro.ts";
78

89
const packageDir = resolve(dirname(fileURLToPath(import.meta.url)), "..");
@@ -60,6 +61,10 @@ test("Astro init pins the Astro 7 scaffolder and dependencies", async () => {
6061
packageManager === "deno" ? "npm:astro@^7.0.7" : "^7.0.7",
6162
);
6263
if (packageManager === "deno") {
64+
strictEqual(
65+
result.dependencies?.["@fedify/astro"],
66+
`npm:@fedify/astro@${PACKAGE_VERSION}`,
67+
);
6368
strictEqual(
6469
result.dependencies?.["@deno/astro-adapter"],
6570
"npm:@deno/astro-adapter@^0.6.0",

packages/init/src/test/create.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import $ from "@david/dax";
22
import { filter, isEmpty, pipe, toArray } from "@fxts/core";
33
import { values } from "@optique/core";
4-
import { appendFile, mkdir, stat } from "node:fs/promises";
5-
import { join, sep } from "node:path";
4+
import { appendFile, mkdir, readFile, stat, symlink } from "node:fs/promises";
5+
import { dirname, join, resolve, sep } from "node:path";
66
import process from "node:process";
77
import packageManagers from "../json/pm.json" with { type: "json" };
88
import { getBuildCommand, kvStores, messageQueues } from "../lib.ts";
@@ -180,7 +180,8 @@ async function validateFrameworkBuild(
180180
KvStore,
181181
MessageQueue,
182182
];
183-
if (webFramework !== "astro" || packageManager === "deno") return true;
183+
if (webFramework !== "astro") return true;
184+
if (packageManager === "deno") await linkDenoWorkspacePackages(dir);
184185
const result = await $`${getBuildCommand(packageManager)}`
185186
.cwd(dir)
186187
.stdin("null")
@@ -192,6 +193,23 @@ async function validateFrameworkBuild(
192193
return result.code === 0;
193194
}
194195

196+
async function linkDenoWorkspacePackages(dir: string): Promise<void> {
197+
const config = JSON.parse(await readFile(join(dir, "deno.json"), "utf8"));
198+
for (const link of config.links ?? []) {
199+
const packageDir = resolve(dir, link);
200+
const metadata = JSON.parse(
201+
await readFile(join(packageDir, "package.json"), "utf8"),
202+
);
203+
const target = join(dir, "node_modules", ...metadata.name.split("/"));
204+
await mkdir(dirname(target), { recursive: true });
205+
try {
206+
await stat(target);
207+
} catch {
208+
await symlink(packageDir, target, "junction");
209+
}
210+
}
211+
}
212+
195213
export function filterOptions(
196214
options: GeneratedType<ReturnType<typeof generateTestCases>>,
197215
): boolean {

packages/init/src/webframeworks/astro.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,14 @@ const astroDescription: WebFrameworkDescription = {
2626
const dependencies: Record<string, string> = pm === "deno"
2727
? {
2828
...defaultDenoDependencies,
29+
"@fedify/fedify": `npm:@fedify/fedify@${PACKAGE_VERSION}`,
30+
"@fedify/vocab": `npm:@fedify/vocab@${PACKAGE_VERSION}`,
31+
"@logtape/logtape": `npm:@logtape/logtape@${deps["@logtape/logtape"]}`,
2932
astro: `npm:astro@${deps["npm:astro"]}`,
3033
"@deno/astro-adapter": `npm:@deno/astro-adapter@${
3134
deps["npm:@deno/astro-adapter"]
3235
}`,
33-
"@fedify/astro": PACKAGE_VERSION,
36+
"@fedify/astro": `npm:@fedify/astro@${PACKAGE_VERSION}`,
3437
}
3538
: pm === "bun"
3639
? {

0 commit comments

Comments
 (0)