tauri/tooling/create-tauri-app/bin/create-tauri-app.js
2021-04-13 21:53:40 -03:00

234 lines
6.2 KiB
JavaScript
Executable File

#!/usr/bin/env node
// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
const parseArgs = require("minimist");
const inquirer = require("inquirer");
const { resolve, join } = require("path");
const {
recipeShortNames,
recipeDescriptiveNames,
recipeByDescriptiveName,
recipeByShortName,
install,
checkPackageManager,
shell,
} = require("../dist/");
/**
* @type {object}
* @property {boolean} h
* @property {boolean} help
* @property {boolean} v
* @property {boolean} version
* @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
*/
const createTauriApp = async (cliArgs) => {
const argv = parseArgs(cliArgs, {
alias: {
h: "help",
v: "version",
f: "force",
l: "log",
m: "manager",
d: "directory",
b: "binary",
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.v) {
console.log(require("../package.json").version);
return false; // do this for node consumers and tests
}
if (argv.ci) {
return runInit(argv);
} else {
return getOptionsInteractive(argv).then((responses) =>
runInit(argv, responses)
);
}
};
function printUsage() {
console.log(`
Description
Starts a new tauri app from a "recipe" or pre-built template.
Usage
$ yarn create tauri-app <app-name> # npm create-tauri-app <app-name>
Options
--help, -h Displays this message
-v, --version Displays the Tauri CLI version
--ci Skip prompts
--force, -f Force init to overwrite [conf|template|all]
--log, -l Logging [boolean]
--manager, -d Set package manager to use [npm|yarn]
--directory, -d Set target directory for init
--binary, -b Optional path to a tauri binary from which to run init
--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 <project-dir>/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 || "tauri-app";
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,
},
])
.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 went wrong
console.error("An unknown error occurred:", error);
}
});
};
async function runInit(argv, config = {}) {
const {
appName,
recipeName,
tauri: {
window: { title },
},
} = config;
// this little fun snippet pulled from vite determines the package manager the script was run from
const packageManager = /yarn/.test(process.env.npm_execpath) ? "yarn" : "npm";
let recipe;
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) {
buildConfig = recipe.configUpdate({ buildConfig, packageManager });
}
const directory = argv.d || process.cwd();
const cfg = {
...buildConfig,
appName: appName || argv.A,
windowTitle: title || argv.w,
};
// note that our app directory is reliant on the appName and
// generally there are issues if the path has spaces (see Windows)
// future TODO prevent app names with spaces or escape here?
const appDirectory = join(directory, cfg.appName);
// this throws an error if we can't run the package manager they requested
await checkPackageManager({ cwd: directory, packageManager });
if (recipe.preInit) {
console.log("===== running initial command(s) =====");
await recipe.preInit({ cwd: directory, cfg, packageManager });
}
const initArgs = [
["--app-name", cfg.appName],
["--window-title", cfg.windowTitle],
["--dist-dir", cfg.distDir],
["--dev-path", cfg.devPath],
].reduce((final, argSet) => {
if (argSet[1]) {
return final.concat(argSet);
} else {
return final;
}
}, []);
// Vue CLI plugin automatically runs these
if (recipe.shortName !== "vuecli") {
console.log("===== installing any additional needed deps =====");
await install({
appDir: appDirectory,
dependencies: recipe.extraNpmDependencies,
devDependencies: ["@tauri-apps/cli", ...recipe.extraNpmDevDependencies],
packageManager,
});
console.log("===== running tauri init =====");
const binary = !argv.b ? packageManager : resolve(appDirectory, argv.b);
const runTauriArgs =
packageManager === "npm" && !argv.b
? ["run", "tauri", "--", "init"]
: ["tauri", "init"];
await shell(binary, [...runTauriArgs, ...initArgs], {
cwd: appDirectory,
});
}
if (recipe.postInit) {
console.log("===== running final command(s) =====");
await recipe.postInit({
cwd: appDirectory,
cfg,
packageManager,
});
}
}
createTauriApp(process.argv.slice(2)).catch((err) => {
console.error(err);
});