From ea28d0169168953e11416231e50b08061413a27e Mon Sep 17 00:00:00 2001 From: Jacob Bolda Date: Sun, 9 May 2021 09:31:01 -0500 Subject: [PATCH] create-tauri-app welcome prompt and recipes links (#1748) * CTA welcome prompt and recipes links * fix tests for new recipe names * check that package file exists before build * change file * turn off vuecli tests until we can get them to pass --- .changes/cta-welcome-prompt-and-links.md | 5 ++ .github/workflows/test-cta.yml | 4 +- tooling/create-tauri-app/rollup.config.js | 1 + tooling/create-tauri-app/src/index.ts | 60 +++++++++++++--- tooling/create-tauri-app/src/recipes/react.ts | 72 +++++++++---------- .../create-tauri-app/src/recipes/vanilla.ts | 5 +- tooling/create-tauri-app/src/recipes/vite.ts | 6 +- .../create-tauri-app/src/recipes/vue-cli.ts | 5 +- tooling/create-tauri-app/src/types/recipe.ts | 2 +- tooling/create-tauri-app/test/index.spec.ts | 21 +++--- 10 files changed, 118 insertions(+), 63 deletions(-) create mode 100644 .changes/cta-welcome-prompt-and-links.md diff --git a/.changes/cta-welcome-prompt-and-links.md b/.changes/cta-welcome-prompt-and-links.md new file mode 100644 index 000000000..4b36854b8 --- /dev/null +++ b/.changes/cta-welcome-prompt-and-links.md @@ -0,0 +1,5 @@ +--- +"create-tauri-app": patch +--- + +Add a welcome prompt to let the user know about the process and links to more info including prerequisite setup steps. Also add links to each of the templates to give the user more context what they are getting into. diff --git a/.github/workflows/test-cta.yml b/.github/workflows/test-cta.yml index 8449f74ce..e68e5ebfb 100644 --- a/.github/workflows/test-cta.yml +++ b/.github/workflows/test-cta.yml @@ -26,7 +26,7 @@ jobs: matrix: node: ["14", "16"] manager: ["6", "7"] - recipe: ["vanillajs", "reactjs", "reactts", "vite", "vuecli"] + recipe: ["vanillajs", "cra", "vite"] exclude: - node: "16" manager: "6" @@ -66,7 +66,7 @@ jobs: fail-fast: false matrix: node: ["14", "16"] - recipe: ["vanillajs", "reactjs", "reactts", "vite", "vuecli"] + recipe: ["vanillajs", "cra", "vite"] steps: - uses: actions/checkout@v2 diff --git a/tooling/create-tauri-app/rollup.config.js b/tooling/create-tauri-app/rollup.config.js index b308bda8a..6ec249be3 100644 --- a/tooling/create-tauri-app/rollup.config.js +++ b/tooling/create-tauri-app/rollup.config.js @@ -16,6 +16,7 @@ export default { external: [ 'fs', 'path', + 'os', ...Object.keys(pkg.dependencies || {}), ...Object.keys(pkg.peerDependencies || {}) ], diff --git a/tooling/create-tauri-app/src/index.ts b/tooling/create-tauri-app/src/index.ts index cc7e13cb5..0b74a4f68 100644 --- a/tooling/create-tauri-app/src/index.ts +++ b/tooling/create-tauri-app/src/index.ts @@ -5,8 +5,9 @@ import minimist from 'minimist' import inquirer from 'inquirer' import { bold, cyan, green, reset, yellow } from 'chalk' +import { platform } from 'os' import { resolve, join } from 'path' -import { reactjs, reactts } from './recipes/react' +import { cra } from './recipes/react' import { vuecli } from './recipes/vue-cli' import { vanillajs } from './recipes/vanilla' import { vite } from './recipes/vite' @@ -112,19 +113,62 @@ interface Responses { recipeName: string } -const allRecipes: Recipe[] = [vanillajs, reactjs, reactts, vite, vuecli] +const allRecipes: Recipe[] = [vanillajs, cra, vite, vuecli] const recipeByShortName = (name: string): Recipe | undefined => allRecipes.find((r) => r.shortName === name) const recipeByDescriptiveName = (name: string): Recipe | undefined => - allRecipes.find((r) => r.descriptiveName === name) + allRecipes.find((r) => r.descriptiveName.value === name) const recipeShortNames = allRecipes.map((r) => r.shortName) const recipeDescriptiveNames = allRecipes.map((r) => r.descriptiveName) +const keypress = async (skip: boolean): Promise => { + if (skip) return + process.stdin.setRawMode(true) + return await new Promise((resolve, reject) => { + console.log('Press any key to continue...') + process.stdin.once('data', (data) => { + const byteArray = [...data] + if (byteArray.length > 0 && byteArray[0] === 3) { + console.log('^C') + process.exit(1) + } + process.stdin.setRawMode(false) + resolve() + }) + }) +} + const runInit = async (argv: Argv): Promise => { + console.log( + `We hope to help you create something special with ${bold( + yellow('Tauri') + )}!` + ) + console.log( + 'You will have a choice of one of the UI frameworks supported by the greater web tech community.' + ) + console.log( + `This should get you started. See our docs at https://tauri.studio/` + ) + + const setupLink = + platform() === 'win32' + ? 'https://tauri.studio/en/docs/getting-started/setup-windows/' + : platform() === 'darwin' + ? 'https://tauri.studio/en/docs/getting-started/setup-macos/' + : 'https://tauri.studio/en/docs/getting-started/setup-linux/' + + console.log( + `If you haven't already, please take a moment to setup your system.` + ) + console.log(`You may find the requirements here: ${setupLink}`) + + await keypress(argv.ci) + const defaults = { appName: 'tauri-app', tauri: { window: { title: 'Tauri App' } }, @@ -184,15 +228,9 @@ const runInit = async (argv: Argv): Promise => { recipe = recipeByDescriptiveName(recipeName) } + // throw if recipe is not set if (!recipe) { - if (argv.ci) { - recipe = recipeByShortName('vanillajs') - } - // throw if recipe is not set - // if it fails to set in CI, throw as well - if (!recipe) { - throw new Error('Could not find the recipe specified.') - } + throw new Error('Could not find the recipe specified.') } const packageManager = diff --git a/tooling/create-tauri-app/src/recipes/react.ts b/tooling/create-tauri-app/src/recipes/react.ts index 17136f6cf..8d222f48b 100644 --- a/tooling/create-tauri-app/src/recipes/react.ts +++ b/tooling/create-tauri-app/src/recipes/react.ts @@ -28,9 +28,12 @@ const afterCra = async ( } } -const reactjs: Recipe = { - descriptiveName: 'React.js', - shortName: 'reactjs', +export const cra: Recipe = { + descriptiveName: { + name: 'create-react-app (https://create-react-app.dev/)', + value: 'create-react-app' + }, + shortName: 'cra', configUpdate: ({ cfg, packageManager }) => ({ ...cfg, distDir: `../build`, @@ -42,39 +45,37 @@ const reactjs: Recipe = { }), extraNpmDevDependencies: [], extraNpmDependencies: [], - preInit: async ({ cwd, cfg, packageManager }) => { - // CRA creates the folder for you - if (packageManager === 'yarn') { - await shell('yarn', ['create', 'react-app', `${cfg.appName}`], { - cwd - }) - } else { - await shell('npx', ['create-react-app', `${cfg.appName}`, '--use-npm'], { - cwd - }) - } - await afterCra(cwd, cfg.appName) + extraQuestions: ({ ci }) => { + return [ + { + type: 'list', + name: 'template', + message: 'Which vite template would you like to use?', + choices: [ + { name: 'create-react-app (JavaScript)', value: 'cra.js' }, + { name: 'create-react-app (Typescript)', value: 'cra.ts' } + ], + default: 'cra.js', + loop: false, + when: !ci + } + ] }, - postInit: async ({ packageManager }) => { - console.log(` - Your installation completed. - To start, run ${packageManager === 'yarn' ? 'yarn' : 'npm run'} tauri dev - `) - return await Promise.resolve() - } -} - -const reactts: Recipe = { - ...reactjs, - descriptiveName: 'React with Typescript', - shortName: 'reactts', - extraNpmDependencies: [], - preInit: async ({ cwd, cfg, packageManager }) => { + preInit: async ({ cwd, cfg, packageManager, answers }) => { + let template = 'cra.js' + if (answers) { + template = answers.template ? (answers.template as string) : 'vue' + } // CRA creates the folder for you if (packageManager === 'yarn') { await shell( 'yarn', - ['create', 'react-app', '--template', 'typescript', `${cfg.appName}`], + [ + 'create', + 'react-app', + ...(template === 'cra.ts' ? ['--template', 'typescript'] : []), + `${cfg.appName}` + ], { cwd } @@ -84,17 +85,16 @@ const reactts: Recipe = { 'npx', [ 'create-react-app', + ...(template === 'cra.ts' ? ['--template', 'typescript'] : []), `${cfg.appName}`, - '--use-npm', - '--template', - 'typescript' + '--use-npm' ], { cwd } ) } - await afterCra(cwd, cfg.appName, true) + await afterCra(cwd, cfg.appName, template === 'cra.ts') }, postInit: async ({ packageManager }) => { console.log(` @@ -104,5 +104,3 @@ const reactts: Recipe = { return await Promise.resolve() } } - -export { reactjs, reactts } diff --git a/tooling/create-tauri-app/src/recipes/vanilla.ts b/tooling/create-tauri-app/src/recipes/vanilla.ts index fdc5f2942..98b6f6489 100644 --- a/tooling/create-tauri-app/src/recipes/vanilla.ts +++ b/tooling/create-tauri-app/src/recipes/vanilla.ts @@ -8,7 +8,10 @@ import scaffe from 'scaffe' import { Recipe } from '../types/recipe' export const vanillajs: Recipe = { - descriptiveName: 'Vanilla.js', + descriptiveName: { + name: 'Vanilla.js (html, css, and js without the bundlers)', + value: 'Vanilla.js' + }, shortName: 'vanillajs', configUpdate: ({ cfg }) => ({ ...cfg, diff --git a/tooling/create-tauri-app/src/recipes/vite.ts b/tooling/create-tauri-app/src/recipes/vite.ts index 0643ee00d..2bc6ea49e 100644 --- a/tooling/create-tauri-app/src/recipes/vite.ts +++ b/tooling/create-tauri-app/src/recipes/vite.ts @@ -25,7 +25,11 @@ const afterViteCA = async ( } const vite: Recipe = { - descriptiveName: 'Vite backed recipe', + descriptiveName: { + name: + '@vitejs/create-app (https://vitejs.dev/guide/#scaffolding-your-first-vite-project)', + value: 'vite-create-app' + }, shortName: 'vite', configUpdate: ({ cfg, packageManager }) => ({ ...cfg, diff --git a/tooling/create-tauri-app/src/recipes/vue-cli.ts b/tooling/create-tauri-app/src/recipes/vue-cli.ts index cc544485c..cb6e581d8 100644 --- a/tooling/create-tauri-app/src/recipes/vue-cli.ts +++ b/tooling/create-tauri-app/src/recipes/vue-cli.ts @@ -12,7 +12,10 @@ const completeLogMsg = ` ` const vuecli: Recipe = { - descriptiveName: 'Vue CLI', + descriptiveName: { + name: 'Vue CLI (https://cli.vuejs.org/)', + value: 'vue-cli' + }, shortName: 'vuecli', extraNpmDevDependencies: [], extraNpmDependencies: [], diff --git a/tooling/create-tauri-app/src/types/recipe.ts b/tooling/create-tauri-app/src/types/recipe.ts index 303ad7a1a..a127a708a 100644 --- a/tooling/create-tauri-app/src/types/recipe.ts +++ b/tooling/create-tauri-app/src/types/recipe.ts @@ -12,7 +12,7 @@ export interface RecipeArgs { } export interface Recipe { - descriptiveName: string + descriptiveName: { name: string; value: string } shortName: string configUpdate?: (args: RecipeArgs) => TauriBuildConfig extraNpmDependencies: string[] diff --git a/tooling/create-tauri-app/test/index.spec.ts b/tooling/create-tauri-app/test/index.spec.ts index dd5a49459..be4a3d1ff 100644 --- a/tooling/create-tauri-app/test/index.spec.ts +++ b/tooling/create-tauri-app/test/index.spec.ts @@ -15,7 +15,7 @@ const api = path.resolve('../api/') const manager = process.env.TAURI_RUN_MANAGER ?? 'npm' const recipes = process.env.TAURI_RECIPE ? [process.env.TAURI_RECIPE] - : ['vanillajs', 'reactjs', 'reactts', 'vite', 'vuecli'] + : ['vanillajs', 'cra', 'vite', 'vuecli'] const timeoutLong = 900000 const timeoutLittleLonger = 930000 const logOut = false ? 'inherit' : 'pipe' @@ -96,6 +96,16 @@ describe('CTA', () => { expect(cta.killed).toBe(false) expect(cta.signal).toBe(undefined) + const packageFileInitial: { + [k: string]: string | object + } = JSON.parse( + await fs.promises.readFile( + path.join(appFolder, 'package.json'), + 'utf-8' + ) + ) + expect(packageFileInitial['name']).toBe(appName) + // run a tauri build to check if what we produced // can actually create an app // TODO long term we will want to hook this up to a real test harness @@ -138,14 +148,7 @@ describe('CTA', () => { tauri: 'tauri' }) }, - reactjs: () => { - expect(packageFileOutput['scripts']).toEqual( - expect.objectContaining({ - tauri: 'tauri' - }) - ) - }, - reactts: () => { + cra: () => { expect(packageFileOutput['scripts']).toEqual( expect.objectContaining({ tauri: 'tauri'