UNPKG

create-nicsde-next-app

Version:

A CLI tool to create Next.js applications with custom configurations

273 lines (238 loc) 8.84 kB
#!/usr/bin/env node const path = require('path'); const fs = require('fs'); const fse = require('fs-extra'); // 定制化内容(可以根据项目需求进行修改) const customFiles = [ { src: '.gitignore', dest: '.gitignore' }, { src: 'next.config.ts', dest: 'next.config.ts' }, { src: 'Dockerfile', dest: 'Dockerfile' }, { src: '.dockerignore', dest: '.dockerignore' }, { src: '.eslintrc.js', dest: '.eslintrc.js' }, { src: '.npmrc', dest: '.npmrc' }, { src: '.prettierignore', dest: '.prettierignore' }, { src: '.prettierrc', dest: '.prettierrc' }, { src: 'tailwind.config.ts', dest: 'tailwind.config.ts' }, { src: 'postcss.config.mjs', dest: 'postcss.config.mjs' }, { src: 'components.json', dest: 'components.json' } ]; // 模板文件路径配置 const templatePath = path.join(__dirname); const templateFiles = { srcApp: path.join(templatePath, 'src', 'app'), public: path.join(templatePath, 'public') }; // 清理目标目录并复制模板文件 async function copyTemplateFiles(projectName) { const targetSrcApp = path.join(process.cwd(), projectName, 'src', 'app'); const targetPublic = path.join(process.cwd(), projectName, 'public'); try { // 清空目标目录 await fse.emptyDir(targetSrcApp); await fse.emptyDir(targetPublic); console.log('Source public path:', templateFiles.public); console.log('Target public path:', targetPublic); // 复制模板文件 await fse.copy(templateFiles.srcApp, targetSrcApp); await fse.copy(templateFiles.public, targetPublic); console.log('Template files copied successfully!'); } catch (error) { console.error('Error copying template files:', error); throw error; } } // 运行 `create-next-app` 命令 async function createApp(projectName) { const { execa } = await import('execa'); try { console.log('Creating Next.js app...'); await execa('npx', [ 'create-next-app', projectName, '--use-npm', '--typescript', '--turbo', '--eslint', '--tailwind', '--src-dir', '--app', '--import-alias', '@/*', '--yes' ], { stdio: 'inherit', }); // 复制模板文件 await copyTemplateFiles(projectName); // 自定义文件复制 customFiles.forEach((file) => { const srcPath = path.resolve(__dirname, file.src); const destPath = path.join(process.cwd(), projectName, file.dest); if (fs.existsSync(srcPath)) { fs.copyFileSync(srcPath, destPath); console.log(`Copied ${file.src} to ${file.dest}`); } else { console.log(`Source file ${file.src} does not exist`); } }); // 安装指定版本的tailwindcss console.log('Installing tailwindcss@3.4.1...'); await execa('npm', [ 'install', 'tailwindcss@3.4.1', 'postcss@latest' ], { cwd: path.join(process.cwd(), projectName), stdio: 'inherit' }); console.log(`Project ${projectName} created successfully!`); } catch (error) { console.error('Error creating the project:', error); } } // 询问用户是否要添加同济统一身份认证 async function promptForAuth() { const readline = require('readline').createInterface({ input: process.stdin, output: process.stdout }); return new Promise(resolve => { readline.question('是否要添加同济统一身份认证? (Y/n): ', answer => { readline.close(); resolve(answer.trim().toLowerCase() === 'y' || answer.trim() === ''); }); }); } // 询问是否需要对接开放平台 sdk async function promptForOpenplatform() { const readline = require('readline').createInterface({ input: process.stdin, output: process.stdout }); return new Promise(resolve => { readline.question('是否要添加同济大学开放平台sdk? (Y/n): ', answer => { readline.close(); resolve(answer.trim().toLowerCase() === 'y' || answer.trim() === ''); }); }); } // 安装next-auth和相关依赖 async function installAuth(projectName) { const { execa } = await import('execa'); try { // 复制auth配置文件 console.log('正在复制同济统一身份认证配置文件...') const apiSrc = path.join(__dirname, 'auth', 'api'); const apiDest = path.join(process.cwd(), projectName, 'src', 'app', 'api'); await fse.copySync(apiSrc, apiDest); const componentsSrc = path.join(__dirname, 'auth', 'components'); const componentsDest = path.join(process.cwd(), projectName, 'src', 'components'); await fse.copySync(componentsSrc, componentsDest); const envSrc = path.join(__dirname, 'auth/.env'); const envDest = path.join(process.cwd(), projectName, '.env'); await fse.copySync(envSrc, envDest); const packageJsonSrc = path.join(__dirname, 'auth/package.json'); const packageJsonDest = path.join(process.cwd(), projectName, 'package.json'); await fse.copySync(packageJsonSrc, packageJsonDest); const layoutSrc = path.join(__dirname, 'auth/layout.tsx'); const layoutDest = path.join(process.cwd(), projectName, 'src/app/layout.tsx'); await fse.copySync(layoutSrc, layoutDest); // const pageSrc = path.join(__dirname, 'auth/page.tsx'); // const pageDest = path.join(process.cwd(), projectName, 'src/app/page.tsx'); // await fse.copySync(pageSrc, pageDest); const authSrc = path.join(__dirname, 'auth/auth.ts'); const authDest = path.join(process.cwd(), projectName, 'src/auth.ts'); await fse.copySync(authSrc, authDest); console.log('正在安装next-auth...'); await execa('npm', ['install', 'next-auth@5.0.0-beta.28'], { cwd: path.join(process.cwd(), projectName), stdio: 'inherit' }); console.log('同济统一身份认证配置已添加'); } catch (error) { console.error('安装next-auth失败:', error); } } // 安装@tongji_api/sdk async function installOpenplatformSDK(projectName) { const { execa } = await import('execa'); try { console.log('正在复制同济开放平台SDK使用文档文件...') const apiSrc = path.join(__dirname, 'sdk'); const apiDest = path.join(process.cwd(), projectName, 'src', 'app', 'sdk'); await fse.copySync(apiSrc, apiDest); await execa('npm', ['install', '@tongji_api/sdk@1.0.6-test'], { cwd: path.join(process.cwd(), projectName), stdio: 'inherit' }); } catch (error) { console.error('安装开放平台sdk失败:', error); } } // 动态修改 page.tsx async function modifyPageTsx(projectName, needAuth, needOpenplatformSDK) { const filePath = path.join(process.cwd(), projectName, 'src/app/page.tsx'); // 读取文件内容 fs.readFile(filePath, 'utf8', (err, data) => { if (err) { return console.error('读取文件时出错:', err); } // 将文件内容按行分割 const lines = data.split('\n'); // 确定要插入内容的行索引 const insertIndex = lines.length - 4; // 插入新内容(例如,添加一个注释) let newContent = ' <div className={styles.grid}>'; let insertAuthImport = 0 if (needAuth) { // 第三行导入 insertAuthImport = 1 lines.splice(insertAuthImport, 0 , `import Button from "@/components/auth/Button"`) newContent += ` <div className={styles.card}> <h2>同济大学统一身份认证 &rarr;</h2> <Button></Button> </div>`; } if (needOpenplatformSDK) { newContent += ` <a href="/sdk" className={styles.card}> <h2>sdk 文档 &rarr;</h2> <p>集成 开放平台 sdk调用,快速获取数据 </p> </a>`; } newContent += '\n </div>'; lines.splice(insertIndex+insertAuthImport, 0, newContent); // 将修改后的内容重新组合成字符串 const updatedData = lines.join('\n'); // 写回文件 fs.writeFile(filePath, updatedData, 'utf8', (err) => { if (err) { return console.error('写入文件时出错:', err); } console.log('文件已成功修改。'); }); }); } // 运行脚本 async function main() { const projectName = process.argv[2] || 'my-next-app'; const needAuth = await promptForAuth(); const needOpenplatformSDK = await promptForOpenplatform(); await createApp(projectName); if (needAuth || needOpenplatformSDK) { if (needAuth) await installAuth(projectName); if (needOpenplatformSDK) await installOpenplatformSDK(projectName); await modifyPageTsx(projectName, needAuth, needOpenplatformSDK); } const { execa } = await import('execa'); await execa('npm', [ 'install', 'class-variance-authority@^0.7.0', 'tailwind-merge@^2.5.4' ], { cwd: path.join(process.cwd(), projectName), stdio: 'inherit' }); } main();