create-tauri-app.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. #!/usr/bin/env node
  2. const parseArgs = require("minimist");
  3. const inquirer = require("inquirer");
  4. const { resolve, join } = require("path");
  5. const {
  6. recipeShortNames,
  7. recipeDescriptiveNames,
  8. recipeByDescriptiveName,
  9. recipeByShortName,
  10. install,
  11. shell,
  12. } = require("../dist/");
  13. const { dir } = require("console");
  14. /**
  15. * @type {object}
  16. * @property {boolean} h
  17. * @property {boolean} help
  18. * @property {boolean} v
  19. * @property {boolean} version
  20. * @property {string|boolean} f
  21. * @property {string|boolean} force
  22. * @property {boolean} l
  23. * @property {boolean} log
  24. * @property {boolean} d
  25. * @property {boolean} directory
  26. * @property {string} r
  27. * @property {string} recipe
  28. */
  29. const createTauriApp = async (cliArgs) => {
  30. const argv = parseArgs(cliArgs, {
  31. alias: {
  32. h: "help",
  33. v: "version",
  34. f: "force",
  35. l: "log",
  36. d: "directory",
  37. b: "binary",
  38. t: "tauri-path",
  39. A: "app-name",
  40. W: "window-title",
  41. D: "dist-dir",
  42. P: "dev-path",
  43. r: "recipe",
  44. },
  45. boolean: ["h", "l", "ci"],
  46. });
  47. if (argv.help) {
  48. printUsage();
  49. return 0;
  50. }
  51. if (argv.v) {
  52. console.log(require("../package.json").version);
  53. return false; // do this for node consumers and tests
  54. }
  55. if (argv.ci) {
  56. return runInit(argv);
  57. } else {
  58. return getOptionsInteractive(argv).then((responses) =>
  59. runInit(argv, responses)
  60. );
  61. }
  62. };
  63. function printUsage() {
  64. console.log(`
  65. Description
  66. Starts a new tauri app from a "recipe" or pre-built template.
  67. Usage
  68. $ yarn create tauri-app <app-name> # npm create-tauri-app <app-name>
  69. Options
  70. --help, -h Displays this message
  71. -v, --version Displays the Tauri CLI version
  72. --ci Skip prompts
  73. --force, -f Force init to overwrite [conf|template|all]
  74. --log, -l Logging [boolean]
  75. --directory, -d Set target directory for init
  76. --binary, -b Optional path to a tauri binary from which to run init
  77. --app-name, -A Name of your Tauri application
  78. --window-title, -W Window title of your Tauri application
  79. --dist-dir, -D Web assets location, relative to <project-dir>/src-tauri
  80. --dev-path, -P Url of your dev server
  81. --recipe, -r Add UI framework recipe. None by default.
  82. Supported recipes: [${recipeShortNames.join("|")}]
  83. `);
  84. }
  85. const getOptionsInteractive = (argv) => {
  86. let defaultAppName = argv.A || "tauri-app";
  87. return inquirer
  88. .prompt([
  89. {
  90. type: "input",
  91. name: "appName",
  92. message: "What is your app name?",
  93. default: defaultAppName,
  94. when: !argv.A,
  95. },
  96. {
  97. type: "input",
  98. name: "tauri.window.title",
  99. message: "What should the window title be?",
  100. default: "Tauri App",
  101. when: () => !argv.W,
  102. },
  103. {
  104. type: "list",
  105. name: "recipeName",
  106. message: "Would you like to add a UI recipe?",
  107. choices: recipeDescriptiveNames,
  108. default: "No recipe",
  109. when: () => !argv.r,
  110. },
  111. ])
  112. .catch((error) => {
  113. if (error.isTtyError) {
  114. // Prompt couldn't be rendered in the current environment
  115. console.log(
  116. "It appears your terminal does not support interactive prompts. Using default values."
  117. );
  118. runInit();
  119. } else {
  120. // Something else when wrong
  121. console.error("An unknown error occurred:", error);
  122. }
  123. });
  124. };
  125. async function runInit(argv, config = {}) {
  126. const {
  127. appName,
  128. recipeName,
  129. tauri: {
  130. window: { title },
  131. },
  132. } = config;
  133. let recipe;
  134. if (recipeName !== undefined) {
  135. recipe = recipeByDescriptiveName(recipeName);
  136. } else if (argv.r) {
  137. recipe = recipeByShortName(argv.r);
  138. }
  139. let buildConfig = {
  140. distDir: argv.D,
  141. devPath: argv.P,
  142. };
  143. if (recipe !== undefined) {
  144. buildConfig = recipe.configUpdate(buildConfig);
  145. }
  146. const directory = argv.d || process.cwd();
  147. const cfg = {
  148. ...buildConfig,
  149. appName: appName || argv.A,
  150. windowTitle: title || argv.w,
  151. };
  152. // note that our app directory is reliant on the appName and
  153. // generally there are issues if the path has spaces (see Windows)
  154. // future TODO prevent app names with spaces or escape here?
  155. const appDirectory = join(directory, cfg.appName);
  156. if (recipe.preInit) {
  157. console.log("===== running initial command(s) =====");
  158. await recipe.preInit({ cwd: directory, cfg });
  159. }
  160. const initArgs = [
  161. ["--app-name", cfg.appName],
  162. ["--window-title", cfg.windowTitle],
  163. ["--dist-dir", cfg.distDir],
  164. ["--dev-path", cfg.devPath],
  165. ].reduce((final, argSet) => {
  166. if (argSet[1]) {
  167. return final.concat([argSet[0], `\"${argSet[1]}\"`]);
  168. } else {
  169. return final;
  170. }
  171. }, []);
  172. const installed = await install({
  173. appDir: appDirectory,
  174. dependencies: recipe.extraNpmDependencies,
  175. devDependencies: ["tauri", ...recipe.extraNpmDevDependencies],
  176. });
  177. console.log("===== running tauri init =====");
  178. const binary = !argv.b
  179. ? installed.packageManager
  180. : resolve(appDirectory, argv.b);
  181. const runTauriArgs =
  182. installed.packageManager === "npm" && !argv.b
  183. ? ["run", "tauri", "--", "init"]
  184. : ["tauri", "init"];
  185. await shell(binary, [...runTauriArgs, ...initArgs], {
  186. cwd: appDirectory,
  187. });
  188. if (recipe.postInit) {
  189. console.log("===== running final command(s) =====");
  190. await recipe.postInit({
  191. cwd: appDirectory,
  192. cfg,
  193. });
  194. }
  195. }
  196. createTauriApp(process.argv.slice(2)).catch((err) => {
  197. console.error(err);
  198. });