Skip to content

Commit a6496a7

Browse files
authored
Merge branch 'main' into rename-FreshContext-req-to-request
2 parents 67ead43 + b2c4f04 commit a6496a7

4 files changed

Lines changed: 129 additions & 8 deletions

File tree

packages/init/src/init.ts

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ export async function initProject(
6666
force?: boolean | null;
6767
tailwind?: boolean | null;
6868
vscode?: boolean | null;
69+
vite?: boolean | null;
6970
} = {},
7071
): Promise<void> {
7172
console.log();
@@ -108,6 +109,8 @@ export async function initProject(
108109
}
109110
}
110111

112+
const useVite = flags.vite ?? false;
113+
111114
const useDocker = flags.docker;
112115
let useTailwind = flags.tailwind || false;
113116
if (flags.tailwind == null) {
@@ -320,7 +323,13 @@ ${GRADIENT_CSS}`;
320323
${GRADIENT_CSS}`;
321324

322325
const cssStyles = useTailwind ? TAILWIND_CSS : NO_TAILWIND_STYLES;
323-
await writeFile("static/styles.css", cssStyles);
326+
327+
if (useVite) {
328+
await writeFile("assets/styles.css", cssStyles);
329+
await writeFile("client.ts", `import "./assets/styles.css";`);
330+
} else {
331+
await writeFile("static/styles.css", cssStyles);
332+
}
324333
// deno-fmt-ignore
325334
const STATIC_LOGO =
326335
`<svg width="40" height="40" fill="none" xmlns="http://www.w3.org/2000/svg">
@@ -458,8 +467,9 @@ export default define.page(function App({ Component }) {
458467
<head>
459468
<meta charset="utf-8" />
460469
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
461-
<title>${path.basename(projectDir)}</title>
462-
<link rel="stylesheet" href="/styles.css" />
470+
<title>${path.basename(projectDir)}</title>${
471+
useVite ? "" : `\n <link rel="stylesheet" href="/styles.css" />`
472+
}
463473
</head>
464474
<body>
465475
<Component />
@@ -510,7 +520,9 @@ if (Deno.args.includes("build")) {
510520
} else {
511521
await builder.listen(() => import("./main.ts"));
512522
}`;
513-
await writeFile("dev.ts", DEV_TS);
523+
if (!useVite) {
524+
await writeFile("dev.ts", DEV_TS);
525+
}
514526

515527
const denoJson = {
516528
nodeModulesDir: "auto",
@@ -555,7 +567,19 @@ if (Deno.args.includes("build")) {
555567
},
556568
};
557569

558-
if (useTailwind) {
570+
if (useVite) {
571+
denoJson.tasks.dev = "vite";
572+
denoJson.tasks.build = "vite build";
573+
574+
denoJson.imports["@fresh/plugin-vite"] = "jsr:@fresh/plugin-vite@^0.9.5";
575+
denoJson.imports["vite"] = "npm:vite@^7.1.3";
576+
577+
if (useTailwind) {
578+
denoJson.imports["tailwindcss"] =
579+
`npm:tailwindcss@^${TAILWINDCSS_VERSION}`;
580+
denoJson.imports["@tailwindcss/vite"] = `npm:@tailwindcss/vite@^4.1.12`;
581+
}
582+
} else if (useTailwind) {
559583
denoJson.imports["tailwindcss"] = `npm:tailwindcss@^${TAILWINDCSS_VERSION}`;
560584
denoJson.imports["@fresh/plugin-tailwind"] =
561585
`jsr:@fresh/plugin-tailwind@^${FRESH_TAILWIND_VERSION}`;
@@ -566,6 +590,21 @@ if (Deno.args.includes("build")) {
566590

567591
await writeFile("deno.json", denoJson);
568592

593+
if (useVite) {
594+
let viteConfig = `import { defineConfig } from "vite";
595+
import { fresh } from "@fresh/plugin-vite";\n`;
596+
597+
if (useTailwind) {
598+
viteConfig += `import tailwindcss from "@tailwindcss/vite";\n`;
599+
}
600+
601+
viteConfig += `\nexport default defineConfig({
602+
plugins: [fresh()${useTailwind ? ", tailwindcss()" : ""}],
603+
});`;
604+
605+
await writeFile("vite.config.ts", viteConfig);
606+
}
607+
569608
const README_MD = `# Fresh project
570609
571610
Your new Fresh project is ready to go. You can follow the Fresh "Getting

packages/init/src/init_test.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,20 @@ async function expectProjectFile(dir: string, pathname: string) {
5151
}
5252
}
5353

54+
async function expectNotProjectFile(dir: string, pathname: string) {
55+
const filePath = path.join(dir, ...pathname.split("/").filter(Boolean));
56+
try {
57+
const stat = await Deno.stat(filePath);
58+
if (stat.isFile) {
59+
throw new Error(`A project file but expected it not to be: ${filePath}`);
60+
}
61+
} catch (err) {
62+
if (!(err instanceof Deno.errors.NotFound)) {
63+
throw err;
64+
}
65+
}
66+
}
67+
5468
async function readProjectFile(dir: string, pathname: string): Promise<string> {
5569
const filePath = path.join(dir, ...pathname.split("/").filter(Boolean));
5670
const content = await Deno.readTextFile(filePath);
@@ -247,3 +261,61 @@ Deno.test("init - errors on missing build cache in prod", async () => {
247261

248262
expect(stderr).toMatch(/Module not found/);
249263
});
264+
265+
// There is a peerDependency issue with links
266+
Deno.test.ignore("init - vite dev server", async () => {
267+
await using tmp = await withTmpDir();
268+
const dir = tmp.dir;
269+
using _promptStub = stubPrompt(".");
270+
using _confirmStub = stubConfirm();
271+
await initProject(dir, [], { vite: true });
272+
273+
await expectProjectFile(dir, "vite.config.ts");
274+
await expectNotProjectFile(dir, "dev.ts");
275+
276+
await patchProject(dir);
277+
278+
await withChildProcessServer(
279+
{ cwd: dir, args: ["task", "dev"] },
280+
async (address) => {
281+
await withBrowser(async (page) => {
282+
await page.goto(address);
283+
await page.locator("#decrement").click();
284+
await waitForText(page, "button + p", "2");
285+
});
286+
},
287+
);
288+
});
289+
290+
// There is a peerDependency issue with links
291+
Deno.test.ignore("init - vite build", async () => {
292+
await using tmp = await withTmpDir();
293+
const dir = tmp.dir;
294+
using _promptStub = stubPrompt(".");
295+
using _confirmStub = stubConfirm();
296+
await initProject(dir, [], { vite: true });
297+
298+
await expectProjectFile(dir, "vite.config.ts");
299+
300+
await patchProject(dir);
301+
302+
// Build
303+
await new Deno.Command(Deno.execPath(), {
304+
args: ["task", "build"],
305+
stdin: "null",
306+
stdout: "piped",
307+
stderr: "piped",
308+
cwd: dir,
309+
}).output();
310+
311+
await withChildProcessServer(
312+
{ cwd: dir, env: { PORT: "0" }, args: ["task", "start"] },
313+
async (address) => {
314+
await withBrowser(async (page) => {
315+
await page.goto(address);
316+
await page.locator("button").click();
317+
await waitForText(page, "button + p", "2");
318+
});
319+
},
320+
);
321+
});

packages/init/src/mod.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@ import { initProject } from "./init.ts";
33
import { InitError } from "./init.ts";
44

55
const flags = parseArgs(Deno.args, {
6-
boolean: ["force", "tailwind", "vscode", "docker", "help"],
6+
boolean: ["force", "tailwind", "vscode", "docker", "help", "vite"],
77
default: {
88
force: null,
99
tailwind: null,
1010
vscode: null,
1111
docker: null,
12+
vite: null,
1213
},
1314
alias: {
1415
help: "h",

packages/plugin-vite/src/plugins/server_snapshot.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@ import {
1414
specToName,
1515
UniqueNamer,
1616
} from "fresh/internal-dev";
17-
import { pathWithRoot, type ResolvedFreshViteConfig } from "../utils.ts";
17+
import {
18+
JS_REG,
19+
pathWithRoot,
20+
type ResolvedFreshViteConfig,
21+
} from "../utils.ts";
1822
import * as path from "@std/path";
1923
import { getBuildId } from "./build_id.ts";
2024

@@ -268,7 +272,12 @@ export function serverSnapshot(options: ResolvedFreshViteConfig): Plugin[] {
268272
name: "fresh:island-resolver",
269273
resolveId(id) {
270274
if (id.startsWith("fresh-island::")) {
271-
const name = id.slice("fresh-island::".length);
275+
let name = id.slice("fresh-island::".length);
276+
277+
if (JS_REG.test(name)) {
278+
name = name.slice(0, name.lastIndexOf("."));
279+
}
280+
272281
const spec = islandSpecByName.get(name);
273282
if (spec !== undefined) return spec;
274283
}

0 commit comments

Comments
 (0)