create-manu-app
Version:
Create a new Next.js project with Tailwind CSS and TypeScript pre-configured. Simplify your project setup process with this scaffolding tool and start building your web application with ease.
191 lines (160 loc) ⢠6.49 kB
text/typescript
import { cancel, confirm, group, intro, outro, select, spinner, text } from '@clack/prompts';
import colors from 'picocolors';
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
import { createNextApp, createSE2, createViteReactApp } from './commands/create';
import { makeCommit } from './helpers/gitUtils';
import { installRainbowKit, installShadcn, installTailwindAndInit } from './helpers/installation';
import { checkIfYarnIsInstalled, getPkgManager, removeFiles, replaceFiles } from './helpers/utils';
// List of web 2 templates
const TEMPLATES_WEB2 = [
{
label: 'Next.js + ESLint + TypeScript + Shadcn/ui',
value: 'next-shadcn',
},
{
label: 'Next.js + ESLint + TypeScript + Tailwind',
value: 'next-tw',
},
{
label: 'React (vite) + ESLint + TypeScript + Shadcn/ui',
value: 'react-vite-shadcn',
},
];
// List of web 3 templates
const TEMPLATES_WEB3 = [
{
label: 'Next.js + ESLint + TypeScript + Shadcn/ui + RainbowKit',
value: 'next-rainbowkit',
},
{
label: 'Scaffold-Eth-2 Windows: Updated toolkit for building Ethereum dapps with Next.js.',
value: 'se2-w',
},
];
const s = spinner();
async function main() {
const argv = await yargs(hideBin(process.argv)).argv;
intro(colors.bold(colors.white(' Assistant to create a project as Manu would ')));
const promptsGroup = await group(
{
projectName: () =>
text({
message: colors.cyan('TTest What is your project named?'),
placeholder: 'my-app',
validate(value) {
if (value.length === 0) return `Name is required!`;
if (value.match(/[^a-zA-Z0-9-_]+/g))
return 'Project name can only contain letters, numbers, dashes and underscores';
},
}),
projectType: () =>
select({
message: colors.cyan('Select a project type.'),
initialValue: 'web2',
options: [
{ value: 'web2', label: 'š» Web 2' },
{ value: 'web3', label: 'š Web 3' },
],
}),
template: ({ results: { projectType } }) =>
select({
message: colors.cyan('Select a template.'),
initialValue: projectType === 'web2' ? TEMPLATES_WEB2[0].value : TEMPLATES_WEB3[0].value,
options: projectType === 'web2' ? TEMPLATES_WEB2 : TEMPLATES_WEB3,
}),
},
{
onCancel: () => {
cancel('Cancelled.');
process.exit(0);
},
},
);
const { projectName, projectType, template } = promptsGroup as {
projectName: string;
projectType: string;
template: string;
};
let pkgManager = getPkgManager(argv);
if (template === 'se2-w') {
// Check if template is se2-w and pkgManager is yarn and exit if so to avoid yarn conflicts
if (pkgManager !== 'yarn') {
const shouldChangePkgManager = await confirm({
message: colors.bold(colors.italic(colors.yellow('Scaffold-Eth-2 only supports yarn'))),
});
if (!shouldChangePkgManager) {
outro(colors.bold(colors.italic(colors.red('Cancelled'))));
process.exit(0);
}
const yarnIsInstalled = await checkIfYarnIsInstalled();
if (!yarnIsInstalled) {
outro(colors.bold(colors.italic(colors.red('Yarn is not installed'))));
process.exit(1);
}
pkgManager = 'yarn';
}
s.start(colors.yellow('š Creating Scaffold-Eth-2 project'));
await createSE2(projectName);
s.stop(colors.green('š Successfully Scaffold-Eth-2 project created!'));
}
if (template.includes('next')) {
// Create Next App
s.start(colors.yellow('š Creating Next project'));
await createNextApp(projectName, pkgManager);
s.stop(colors.green('š Successfully Next project created!'));
if (template === 'next-rainbowkit') {
// Install RainbowKit
s.start(colors.yellow('š Installing RainbowKit'));
await installRainbowKit(projectName, pkgManager);
s.stop(colors.green('š RainbowKit successfully installed!'));
}
if (template === 'next-shadcn') {
// Install Shadcn
s.start(colors.yellow('š§© Installing Shadcn'));
await installShadcn(projectName, template, pkgManager);
s.stop(colors.green('š§© Shadcn successfully installed!'));
}
// Replace files
s.start(colors.yellow('š Configuring files'));
await replaceFiles(projectName, projectType, template);
s.stop(colors.green('š Files configured successfully!'));
// Remove unnecessary files
s.start(colors.yellow('šļø Removing unnecessary files'));
await removeFiles(projectName, template);
s.stop(colors.green('šļø Unnecessary files deleted correctly!'));
await makeCommit(projectName);
}
if (template.includes('vite')) {
// Create Vite React App
s.start(colors.yellow('š Creating Vite React project'));
await createViteReactApp(projectName, pkgManager);
s.stop(colors.green('š Successfully Vite React project created!'));
// install tailwind
s.start(colors.yellow('šØ Installing Tailwind'));
await installTailwindAndInit(pkgManager, projectName);
s.stop(colors.green('šØ Tailwind successfully installed!'));
// Replace files
s.start(colors.yellow('š Configuring files'));
await replaceFiles(projectName, projectType, template);
s.stop(colors.green('š Files configured successfully!'));
// Install Shadcn
s.start(colors.yellow('š§© Installing Shadcn'));
await installShadcn(projectName, template, pkgManager);
s.stop(colors.green('š§© Shadcn successfully installed!'));
// Remove unnecessary files
s.start(colors.yellow('šļø Removing unnecessary files'));
await removeFiles(projectName, template);
s.stop(colors.green('šļø Unnecessary files deleted correctly!'));
}
const command = `${pkgManager} ${pkgManager === 'npm' ? 'run dev' : 'dev'}`;
const message = `\nš To get started, run ${colors.italic(
`cd ${projectName}`,
)} and then ${colors.italic(command)}`;
console.log(colors.white(message));
outro(colors.bold(colors.italic(colors.white(" Let's do great things! š "))));
process.exit(0);
}
// Run the main function
main().catch(console.error);