Skip to content

Commit

Permalink
feat: add back twind in init wizard (denoland#2290)
Browse files Browse the repository at this point in the history
  • Loading branch information
rojvv authored Jan 30, 2024
1 parent dfabf50 commit d19c22d
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 19 deletions.
89 changes: 73 additions & 16 deletions init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
dotenvImports,
freshImports,
tailwindImports,
twindImports,
} from "./src/dev/imports.ts";

ensureMinDenoVersion();
Expand All @@ -26,22 +27,26 @@ USAGE:
OPTIONS:
--force Overwrite existing files
--tailwind Setup project to use 'tailwind' for styling
--vscode Setup project for VSCode
--tailwind Use Tailwind for styling
--twind Use Twind for styling
--vscode Setup project for VS Code
--docker Setup Project to use Docker
`;

const CONFIRM_EMPTY_MESSAGE =
"The target directory is not empty (files could get overwritten). Do you want to continue anyway?";

const USE_TAILWIND_MESSAGE =
"Fresh has built in support for styling using Tailwind CSS. Do you want to use this?";

const USE_VSCODE_MESSAGE = "Do you use VS Code?";

const flags = parse(Deno.args, {
boolean: ["force", "tailwind", "vscode", "docker", "help"],
default: { "force": null, "tailwind": null, "vscode": null, "docker": null },
boolean: ["force", "tailwind", "twind", "vscode", "docker", "help"],
default: {
force: null,
tailwind: null,
twind: null,
vscode: null,
docker: null,
},
alias: {
help: "h",
},
Expand All @@ -52,6 +57,10 @@ if (flags.help) {
Deno.exit(0);
}

if (flags.tailwind && flags.twind) {
error("Cannot use Tailwind and Twind at the same time.");
}

console.log();
console.log(
colors.bgRgb8(
Expand Down Expand Up @@ -90,9 +99,25 @@ try {
}
console.log("%cLet's set up your new Fresh project.\n", "font-weight: bold");

const useTailwind = flags.tailwind === null
? confirm(USE_TAILWIND_MESSAGE)
: flags.tailwind;
let useTailwind = flags.tailwind || false;
let useTwind = flags.twind || false;

if (flags.tailwind == null && flags.twind == null) {
if (confirm("Do you want to use a styling library?")) {
console.log();
console.log("1. Tailwind");
console.log("2. Twind");
switch (
(prompt("Which styling library do you want to use? [1]") || "1").trim()
) {
case "2":
useTwind = true;
break;
default:
useTailwind = true;
}
}
}

const useVSCode = flags.vscode === null
? confirm(USE_VSCODE_MESSAGE)
Expand Down Expand Up @@ -322,6 +347,24 @@ if (useTailwind) {
);
}

const TWIND_CONFIG_TS = `import { defineConfig, Preset } from "@twind/core";
import presetTailwind from "@twind/preset-tailwind";
import presetAutoprefix from "@twind/preset-autoprefix";
export default {
...defineConfig({
presets: [presetTailwind() as Preset, presetAutoprefix() as Preset],
}),
selfURL: import.meta.url,
};
`;
if (useTwind) {
await Deno.writeTextFile(
join(resolvedDirectory, "twind.config.ts"),
TWIND_CONFIG_TS,
);
}

const NO_TAILWIND_STYLES = `
*,
*::before,
Expand Down Expand Up @@ -461,7 +504,7 @@ export default function App({ Component }: PageProps) {
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>${basename(resolvedDirectory)}</title>
<link rel="stylesheet" href="/styles.css" />
${useTwind ? "" : `<link rel="stylesheet" href="/styles.css" />`}
</head>
<body>
<Component />
Expand All @@ -481,10 +524,12 @@ const TAILWIND_CSS = `@tailwind base;
@tailwind utilities;`;

const cssStyles = useTailwind ? TAILWIND_CSS : NO_TAILWIND_STYLES;
await Deno.writeTextFile(
join(resolvedDirectory, "static", "styles.css"),
cssStyles,
);
if (!useTwind) {
await Deno.writeTextFile(
join(resolvedDirectory, "static", "styles.css"),
cssStyles,
);
}

const STATIC_LOGO =
`<svg width="40" height="40" fill="none" xmlns="http://www.w3.org/2000/svg">
Expand Down Expand Up @@ -515,10 +560,19 @@ if (useTailwind) {
FRESH_CONFIG_TS += `import tailwind from "$fresh/plugins/tailwind.ts";
`;
}
if (useTwind) {
FRESH_CONFIG_TS += `import twind from "$fresh/plugins/twindv1.ts";
import twindConfig from "./twind.config.ts";
`;
}

FRESH_CONFIG_TS += `
export default defineConfig({${
useTailwind ? `\n plugins: [tailwind()],\n` : ""
useTailwind
? `\n plugins: [tailwind()],\n`
: useTwind
? `\n plugins: [twind(twindConfig)],\n`
: ""
}});
`;
const CONFIG_TS_PATH = join(resolvedDirectory, "fresh.config.ts");
Expand Down Expand Up @@ -592,6 +646,9 @@ if (useTailwind) {
// deno-lint-ignore no-explicit-any
(config as any).nodeModulesDir = true;
}
if (useTwind) {
twindImports(config.imports);
}
dotenvImports(config.imports);

const DENO_CONFIG = JSON.stringify(config, null, 2) + "\n";
Expand Down
12 changes: 9 additions & 3 deletions src/dev/imports.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
export const RECOMMENDED_PREACT_VERSION = "10.19.2";
export const RECOMMENDED_PREACT_SIGNALS_VERSION = "1.2.1";
export const RECOMMENDED_PREACT_SIGNALS_CORE_VERSION = "1.5.0";
export const RECOMMENDED_TWIND_VERSION = "0.16.19";
export const RECOMMENDED_TWIND_CORE_VERSION = "1.1.3";
export const RECOMMENDED_TWIND_PRESET_AUTOPREFIX_VERSION = "1.0.7";
export const RECOMMENDED_TWIND_PRESET_TAILWIND_VERSION = "1.1.4";
export const RECOMMENDED_STD_VERSION = "0.211.0";
export const RECOMMENDED_TAILIWIND_VERSION = "3.4.1";

Expand All @@ -16,8 +18,12 @@ export function freshImports(imports: Record<string, string>) {
}

export function twindImports(imports: Record<string, string>) {
imports["twind"] = `https://esm.sh/twind@${RECOMMENDED_TWIND_VERSION}`;
imports["twind/"] = `https://esm.sh/twind@${RECOMMENDED_TWIND_VERSION}/`;
imports["@twind/core"] =
`https://esm.sh/@twind/core@${RECOMMENDED_TWIND_CORE_VERSION}`;
imports["@twind/preset-tailwind"] =
`https://esm.sh/@twind/preset-tailwind@${RECOMMENDED_TWIND_PRESET_TAILWIND_VERSION}/`;
imports["@twind/preset-autoprefix"] =
`https://esm.sh/@twind/preset-autoprefix@${RECOMMENDED_TWIND_PRESET_AUTOPREFIX_VERSION}/`;
}

export function tailwindImports(imports: Record<string, string>) {
Expand Down
94 changes: 94 additions & 0 deletions tests/init_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,100 @@ Deno.test({
},
});

Deno.test({
name: "fresh-init --twind --vscode",
async fn(t) {
// Preparation
const tmpDirName = await Deno.makeTempDir();

await t.step("execute init command", async () => {
const cliProcess = new Deno.Command(Deno.execPath(), {
args: [
"run",
"-A",
"init.ts",
tmpDirName,
"--twind",
"--vscode",
],
stdin: "null",
stdout: "null",
});
const { code } = await cliProcess.output();
assertEquals(code, 0);
});

const files = [
"/README.md",
"/fresh.gen.ts",
"/twind.config.ts",
"/components/Button.tsx",
"/islands/Counter.tsx",
"/main.ts",
"/routes/greet/[name].tsx",
"/routes/api/joke.ts",
"/routes/_app.tsx",
"/routes/index.tsx",
"/static/logo.svg",
"/.vscode/settings.json",
"/.vscode/extensions.json",
"/.gitignore",
];

await t.step("check generated files", async () => {
await assertFileExistence(files, tmpDirName);
});

await t.step("start up the server and access the root page", async () => {
const { serverProcess, lines, address } = await startFreshServer({
args: ["run", "-A", "--check", "main.ts"],
cwd: tmpDirName,
});

await delay(100);

// Access the root page
const res = await fetch(address);
await res.body?.cancel();
assertEquals(res.status, STATUS_CODE.OK);

// verify the island is revived.
const browser = await puppeteer.launch({ args: ["--no-sandbox"] });
const page = await browser.newPage();
await page.goto(address, { waitUntil: "networkidle2" });

const counter = await page.$("body > div > div > div > p");
let counterValue = await counter?.evaluate((el) => el.textContent);
assertEquals(counterValue, "3");

const fontWeight = await counter?.evaluate((el) =>
getComputedStyle(el).fontWeight
);
assertEquals(fontWeight, "400");

const buttonPlus = await page.$(
"body > div > div > div > button:nth-child(3)",
);
await buttonPlus?.click();

await waitForText(page, "body > div > div > div > p", "4");

counterValue = await counter?.evaluate((el) => el.textContent);
assert(counterValue === "4");
await page.close();
await browser.close();

serverProcess.kill("SIGTERM");
await serverProcess.status;

// Drain the lines stream
for await (const _ of lines) { /* noop */ }
});

await retry(() => Deno.remove(tmpDirName, { recursive: true }));
},
});

Deno.test("fresh-init error(help)", async function (t) {
const includeText = "fresh-init";

Expand Down

0 comments on commit d19c22d

Please sign in to comment.