Skip to content

Commit 1d4ffb6

Browse files
BWsixcola119
andauthored
refactor: ensures dependencies are up-to-date (#15)
* fix: remove `linebreak-style: [error, unitx]` All the linebreaks in this project are `CRLF` so I decided to remove it. * refactor: install dependencies in runtime * refactor: remove liff version upgradation script * fix: install vue 2 instead of vue 3 * fix: generate package.json when `installNow` is false * fix: nuxtjs dependencies * fix: pin depencency versions in nuxtjs template * refactor: install dependencies by default * fix: make sure template exist Co-authored-by: Kohei Ueno <[email protected]> * fix: undo unnecessary change https://github.com/line/create-liff-app/pull/15/files#r891931246 * feat: use `create-app` to generate next/nuxt app * feat: remove files that are the same as create-app generated ones Co-authored-by: Kohei Ueno <[email protected]>
1 parent d52c356 commit 1d4ffb6

29 files changed

+184
-646
lines changed

.eslintrc.js

-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ module.exports = {
1313
plugins: ['@typescript-eslint', 'jest'],
1414
rules: {
1515
indent: ['error', 2],
16-
'linebreak-style': ['error', 'unix'],
1716
quotes: ['error', 'single'],
1817
semi: ['error', 'always'],
1918
'@typescript-eslint/no-var-requires': ['off'],

create-liff-app.ts

+183-65
Original file line numberDiff line numberDiff line change
@@ -21,24 +21,6 @@ import chalk from 'chalk';
2121
import validate from 'validate-npm-package-name';
2222
import inquirer, { ListQuestion, Question } from 'inquirer';
2323

24-
const envPrefix: Record<string, string> = {
25-
vanilla: 'VITE_',
26-
'vanilla-ts': 'VITE_',
27-
react: 'VITE_',
28-
'react-ts': 'VITE_',
29-
vue: 'VITE_',
30-
'vue-ts': 'VITE_',
31-
svelte: 'VITE_',
32-
'svelte-ts': 'VITE_',
33-
nextjs: 'NEXT_PUBLIC_',
34-
'nextjs-ts': 'NEXT_PUBLIC_',
35-
nuxtjs: '',
36-
'nuxtjs-ts': ''
37-
};
38-
const envFileNameVariant: Record<string, string> = {
39-
nextjs: '.env.local',
40-
'nextjs-ts': '.env.local',
41-
};
4224
const rename: Record<string, string> = {
4325
'.gitignore.default': '.gitignore'
4426
};
@@ -47,40 +29,36 @@ export function init() {
4729
console.log(
4830
`${chalk.greenBright('Welcome')} to the ${chalk.cyan('Create LIFF App')}`
4931
);
50-
prompt(questions).then(async (answers) => await createLiffApp(answers));
32+
prompt(questions).then(async (answers) => await createLiffApp(answers));
5133
}
5234

5335
type PackageManager = 'npm' | 'yarn'
5436

5537
export async function createLiffApp(answers: Answers) {
56-
const { projectName, template, language, installNow, liffId } = answers;
57-
const packageManager: PackageManager = installNow ? await inquirer.prompt({
58-
type: 'list',
59-
name: 'packageManager',
60-
message: 'Which package manager do you want to use?',
61-
choices: [
62-
{
63-
key: 'yarn',
64-
value: 'yarn',
65-
checked: true,
66-
},
67-
{
68-
key: 'npm',
69-
value: 'npm',
70-
checked: false,
71-
},
72-
],
73-
}).then(({ packageManager }) => packageManager as PackageManager) : 'npm';
74-
75-
const templateName = `${template}${language === 'JavaScript' ? '' : '-ts'}`;
38+
const { projectName, template, language, liffId } = answers;
39+
const templateConfig = templates[template] as TemplateOptions | undefined;
40+
if (!templateConfig) {
41+
throw new Error(`Invalid template name: ${template}`);
42+
}
43+
const isTypescript = language === 'TypeScript';
7644
const cwd = process.cwd();
7745
const root = path.join(cwd, projectName);
46+
const packageManager = answers.packageManager as PackageManager;
47+
const isYarn = packageManager === 'yarn';
7848

7949
try {
80-
// create directory
81-
fs.mkdirSync(root, { recursive: true });
50+
if (templateConfig?.getCreateAppScript) {
51+
// generate project using `create-app`
52+
const script = templateConfig.getCreateAppScript({ isTypescript, isYarn, projectName });
53+
console.log('\nGenerating liff app using `create-app`, this might take a while.\n');
54+
await executeCreateAppScript(script);
55+
} else {
56+
// create directory
57+
fs.mkdirSync(root, { recursive: true });
58+
}
8259

8360
// copy files
61+
const templateName = `${template}${isTypescript ? '-ts' : ''}`;
8462
const templateDir = path.join(__dirname, '../templates', templateName);
8563
const files = fs.readdirSync(templateDir);
8664
for(const file of files.filter(f => f !== 'package.json')) {
@@ -89,25 +67,37 @@ export async function createLiffApp(answers: Answers) {
8967
copy(src, dest);
9068
}
9169

92-
// create package.json
93-
const packageName = isValidPackageName(projectName) ? projectName : toValidPackageName(projectName);
94-
const pkg = require(path.join(templateDir, 'package.json'));
95-
pkg.name = packageName;
96-
fs.writeFileSync(path.join(root, 'package.json'), JSON.stringify(pkg, null, 2));
70+
if (!templateConfig?.getCreateAppScript) {
71+
// create package.json
72+
const packageName = isValidPackageName(projectName) ? projectName : toValidPackageName(projectName);
73+
const pkg = require(path.join(templateDir, 'package.json'));
74+
pkg.name = packageName;
75+
fs.writeFileSync(path.join(root, 'package.json'), JSON.stringify(pkg, null, 2));
76+
}
9777

9878
// create .env file
99-
const content = `${envPrefix[templateName]}LIFF_ID=${liffId}`;
100-
const envFileName = envFileNameVariant[templateName] || '.env';
79+
const content = `${templateConfig.envPrefix}LIFF_ID=${liffId}`;
80+
const envFileName = templateConfig?.envFileNameVariant || '.env';
10181
fs.writeFileSync(path.join(root, envFileName), content);
10282

10383
// install
104-
const isYarn = packageManager === 'yarn';
105-
if (installNow) {
106-
await install(root, isYarn);
84+
const { dependencies, devDependencies, tsDevDependencies } = templateConfig;
85+
if (isTypescript) devDependencies.push(...tsDevDependencies);
86+
87+
console.log('\nInstalling dependencies:');
88+
dependencies.forEach((dependency) => console.log(`- ${chalk.blue(dependency)}`));
89+
console.log();
90+
await install({ root, isYarn, dependencies, isDev: false });
91+
92+
if (devDependencies.length) {
93+
console.log('\nInstalling devDependencies:');
94+
devDependencies.forEach((dependency) => console.log(`- ${chalk.blue(dependency)}`));
95+
console.log();
96+
await install({ root, isYarn, dependencies: devDependencies, isDev: true });
10797
}
10898

10999
// Done
110-
showDoneComments({ projectName, installNow, isYarn });
100+
showDoneComments({ projectName, isYarn });
111101
} catch(error) {
112102
console.error(error);
113103
process.exit(1);
@@ -148,11 +138,51 @@ function toValidPackageName(name: string): string {
148138
.replace(/[^a-z0-9-~]+/g, '-');
149139
}
150140

151-
function install(root: string, isYarn: boolean) {
141+
function executeCreateAppScript(script: string[]) {
142+
return new Promise<void>((resolve, reject) => {
143+
try {
144+
const [command, ...args] = script;
145+
const child = spawn(command, args, {
146+
stdio: 'inherit',
147+
env: { ...process.env, ADBLOCK: '1', DISABLE_OPENCOLLECTIVE: '1' },
148+
});
149+
child.on('close', (code) => {
150+
if (code !== 0) {
151+
reject({ command: `${command} ${args.join(' ')}` });
152+
return;
153+
}
154+
resolve();
155+
});
156+
} catch (error) {
157+
reject(`Error occurred during installation: ${error}`);
158+
}
159+
});
160+
}
161+
162+
function install({
163+
root,
164+
dependencies,
165+
isYarn,
166+
isDev,
167+
}: {
168+
root: string;
169+
dependencies: string[];
170+
isYarn: boolean;
171+
isDev: boolean;
172+
}) {
152173
return new Promise<void>((resolve, reject) => {
153174
try {
154175
const command = isYarn ? 'yarnpkg' : 'npm';
155-
const args = ['install', isYarn ? '--cwd' : '--prefix', root];
176+
const args: string[] = [];
177+
if (isYarn) {
178+
args.push('add', '--exact', '--cwd', root);
179+
if (isDev) args.push('--dev');
180+
} else {
181+
args.push('install', '--save-exact', '--prefix', root);
182+
if (isDev) args.push('--save-dev');
183+
}
184+
args.push(...dependencies);
185+
156186
const child = spawn(command, args, {
157187
stdio: 'inherit',
158188
env: { ...process.env, ADBLOCK: '1', DISABLE_OPENCOLLECTIVE: '1' }
@@ -170,16 +200,9 @@ function install(root: string, isYarn: boolean) {
170200
});
171201
}
172202

173-
function showDoneComments({projectName, installNow, isYarn}: {projectName: string, installNow: boolean, isYarn: boolean}){
203+
function showDoneComments({ projectName, isYarn }: { projectName: string; isYarn: boolean }) {
174204
console.log('\n\nDone! Now run: \n');
175205
console.log(` cd ${chalk.blue(projectName)}`);
176-
if (!installNow) {
177-
if (isYarn) {
178-
console.log(' yarn');
179-
} else {
180-
console.log(' npm install');
181-
}
182-
}
183206
if (isYarn) {
184207
console.log(' yarn dev\n\n');
185208
} else {
@@ -270,8 +293,103 @@ const questions: Array<Question | ListQuestion> = [
270293
}
271294
},
272295
{
273-
type: 'confirm',
274-
name: 'installNow',
275-
message: 'Do you want to install it now with package manager?'
296+
type: 'list',
297+
name: 'packageManager',
298+
message: 'Which package manager do you want to use?',
299+
choices: [
300+
{
301+
key: 'yarn',
302+
value: 'yarn',
303+
checked: true,
304+
},
305+
{
306+
key: 'npm',
307+
value: 'npm',
308+
checked: false,
309+
},
310+
],
276311
}
277312
];
313+
314+
type TemplateOptions = {
315+
envPrefix: string;
316+
envFileNameVariant?: string;
317+
dependencies: string[];
318+
devDependencies: string[];
319+
tsDevDependencies: string[];
320+
getCreateAppScript?: (args: CreateAppScriptOptions) => string[];
321+
};
322+
type CreateAppScriptOptions = {
323+
isTypescript: boolean;
324+
isYarn: boolean;
325+
projectName: string;
326+
};
327+
const templates: Record<string, TemplateOptions> = {
328+
vanilla: {
329+
envPrefix: 'VITE_',
330+
dependencies: ['@line/liff'],
331+
devDependencies: ['vite'],
332+
tsDevDependencies: ['typescript'],
333+
},
334+
react: {
335+
envPrefix: 'VITE_',
336+
dependencies: ['@line/liff', 'react', 'react-dom'],
337+
devDependencies: ['@vitejs/plugin-react', 'vite'],
338+
tsDevDependencies: ['@types/react', '@types/react-dom', 'typescript'],
339+
},
340+
vue: {
341+
envPrefix: 'VITE_',
342+
dependencies: ['@line/liff', 'vue'],
343+
devDependencies: ['@vitejs/plugin-vue', 'vite'],
344+
tsDevDependencies: ['typescript', 'vue-tsc'],
345+
},
346+
svelte: {
347+
envPrefix: 'VITE_',
348+
dependencies: ['@line/liff'],
349+
devDependencies: ['@sveltejs/vite-plugin-svelte', 'svelte', 'vite'],
350+
tsDevDependencies: ['@tsconfig/svelte', 'svelte-check', 'svelte-preprocess', 'tslib', 'typescript'],
351+
},
352+
nextjs: {
353+
envPrefix: 'NEXT_PUBLIC_',
354+
envFileNameVariant: '.env.local',
355+
dependencies: ['@line/liff'],
356+
devDependencies: [],
357+
tsDevDependencies: [],
358+
getCreateAppScript: ({ isTypescript, isYarn, projectName }) => {
359+
const script = [];
360+
if (isYarn) {
361+
script.push('yarnpkg', 'create', 'next-app');
362+
} else {
363+
script.push('npx', 'create-next-app', '--use-npm');
364+
}
365+
script.push(projectName);
366+
if (isTypescript) script.push('--ts');
367+
368+
return script;
369+
},
370+
},
371+
nuxtjs: {
372+
envPrefix: '',
373+
dependencies: ['@line/liff'],
374+
devDependencies: [],
375+
tsDevDependencies: [],
376+
getCreateAppScript: ({ isTypescript, isYarn, projectName }) => {
377+
const answers = {
378+
name: projectName,
379+
pm: isYarn ? 'yarn' : 'npm',
380+
language: isTypescript ? 'ts' : 'js',
381+
features: ['axios'],
382+
linter: ['eslint'],
383+
ui: 'none',
384+
test: 'none',
385+
mode: 'universal',
386+
target: 'server',
387+
devTools: 'none',
388+
vcs: 'none',
389+
};
390+
const script = ['npx', 'create-nuxt-app', projectName, '--answers', JSON.stringify(answers)];
391+
392+
return script;
393+
},
394+
},
395+
};

package.json

+1-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@
1313
"start": "yarn build && node dist/index.js",
1414
"test": "yarn build && jest",
1515
"lint:eslint": "eslint '**/*.{ts,js}'",
16-
"fix:eslint": "yarn lint:eslint --fix",
17-
"update:liff-versions": "node scripts/updateLiffVersions.js"
16+
"fix:eslint": "yarn lint:eslint --fix"
1817
},
1918
"keywords": [
2019
"LINE",

scripts/updateLiffVersions.js

-40
This file was deleted.

templates/nextjs-ts/.eslintrc.json

-3
This file was deleted.

0 commit comments

Comments
 (0)