create-viewlogic
Version:
CLI tool to create ViewLogic Vue 3 applications with zero configuration
236 lines (197 loc) • 6.89 kB
JavaScript
const fs = require('fs-extra');
const path = require('path');
const chalk = require('chalk');
const ora = require('ora');
const inquirer = require('inquirer');
const { execSync } = require('child_process');
/**
* ViewLogic 프로젝트 초기화 (현재 디렉토리 또는 지정된 디렉토리)
*/
async function init(projectName, options) {
const targetDir = projectName ? path.resolve(projectName) : process.cwd();
const isCurrentDir = !projectName;
console.log(chalk.cyan.bold('\n🚀 ViewLogic Template 초기화\n'));
// 현재 디렉토리가 비어있는지 확인
if (isCurrentDir && fs.readdirSync(targetDir).length > 0) {
const { confirm } = await inquirer.prompt([
{
type: 'confirm',
name: 'confirm',
message: '현재 디렉토리가 비어있지 않습니다. 계속하시겠습니까?',
default: false
}
]);
if (!confirm) {
console.log(chalk.yellow('취소되었습니다.'));
return;
}
}
await installTemplate(targetDir, options);
}
/**
* 새 ViewLogic 프로젝트 생성
*/
async function create(projectName, options) {
const targetDir = path.resolve(projectName);
console.log(chalk.cyan.bold('\n🚀 ViewLogic Template 프로젝트 생성\n'));
// 디렉토리가 이미 존재하는지 확인
if (fs.existsSync(targetDir)) {
const { overwrite } = await inquirer.prompt([
{
type: 'confirm',
name: 'overwrite',
message: `${projectName} 디렉토리가 이미 존재합니다. 덮어쓰시겠습니까?`,
default: false
}
]);
if (!overwrite) {
console.log(chalk.yellow('취소되었습니다.'));
return;
}
await fs.remove(targetDir);
}
// 디렉토리 생성
await fs.ensureDir(targetDir);
await installTemplate(targetDir, options);
}
/**
* 템플릿 설치 공통 로직
*/
async function installTemplate(targetDir, options) {
const spinner = ora('ViewLogic 템플릿 복사 중...').start();
try {
// 템플릿 파일 복사
const templateDir = path.join(__dirname, '../templates');
// templates 폴더가 없으면 GitHub에서 다운로드
if (!fs.existsSync(templateDir)) {
spinner.text = 'GitHub에서 ViewLogic 템플릿 다운로드 중...';
await downloadFromGitHub(templateDir);
}
// 파일 복사
const items = [
'src',
'js',
'css',
'build.cjs',
'index.html',
'production.html',
'.gitignore'
];
for (const item of items) {
const source = path.join(templateDir, item);
const target = path.join(targetDir, item);
if (fs.existsSync(source)) {
await fs.copy(source, target);
}
}
// package.json 생성 및 수정
const pkgSource = path.join(templateDir, 'package.json');
const pkgTarget = path.join(targetDir, 'package.json');
let pkgJson;
if (fs.existsSync(pkgSource)) {
pkgJson = await fs.readJson(pkgSource);
} else {
// 기본 package.json 생성
pkgJson = {
name: path.basename(targetDir),
version: "1.0.0",
description: "ViewLogic Vue3 SPA Application",
main: "index.html",
type: "module",
scripts: {
"dev": "python -m http.server 8000",
"build": "node build.cjs build",
"build:prod": "node build.cjs build --minify --optimize",
"serve": "python -m http.server 8000"
},
keywords: ["vue3", "viewlogic", "spa"],
author: "",
license: "MIT",
devDependencies: {
"esbuild": "^0.25.9"
}
};
}
// 프로젝트 이름 설정
pkgJson.name = path.basename(targetDir);
await fs.writeJson(pkgTarget, pkgJson, { spaces: 2 });
// router.js 설정 수정
const routerPath = path.join(targetDir, 'js/router.js');
if (fs.existsSync(routerPath)) {
let routerContent = await fs.readFile(routerPath, 'utf8');
// 인증 설정
if (options.auth) {
routerContent = routerContent.replace(
'authEnabled: options.authEnabled || false',
'authEnabled: true'
);
if (options.storage) {
routerContent = routerContent.replace(
`authStorage: options.authStorage || 'localStorage'`,
`authStorage: '${options.storage}'`
);
}
}
// i18n 설정
if (options.i18n) {
routerContent = routerContent.replace(
'useI18n: options.useI18n !== false',
'useI18n: true'
);
}
await fs.writeFile(routerPath, routerContent);
}
spinner.succeed('ViewLogic 템플릿 설치 완료!');
// npm install 실행
if (options.install !== false) {
const installSpinner = ora('의존성 패키지 설치 중...').start();
try {
execSync('npm install', {
cwd: targetDir,
stdio: 'ignore'
});
installSpinner.succeed('의존성 패키지 설치 완료!');
} catch (error) {
installSpinner.warn('npm install을 수동으로 실행해주세요.');
}
}
// 완료 메시지
console.log('\n' + chalk.green.bold('✨ ViewLogic 프로젝트가 준비되었습니다!\n'));
console.log('다음 명령어로 시작하세요:\n');
const isCurrentDir = targetDir === process.cwd();
if (!isCurrentDir) {
console.log(chalk.cyan(` cd ${path.relative(process.cwd(), targetDir)}`));
}
if (options.install === false) {
console.log(chalk.cyan(' npm install'));
}
console.log(chalk.cyan(' npm run build'));
console.log(chalk.cyan(' npm run dev'));
console.log('\n' + chalk.gray('자세한 사용법: https://github.com/hopegiver/viewlogic-template'));
} catch (error) {
spinner.fail('설치 실패');
console.error(chalk.red(error.message));
process.exit(1);
}
}
/**
* GitHub에서 템플릿 다운로드 (대체 방법)
*/
async function downloadFromGitHub(targetDir) {
try {
// git clone 시도
execSync(
'git clone --depth 1 https://github.com/hopegiver/viewlogic-vue.git temp_viewlogic',
{ stdio: 'ignore' }
);
await fs.ensureDir(targetDir);
await fs.copy('./temp_viewlogic', targetDir);
await fs.remove('./temp_viewlogic');
} catch (error) {
throw new Error('GitHub에서 템플릿을 다운로드할 수 없습니다. 인터넷 연결을 확인해주세요.');
}
}
module.exports = {
init,
create
};