@tauri-native/cli 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 tauri-native contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,40 @@
1
+ # @tauri-native/cli
2
+
3
+ Experimental CLI for packaging a Tauri microfrontend and its Rust application core for an iOS host.
4
+
5
+ ## Install
6
+
7
+ ```sh
8
+ npm install --save-dev @tauri-native/cli@experimental
9
+ ```
10
+
11
+ Node.js 22.12 or newer, Rust with the iOS targets, and Xcode are required.
12
+
13
+ Install the package in the Tauri project that owns the frontend and Rust core. React Native and Lynx hosts consume its exported artifacts and do not need the CLI as a dependency.
14
+
15
+ ## Export for iOS
16
+
17
+ ```sh
18
+ npx tauri-native export ios
19
+ ```
20
+
21
+ Run this from the Tauri project root. By default, the command reads `src-tauri/tauri.conf.json`, builds `src-tauri/crates/app-core/Cargo.toml`, uses `src-tauri/crates/app-core/include/tauri_native.h`, and writes the co-located export to `src-tauri/gen/tauri-native/ios`. Use `--tauri-dir`, `--manifest`, or `--header` when the project uses another layout.
22
+
23
+ Pass `--output-dir` to export directly into a native host instead:
24
+
25
+ ```sh
26
+ npx tauri-native export ios \
27
+ --output-dir ../mobile-app/ios/tauri-native
28
+ ```
29
+
30
+ The output directory contains:
31
+
32
+ - `TauriNativeCore.xcframework`
33
+ - `TauriNativeAssets.bundle`
34
+ - `TauriNativeGenerated.podspec`
35
+
36
+ Copy or reference the exported directory from the native host, then add its generated local Pod before installing native dependencies.
37
+
38
+ ## License
39
+
40
+ MIT
package/dist/index.mjs ADDED
@@ -0,0 +1,180 @@
1
+ #!/usr/bin/env node
2
+ import process from "node:process";
3
+ import { Command } from "commander";
4
+ import { execFileSync, execSync } from "node:child_process";
5
+ import { cpSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
6
+ import path from "node:path";
7
+ import { wrapTextWithPrefix } from "@clack/core";
8
+ //#region src/utils/cargo-manifest.ts
9
+ function libraryNameFromManifest(source) {
10
+ const libSection = source.match(/\[lib\]([\s\S]*?)(?=\n\[|$)/)?.[1];
11
+ const packageSection = source.match(/\[package\]([\s\S]*?)(?=\n\[|$)/)?.[1];
12
+ const name = libSection?.match(/^name\s*=\s*"([^"]+)"/m)?.[1] ?? packageSection?.match(/^name\s*=\s*"([^"]+)"/m)?.[1];
13
+ if (!name) throw new Error("Could not find a package or library name");
14
+ return name.replaceAll("-", "_");
15
+ }
16
+ function readLibraryName(manifest) {
17
+ try {
18
+ return libraryNameFromManifest(readFileSync(manifest, "utf8"));
19
+ } catch (error) {
20
+ if (error instanceof Error && error.message === "Could not find a package or library name") throw new Error(`${error.message} in ${manifest}`);
21
+ throw error;
22
+ }
23
+ }
24
+ //#endregion
25
+ //#region src/utils/files.ts
26
+ function requireFile(file) {
27
+ if (!existsSync(file)) throw new Error(`Required file does not exist: ${file}`);
28
+ }
29
+ //#endregion
30
+ //#region src/utils/output.ts
31
+ function message(text, startPrefix = "◇ ") {
32
+ process.stdout.write(`${wrapTextWithPrefix(process.stdout, text, "│ ", startPrefix, "│ ")}\n`);
33
+ }
34
+ function writeError(text) {
35
+ process.stderr.write(`${wrapTextWithPrefix(process.stderr, text, "│ ", "■ ", "│ ")}\n`);
36
+ }
37
+ //#endregion
38
+ //#region src/utils/process.ts
39
+ function run(command, args, options = {}) {
40
+ message(`${command} ${args.join(" ")}`);
41
+ execFileSync(command, args, {
42
+ stdio: "inherit",
43
+ ...options
44
+ });
45
+ }
46
+ //#endregion
47
+ //#region src/commands/export-ios.ts
48
+ const IOS_TARGETS = [
49
+ "aarch64-apple-ios",
50
+ "aarch64-apple-ios-sim",
51
+ "x86_64-apple-ios"
52
+ ];
53
+ const ASSET_BUNDLE_INFO = `<?xml version="1.0" encoding="UTF-8"?>
54
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
55
+ <plist version="1.0"><dict>
56
+ <key>CFBundleIdentifier</key><string>dev.tauri-native.assets</string>
57
+ <key>CFBundleName</key><string>TauriNativeAssets</string>
58
+ <key>CFBundlePackageType</key><string>BNDL</string>
59
+ <key>CFBundleVersion</key><string>1</string>
60
+ </dict></plist>
61
+ `;
62
+ const GENERATED_PODSPEC = `Pod::Spec.new do |s|
63
+ s.name = "TauriNativeGenerated"
64
+ s.version = "0.0.0"
65
+ s.summary = "Application-specific artifacts generated by @tauri-native/cli"
66
+ s.homepage = "https://github.com/gronxb/tauri-native"
67
+ s.license = { :type => "MIT" }
68
+ s.authors = "tauri-native contributors"
69
+ s.source = { :git => "https://github.com/gronxb/tauri-native.git", :branch => "main" }
70
+ s.platform = :ios, "13.0"
71
+ s.static_framework = true
72
+ s.vendored_frameworks = "TauriNativeCore.xcframework"
73
+ s.resources = "TauriNativeAssets.bundle"
74
+ end
75
+ `;
76
+ function writeGeneratedPodspec(outputDirectory) {
77
+ const podspec = path.join(outputDirectory, "TauriNativeGenerated.podspec");
78
+ writeFileSync(podspec, GENERATED_PODSPEC);
79
+ return podspec;
80
+ }
81
+ function exportIos(options) {
82
+ const workingDirectory = process.cwd();
83
+ const tauriDirectory = path.resolve(workingDirectory, options.tauriDir);
84
+ const manifest = options.manifest ? path.resolve(workingDirectory, options.manifest) : path.join(tauriDirectory, "crates/app-core/Cargo.toml");
85
+ const manifestDirectory = path.dirname(manifest);
86
+ const header = options.header ? path.resolve(workingDirectory, options.header) : path.join(manifestDirectory, "include/tauri_native.h");
87
+ const outputDirectory = path.resolve(workingDirectory, options.outputDir ?? path.join(tauriDirectory, "gen/tauri-native/ios"));
88
+ const configPath = path.join(tauriDirectory, "tauri.conf.json");
89
+ for (const requiredPath of [
90
+ manifest,
91
+ header,
92
+ configPath
93
+ ]) requireFile(requiredPath);
94
+ const config = JSON.parse(readFileSync(configPath, "utf8"));
95
+ const frontendDirectory = path.dirname(tauriDirectory);
96
+ if (typeof config.build?.beforeBuildCommand === "string") {
97
+ message(`Building the Tauri microfrontend in ${frontendDirectory}`);
98
+ execSync(config.build.beforeBuildCommand, {
99
+ cwd: frontendDirectory,
100
+ stdio: "inherit"
101
+ });
102
+ }
103
+ if (typeof config.build?.frontendDist !== "string") throw new Error(`${configPath} must define build.frontendDist`);
104
+ const frontendDist = path.resolve(tauriDirectory, config.build.frontendDist);
105
+ requireFile(path.join(frontendDist, "index.html"));
106
+ const libraryName = readLibraryName(manifest);
107
+ const targetDirectory = path.join(tauriDirectory, "target/tauri-native");
108
+ const cargoEnvironment = {
109
+ ...process.env,
110
+ CARGO_TARGET_DIR: targetDirectory
111
+ };
112
+ run("rustup", [
113
+ "target",
114
+ "add",
115
+ ...IOS_TARGETS
116
+ ]);
117
+ for (const target of IOS_TARGETS) run("cargo", [
118
+ "build",
119
+ "--manifest-path",
120
+ manifest,
121
+ "--target",
122
+ target,
123
+ "--release"
124
+ ], { env: cargoEnvironment });
125
+ mkdirSync(outputDirectory, { recursive: true });
126
+ const framework = path.join(outputDirectory, "TauriNativeCore.xcframework");
127
+ const assetBundle = path.join(outputDirectory, "TauriNativeAssets.bundle");
128
+ const universalDirectory = path.join(targetDirectory, "ios-simulator-universal/release");
129
+ const universalLibrary = path.join(universalDirectory, `lib${libraryName}.a`);
130
+ mkdirSync(universalDirectory, { recursive: true });
131
+ run("lipo", [
132
+ "-create",
133
+ path.join(targetDirectory, `aarch64-apple-ios-sim/release/lib${libraryName}.a`),
134
+ path.join(targetDirectory, `x86_64-apple-ios/release/lib${libraryName}.a`),
135
+ "-output",
136
+ universalLibrary
137
+ ]);
138
+ rmSync(framework, {
139
+ recursive: true,
140
+ force: true
141
+ });
142
+ run("xcodebuild", [
143
+ "-create-xcframework",
144
+ "-library",
145
+ path.join(targetDirectory, `aarch64-apple-ios/release/lib${libraryName}.a`),
146
+ "-headers",
147
+ path.dirname(header),
148
+ "-library",
149
+ universalLibrary,
150
+ "-headers",
151
+ path.dirname(header),
152
+ "-output",
153
+ framework
154
+ ]);
155
+ rmSync(assetBundle, {
156
+ recursive: true,
157
+ force: true
158
+ });
159
+ cpSync(frontendDist, assetBundle, { recursive: true });
160
+ writeFileSync(path.join(assetBundle, "Info.plist"), ASSET_BUNDLE_INFO);
161
+ message(`Created ${framework}\nCreated ${assetBundle}\nCreated ${writeGeneratedPodspec(outputDirectory)}`, "◆ ");
162
+ }
163
+ //#endregion
164
+ //#region src/cli.ts
165
+ function createProgram() {
166
+ const program = new Command();
167
+ program.name("tauri-native").description("Export a Tauri microfrontend for a native host").showHelpAfterError();
168
+ program.command("export").description("Export Tauri artifacts for a native host").command("ios").description("Export an XCFramework and a Tauri web asset bundle").option("--tauri-dir <path>", "Tauri Rust directory", "src-tauri").option("--manifest <path>", "native core Cargo.toml").option("--header <path>", "C ABI header").option("--output-dir <path>", "generated artifact directory").action((options) => exportIos(options));
169
+ return program;
170
+ }
171
+ //#endregion
172
+ //#region src/index.ts
173
+ try {
174
+ await createProgram().parseAsync(process.argv);
175
+ } catch (error) {
176
+ writeError(error instanceof Error ? error.message : String(error));
177
+ process.exitCode = 1;
178
+ }
179
+ //#endregion
180
+ export {};
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@tauri-native/cli",
3
+ "version": "0.0.2",
4
+ "description": "Export a Tauri microfrontend and its Rust core for native hosts",
5
+ "type": "module",
6
+ "bin": {
7
+ "tauri-native": "./dist/index.mjs"
8
+ },
9
+ "exports": {
10
+ "./package.json": "./package.json"
11
+ },
12
+ "files": [
13
+ "dist",
14
+ "LICENSE",
15
+ "README.md"
16
+ ],
17
+ "scripts": {
18
+ "build": "tsdown",
19
+ "prepack": "tsdown",
20
+ "test": "nub run build && node --experimental-strip-types --test test/*.test.ts && nub run test:package",
21
+ "test:package": "node ../../scripts/verify-package.mjs",
22
+ "typecheck": "tsc --noEmit"
23
+ },
24
+ "dependencies": {
25
+ "@clack/core": "^1.4.3",
26
+ "commander": "^15.0.0"
27
+ },
28
+ "keywords": [
29
+ "ios",
30
+ "react-native",
31
+ "rust",
32
+ "tauri"
33
+ ],
34
+ "engines": {
35
+ "node": ">=22.12.0"
36
+ },
37
+ "license": "MIT",
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "git+https://github.com/gronxb/tauri-native.git",
41
+ "directory": "packages/cli"
42
+ },
43
+ "homepage": "https://github.com/gronxb/tauri-native#readme",
44
+ "bugs": {
45
+ "url": "https://github.com/gronxb/tauri-native/issues"
46
+ },
47
+ "publishConfig": {
48
+ "access": "public",
49
+ "registry": "https://registry.npmjs.org/",
50
+ "tag": "experimental"
51
+ },
52
+ "devDependencies": {
53
+ "@types/node": "^22.20.1",
54
+ "tsdown": "^0.22.14",
55
+ "typescript": "7.0.2"
56
+ }
57
+ }