tauri-apps / tauri

Build smaller, faster, and more secure desktop applications with a web frontend.
https://tauri.app
Apache License 2.0
79.49k stars 2.36k forks source link

[feat]: add additional parameters to create tauri-app so it is compatible with Monorepo approaches #7975

Open ErickRodrCodes opened 9 months ago

ErickRodrCodes commented 9 months ago

Describe the problem

I do think that when you generate the tauri-app, it is tied up to only one app, or only one frontend app:

.
├── src /** it picks only one app, default is "src" **/
│   ├── assets
│   │   ├── tauri.svg
│   │   ├── typescript.svg
│   │   └── vite.svg
│   ├── main.ts
│   └── styles.css
├── src-tauri /**it picks only main renderer app, default is "src-tauri"
│   ├── icons
│   │   ├── 128x128.png
│   │   ├── .... other images
│   ├── src
│   │   └── main.rs
│   ├── .gitignore
│   ├── build.rs
│   ├── Cargo.toml
│   └── tauri.conf.json
├── .gitignore
├── index.html <=== this should be on the src folder instead root level as simple vanilla or other code
├── package.json
├── README.md
├── tsconfig.json
└── vite.config.ts

it would be suggested to keep apps segregated (it would benefit on the long run to have segregation between applications and multiple tauri apps because, in my project, I need to build two desktop applications, each one with its own tauri main process), but running in a centric package.json. Vite would run on the client frontend app:

.
├── myTsApp /** it picks only one app, default is "src" **/
│   ├── assets
│   │   ├── tauri.svg
│   │   ├── typescript.svg
│   │   └── vite.svg
│   ├── main.ts
│   ├── vite.config.ts
│   ├── index.html
│   └── styles.css
├── myTauriApp /**it picks only main renderer app, default is "src-tauri"
│   ├── icons
│   │   ├── 128x128.png
│   │   ├── .... other images
│   ├── src
│   │   └── main.rs
│   ├── .gitignore
│   ├── build.rs
│   ├── Cargo.toml
│   └── tauri.conf.json
├── .gitignore
├── package.json
├── README.md
└── tsconfig.json

OR

if used along a monorepo, such Nx:

.
├── apps 
│   ├── myReactApp
│   └── tauri-app
│       ├──  icons
│       │    ├── 128x128.png
│       │    └── .... other images
│       ├── src
│       │    └── main.rs
│       ├── .gitignore
│       ├── build.rs
│       ├── Cargo.toml
│       ├── project.json /** nx project file configuration
│       └── tauri.conf.json
├── .gitignore
├── package.json
├── README.md
└── tsconfig.json

It would be good to pass parameters to tauri to indicate from where to run stuff:

$ npm run tauri dev --mainProcessProject=apps/myMainTauriApp --projectServe=apps/myfrontendProject

so it would be possible for tauri to run multiple tauri apps for multiple frontend projects, or tied those accordingly.

Describe the solution you'd like

  1. changes on the command line for create tauri-app

My intention here is to have tauri-app to create a tauri-src project in a mono repo approach, without generating a frontend interface (Nx and other mono repo tools can run that)

a flag could be used to skip such task:

--SkipFrontend: it will skip questions regarding the kind of package manager, UI template, and UI Flavor. This however triggers what port to use, so it can be associated with an existing application.

  1. changes on tauri dev

npm run dev or npm run Tauri dev doesn't come with parameters to customize what to launch. it would be suggested the following:

--frontendPort=int changes the default port tauri is listening to and uses the one that we want to target (an existing angular project, or react project would suffice to serve such a project. the only requirement is the target can communicate with tauri's main process by using import { invoke } from "@tauri-apps/api/tauri";

Given this,it could be possible that two or more Tauri projects can run simultaneously on a desktop computer. in that case, an application UUID might be needed in order to tell the frontend apps to which process you are talking.

  1. changes on tauri build

--frontendBuildFolder=/dist/myReactApp indicates where is the location of the build frontend app you want to attach to your project.

Alternatives considered

Creating an Nx plugin that leverages this can be an ideal option

Additional context

No response

FabianLars commented 8 months ago

Great writeup with valuable feedback, thanks!

For point 1, you're basically asking for the tauri init command, imo create-tauri-app should not care about this use case.

For point 2&3 you can use the --config flag to overwrite the devPath/distDir (or virtually whatever else you wanna change). I'd like to keep it this way and not introduce too many flags for things that can be configured via the existing tauri configs. (Thinking like "If we add those, which other flags do we add later" - so basically "poluting" the cli)

The only thing in my opinion that's really missing is something like cargo's --manifest-path flag where you can tell the tauri cli which tauri config/app you want to start. Right now it uses the first one it find searching through the cwd recursively.

ErickRodrCodes commented 8 months ago

mmm, in Nx, when you create an executor, we can pass the project path through the context of the generator, something like:...

import { ExecutorContext } from '@nx/devkit';
import { AmelioratedExecutorSchema } from './schema';
import { execSync } from 'child_process';
import * as path from 'path';

/**
 * A function that executes on the selected project a Tauri dev project
 * @param options
 * @param context
 */
export default async function runExecutor(
  options: TauriDevExecutorSchema, // <== pass an interface with the shape of options
  context: ExecutorContext //<== Object that represents the whole Nx workspace configuration
) {
  const workspaceDir = context.root;
  const projectName = context.projectName;
  const projectContext = context.workspace.projects[projectName];
  const projectSourceRoot= projectContext.sourceRoot;
  const args = ['--manifest-path', projectSourceRoot];

  const command = ['npm', 'run', 'tauri','dev'].concat(args).join(' ');
  execSync(command, {
    stdio: 'inherit',
    cwd: path.resolve(process.cwd(), workspaceDir),
  });
  return { success: true };
}

So from a context perspective, there is not a problem. Please tell me the config options so I can create the right generator.

FabianLars commented 8 months ago

--config accepts either a path, or a string to/of json with the same format as tauri.conf.json. So for example you can have a file (or inline) with this:

{
  "build": {
    "devPath": "http://123:123",
    "distDir": "../path/to/dist"
  }
}

and then call npm run tauri dev -- --config that-file-from-above.json

vonPB commented 8 months ago

The only thing in my opinion that's really missing is something like cargo's --manifest-path flag where you can tell the tauri cli which tauri config/app you want to start. Right now it uses the first one it find searching through the cwd recursively.

I am trying to build two versions of 1 app. I want the second version to be a simplified version of the main app. The front-end can be shared. It would be awsome to have the said --manifest-path available.

 ├── src/
 ├── src-ABC
│   ├── Cargo.toml
│   ├── ...
 ├── src-XYZ
│   ├── Cargo.toml
│   ├── ...
├── .gitignore
├── package.json
├── README.md
└── tsconfig.json

And then simply run either app by running

 "ABC:dev": "yarn tauri --manifest-path src-tauri/Cargo.toml dev",
 "XYS:dev": "yarn tauri --manifest-path src-client/Cargo.toml dev"
ErickRodrCodes commented 8 months ago

that

The only thing in my opinion that's really missing is something like cargo's --manifest-path flag where you can tell the tauri cli which tauri config/app you want to start. Right now it uses the first one it find searching through the cwd recursively.

I am trying to build two versions of 1 app. I want the second version to be a simplified version of the main app. The front-end can be shared. It would be awsome to have the said --manifest-path available.

├── src/
├── src-ABC
│   ├── Cargo.toml
│   ├── ...
├── src-XYZ
│   ├── Cargo.toml
│   ├── ...
├── .gitignore
├── package.json
├── README.md
└── tsconfig.json

And then simply run either app by running

 "ABC:dev": "yarn tauri --manifest-path src-tauri/Cargo.toml dev",
 "XYS:dev": "yarn tauri --manifest-path src-client/Cargo.toml dev"

yup, pretty much.

in an Nx Executor/Generator, the project referenced can be easily tied when you run the command:

the Generator creates the folder structure based on a template:

export async function createAppGenerator(
  tree: Tree,
  options: CreateAppGeneratorSchema
) {
  addProjectConfiguration(tree, options.name, {
    projectType: 'application',
    sourceRoot: `${options.directory}/src`,
    root: options.directory,
    targets: {
      build: {
        executor: '@tbogard/nx-vite-electron:build',
        outputs: ['{options.outputPath}'],
        options: {
          outputPath: `dist/${options.name}/`,
        },
      },
    },
  });

  const srcFolder = join(__dirname, 'files');
  const target = options.directory;
  generateFiles(tree, srcFolder, target, options);
  await formatFiles(tree);
  const devDependencies = {
    '@tauri/cli': 'latest',
  };
  addDependenciesToPackageJson(tree, {}, devDependencies);
}

once the generator creates the folder structure, we can use an Executor to reference the cargo file:

export default async function runExecutor(
  options: NxViteElectronExecutorSchema,
  context: ExecutorContext
) {
  const projectName = context.projectName;
  const projectContext = context.workspace.projects[projectName];
  const sourceRoot = projectContext.sourceRoot;
  const root = projectContext.root;
  const targetProjectPort = projectContext.targetProjectPort;
  const fixedSourceDir = path.resolve(process.cwd(), sourceRoot, 'Cargo.toml');

  const args = ['--manifest-file', fixedSourceDir, '--targetProjectPort', targetProjectPort];

 //TODO: change the command to read the node_module bin folder to pinpoint tauri's cli executable.
// so we don't rely on a script executable.
  const command = ['npm', 'run', 'tauri', 'dev'].concat(args).join(' ');
  execSync(command, {
    stdio: 'inherit',
    cwd: path.resolve(process.cwd(), root),
  });
  return { success: true };
}

In that way the project can be served, also exposing the port of the local frontend project in development mode.

ErickRodrCodes commented 8 months ago

--config accepts either a path, or a string to/of json with the same format as tauri.conf.json. So for example you can have a file (or inline) with this:

{
  "build": {
    "devPath": "http://123:123",
    "distDir": "../path/to/dist"
  }
}

and then call npm run tauri dev -- --config that-file-from-above.json

I might skip this on Nx since I have executors that run something like

$ nx run myTauriProject:serve

or

$ nx run-many --projects=myTauriProject,myFrontendProject --target=serve --parallel=true

I would potentially configure the serve app to find the target folder on the Nx project configuration so that in one command you serve two things.

lopo12123 commented 8 months ago

Great writeup with valuable feedback, thanks!

For point 1, you're basically asking for the tauri init command, imo create-tauri-app should not care about this use case.

For point 2&3 you can use the --config flag to overwrite the devPath/distDir (or virtually whatever else you wanna change). I'd like to keep it this way and not introduce too many flags for things that can be configured via the existing tauri configs. (Thinking like "If we add those, which other flags do we add later" - so basically "poluting" the cli)

The only thing in my opinion that's really missing is something like cargo's --manifest-path flag where you can tell the tauri cli which tauri config/app you want to start. Right now it uses the first one it find searching through the cwd recursively.

Perhaps this should be more inclusive rather than just accepting std::env::current_dir() as the location of the configuration file. Also, the file name here should not be just tauri.conf.json, at least Configurable selection of json5 or toml as they are accepted by --config

FabianLars commented 8 months ago

Perhaps this should be more inclusive rather than just accepting std::env::current_dir() as the location of the configuration file.

What do you have in mind with "more inclusive"? Remember that tauri-build is part of the cargo project, not the CLI so that complicates it quite a bit, and may not even matter unless you want the config to be uncoupled from the location of the cargo project?

Also, the file name here should not be just tauri.conf.json, at least Configurable selection of json5 or toml as they are accepted by --config

That's just a confusing api design choice, it checks for json5 and toml later in parse_value/do_parse.

lopo12123 commented 8 months ago

That's just a confusing api design choice, it checks for json5 and toml later in parse_value/do_parse.

Sorry here, I didn't look carefully enough

What do you have in mind with "more inclusive"? Remember that tauri-build is part of the cargo project, not the CLI so that complicates it quite a bit, and may not even matter unless you want the config to be uncoupled from the location of the cargo project?

I'm not very used to the fact that --config specifies something that is merged into tauri.conf.json instead of specifying the only configuration used. I mean no offense, it's just that "--config" in the cli of most tools I use (e.g. vite/webpack) means "specify" not "merge", maybe a more accurate name would be --patch-config or --merge -config (but then this flag is too long haha

I have thought about it carefully and you are right. There is no very necessary reason to change the current processing.

...The thing is, I tried to create a tauri application for my rust library yesterday, but when I changed the default generated template to tauri.conf.json5, it always reported an error saying that there was an error in parsing the json5 file (the "config-json5" feature has turned on), so I thought there was some problem. The strange thing is that today I opened the idea again without making any changes and ran it without reporting an error again

Thank you for your explanation 😊


by the way, a typo here (Tauri.json => Tauri.toml)

FabianLars commented 8 months ago

Yeah, i agree on the naming thing. Not the biggest fan of it either especially once we add another one that actually sets the path to the main config.