UNPKG

@line/create-liff-app

Version:

Start developing LIFF application with a simple CLI command.

363 lines (359 loc) 12.9 kB
"use strict"; /* Copyright 2023 LY Corporation * LY Corporation licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * https://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.templateNames = exports.createLiffApp = exports.init = void 0; const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); const cross_spawn_1 = __importDefault(require("cross-spawn")); const chalk_1 = __importDefault(require("chalk")); const validate_npm_package_name_1 = __importDefault(require("validate-npm-package-name")); const inquirer_1 = __importDefault(require("inquirer")); const rename = { '.gitignore.default': '.gitignore' }; function init(answers = {}) { console.log(`${chalk_1.default.greenBright('Welcome')} to the ${chalk_1.default.cyan('Create LIFF App')}`); prompt(questions, answers).then(async (answers) => await createLiffApp(answers)); } exports.init = init; async function createLiffApp(answers) { const { projectName, template, language, liffId } = answers; const templateConfig = templates[template]; if (!templateConfig) { throw new Error(`Invalid template name: ${template}`); } const isTypescript = language === 'TypeScript'; const cwd = process.cwd(); const root = path_1.default.join(cwd, projectName); const packageManager = answers.packageManager; const isYarn = packageManager === 'yarn'; try { if (templateConfig?.getCreateAppScript) { // generate project using `create-app` const script = templateConfig.getCreateAppScript({ isTypescript, isYarn, projectName }); console.log('\nGenerating liff app using `create-app`, this might take a while.\n'); await executeCreateAppScript(script); } else { // create directory fs_1.default.mkdirSync(root, { recursive: true }); } // copy files const templateName = `${template}${isTypescript ? '-ts' : ''}`; const templateDir = path_1.default.join(__dirname, '../templates', templateName); const files = fs_1.default.readdirSync(templateDir); for (const file of files.filter(f => f !== 'package.json')) { const src = path_1.default.join(templateDir, file); const dest = rename[file] ? path_1.default.join(root, rename[file]) : path_1.default.join(root, file); copy(src, dest); } if (!templateConfig?.getCreateAppScript) { // create package.json const packageName = isValidPackageName(projectName) ? projectName : toValidPackageName(projectName); const pkg = require(path_1.default.join(templateDir, 'package.json')); pkg.name = packageName; fs_1.default.writeFileSync(path_1.default.join(root, 'package.json'), JSON.stringify(pkg, null, 2)); } // create .env file const content = `${templateConfig.envPrefix}LIFF_ID=${liffId}`; const envFileName = templateConfig?.envFileNameVariant || '.env'; fs_1.default.writeFileSync(path_1.default.join(root, envFileName), content); // install const { dependencies, devDependencies, tsDevDependencies } = templateConfig; if (isTypescript) devDependencies.push(...tsDevDependencies); console.log('\nInstalling dependencies:'); dependencies.forEach((dependency) => console.log(`- ${chalk_1.default.blue(dependency)}`)); console.log(); await install({ root, isYarn, dependencies, isDev: false }); if (devDependencies.length) { console.log('\nInstalling devDependencies:'); devDependencies.forEach((dependency) => console.log(`- ${chalk_1.default.blue(dependency)}`)); console.log(); await install({ root, isYarn, dependencies: devDependencies, isDev: true }); } // Done showDoneComments({ projectName, isYarn }); } catch (error) { console.error(error); process.exit(1); } } exports.createLiffApp = createLiffApp; function copy(src, dest) { const stat = fs_1.default.statSync(src); if (stat.isDirectory()) { copyDir(src, dest); } else { fs_1.default.copyFileSync(src, dest); } } function copyDir(srcDir, destDir) { fs_1.default.mkdirSync(destDir, { recursive: true }); for (const file of fs_1.default.readdirSync(srcDir)) { const srcFile = path_1.default.resolve(srcDir, file); const destFile = path_1.default.resolve(destDir, file); copy(srcFile, destFile); } } function isValidPackageName(name) { const { validForNewPackages } = (0, validate_npm_package_name_1.default)(name); return validForNewPackages; } function toValidPackageName(name) { return name .trim() .toLowerCase() .replace(/\s+/g, '-') .replace(/^[._]/, '') .replace(/[^a-z0-9-~]+/g, '-'); } function executeCreateAppScript(script) { return new Promise((resolve, reject) => { try { const [command, ...args] = script; const child = (0, cross_spawn_1.default)(command, args, { stdio: 'inherit', env: { ...process.env, ADBLOCK: '1', DISABLE_OPENCOLLECTIVE: '1' }, }); child.on('close', (code) => { if (code !== 0) { reject({ command: `${command} ${args.join(' ')}` }); return; } resolve(); }); } catch (error) { reject(`Error occurred during installation: ${error}`); } }); } function install({ root, dependencies, isYarn, isDev, }) { return new Promise((resolve, reject) => { try { const command = isYarn ? 'yarnpkg' : 'npm'; const args = []; if (isYarn) { args.push('add', '--exact', '--cwd', root); if (isDev) args.push('--dev'); } else { args.push('install', '--save-exact', '--prefix', root); if (isDev) args.push('--save-dev'); } args.push(...dependencies); const child = (0, cross_spawn_1.default)(command, args, { stdio: 'inherit', env: { ...process.env, ADBLOCK: '1', DISABLE_OPENCOLLECTIVE: '1' } }); child.on('close', code => { if (code !== 0) { reject({ command: `${command} ${args.join(' ')}` }); return; } resolve(); }); } catch (error) { reject(`Error occurred during installation: ${error}`); } }); } function showDoneComments({ projectName, isYarn }) { console.log('\n\nDone! Now run: \n'); console.log(` cd ${chalk_1.default.blue(projectName)}`); if (isYarn) { console.log(' yarn dev\n\n'); } else { console.log(' npm run dev\n\n'); } } const prompt = inquirer_1.default.createPromptModule(); const questions = [ { type: 'input', name: 'projectName', message: 'Enter your project name: ', default: 'my-app', validate: (input) => { const projectName = input.trim(); if (!projectName) { console.log(`\n${chalk_1.default.yellow('Project name is required.')}`); return false; } if (fs_1.default.existsSync(path_1.default.basename(projectName)) && fs_1.default.readdirSync(projectName).length !== 0) { console.log(`\n${chalk_1.default.yellow('The project is already exists.')}`); return false; } return true; }, }, { type: 'list', name: 'template', message: 'Which template do you want to use?', choices: [ { value: 'vanilla', checked: true, }, { value: 'react', checked: false, }, { value: 'vue', checked: false, }, { value: 'svelte', checked: false, }, { value: 'nextjs', checked: false, }, { value: 'nuxtjs', checked: false, }, ], }, { type: 'list', name: 'language', message: 'JavaScript or TypeScript?', choices: [ { value: 'JavaScript', checked: true }, { value: 'TypeScript', checked: false } ] }, { type: 'input', name: 'liffId', message: `Please enter your LIFF ID: \n ${chalk_1.default.gray('Don\'t you have LIFF ID? Check out https://developers.line.biz/ja/docs/liff/getting-started/')}`, default: 'liffId', validate: (input) => { const liffId = input.trim(); if (!liffId) { console.log(); console.log(`${chalk_1.default.yellow('LIFF ID is required.')}`); return false; } return true; } }, { type: 'list', name: 'packageManager', message: 'Which package manager do you want to use?', choices: [ { key: 'yarn', value: 'yarn', checked: true, }, { key: 'npm', value: 'npm', checked: false, }, ], } ]; const templates = { vanilla: { envPrefix: 'VITE_', dependencies: ['@line/liff'], devDependencies: ['vite'], tsDevDependencies: ['typescript'], }, react: { envPrefix: 'VITE_', dependencies: ['@line/liff', 'react', 'react-dom'], devDependencies: ['@vitejs/plugin-react', 'vite'], tsDevDependencies: ['@types/react', '@types/react-dom', 'typescript'], }, vue: { envPrefix: 'VITE_', dependencies: ['@line/liff', 'vue'], devDependencies: ['@vitejs/plugin-vue', 'vite'], tsDevDependencies: ['typescript', 'vue-tsc'], }, svelte: { envPrefix: 'VITE_', dependencies: ['@line/liff'], devDependencies: ['@sveltejs/vite-plugin-svelte', 'svelte', 'vite'], tsDevDependencies: ['@tsconfig/svelte', 'svelte-check', 'svelte-preprocess', 'tslib', 'typescript'], }, nextjs: { envPrefix: 'NEXT_PUBLIC_', envFileNameVariant: '.env.local', dependencies: ['@line/liff'], devDependencies: [], tsDevDependencies: [], getCreateAppScript: ({ isTypescript, isYarn, projectName }) => { const script = []; if (isYarn) { script.push('yarnpkg', 'create', 'next-app'); } else { script.push('npx', 'create-next-app', '--use-npm'); } script.push(projectName); if (isTypescript) script.push('--ts'); return script; }, }, nuxtjs: { envPrefix: '', dependencies: ['@line/liff'], devDependencies: [], tsDevDependencies: [], getCreateAppScript: ({ isTypescript, isYarn, projectName }) => { const answers = { name: projectName, pm: isYarn ? 'yarn' : 'npm', language: isTypescript ? 'ts' : 'js', features: ['axios'], linter: ['eslint'], ui: 'none', test: 'none', mode: 'universal', target: 'server', template: 'html', devTools: 'none', vcs: 'none', }; const script = ['npx', 'create-nuxt-app', projectName, '--answers', JSON.stringify(answers)]; return script; }, }, }; exports.templateNames = Object.keys(templates);