Browse Source

Merge pull request #1331 from tauri-apps/feature/create-tauri-app

feat: create-tauri-app
Jacob Bolda 4 years ago
parent
commit
8978c0bbfe

+ 5 - 0
.changes/config.json

@@ -169,6 +169,11 @@
         }
       ]
     },
+    "create-tauri-app": {
+      "path": "./cli/create-tauri-app",
+      "manager": "javascript",
+      "dependencies": ["tauri.js"]
+    },
     "tauri-utils": {
       "path": "./core/tauri-utils",
       "manager": "rust"

+ 5 - 0
.changes/create-vanilla-js-templated.md

@@ -0,0 +1,5 @@
+---
+"create-tauri-app": minor
+---
+
+Add vanilla javascript option to `create-tauri-app` through templating.

+ 6 - 0
.changes/revert-and-shift-tauri-create.md

@@ -0,0 +1,6 @@
+---
+"create-tauri-app": minor
+"tauri.js": patch
+---
+
+Revert `tauri create` deletion and shift remaining pieces that weren't deleted to `create-tauri-app`.

+ 69 - 0
cli/core/templates/src-tauri/src/main.rs

@@ -0,0 +1,69 @@
+# Build output
+/dist
+/api
+
+# lock for libs
+/Cargo.lock
+/yarn.lock
+
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+
+# nyc test coverage
+.nyc_output
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (http://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules/
+jspm_packages/
+
+# Typescript v1 declaration files
+typings/
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# dotenv environment variables file
+.env
+
+/.vs
+.DS_Store
+.Thumbs.db
+*.sublime*
+.idea/
+debug.log
+package-lock.json
+.vscode/settings.json

+ 218 - 0
cli/create-tauri-app/bin/create-tauri-app.js

@@ -0,0 +1,218 @@
+#!/usr/bin/env node
+
+const parseArgs = require("minimist");
+const inquirer = require("inquirer");
+const { resolve, join } = require("path");
+const {
+  recipeShortNames,
+  recipeDescriptiveNames,
+  recipeByDescriptiveName,
+  recipeByShortName,
+  install,
+  shell,
+} = require("../dist/");
+const { dir } = require("console");
+
+/**
+ * @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",
+      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]
+    --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 when wrong
+        console.error("An unknown error occurred:", error);
+      }
+    });
+};
+
+async function runInit(argv, config = {}) {
+  const {
+    appName,
+    recipeName,
+    tauri: {
+      window: { title },
+    },
+  } = config;
+
+  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);
+  }
+
+  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);
+
+  if (recipe.preInit) {
+    console.log("===== running initial command(s) =====");
+    await recipe.preInit({ cwd: directory, cfg });
+  }
+
+  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[0], `\"${argSet[1]}\"`]);
+    } else {
+      return final;
+    }
+  }, []);
+
+  const installed = await install({
+    appDir: appDirectory,
+    dependencies: recipe.extraNpmDependencies,
+    devDependencies: ["tauri", ...recipe.extraNpmDevDependencies],
+  });
+
+  console.log("===== running tauri init =====");
+  const binary = !argv.b
+    ? installed.packageManager
+    : resolve(appDirectory, argv.b);
+  const runTauriArgs =
+    installed.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,
+    });
+  }
+}
+
+createTauriApp(process.argv.slice(2)).catch((err) => {
+  console.error(err);
+});

+ 43 - 0
cli/create-tauri-app/package.json

@@ -0,0 +1,43 @@
+{
+  "name": "create-tauri-app",
+  "version": "0.0.0",
+  "description": "Jump right into a Tauri App!",
+  "bin": {
+    "create-tauri-app": "./bin/create-tauri-app.js"
+  },
+  "repository": "git+https://github.com/tauri-apps/tauri.git",
+  "license": "MIT",
+  "bugs": {
+    "url": "https://github.com/tauri-apps/tauri/issues"
+  },
+  "homepage": "https://github.com/tauri-apps/tauri#readme",
+  "contributors": [
+    "Tauri Team <team@tauri-apps.org> (https://tauri.studio)",
+    "Jacob Bolda <me@jacobbolda.com> (https://www.jacobbolda.com)"
+  ],
+  "scripts": {
+    "create-tauri-app": "create-tauri-app",
+    "build": "rollup --config",
+    "prepublishOnly": "yarn build"
+  },
+  "dependencies": {
+    "execa": "^5.0.0",
+    "inquirer": "^8.0.0",
+    "lodash": "4.17.21",
+    "minimist": "^1.2.5",
+    "scaffe": "1.0.0"
+  },
+  "devDependencies": {
+    "@rollup/plugin-commonjs": "^18.0.0",
+    "@rollup/plugin-node-resolve": "^11.2.1",
+    "@rollup/plugin-typescript": "^8.2.1",
+    "@types/cross-spawn": "6.0.2",
+    "@types/inquirer": "7.3.1",
+    "@types/lodash": "4.14.168",
+    "@types/semver": "7.3.4",
+    "prettier": "^2.2.1",
+    "rollup": "^2.45.1",
+    "tslib": "^2.2.0",
+    "typescript": "4.2.4"
+  }
+}

+ 25 - 0
cli/create-tauri-app/readme.md

@@ -0,0 +1,25 @@
+# create-tauri-app
+
+Run and answer the prompts to get started with your first Tauri app!
+
+With npx:
+
+```shell
+npx create-tauri-app
+```
+
+With npm:
+
+```shell
+npm x create-tauri-app
+```
+
+With yarn:
+
+```shell
+yarn create tauri-app
+```
+
+# Additional Args
+
+TODO

+ 25 - 0
cli/create-tauri-app/rollup.config.js

@@ -0,0 +1,25 @@
+import typescript from "@rollup/plugin-typescript";
+import commonjs from "@rollup/plugin-commonjs";
+import pkg from "./package.json";
+
+export default {
+  treeshake: true,
+  perf: true,
+  input: "src/index.ts",
+  output: {
+    dir: "dist",
+    format: "cjs",
+    entryFileNames: "[name].js",
+    exports: "named",
+  },
+  plugins: [typescript(), commonjs({ extensions: [".js"] })],
+  external: [
+    ...Object.keys(pkg.dependencies || {}),
+    ...Object.keys(pkg.peerDependencies || {}),
+  ],
+  watch: {
+    chokidar: true,
+    include: "src/**",
+    exclude: "node_modules/**",
+  },
+};

+ 99 - 0
cli/create-tauri-app/src/dependency-manager.ts

@@ -0,0 +1,99 @@
+import { ManagementType, Result } from "./types/deps";
+import { shell } from "./shell";
+import { existsSync } from "fs";
+import { join } from "path";
+
+export async function install({
+  appDir,
+  dependencies,
+  devDependencies,
+}: {
+  appDir: string;
+  dependencies: string[];
+  devDependencies?: string[];
+}) {
+  return await manageDependencies(appDir, dependencies, devDependencies);
+}
+
+async function manageDependencies(
+  appDir: string,
+  dependencies: string[] = [],
+  devDependencies: string[] = []
+): Promise<{ result: Result; packageManager: string }> {
+  const installedDeps = [...dependencies, ...devDependencies];
+  console.log(`Installing ${installedDeps.join(", ")}...`);
+
+  const packageManager = await usePackageManager(appDir);
+
+  await installNpmDevPackage(devDependencies, packageManager, appDir);
+  await installNpmPackage(dependencies, packageManager, appDir);
+
+  const result: Result = new Map<ManagementType, string[]>();
+  result.set(ManagementType.Install, installedDeps);
+
+  return { result, packageManager };
+}
+
+async function usePackageManager(appDir: string): Promise<"yarn" | "npm"> {
+  const hasYarnLockfile = existsSync(join(appDir, "yarn.lock"));
+  let yarnChild;
+  // try yarn first if there is a lockfile
+  if (hasYarnLockfile) {
+    yarnChild = await shell("yarn", ["--version"], { stdio: "pipe" });
+    if (!yarnChild.failed) return "yarn";
+  }
+
+  // try npm then as the "default"
+  const npmChild = await shell("npm", ["--version"], { stdio: "pipe" });
+  if (!npmChild.failed) return "npm";
+
+  // try yarn as maybe only yarn is installed
+  if (yarnChild && !yarnChild.failed) return "yarn";
+
+  // if we have reached here, we can't seem to run anything
+  throw new Error(
+    `Must have npm or yarn installed to manage dependencies. Is either in your PATH? We tried running in ${appDir}`
+  );
+}
+
+async function installNpmPackage(
+  packageNames: string[],
+  packageManager: string,
+  appDir: string
+): Promise<void> {
+  if (packageNames.length === 0) return;
+  if (packageManager === "yarn") {
+    await shell("yarn", ["add", packageNames.join(" ")], {
+      cwd: appDir,
+    });
+  } else {
+    await shell("npm", ["install", packageNames.join(" ")], {
+      cwd: appDir,
+    });
+  }
+}
+
+async function installNpmDevPackage(
+  packageNames: string[],
+  packageManager: string,
+  appDir: string
+): Promise<void> {
+  if (packageNames.length === 0) return;
+  if (packageManager === "yarn") {
+    await shell(
+      "yarn",
+      ["add", "--dev", "--ignore-scripts", packageNames.join(" ")],
+      {
+        cwd: appDir,
+      }
+    );
+  } else {
+    await shell(
+      "npm",
+      ["install", "--save-dev", "--ignore-scripts", packageNames.join(" ")],
+      {
+        cwd: appDir,
+      }
+    );
+  }
+}

+ 52 - 0
cli/create-tauri-app/src/index.ts

@@ -0,0 +1,52 @@
+import { map, find } from "lodash";
+import { TauriBuildConfig } from "./types/config";
+import { reactjs, reactts } from "./recipes/react";
+import { vanillajs } from "./recipes/vanilla";
+
+export { shell } from "./shell";
+export { install } from "./dependency-manager";
+
+export interface Recipe {
+  descriptiveName: string;
+  shortName: string;
+  configUpdate?: (cfg: TauriBuildConfig) => TauriBuildConfig;
+  extraNpmDependencies: string[];
+  extraNpmDevDependencies: string[];
+  preInit?: ({
+    cwd,
+    cfg,
+  }: {
+    cwd: string;
+    cfg: TauriBuildConfig;
+  }) => Promise<void>;
+  postInit?: ({
+    cwd,
+    cfg,
+  }: {
+    cwd: string;
+    cfg: TauriBuildConfig;
+  }) => Promise<void>;
+}
+
+export const allRecipes: Recipe[] = [vanillajs, 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
+);

+ 73 - 0
cli/create-tauri-app/src/recipes/react.ts

@@ -0,0 +1,73 @@
+import { Recipe } from "..";
+import { join } from "path";
+//@ts-ignore
+import scaffe from "scaffe";
+import { shell } from "../shell";
+
+const completeLogMsg = `
+  Your installation completed.
+  To start, run yarn tauri dev
+`;
+
+const afterCra = async (cwd: string, appName: string, version: string) => {
+  const templateDir = join(__dirname, "../src/templates/react");
+  const variables = {
+    name: appName,
+    tauri_version: version,
+  };
+
+  try {
+    await scaffe.generate(templateDir, join(cwd, appName), {
+      overwrite: true,
+      variables,
+    });
+  } catch (err) {
+    console.log(err);
+  }
+};
+
+const reactjs: Recipe = {
+  descriptiveName: "React.js",
+  shortName: "reactjs",
+  configUpdate: (cfg) => ({
+    ...cfg,
+    distDir: `../build`,
+    devPath: "http://localhost:3000",
+    beforeDevCommand: `npm start`,
+    beforeBuildCommand: `npm build`,
+  }),
+  extraNpmDevDependencies: [],
+  extraNpmDependencies: [],
+  preInit: async ({ cwd, cfg }) => {
+    // CRA creates the folder for you
+    await shell("npx", ["create-react-app", `${cfg.appName}`], { cwd });
+    const version = await shell("npm", ["view", "tauri", "version"], {
+      stdio: "pipe",
+    });
+    const versionNumber = version.stdout.trim();
+    await afterCra(cwd, cfg.appName, versionNumber);
+  },
+  postInit: async ({ cfg }) => {
+    console.log(completeLogMsg);
+  },
+};
+
+const reactts: Recipe = {
+  ...reactjs,
+  descriptiveName: "React with Typescript",
+  shortName: "reactts",
+  extraNpmDependencies: [],
+  preInit: async ({ cwd, cfg }) => {
+    // CRA creates the folder for you
+    await shell(
+      "npx",
+      ["create-react-app", "--template", "typescript", `${cfg.appName}`],
+      { cwd }
+    );
+  },
+  postInit: async ({ cfg }) => {
+    console.log(completeLogMsg);
+  },
+};
+
+export { reactjs, reactts };

+ 61 - 0
cli/create-tauri-app/src/recipes/vanilla.ts

@@ -0,0 +1,61 @@
+import { Recipe } from "..";
+import { TauriBuildConfig } from "../types/config";
+import { join } from "path";
+//@ts-ignore
+import scaffe from "scaffe";
+import { shell } from "../shell";
+
+export const vanillajs: Recipe = {
+  descriptiveName: "Vanilla.js",
+  shortName: "vanillajs",
+  configUpdate: (cfg) => ({
+    ...cfg,
+    distDir: `../dist`,
+    devPath: `../dist`,
+    beforeDevCommand: `yarn start`,
+    beforeBuildCommand: `yarn build`,
+  }),
+  extraNpmDevDependencies: [],
+  extraNpmDependencies: [],
+  preInit: async ({ cwd, cfg }) => {
+    const version = await shell("npm", ["view", "tauri", "version"], {
+      stdio: "pipe",
+    });
+    const versionNumber = version.stdout.trim();
+    await run(cfg, cwd, versionNumber);
+  },
+  postInit: async ({ cfg }) => {
+    console.log(`
+      change directory:
+        $ cd ${cfg.appName}
+    
+      install dependencies:
+        $ yarn # npm install
+    
+      run the app:
+        $ yarn tauri dev # npm run tauri dev
+            `);
+  },
+};
+
+export const run = async (
+  args: TauriBuildConfig,
+  cwd: string,
+  version: string
+) => {
+  const { appName } = args;
+  const templateDir = join(__dirname, "../src/templates/vanilla");
+  const variables = {
+    name: appName,
+    tauri_version: version,
+  };
+
+  try {
+    await scaffe.generate(templateDir, join(cwd, appName), {
+      overwrite: true,
+      variables,
+    });
+  } catch (err) {
+    console.log(err);
+  }
+};

+ 32 - 0
cli/create-tauri-app/src/shell.ts

@@ -0,0 +1,32 @@
+import execa from "execa";
+
+export const shell = async (
+  command: string,
+  args?: string[],
+  options?: execa.Options,
+  log: boolean = false
+) => {
+  try {
+    if (options && options.shell === true) {
+      const stringCommand = [command, ...(!args ? [] : args)].join(" ");
+      if (log) console.log(`[running]: ${stringCommand}`);
+      return await execa(stringCommand, {
+        stdio: "inherit",
+        cwd: process.cwd(),
+        env: process.env,
+        ...options,
+      });
+    } else {
+      if (log) console.log(`[running]: ${command}`);
+      return await execa(command, args, {
+        stdio: "inherit",
+        cwd: process.cwd(),
+        env: process.env,
+        ...options,
+      });
+    }
+  } catch (error) {
+    console.error("Error with command: %s", command);
+    throw new Error(error);
+  }
+};

+ 54 - 0
cli/create-tauri-app/src/templates/react/src/App.css

@@ -0,0 +1,54 @@
+.App {
+  text-align: center;
+}
+
+.App-logo {
+  height: 20vmin;
+  pointer-events: none;
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  .App-logo.rotate {
+    animation: App-logo-spin infinite 20s linear;
+  }
+}
+
+div.inline-logo {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  justify-content: center;
+}
+
+div.inline-logo > img {
+  margin-right: 3vw;
+}
+
+div.inline-logo .smaller {
+  height: 10vh;
+}
+
+.App-header {
+  background-color: #282c34;
+  min-height: 100vh;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  font-size: calc(10px + 2vmin);
+  color: white;
+}
+
+.App-link {
+  color: #61dafb;
+  margin-bottom: 5vh;
+}
+
+@keyframes App-logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}

+ 40 - 0
cli/create-tauri-app/src/templates/react/src/App.js

@@ -0,0 +1,40 @@
+import React from "react";
+import logo from "./logo.svg";
+import tauriCircles from "./tauri.svg";
+import tauriWord from "./wordmark.svg";
+import "./App.css";
+
+function App() {
+  return (
+    <div className="App">
+      <header className="App-header">
+        <div className="inline-logo">
+          <img src={tauriCircles} className="App-logo rotate" alt="logo" />
+          <img src={tauriWord} className="App-logo smaller" alt="logo" />
+        </div>
+        <a
+          className="App-link"
+          href="https://tauri.studio"
+          target="_blank"
+          rel="noopener noreferrer"
+        >
+          Learn Tauri
+        </a>
+        <img src={logo} className="App-logo rotate" alt="logo" />
+        <a
+          className="App-link"
+          href="https://reactjs.org"
+          target="_blank"
+          rel="noopener noreferrer"
+        >
+          Learn React
+        </a>
+        <p>
+          Edit <code>src/App.js</code> and save to reload.
+        </p>
+      </header>
+    </div>
+  );
+}
+
+export default App;

+ 21 - 0
cli/create-tauri-app/src/templates/react/src/tauri.svg

@@ -0,0 +1,21 @@
+<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" version="1.1" viewBox="0 0 383.44479 435.98273" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
+    <g transform="translate(-703.62301,-1339.6611)">
+            <g transform="rotate(-19.354322)">
+                <circle cx="274.08301" cy="1813.09" r="32" fill="url(#d)"/>
+            </g>
+            <g transform="rotate(-19.354322)">
+                <circle cx="382.97299" cy="1719.61" r="32" fill="url(#c)"/>
+            </g>
+            <path d="m796.022 1418.15c-21.659 37.92-27.401 84.66-11.828 129 4.38 12.47 10.212 24.01 17.214 34.55 1.051 1.88 2.59 3.45 4.455 4.53 5.701 3.29 13.101 1.31 16.392-4.39 2.286-3.97 2.104-8.92-0.468-12.72l0.027-0.02c-6.097-9.09-11.178-19.08-14.98-29.9-24.177-68.83 11.861-143.9 80.692-168.08s143.904 11.86 168.084 80.69-11.87 143.91-80.699 168.09c-17.276 6.06-34.942 8.32-52.099 7.23h-0.052c-4.759-0.57-9.423 1.76-11.82 5.91-3.291 5.71-1.309 13.1 4.392 16.4 1.905 1.09 4.073 1.64 6.268 1.59 20.21 1.28 40.988-1.37 61.264-8.49 81.066-28.48 123.866-117.61 95.386-198.68s-117.609-123.86-198.678-95.38c-36.734 12.9-65.607 38.26-83.553 69.67z" fill="url(#b)" fill-rule="nonzero"/>
+            <path d="m724.265 1542.44c-21.659 37.92-27.397 84.66-11.824 129 28.476 81.07 117.602 123.86 198.67 95.39 81.069-28.48 123.859-117.61 95.389-198.68-4.33-12.34-10.09-23.77-16.991-34.21-1.05-2.05-2.668-3.75-4.659-4.91-5.701-3.29-13.101-1.31-16.392 4.39-2.287 3.98-2.105 8.93 0.467 12.72l-0.058 0.04c6.101 9.1 11.186 19.09 14.989 29.92 24.174 68.83-11.866 143.91-80.697 168.08-68.831 24.18-143.899-11.86-168.076-80.7-24.178-68.83 11.859-143.9 80.69-168.08 17.493-6.14 35.388-8.39 52.75-7.2l1e-3 -0.03c4.572 0.33 8.949-1.99 11.246-5.95 3.291-5.7 1.309-13.1-4.392-16.39-2.026-1.17-4.349-1.72-6.682-1.58-20.088-1.23-40.73 1.43-60.877 8.51-36.734 12.9-65.609 38.26-83.554 69.67z" fill="url(#a)" fill-rule="nonzero"/>
+        </g>
+    <defs>
+        <linearGradient id="d" x2="1" gradientTransform="matrix(48.6643,-41.7777,41.7777,48.6643,249.699,1834.02)" gradientUnits="userSpaceOnUse"><stop stop-color="#0096f2" offset="0"/><stop stop-color="#4cffc4" offset="1"/></linearGradient>
+        <linearGradient id="c" x2="1" gradientTransform="matrix(-48.5635,41.6911,-41.6911,-48.5635,407.745,1699.34)" gradientUnits="userSpaceOnUse"><stop stop-color="#ff8a11" offset="0"/><stop stop-color="#fff550" offset="1"/></linearGradient>
+        <linearGradient id="b" x2="1" gradientTransform="matrix(-150.612,260.867,-260.867,-150.612,960.685,1332.65)" gradientUnits="userSpaceOnUse"><stop stop-color="#ff8a11" offset="0"/><stop stop-color="#fff550" offset="1"/></linearGradient>
+        <linearGradient id="a" x2="1" gradientTransform="matrix(150.613,-260.87,260.87,150.613,781.584,1754.69)" gradientUnits="userSpaceOnUse"><stop stop-color="#0096f2" offset="0"/><stop stop-color="#4cffc4" offset="1"/></linearGradient>
+    
+        
+        
+    </defs>
+</svg>

File diff suppressed because it is too large
+ 4 - 0
cli/create-tauri-app/src/templates/react/src/wordmark.svg


+ 9 - 0
cli/create-tauri-app/src/templates/vanilla/_package.json

@@ -0,0 +1,9 @@
+{
+  "name": "<%= name %>",
+  "scripts": {
+    "tauri": "tauri"
+  },
+  "dependencies": {
+    "tauri": "<%= tauri_version %>"
+  }
+}

+ 21 - 0
cli/create-tauri-app/src/templates/vanilla/dist/_index.html

@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+  <style>
+    html,
+    body {
+      margin: 0;
+      padding: 0;
+      width: 100%;
+      height: 100%;
+    }
+
+    body {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+    }
+  </style>
+  <body>
+    <h1><%= name %></h1>
+  </body>
+</html>

+ 7 - 5
cli/tauri.js/src/types/config.ts → cli/create-tauri-app/src/types/config.ts

@@ -3,22 +3,24 @@
 // SPDX-License-Identifier: MIT
 
 export interface TauriBuildConfig {
+  appName: string;
+  windowTitle: string;
   /**
    * the path to the app's dist dir
    * this path must contain your index.html file
    */
-  distDir: string
+  distDir: string;
   /**
    * the app's dev server URL, or the path to the directory containing an index.html to open
    */
-  devPath: string
+  devPath: string;
   /**
    * a shell command to run before `tauri dev` kicks in
    */
-  beforeDevCommand?: string
+  beforeDevCommand?: string;
   /**
    * a shell command to run before `tauri build` kicks in
    */
-  beforeBuildCommand?: string
-  withGlobalTauri?: boolean
+  beforeBuildCommand?: string;
+  withGlobalTauri?: boolean;
 }

+ 7 - 0
cli/create-tauri-app/src/types/deps.ts

@@ -0,0 +1,7 @@
+export enum ManagementType {
+  Install,
+  InstallDev,
+  Update,
+}
+
+export type Result = Map<ManagementType, string[]>;

+ 13 - 0
cli/create-tauri-app/tsconfig.json

@@ -0,0 +1,13 @@
+{
+  "compilerOptions": {
+    "strict": true,
+    "module": "esnext",
+    "target": "es6",
+    "allowJs": true,
+    "pretty": true,
+    "esModuleInterop": true,
+    "resolveJsonModule": true,
+    "moduleResolution": "node"
+  },
+  "include": ["src"]
+}

BIN
core/tauri/test/fixture/src-tauri/icons/icon.ico~dev


+ 0 - 1
examples/helloworld/src-tauri/Cargo.toml

@@ -3,7 +3,6 @@ name = "helloworld"
 version = "0.1.0"
 description = "A very simple Tauri Appplication"
 edition = "2018"
-license = "Apache-2.0 OR MIT"
 
 [build-dependencies]
 tauri-build = { path = "../../../core/tauri-build", features = [ "codegen" ]}

Some files were not shown because too many files changed in this diff