Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: bring back the posibility to initialize projects with Twind #2290

Merged
merged 2 commits into from
Jan 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading