From b29c0685bc52bfee0ab005a4d759b679ab43f14e Mon Sep 17 00:00:00 2001 From: Noah Klayman Date: Sun, 21 Feb 2021 06:26:56 -0800 Subject: [PATCH] refactor(tauri.js): remove create command (#1265) also fixes window title not setting properly because window config is an array --- cli/tauri.js/bin/tauri-create.js | 207 ------------------------ cli/tauri.js/bin/tauri-init.js | 125 ++++++++++++-- cli/tauri.js/bin/tauri.js | 4 +- cli/tauri.js/src/api/recipes/index.ts | 44 ----- cli/tauri.js/src/api/recipes/install.ts | 35 ---- cli/tauri.js/src/api/recipes/react.ts | 65 -------- cli/tauri.js/src/template/index.ts | 12 ++ cli/tauri.js/webpack.config.js | 2 - 8 files changed, 127 insertions(+), 367 deletions(-) delete mode 100644 cli/tauri.js/bin/tauri-create.js delete mode 100644 cli/tauri.js/src/api/recipes/index.ts delete mode 100644 cli/tauri.js/src/api/recipes/install.ts delete mode 100644 cli/tauri.js/src/api/recipes/react.ts diff --git a/cli/tauri.js/bin/tauri-create.js b/cli/tauri.js/bin/tauri-create.js deleted file mode 100644 index c07b55965..000000000 --- a/cli/tauri.js/bin/tauri-create.js +++ /dev/null @@ -1,207 +0,0 @@ -const parseArgs = require('minimist') -const inquirer = require('inquirer') -const { resolve } = require('path') -const { merge } = require('lodash') -const { - recipeShortNames, - recipeDescriptiveNames, - recipeByDescriptiveName, - recipeByShortName -} = require('../dist/api/recipes') - -/** - * @type {object} - * @property {boolean} h - * @property {boolean} help - * @property {string|boolean} f - * @property {string|boolean} force - * @property {boolean} l - * @property {boolean} log - * @property {boolean} d - * @property {boolean} directory - * @property {string} r - * @property {string} recipe - */ -function main(cliArgs) { - const argv = parseArgs(cliArgs, { - alias: { - h: 'help', - f: 'force', - l: 'log', - d: 'directory', - t: 'tauri-path', - A: 'app-name', - W: 'window-title', - D: 'dist-dir', - P: 'dev-path', - r: 'recipe' - }, - boolean: ['h', 'l', 'ci'] - }) - - if (argv.help) { - printUsage() - return 0 - } - - if (argv.ci) { - runInit(argv) - } else { - getOptionsInteractive(argv).then((responses) => runInit(argv, responses)) - } -} - -function printUsage() { - console.log(` - Description - Inits the Tauri template. If Tauri cannot find the tauri.conf.json - it will create one. - Usage - $ tauri create - Options - --help, -h Displays this message - --ci Skip prompts - --force, -f Force init to overwrite [conf|template|all] - --log, -l Logging [boolean] - --directory, -d Set target directory for init - --tauri-path, -t Path of the Tauri project to use (relative to the cwd) - --app-name, -A Name of your Tauri application - --window-title, -W Window title of your Tauri application - --dist-dir, -D Web assets location, relative to /src-tauri - --dev-path, -P Url of your dev server - --recipe, -r Add UI framework recipe. None by default. - Supported recipes: [${recipeShortNames.join('|')}] - `) -} - -const getOptionsInteractive = (argv) => { - let defaultAppName = argv.A - if (!defaultAppName) { - try { - const packageJson = JSON.parse( - readFileSync(resolve(process.cwd(), 'package.json')).toString() - ) - defaultAppName = packageJson.displayName || packageJson.name - } catch {} - } - - return inquirer - .prompt([ - { - type: 'input', - name: 'appName', - message: 'What is your app name?', - default: defaultAppName, - when: !argv.A - }, - { - type: 'input', - name: 'tauri.window.title', - message: 'What should the window title be?', - default: 'Tauri App', - when: () => !argv.W - }, - { - type: 'list', - name: 'recipeName', - message: 'Would you like to add a UI recipe?', - choices: recipeDescriptiveNames, - default: 'No recipe', - when: () => !argv.r - } - ]) - .then((answers) => - inquirer - .prompt([ - { - type: 'input', - name: 'build.devPath', - message: 'What is the url of your dev server?', - default: 'http://localhost:4000', - when: () => - (!argv.P && !argv.p && answers.recipeName === 'No recipe') || - argv.r === 'none' - }, - { - type: 'input', - name: 'build.distDir', - message: - 'Where are your web assets (HTML/CSS/JS) located, relative to the "/src-tauri" folder that will be created?', - default: '../dist', - when: () => - (!argv.D && answers.recipeName === 'No recipe') || - argv.r === 'none' - } - ]) - .then((answers2) => ({ ...answers, ...answers2 })) - ) - .catch((error) => { - if (error.isTtyError) { - // Prompt couldn't be rendered in the current environment - console.log( - 'It appears your terminal does not support interactive prompts. Using default values.' - ) - runInit() - } else { - // Something else when wrong - console.error('An unknown error occurred:', error) - } - }) -} - -async function runInit(argv, config = {}) { - const { appName, recipeName, ...configOptions } = config - const init = require('../dist/api/init') - - let recipe - let recipeSelection = 'none' - - if (recipeName !== undefined) { - recipe = recipeByDescriptiveName(recipeName) - } else if (argv.r) { - recipe = recipeByShortName(argv.r) - } - - let buildConfig = { - distDir: argv.D, - devPath: argv.P - } - - if (recipe !== undefined) { - recipeSelection = recipe.shortName - buildConfig = recipe.configUpdate(buildConfig) - } - - const directory = argv.d || process.cwd() - - init({ - directory, - force: argv.f || null, - logging: argv.l || null, - tauriPath: argv.t || null, - appName: appName || argv.A || null, - customConfig: merge(configOptions, { - build: buildConfig, - tauri: { - window: { - title: argv.W - } - } - }) - }) - - const { installDependencies } = require('../dist/api/dependency-manager') - await installDependencies() - - if (recipe !== undefined) { - const { - installRecipeDependencies, - runRecipePostConfig - } = require('../dist/api/recipes/install') - - await installRecipeDependencies(recipe, directory) - await runRecipePostConfig(recipe, directory) - } -} - -module.exports = main diff --git a/cli/tauri.js/bin/tauri-init.js b/cli/tauri.js/bin/tauri-init.js index a959f32c4..c02614215 100644 --- a/cli/tauri.js/bin/tauri-init.js +++ b/cli/tauri.js/bin/tauri-init.js @@ -1,9 +1,10 @@ const parseArgs = require('minimist') -const tauriCreate = require('./tauri-create') +const inquirer = require('inquirer') +const { resolve } = require('path') +const { merge } = require('lodash') /** - * init is an alias for create -r none, same as - * creating a fresh tauri project with no UI recipe applied. + * init creates the src-tauri folder * * @type {object} * @property {boolean} h @@ -18,9 +19,15 @@ const tauriCreate = require('./tauri-create') function main(cliArgs) { const argv = parseArgs(cliArgs, { alias: { - h: 'help' + h: 'help', + f: 'force', + l: 'log', + A: 'app-name', + W: 'window-title', + D: 'dist-dir', + P: 'dev-path' }, - boolean: ['h'] + boolean: ['h', 'l', 'ci'] }) if (argv.help) { @@ -28,8 +35,11 @@ function main(cliArgs) { process.exit(0) } - // delegate actual work to create command - tauriCreate([...cliArgs, '-r', 'none']) + if (argv.ci) { + runInit(argv) + } else { + getOptionsInteractive(argv).then((responses) => runInit(argv, responses)) + } } function printUsage() { @@ -41,16 +51,107 @@ function printUsage() { $ tauri init Options --help, -h Displays this message + --app-name, -a Name of your Tauri application + --window-title, -w Window title of your Tauri application + --dist-dir, -d Web assets location, relative to /src-tauri + --dev-path, -p Url of your dev server --ci Skip prompts --force, -f Force init to overwrite [conf|template|all] --log, -l Logging [boolean] - --directory, -d Set target directory for init --tauri-path, -t Path of the Tauri project to use (relative to the cwd) - --app-name, -A Name of your Tauri application - --window-title, -W Window title of your Tauri application - --dist-dir, -D Web assets location, relative to /src-tauri - --dev-path, -P Url of your dev server + --directory, -D Set target directory for init `) } +const getOptionsInteractive = (argv) => { + let defaultAppName = argv.a + if (!defaultAppName) { + try { + const packageJson = JSON.parse( + readFileSync(resolve(process.cwd(), 'package.json')).toString() + ) + defaultAppName = packageJson.displayName || packageJson.name + } catch {} + } + + return inquirer + .prompt([ + { + type: 'input', + name: 'appName', + message: 'What is your app name?', + default: defaultAppName, + when: !argv.a + }, + { + type: 'input', + name: 'windowTitle', + message: 'What should the window title be?', + default: 'Tauri App', + when: () => !argv.w + }, + { + type: 'input', + name: 'build.devPath', + message: 'What is the url of your dev server?', + default: 'http://localhost:4000', + when: () => !argv.p + }, + { + type: 'input', + name: 'build.distDir', + message: + 'Where are your web assets (HTML/CSS/JS) located, relative to the "/src-tauri" folder that will be created?', + default: '../dist', + when: () => !argv.d + } + ]) + .then((answers) => answers) + .catch((error) => { + if (error.isTtyError) { + // Prompt couldn't be rendered in the current environment + console.log( + 'It appears your terminal does not support interactive prompts. Using default values.' + ) + runInit() + } else { + // Something else when wrong + console.error('An unknown error occurred:', error) + } + }) +} + +async function runInit(argv, config = {}) { + const { appName, windowTitle, ...configOptions } = config + const init = require('../dist/api/init') + + let buildConfig = { + distDir: argv.d, + devPath: argv.p + } + + const directory = argv.D || process.cwd() + + init({ + directory, + force: argv.f || null, + logging: argv.l || null, + tauriPath: argv.t || null, + appName: appName || argv.a || null, + customConfig: merge(configOptions, { + build: buildConfig, + tauri: { + windows: [ + { + title: windowTitle || argv.w + } + ] + } + }) + }) + + const { installDependencies } = require('../dist/api/dependency-manager') + await installDependencies() +} + module.exports = main diff --git a/cli/tauri.js/bin/tauri.js b/cli/tauri.js/bin/tauri.js index 6b120cf5e..a2dc52724 100755 --- a/cli/tauri.js/bin/tauri.js +++ b/cli/tauri.js/bin/tauri.js @@ -1,6 +1,6 @@ #!/usr/bin/env node -const cmds = ['create', 'init', 'help', 'icon', 'info', 'deps'] +const cmds = ['init', 'help', 'icon', 'info', 'deps'] const rustCliCmds = ['dev', 'build'] const cmd = process.argv[2] @@ -57,7 +57,7 @@ const tauri = function (command) { } console.log(`[tauri]: running ${command}`) // eslint-disable-next-line security/detect-non-literal-require - if (['create', 'init'].includes(command)) { + if (['init'].includes(command)) { require(`./tauri-${command}`)(process.argv.slice(2)) } else { require(`./tauri-${command}`) diff --git a/cli/tauri.js/src/api/recipes/index.ts b/cli/tauri.js/src/api/recipes/index.ts deleted file mode 100644 index 903762d91..000000000 --- a/cli/tauri.js/src/api/recipes/index.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { map, identity, find } from 'lodash' -import { TauriBuildConfig } from '../../types/config' -import { reactjs, reactts } from './react' - -export interface Recipe { - descriptiveName: string - shortName: string - configUpdate: (cfg: TauriBuildConfig) => TauriBuildConfig - extraNpmDependencies: string[] - extraNpmDevDependencies: string[] - postConfiguration: (cwd: string) => void -} - -const none = { - descriptiveName: 'No recipe', - shortName: 'none', - configUpdate: identity, - extraNpmDependencies: [], - extraNpmDevDependencies: [], - postConfiguration: (cwd: string) => {} -} - -export const allRecipes: Recipe[] = [none, reactjs, reactts] - -export const recipeNames: Array<[string, string]> = map( - allRecipes, - (r: Recipe) => [r.shortName, r.descriptiveName] -) - -export const recipeByShortName = (name: string): Recipe | undefined => - find(allRecipes, (r: Recipe) => r.shortName === name) - -export const recipeByDescriptiveName = (name: string): Recipe | undefined => - find(allRecipes, (r: Recipe) => r.descriptiveName === name) - -export const recipeShortNames: string[] = map( - allRecipes, - (r: Recipe) => r.shortName -) - -export const recipeDescriptiveNames: string[] = map( - allRecipes, - (r: Recipe) => r.descriptiveName -) diff --git a/cli/tauri.js/src/api/recipes/install.ts b/cli/tauri.js/src/api/recipes/install.ts deleted file mode 100644 index 4e9644d8c..000000000 --- a/cli/tauri.js/src/api/recipes/install.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { - installThese, - installTheseDev -} from '../dependency-manager/npm-packages' -import { Recipe } from '.' -import { Result } from '../dependency-manager/types' -import logger from '../../helpers/logger' - -export async function installRecipeDependencies( - recipe: Recipe -): Promise { - const log = logger('recipe:install') - - log(`Installing dependencies for ${recipe.descriptiveName}`) - return await installThese(recipe.extraNpmDependencies).then( - async (results) => - await installTheseDev(recipe.extraNpmDevDependencies).then( - (results2) => - new Map([ - ...Array.from(results.entries()), - ...Array.from(results2.entries()) - ]) - ) - ) -} - -export async function runRecipePostConfig( - recipe: Recipe, - cwd: string -): Promise { - const log = logger('recipe:postconfig') - - log(`Running post configuration for ${recipe.descriptiveName}`) - return await new Promise(() => recipe.postConfiguration(cwd)) -} diff --git a/cli/tauri.js/src/api/recipes/react.ts b/cli/tauri.js/src/api/recipes/react.ts deleted file mode 100644 index c5f004b9a..000000000 --- a/cli/tauri.js/src/api/recipes/react.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { Recipe } from '.' -import { TauriBuildConfig } from '../../types/config' -import { spawnSync } from '../../helpers/spawn' -import logger from '../../helpers/logger' -import copyTemplates from '../../helpers/copy-templates' -import { resolve, join } from 'path' - -const uiAppDir = 'app-ui' - -const log = logger('react-recipe') - -const completeLogMsg = ` - Your installation completed. - To start, run yarn tauri dev -` - -const afterCra = (): void => { - copyTemplates({ - source: resolve(__dirname, '../../templates/recipes/react/'), - scope: {}, - target: join(uiAppDir, './src/') - }) - log(completeLogMsg) -} - -const reactjs: Recipe = { - descriptiveName: 'React.js', - shortName: 'reactjs', - configUpdate: (cfg: TauriBuildConfig): TauriBuildConfig => ({ - ...cfg, - distDir: `../${uiAppDir}/build`, - devPath: 'http://localhost:3000', - beforeDevCommand: `yarn --cwd ${uiAppDir} start`, - beforeBuildCommand: `yarn --cwd ${uiAppDir} build` - }), - extraNpmDevDependencies: ['create-react-app'], - extraNpmDependencies: ['react'], - postConfiguration: (cwd: string) => { - spawnSync('yarn', ['create-react-app', uiAppDir], cwd) - afterCra() - } -} - -const reactts: Recipe = { - ...reactjs, - descriptiveName: 'React with Typescript', - shortName: 'reactts', - extraNpmDependencies: [ - 'typescript', - '@types/node', - '@types/react', - '@types/react-dom', - '@types/jest' - ], - postConfiguration: (cwd: string) => { - spawnSync( - 'yarn', - ['create-react-app', '--template', 'typescript', uiAppDir], - cwd - ) - afterCra() - } -} - -export { reactjs, reactts } diff --git a/cli/tauri.js/src/template/index.ts b/cli/tauri.js/src/template/index.ts index 49075e592..1aca73006 100644 --- a/cli/tauri.js/src/template/index.ts +++ b/cli/tauri.js/src/template/index.ts @@ -44,6 +44,18 @@ const injectConfFile = ( } /* eslint-enable security/detect-object-injection */ }) + // Window config should be merged + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + if ((customConfig as UnknownObject).tauri?.windows[0]) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment + ;(customConfig as UnknownObject).tauri.windows[0] = { + ...defaultConfig.tauri.windows[0], + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + ...(customConfig as UnknownObject).tauri.windows[0] + } + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + delete (defaultConfig as UnknownObject).tauri.windows + } const finalConf = merge( defaultConfig as any, customConfig as any diff --git a/cli/tauri.js/webpack.config.js b/cli/tauri.js/webpack.config.js index 3463bceee..cf9bea328 100644 --- a/cli/tauri.js/webpack.config.js +++ b/cli/tauri.js/webpack.config.js @@ -5,8 +5,6 @@ module.exports = { entry: { 'api/cli': './src/api/cli.ts', 'api/init': './src/api/init.ts', - 'api/recipes': './src/api/recipes/index.ts', - 'api/recipes/install': './src/api/recipes/install.ts', 'api/tauricon': './src/api/tauricon.ts', 'api/info': './src/api/info.ts', 'api/dependency-manager': './src/api/dependency-manager/index.ts',