init
This commit is contained in:
228
packages/cli/src/index.ts
Normal file
228
packages/cli/src/index.ts
Normal file
@@ -0,0 +1,228 @@
|
||||
import { Command } from "commander";
|
||||
import fs from "fs-extra";
|
||||
import path from "path";
|
||||
import chalk from "chalk";
|
||||
import { fileURLToPath } from "url";
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const program = new Command();
|
||||
|
||||
program
|
||||
.name("mintel")
|
||||
.description("CLI for Mintel monorepo management")
|
||||
.version("1.0.0");
|
||||
|
||||
program
|
||||
.command("init <path>")
|
||||
.description("Initialize a new website project")
|
||||
.action(async (projectPath) => {
|
||||
const fullPath = path.isAbsolute(projectPath)
|
||||
? projectPath
|
||||
: path.resolve(process.cwd(), "../../", projectPath);
|
||||
const projectName = path.basename(fullPath);
|
||||
|
||||
console.log(chalk.blue(`Initializing new project: ${projectName}...`));
|
||||
|
||||
try {
|
||||
// Create directory
|
||||
await fs.ensureDir(fullPath);
|
||||
|
||||
// Create package.json
|
||||
const pkgJson = {
|
||||
name: projectName,
|
||||
version: "0.1.0",
|
||||
private: true,
|
||||
type: "module",
|
||||
scripts: {
|
||||
dev: "next dev",
|
||||
build: "next build",
|
||||
start: "next start",
|
||||
lint: "next lint",
|
||||
},
|
||||
dependencies: {
|
||||
next: "15.1.6",
|
||||
react: "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"@mintel/next-utils": "workspace:*",
|
||||
},
|
||||
devDependencies: {
|
||||
"@types/node": "^20.0.0",
|
||||
"@types/react": "^19.0.0",
|
||||
"@types/react-dom": "^19.0.0",
|
||||
typescript: "^5.0.0",
|
||||
"@mintel/tsconfig": "workspace:*",
|
||||
"@mintel/eslint-config": "workspace:*",
|
||||
"@mintel/next-config": "workspace:*",
|
||||
},
|
||||
};
|
||||
await fs.writeJson(path.join(fullPath, "package.json"), pkgJson, {
|
||||
spaces: 2,
|
||||
});
|
||||
|
||||
// Create next.config.ts
|
||||
const nextConfig = `import mintelNextConfig from "@mintel/next-config";
|
||||
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {};
|
||||
|
||||
export default mintelNextConfig(nextConfig);
|
||||
`;
|
||||
await fs.writeFile(path.join(fullPath, "next.config.ts"), nextConfig);
|
||||
|
||||
// Create tsconfig.json
|
||||
const tsConfig = {
|
||||
extends: "@mintel/tsconfig/nextjs.json",
|
||||
compilerOptions: {
|
||||
paths: {
|
||||
"@/*": ["./src/*"],
|
||||
},
|
||||
},
|
||||
include: [
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
".next/types/**/*.ts",
|
||||
],
|
||||
exclude: ["node_modules"],
|
||||
};
|
||||
await fs.writeJson(path.join(fullPath, "tsconfig.json"), tsConfig, {
|
||||
spaces: 2,
|
||||
});
|
||||
|
||||
// Create eslint.config.mjs
|
||||
const eslintConfig = `import { nextConfig } from "@mintel/eslint-config/next";
|
||||
|
||||
export default nextConfig;
|
||||
`;
|
||||
await fs.writeFile(
|
||||
path.join(fullPath, "eslint.config.mjs"),
|
||||
eslintConfig
|
||||
);
|
||||
|
||||
// Create basic src structure
|
||||
await fs.ensureDir(path.join(fullPath, "src/app/[locale]"));
|
||||
await fs.writeFile(
|
||||
path.join(fullPath, "src/middleware.ts"),
|
||||
`import { createMintelMiddleware } from "@mintel/next-utils";
|
||||
|
||||
export default createMintelMiddleware({
|
||||
locales: ["en", "de"],
|
||||
defaultLocale: "en",
|
||||
logRequests: true,
|
||||
});
|
||||
|
||||
export const config = {
|
||||
matcher: ["/((?!api|_next|_vercel|health|.*\\\\..*).*)", "/", "/(de|en)/:path*"]
|
||||
};
|
||||
`
|
||||
);
|
||||
|
||||
// Create i18n/request.ts
|
||||
await fs.ensureDir(path.join(fullPath, "src/i18n"));
|
||||
await fs.writeFile(
|
||||
path.join(fullPath, "src/i18n/request.ts"),
|
||||
`import { createMintelI18nRequestConfig } from "@mintel/next-utils";
|
||||
|
||||
export default createMintelI18nRequestConfig(
|
||||
["en", "de"],
|
||||
"en",
|
||||
(locale) => import(\`../../messages/\${locale}.json\`)
|
||||
);
|
||||
`
|
||||
);
|
||||
|
||||
// Create messages directory
|
||||
await fs.ensureDir(path.join(fullPath, "messages"));
|
||||
await fs.writeJson(path.join(fullPath, "messages/en.json"), {
|
||||
Index: {
|
||||
title: "Welcome"
|
||||
}
|
||||
}, { spaces: 2 });
|
||||
await fs.writeJson(path.join(fullPath, "messages/de.json"), {
|
||||
Index: {
|
||||
title: "Willkommen"
|
||||
}
|
||||
}, { spaces: 2 });
|
||||
|
||||
// Create instrumentation.ts
|
||||
await fs.writeFile(
|
||||
path.join(fullPath, "src/instrumentation.ts"),
|
||||
`import * as Sentry from '@sentry/nextjs';
|
||||
|
||||
export async function register() {
|
||||
if (process.env.NEXT_RUNTIME === 'nodejs') {
|
||||
// Server-side initialization
|
||||
}
|
||||
}
|
||||
|
||||
export const onRequestError = Sentry.captureRequestError;
|
||||
`
|
||||
);
|
||||
|
||||
await fs.writeFile(
|
||||
path.join(fullPath, "src/app/[locale]/layout.tsx"),
|
||||
`import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "${projectName}",
|
||||
description: "Created with Mintel CLI",
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
params: { locale }
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
params: { locale: string };
|
||||
}) {
|
||||
return (
|
||||
<html lang={locale}>
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
`
|
||||
);
|
||||
|
||||
await fs.writeFile(
|
||||
path.join(fullPath, "src/app/[locale]/page.tsx"),
|
||||
`export default function Home() {
|
||||
return (
|
||||
<main>
|
||||
<h1>Welcome to ${projectName}</h1>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
`
|
||||
);
|
||||
|
||||
// Copy infra templates
|
||||
const infraPath = path.resolve(__dirname, "../../infra");
|
||||
if (await fs.pathExists(infraPath)) {
|
||||
await fs.copy(
|
||||
path.join(infraPath, "docker/Dockerfile.nextjs"),
|
||||
path.join(fullPath, "Dockerfile")
|
||||
);
|
||||
await fs.copy(
|
||||
path.join(infraPath, "docker/docker-compose.template.yml"),
|
||||
path.join(fullPath, "docker-compose.yml")
|
||||
);
|
||||
await fs.ensureDir(path.join(fullPath, ".gitea/workflows"));
|
||||
await fs.copy(
|
||||
path.join(infraPath, "gitea/deploy-action.yml"),
|
||||
path.join(fullPath, ".gitea/workflows/deploy.yml")
|
||||
);
|
||||
}
|
||||
|
||||
console.log(
|
||||
chalk.green(`Successfully initialized ${projectName} at ${fullPath}`)
|
||||
);
|
||||
console.log(chalk.yellow("\nNext steps:"));
|
||||
console.log(chalk.cyan("1. pnpm install"));
|
||||
console.log(chalk.cyan(`2. cd ${projectPath} && pnpm dev`));
|
||||
} catch (error) {
|
||||
console.error(chalk.red("Error initializing project:"), error);
|
||||
}
|
||||
});
|
||||
|
||||
program.parse();
|
||||
Reference in New Issue
Block a user