Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CRWA]: Switch to using enquirer, add engine compatibility override option #6723

Merged
merged 17 commits into from
Nov 5, 2022
Merged
3 changes: 2 additions & 1 deletion packages/create-redwood-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,11 @@
"chalk": "4.1.2",
"check-node-version": "4.2.1",
"core-js": "3.25.5",
"enquirer": "2.3.6",
"execa": "5.1.1",
"fs-extra": "10.1.0",
"listr2": "5.0.5",
"prompts": "2.4.2",
"terminal-link": "2.1.1",
"yargs": "17.6.0"
},
"devDependencies": {
Expand Down
181 changes: 106 additions & 75 deletions packages/create-redwood-app/src/create-redwood-app.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ import path from 'path'

import chalk from 'chalk'
import checkNodeVersion from 'check-node-version'
import { prompt } from 'enquirer'
import execa from 'execa'
import fs from 'fs-extra'
import { Listr } from 'listr2'
import prompts from 'prompts'
import { Listr, figures } from 'listr2'
import terminalLink from 'terminal-link'
import { hideBin } from 'yargs/helpers'
import yargs from 'yargs/yargs'

Expand Down Expand Up @@ -104,38 +105,6 @@ import { name, version } from '../package'
.version(version)
.parse()

// Variable to hold the user args as an object that can be used for prompt overides
// This gets more useful as there are more prompts to override
let userArgs = {}

// Handle if typescript is selected via --ts
if (typescript === true) {
Object.assign(userArgs, { typescript: true })
}
// Handle if typescript is skipped via --no-ts
if (typescript === false) {
Object.assign(userArgs, { typescript: false })
}

// User prompts
// See https://github.com/terkelg/prompts
const questions = [
{
type: 'confirm',
name: 'typescript',
message: 'Use TypeScript?',
initial: true,
active: 'Yes',
inactive: 'No',
},
]

// Override prompts based on initial args from user
prompts.override(userArgs)

// Get the answers from the user
const answers = await prompts(questions)

// Get the directory for installation from the args
const targetDir = String(args).replace(/,/g, '-')

Expand Down Expand Up @@ -163,44 +132,6 @@ import { name, version } from '../package'

const createProjectTasks = ({ newAppDir, overwrite }) => {
return [
{
title: 'Checking node and yarn compatibility',
skip: () => {
if (yarnInstall === false) {
return 'Warning: skipping check on request'
}
},
task: () => {
return new Promise((resolve, reject) => {
const { engines } = require(path.join(templateDir, 'package.json'))

// this checks all engine requirements, including Node.js and Yarn
checkNodeVersion(engines, (_error, result) => {
if (result.isSatisfied) {
return resolve()
}

const logStatements = Object.keys(result.versions)
.filter((name) => !result.versions[name].isSatisfied)
.map((name) => {
const { version, wanted } = result.versions[name]
return style.error(
`${name} ${wanted} required, but you have ${version}`
)
})
logStatements.push(
style.header(`\nVisit requirements documentation:`)
)
logStatements.push(
style.warning(
`/docs/tutorial/chapter1/prerequisites/#nodejs-and-yarn-versions\n`
)
)
return reject(new Error(logStatements.join('\n')))
})
})
},
},
{
title: `${
appDirExists ? 'Using' : 'Creating'
Expand Down Expand Up @@ -315,8 +246,105 @@ import { name, version } from '../package'

const startTime = Date.now()

// Engine check Listr. Separate Listr to avoid https://github.com/cenk1cenk2/listr2/issues/296
// Boolean flag
let hasPassedEngineCheck = null
// Array of strings
let engineErrorLog = []
// Docs link for engine errors
const engineErrorDocsLink = terminalLink(
'Tutorial - Prerequisites',
'https://redwoodjs.com/docs/tutorial/chapter1/prerequisites'
)

await new Listr(
[
{
title: 'Checking node and yarn compatibility',
skip: () => {
if (yarnInstall === false) {
return 'Warning: skipping check on request'
}
},
task: () => {
return new Promise((resolve) => {
const { engines } = require(path.join(templateDir, 'package.json'))

// this checks all engine requirements, including Node.js and Yarn
checkNodeVersion(engines, (_error, result) => {
if (result.isSatisfied) {
hasPassedEngineCheck = true
return resolve()
}
const logStatements = Object.keys(result.versions)
.filter((name) => !result.versions[name].isSatisfied)
.map((name) => {
const { version, wanted } = result.versions[name]
return `${name} ${wanted} required, but you have ${version}`
})
engineErrorLog = logStatements
hasPassedEngineCheck = false
return resolve()
})
})
},
},
],
{ rendererOptions: { clearOutput: true } }
).run()

// Show a success message if required engines are present
if (hasPassedEngineCheck === true) {
console.log(`${style.success(figures.tick)} Compatibility checks passed`)
}

// Show an error and prompt if failed engines check
if (hasPassedEngineCheck === false) {
console.log(`${style.error(figures.cross)} Compatibility checks failed`)
console.log(
[
` ${style.warning(figures.warning)} ${engineErrorLog.join('\n')}`,
'',
` This may make your project incompatible with some deploy targets.`,
` See: ${engineErrorDocsLink}`,
'',
].join('\n')
)
// Prompt user for how to proceed
const response = await prompt({
type: 'select',
name: 'override-engine-error',
message: 'How would you like to proceed?',
choices: ['Override error and continue install', 'Quit install'],
initial: 0,
ehowey marked this conversation as resolved.
Show resolved Hide resolved
onCancel: () => process.exit(1),
})
// Quit the install if user selects this option, otherwise it will proceed
if (response['override-engine-error'] === 'Quit install') {
process.exit(1)
}
}

// Main install Listr
new Listr(
[
{
title: 'Language preference',
skip: () => typescript !== null,
task: async (ctx, task) => {
ctx.language = await task.prompt({
type: 'Select',
choices: ['TypeScript', 'JavaScript'],
message: 'Select your preferred coding language',
initial: 'TypeScript',
})

task.output = ctx.language
},
options: {
persistentOutput: true,
},
},
{
title: 'Creating Redwood app',
task: () => new Listr(createProjectTasks({ newAppDir, overwrite })),
Expand All @@ -329,9 +357,9 @@ import { name, version } from '../package'
title: 'Convert TypeScript files to JavaScript',
// Enabled if user selects no to typescript prompt
// Enabled if user specified --no-ts via command line
enabled: () =>
enabled: (ctx) =>
yarnInstall === true &&
(typescript === false || answers.typescript === false),
(typescript === false || ctx.language === 'JavaScript'),
task: () => {
return execa('yarn rw ts-to-js', {
shell: true,
Expand All @@ -350,7 +378,10 @@ import { name, version } from '../package'
},
},
],
{ rendererOptions: { collapse: false }, exitOnError: true }
{
rendererOptions: { collapse: false },
exitOnError: true,
}
)
.run()
.then(() => {
Expand Down
3 changes: 2 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -14029,11 +14029,12 @@ __metadata:
chalk: 4.1.2
check-node-version: 4.2.1
core-js: 3.25.5
enquirer: 2.3.6
execa: 5.1.1
fs-extra: 10.1.0
jest: 29.2.2
listr2: 5.0.5
prompts: 2.4.2
terminal-link: 2.1.1
typescript: 4.7.4
yargs: 17.6.0
bin:
Expand Down