UNPKG

wxt

Version:

⚡ Next-gen Web Extension Framework

141 lines (140 loc) 4.59 kB
import prompts from "prompts"; import { consola } from "consola"; import { downloadTemplate } from "giget"; import fs from "fs-extra"; import path from "node:path"; import pc from "picocolors"; export async function initialize(options) { consola.info("Initializing new project"); const templates = await listTemplates(); const defaultTemplate = templates.find( (template) => template.name === options.template?.toLowerCase().trim() ); const input = await prompts( [ { name: "directory", type: () => options.directory == null ? "text" : void 0, message: "Project Directory", initial: options.directory }, { name: "template", type: () => defaultTemplate == null ? "select" : void 0, message: "Choose a template", choices: templates.map((template) => ({ title: TEMPLATE_COLORS[template.name]?.(template.name) ?? template.name, value: template })) }, { name: "packageManager", type: () => options.packageManager == null ? "select" : void 0, message: "Package Manager", choices: [ { title: pc.red("npm"), value: "npm" }, { title: pc.yellow("pnpm"), value: "pnpm" }, { title: pc.cyan("yarn"), value: "yarn" }, { title: pc.magenta("bun"), value: "bun" } ] } ], { onCancel: () => process.exit(1) } ); input.directory ??= options.directory; input.template ??= defaultTemplate; input.packageManager ??= options.packageManager; const isExists = await fs.pathExists(input.directory); if (isExists) { const isEmpty = (await fs.readdir(input.directory)).filter((dir) => dir !== ".git").length === 0; if (!isEmpty) { consola.error( `The directory ${path.resolve(input.directory)} is not empty. Aborted.` ); process.exit(1); } } await cloneProject(input); const cdPath = path.relative(process.cwd(), path.resolve(input.directory)); console.log(); consola.log( `\u2728 WXT project created with the ${TEMPLATE_COLORS[input.template.name]?.(input.template.name) ?? input.template.name} template.` ); console.log(); consola.log("Next steps:"); let step = 0; if (cdPath !== "") consola.log(` ${++step}.`, pc.cyan(`cd ${cdPath}`)); consola.log(` ${++step}.`, pc.cyan(`${input.packageManager} install`)); console.log(); } async function listTemplates() { const templates = await listTemplatesUngh().catch((err) => { consola.debug("Failed to load templates via ungh:", err); return listTemplatesGithub(); }); return templates.sort((l, r) => { const lWeight = TEMPLATE_SORT_WEIGHT[l.name] ?? Number.MAX_SAFE_INTEGER; const rWeight = TEMPLATE_SORT_WEIGHT[r.name] ?? Number.MAX_SAFE_INTEGER; const diff = lWeight - rWeight; if (diff !== 0) return diff; return l.name.localeCompare(r.name); }); } async function listTemplatesUngh() { const res = await fetch("https://ungh.cc/repos/wxt-dev/wxt/files/main"); if (res.status !== 200) throw Error( `Request failed with status ${res.status} ${res.statusText}: ${await res.text()}` ); const data = await res.json(); return data.files.map((item) => item.path.match(/templates\/(.+)\/package\.json/)?.[1]).filter((name) => name != null).map((name) => ({ name, path: `templates/${name}` })); } async function listTemplatesGithub() { const res = await fetch( `https://api.github.com/repos/${REPO}/contents/templates`, { headers: { Accept: "application/vnd.github+json" } } ); if (res.status !== 200) throw Error( `Request failed with status ${res.status} ${res.statusText}: ${await res.text()}` ); return await res.json(); } async function cloneProject({ directory, template }) { const { default: ora } = await import("ora"); const spinner = ora("Downloading template").start(); try { await downloadTemplate(`gh:${REPO}/${template.path}`, { dir: directory, force: true }); await fs.move( path.join(directory, "_gitignore"), path.join(directory, ".gitignore") ).catch( (err) => consola.warn("Failed to move _gitignore to .gitignore:", err) ); spinner.succeed(); } catch (err) { spinner.fail(); throw Error(`Failed to setup new project: ${JSON.stringify(err, null, 2)}`); } } const TEMPLATE_COLORS = { vanilla: pc.blue, vue: pc.green, react: pc.cyan, svelte: pc.red, solid: pc.blue }; const TEMPLATE_SORT_WEIGHT = { vanilla: 0, vue: 1, react: 2 }; const REPO = "wxt-dev/wxt";