sh-ui-cli 0.87.0 → 0.88.0
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/data/changelog/versions.json +13 -0
- package/package.json +1 -1
- package/src/create/cli-args.js +1 -1
- package/src/create/describeTemplate.js +13 -2
- package/src/create/generator.js +131 -2
- package/src/create/index.mjs +1 -0
- package/src/create/templateManifest.js +12 -0
- package/src/mcp.mjs +26 -0
- package/templates/tauri-shell/Cargo.toml +21 -0
- package/templates/tauri-shell/README.md +49 -0
- package/templates/tauri-shell/build.rs +3 -0
- package/templates/tauri-shell/capabilities/default.json +12 -0
- package/templates/tauri-shell/src/lib.rs +8 -0
- package/templates/tauri-shell/src/main.rs +6 -0
- package/templates/tauri-shell/tauri.conf.json +29 -0
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$description": "sh-ui 릴리즈 노트 단일 소스. docs(React)와 showcase(Flutter)가 함께 읽는다. 새 릴리즈마다 맨 앞에 추가.",
|
|
4
4
|
"versions": [
|
|
5
|
+
{
|
|
6
|
+
"version": "0.88.0",
|
|
7
|
+
"date": "2026-05-14",
|
|
8
|
+
"title": "Tauri 2.x 데스크탑 셸 — sh_ui_create_project platform=vite tauri=true",
|
|
9
|
+
"type": "minor",
|
|
10
|
+
"highlights": [
|
|
11
|
+
"**`--tauri` 플래그 + MCP `tauri: true` 옵션** — `sh-ui-cli create --platform vite --structure standalone --tauri` 한 줄로 Vite SPA + Tauri 2.x 네이티브 셸 (`src-tauri/`) 일괄 emit. ai-org 같은 local-first 데스크탑 앱의 1급 진입점. v0.86.0 의 vite 프리셋과 짝 (Q1-Q5 design decisions 모두 confirmed: assume Rust installed, `src-tauri/` sibling layout, minimal capabilities, identifier placeholder, Tauri 2.x only).",
|
|
12
|
+
"**Tauri 2.x idioms 표준 준수** — `Cargo.toml` 의 lib name 은 snake_case (`{tauri_crate_name}_lib`), `tauri.conf.json` 의 `identifier` 는 `app.{crate}.dev` 플레이스홀더 (README 에 production 전 교체 TODO 명시), `capabilities/default.json` 은 `core:default` + `opener:default` 만 — fs/dialog/shell 권한은 사용자가 명시적 opt-in.",
|
|
13
|
+
"**Vite 패치 자동 적용** — Tauri 권장값(`clearScreen: false`, `server.strictPort: true`, `server.host: false`, `server.port: 5173`) 을 `vite.config.ts` 에 emit. `@tauri-apps/cli` (devDep), `@tauri-apps/api` + `@tauri-apps/plugin-opener` (dep) + `tauri`/`tauri:dev`/`tauri:build` scripts 자동 추가. `.gitignore` 에 `src-tauri/target/` 추가 (Rust 빌드 산출물 보호).",
|
|
14
|
+
"**가드 + 회귀 테스트** — `tauri: true + platform != vite` 또는 `tauri: true + structure == monorepo` 는 CLI 진입점 + MCP 진입점 양쪽에서 명시적 Korean 에러. monorepo + Tauri 는 v0.89 후속. smoke V7a-f 6 개 시나리오로 회귀 가드 (file emission, placeholder substitution, package/vite/gitignore patches, opt-out 회귀, 잘못된 조합 거부)."
|
|
15
|
+
],
|
|
16
|
+
"url": "https://github.com/sanghyeonKim0201/sh-ui/releases/tag/v0.88.0"
|
|
17
|
+
},
|
|
5
18
|
{
|
|
6
19
|
"version": "0.87.0",
|
|
7
20
|
"date": "2026-05-14",
|
package/package.json
CHANGED
package/src/create/cli-args.js
CHANGED
|
@@ -13,7 +13,7 @@ const VALID_PLUGINS = allPlugins.map((p) => p.name);
|
|
|
13
13
|
const VALID_ARCHES = allArchitectures.map((a) => a.name);
|
|
14
14
|
|
|
15
15
|
const VALUE_FLAGS = ['platform', 'structure', 'plugins', 'theme', 'app', 'css', 'arch', 'port'];
|
|
16
|
-
const BOOL_FLAGS = ['yes', 'help', 'dry-run'];
|
|
16
|
+
const BOOL_FLAGS = ['yes', 'help', 'dry-run', 'tauri'];
|
|
17
17
|
|
|
18
18
|
const SUBCOMMANDS = ['add-app', 'add-component'];
|
|
19
19
|
|
|
@@ -35,6 +35,7 @@ import { CSS_FRAMEWORK_DEFAULT } from '../constants.js';
|
|
|
35
35
|
* @property {'tailwind'|'plain'|'css-modules'} [cssFramework]
|
|
36
36
|
* @property {string} [projectName]
|
|
37
37
|
* @property {string} [appName] monorepo 첫 앱 이름. 기본 'web'
|
|
38
|
+
* @property {boolean} [tauri] platform=vite + structure=standalone 일 때 Tauri 2.x 셸 같이 emit
|
|
38
39
|
*/
|
|
39
40
|
|
|
40
41
|
/**
|
|
@@ -62,6 +63,7 @@ export function describeTemplate(opts = {}) {
|
|
|
62
63
|
plugins: pluginNames = [],
|
|
63
64
|
cssFramework = CSS_FRAMEWORK_DEFAULT,
|
|
64
65
|
appName: rawAppName = 'web',
|
|
66
|
+
tauri = false,
|
|
65
67
|
} = opts;
|
|
66
68
|
|
|
67
69
|
if (platform === 'flutter') {
|
|
@@ -85,10 +87,19 @@ export function describeTemplate(opts = {}) {
|
|
|
85
87
|
}
|
|
86
88
|
const baseFiles = tpl.base.slice();
|
|
87
89
|
const archFiles = (tpl.arches?.[safeArchName] ?? []).slice();
|
|
88
|
-
|
|
90
|
+
const groups = [
|
|
89
91
|
makeGroup('base', '베이스 (vite-standalone)', baseFiles),
|
|
90
92
|
makeGroup('arch', `Arch (${safeArchName})`, archFiles),
|
|
91
|
-
]
|
|
93
|
+
];
|
|
94
|
+
if (tauri) {
|
|
95
|
+
const tauriTpl = TEMPLATE_MANIFEST['tauri-shell'];
|
|
96
|
+
if (!tauriTpl) {
|
|
97
|
+
throw new Error("Template manifest missing entry for 'tauri-shell'.");
|
|
98
|
+
}
|
|
99
|
+
const tauriFiles = tauriTpl.base.map((p) => `src-tauri/${p}`);
|
|
100
|
+
groups.push(makeGroup('tauri', 'Tauri 셸 (src-tauri/)', tauriFiles));
|
|
101
|
+
}
|
|
102
|
+
return finalize(groups);
|
|
92
103
|
}
|
|
93
104
|
|
|
94
105
|
// monorepo — vite app 변형. Next monorepo 브랜치와 동일 구조이지만 vite-app 템플릿
|
package/src/create/generator.js
CHANGED
|
@@ -213,6 +213,23 @@ export async function createProject(options = {}) {
|
|
|
213
213
|
],
|
|
214
214
|
});
|
|
215
215
|
|
|
216
|
+
// tauri 옵션은 platform=vite + structure=standalone 일 때만 의미. 다른 조합은 명시적 에러.
|
|
217
|
+
// (MCP 진입점은 mcp.mjs 가 이미 동일 가드 — CLI 직접 호출에도 동일 안전망.)
|
|
218
|
+
if (options.tauri) {
|
|
219
|
+
if (platform !== 'vite') {
|
|
220
|
+
throw new Error(
|
|
221
|
+
`tauri: true 는 platform=vite 일 때만 지원합니다 (현재 platform=${platform}). ` +
|
|
222
|
+
`--tauri 옵션 제거 또는 --platform vite 사용.`,
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
if (options.structure === 'monorepo') {
|
|
226
|
+
throw new Error(
|
|
227
|
+
'platform=vite + structure=monorepo + tauri=true 는 아직 지원 안 함 (v0.89 후속). ' +
|
|
228
|
+
'standalone 으로 시도하거나 tauri 옵션 제거.',
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
216
233
|
// arch 결정 — platform 확정 후. 사용자가 --arch 미지정 시:
|
|
217
234
|
// - next → DEFAULT_ARCH ('fsd')
|
|
218
235
|
// - flutter → 현재 Flutter arch 디스크립터 없음 → null. 미래에 flutter arch 추가되면
|
|
@@ -333,8 +350,15 @@ export async function createProject(options = {}) {
|
|
|
333
350
|
});
|
|
334
351
|
|
|
335
352
|
if (projectType === 'standalone') {
|
|
336
|
-
await generateViteStandalone(targetDir, projectName, theme, cssFramework, arch, themeBase);
|
|
353
|
+
await generateViteStandalone(targetDir, projectName, theme, cssFramework, arch, themeBase, { tauri: !!options.tauri });
|
|
337
354
|
} else {
|
|
355
|
+
// monorepo + tauri 는 v0.89 후속 — 명시적 에러
|
|
356
|
+
if (options.tauri) {
|
|
357
|
+
throw new Error(
|
|
358
|
+
'platform=vite + structure=monorepo + tauri=true 는 아직 지원 안 함 (v0.89 후속). ' +
|
|
359
|
+
'standalone 으로 시도하거나 tauri 옵션 제거.',
|
|
360
|
+
);
|
|
361
|
+
}
|
|
338
362
|
await generateMonorepo(targetDir, projectName, [], { yes: options.yes, theme, css: cssFramework, arch, themeBase, platform: 'vite' });
|
|
339
363
|
}
|
|
340
364
|
|
|
@@ -353,6 +377,11 @@ export async function createProject(options = {}) {
|
|
|
353
377
|
console.log(`\n cd ${projectName}`);
|
|
354
378
|
console.log(' pnpm install');
|
|
355
379
|
console.log(' pnpm dev\n');
|
|
380
|
+
if (options.tauri && projectType === 'standalone') {
|
|
381
|
+
console.log('Tauri 데스크탑 셸:');
|
|
382
|
+
console.log(' pnpm tauri dev # Rust 처음 빌드는 5~10분 — 캐시 후 5~10초');
|
|
383
|
+
console.log(' (Rust 미설치 시 https://rustup.rs/ 참고)\n');
|
|
384
|
+
}
|
|
356
385
|
console.log('다음 단계 — 베이스 컴포넌트 추가 (예시):');
|
|
357
386
|
console.log(' npx sh-ui-cli add button card input dialog\n');
|
|
358
387
|
return;
|
|
@@ -731,7 +760,7 @@ async function generateStandalone(targetDir, projectName, plugins, theme, css, a
|
|
|
731
760
|
await patchShUiConfig(path.join(targetDir, 'sh-ui.config.json'), css, themeBase);
|
|
732
761
|
}
|
|
733
762
|
|
|
734
|
-
async function generateViteStandalone(targetDir, projectName, theme, css, arch, themeBase) {
|
|
763
|
+
async function generateViteStandalone(targetDir, projectName, theme, css, arch, themeBase, { tauri = false } = {}) {
|
|
735
764
|
// 베이스 (arch-neutral) + arch 오버레이 — generateStandalone 과 같은 패턴.
|
|
736
765
|
await fs.copy(path.join(TEMPLATES_DIR, 'vite-standalone'), targetDir, {
|
|
737
766
|
filter: (src) => !src.includes(`${path.sep}_arch${path.sep}`) && !src.endsWith(`${path.sep}_arch`),
|
|
@@ -766,6 +795,106 @@ async function generateViteStandalone(targetDir, projectName, theme, css, arch,
|
|
|
766
795
|
await applyCssFrameworkVariant(targetDir, css, { isMonorepo: false, plugins: [], arch });
|
|
767
796
|
await injectCssTheme(targetDir, theme);
|
|
768
797
|
await patchShUiConfig(path.join(targetDir, 'sh-ui.config.json'), css, themeBase);
|
|
798
|
+
|
|
799
|
+
// Tauri 셸 emit (옵션) — vite SPA + native window. standalone 만 v1 지원.
|
|
800
|
+
if (tauri) {
|
|
801
|
+
await emitTauri(targetDir, projectName);
|
|
802
|
+
await patchViteForTauri(targetDir);
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
/**
|
|
807
|
+
* tauri-shell 템플릿을 `<targetDir>/src-tauri/` 로 복사하고 placeholder 치환.
|
|
808
|
+
*
|
|
809
|
+
* - `{{project_name}}` → projectName (kebab-case 유지, npm 패키지명과 동일)
|
|
810
|
+
* - `{{tauri_crate_name}}` → snake_case 변환 (Rust crate name 규칙: 영숫자+언더스코어).
|
|
811
|
+
* 하이픈/점/대문자가 들어 있으면 모두 안전한 형태로 정규화.
|
|
812
|
+
*
|
|
813
|
+
* generateViteStandalone 에서 tauri: true 인 경우 호출. monorepo+tauri 는 v0.89 후속.
|
|
814
|
+
*/
|
|
815
|
+
async function emitTauri(targetDir, projectName) {
|
|
816
|
+
const srcTauriDir = path.join(targetDir, 'src-tauri');
|
|
817
|
+
await fs.copy(path.join(TEMPLATES_DIR, 'tauri-shell'), srcTauriDir);
|
|
818
|
+
|
|
819
|
+
// crate name: snake_case 강제 — Rust 식별자는 영숫자+'_' 만 허용
|
|
820
|
+
const tauriCrateName = projectName
|
|
821
|
+
.toLowerCase()
|
|
822
|
+
.replace(/[^a-z0-9]+/g, '_')
|
|
823
|
+
.replace(/^_+|_+$/g, '');
|
|
824
|
+
|
|
825
|
+
await replaceInAllFiles(srcTauriDir, '{{tauri_crate_name}}', tauriCrateName);
|
|
826
|
+
await replaceInAllFiles(srcTauriDir, '{{project_name}}', projectName);
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
/**
|
|
830
|
+
* vite 앱의 package.json + vite.config.ts 를 Tauri 친화적으로 패치.
|
|
831
|
+
*
|
|
832
|
+
* - package.json: `@tauri-apps/cli` (devDep), `@tauri-apps/api` (dep), `tauri`/`tauri:dev`/`tauri:build` scripts 추가
|
|
833
|
+
* - vite.config.ts: Tauri 공식 권장값 추가 — `clearScreen: false`, `server.strictPort: true`,
|
|
834
|
+
* `server.host: false`, `server.port: 5173`. 그래야 Tauri 가 dev server 를 안정적으로 wrap.
|
|
835
|
+
*
|
|
836
|
+
* NOTE: vite.config.ts 를 전부 재작성한다. 현재 base template 의 vite.config.ts 는 arch-neutral
|
|
837
|
+
* 이라 안전. 후속 task 에서 arch-specific vite.config.ts overlay 가 생기면 이 자리에서 머지 전략
|
|
838
|
+
* 필요 (현재는 단순 overwrite).
|
|
839
|
+
*/
|
|
840
|
+
async function patchViteForTauri(targetDir) {
|
|
841
|
+
const pkgPath = path.join(targetDir, 'package.json');
|
|
842
|
+
const pkg = await fs.readJson(pkgPath);
|
|
843
|
+
|
|
844
|
+
pkg.dependencies = pkg.dependencies ?? {};
|
|
845
|
+
pkg.devDependencies = pkg.devDependencies ?? {};
|
|
846
|
+
pkg.scripts = pkg.scripts ?? {};
|
|
847
|
+
|
|
848
|
+
pkg.dependencies['@tauri-apps/api'] = '^2.0.0';
|
|
849
|
+
pkg.dependencies['@tauri-apps/plugin-opener'] = '^2.0.0';
|
|
850
|
+
pkg.devDependencies['@tauri-apps/cli'] = '^2.0.0';
|
|
851
|
+
|
|
852
|
+
pkg.scripts.tauri = 'tauri';
|
|
853
|
+
pkg.scripts['tauri:dev'] = 'tauri dev';
|
|
854
|
+
pkg.scripts['tauri:build'] = 'tauri build';
|
|
855
|
+
|
|
856
|
+
pkg.dependencies = sortObjectKeys(pkg.dependencies);
|
|
857
|
+
pkg.devDependencies = sortObjectKeys(pkg.devDependencies);
|
|
858
|
+
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
859
|
+
|
|
860
|
+
// vite.config.ts 재작성 — Tauri 공식 권장 설정 추가.
|
|
861
|
+
const viteCfgPath = path.join(targetDir, 'vite.config.ts');
|
|
862
|
+
const viteCfg = `import { defineConfig } from 'vite';
|
|
863
|
+
import react from '@vitejs/plugin-react';
|
|
864
|
+
import tailwindcss from '@tailwindcss/vite';
|
|
865
|
+
import tsconfigPaths from 'vite-tsconfig-paths';
|
|
866
|
+
|
|
867
|
+
// Tauri 권장 설정 (https://v2.tauri.app/start/frontend/vite/)
|
|
868
|
+
// - clearScreen: false — Rust 컴파일 에러가 터미널을 가리지 않게
|
|
869
|
+
// - server.strictPort — Tauri 가 사용할 포트를 고정 (충돌 시 에러)
|
|
870
|
+
// - server.host: false — Tauri dev 가 host network 안 열어도 됨
|
|
871
|
+
export default defineConfig({
|
|
872
|
+
plugins: [react(), tailwindcss(), tsconfigPaths()],
|
|
873
|
+
clearScreen: false,
|
|
874
|
+
server: {
|
|
875
|
+
port: 5173,
|
|
876
|
+
strictPort: true,
|
|
877
|
+
host: false,
|
|
878
|
+
},
|
|
879
|
+
});
|
|
880
|
+
`;
|
|
881
|
+
await fs.writeFile(viteCfgPath, viteCfg);
|
|
882
|
+
|
|
883
|
+
// .gitignore 에 src-tauri/target 추가 — Rust 빌드 산출물 (수 GB 가능).
|
|
884
|
+
// 스캐폴드 단계에서는 파일명이 `gitignore` (점 없음); finalizeProject 가 나중에 `.gitignore` 로 rename.
|
|
885
|
+
// 양쪽 이름 모두 시도해서 호출 순서가 달라져도 안전하게 적용.
|
|
886
|
+
const gitignoreCandidates = ['.gitignore', 'gitignore'];
|
|
887
|
+
for (const name of gitignoreCandidates) {
|
|
888
|
+
const p = path.join(targetDir, name);
|
|
889
|
+
if (await fs.pathExists(p)) {
|
|
890
|
+
let ignore = await fs.readFile(p, 'utf-8');
|
|
891
|
+
if (!ignore.includes('src-tauri/target')) {
|
|
892
|
+
ignore += `\n# Tauri build artifacts\nsrc-tauri/target/\n`;
|
|
893
|
+
await fs.writeFile(p, ignore);
|
|
894
|
+
}
|
|
895
|
+
break;
|
|
896
|
+
}
|
|
897
|
+
}
|
|
769
898
|
}
|
|
770
899
|
|
|
771
900
|
async function generateMonorepo(targetDir, projectName, plugins, { yes = false, theme, css, arch, themeBase, platform = 'next' } = {}) {
|
package/src/create/index.mjs
CHANGED
|
@@ -314,6 +314,18 @@ export const TEMPLATE_MANIFEST = {
|
|
|
314
314
|
]
|
|
315
315
|
}
|
|
316
316
|
},
|
|
317
|
+
"tauri-shell": {
|
|
318
|
+
"base": [
|
|
319
|
+
".gitignore",
|
|
320
|
+
"Cargo.toml",
|
|
321
|
+
"README.md",
|
|
322
|
+
"build.rs",
|
|
323
|
+
"capabilities/default.json",
|
|
324
|
+
"src/lib.rs",
|
|
325
|
+
"src/main.rs",
|
|
326
|
+
"tauri.conf.json"
|
|
327
|
+
]
|
|
328
|
+
},
|
|
317
329
|
"ui-app-template": {
|
|
318
330
|
"base": [
|
|
319
331
|
"eslint.config.js",
|
package/src/mcp.mjs
CHANGED
|
@@ -367,6 +367,7 @@ export async function startMcpServer() {
|
|
|
367
367
|
{
|
|
368
368
|
description:
|
|
369
369
|
"빈 폴더에 sh-ui 프로젝트 스캐폴드 — Next.js (standalone/monorepo) | Vite (standalone/monorepo) | Flutter. " +
|
|
370
|
+
"+ vite + standalone 인 경우 `tauri: true` 로 Tauri 2.x 데스크탑 셸 (`src-tauri/`) 까지 한 번에 emit (Rust toolchain 필요). " +
|
|
370
371
|
`FSD 폴더 구조 + 토큰 + sh-ui.config.json 일괄 생성. 사용자가 '새 프로젝트' / '빈 폴더' / '스캐폴드부터' 류 요청을 하면 이 툴 사용 (Bash 로 npx ${cliName} create 직접 호출보다 우선). ` +
|
|
371
372
|
"**단일 진입점** — theme/plugins/cssFramework/structure 모두 호출 시점에 정해서 한 번에 박는다. 호출 후 sh-ui.config.json/tokens.css 를 손으로 패치하지 말 것 (다음 재스캐폴드 시 유실). " +
|
|
372
373
|
"산출물: theme 인자가 프리셋이면 sh-ui.config.json 의 theme.base 가 그 이름, base64 면 'custom'. paths.styles · paths.tokens 도 자동 박혀서 sh_ui_add_component 가 사후 패치 없이 동작.",
|
|
@@ -394,6 +395,12 @@ export async function startMcpServer() {
|
|
|
394
395
|
.describe("부모 디렉토리. 기본 process.cwd()"),
|
|
395
396
|
force: z.boolean().optional()
|
|
396
397
|
.describe("기존 디렉토리 덮어쓰기. 기본 false (안전)"),
|
|
398
|
+
tauri: z.boolean().optional()
|
|
399
|
+
.describe(
|
|
400
|
+
"Tauri 2.x 데스크탑 셸 (`src-tauri/`) 함께 emit. platform=vite + structure=standalone 일 때만 지원. " +
|
|
401
|
+
"Rust toolchain (`cargo`/`rustc`) 가 시스템에 설치되어 있어야 첫 `pnpm tauri dev` 가 동작. " +
|
|
402
|
+
"기본 false. monorepo + tauri 는 v0.89 후속.",
|
|
403
|
+
),
|
|
397
404
|
},
|
|
398
405
|
},
|
|
399
406
|
async (input) => {
|
|
@@ -415,6 +422,24 @@ export async function startMcpServer() {
|
|
|
415
422
|
} catch (e) {
|
|
416
423
|
return { isError: true, content: [{ type: "text", text: e.message }] };
|
|
417
424
|
}
|
|
425
|
+
if (input.tauri && input.platform !== "vite") {
|
|
426
|
+
return {
|
|
427
|
+
isError: true,
|
|
428
|
+
content: [{
|
|
429
|
+
type: "text",
|
|
430
|
+
text: "tauri: true 는 platform=vite 일 때만 지원합니다 (현재 platform=" + input.platform + ").",
|
|
431
|
+
}],
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
if (input.tauri && input.structure === "monorepo") {
|
|
435
|
+
return {
|
|
436
|
+
isError: true,
|
|
437
|
+
content: [{
|
|
438
|
+
type: "text",
|
|
439
|
+
text: "platform=vite + structure=monorepo + tauri=true 는 아직 지원 안 함 (v0.89 후속). standalone 으로 시도하거나 tauri 옵션 제거.",
|
|
440
|
+
}],
|
|
441
|
+
};
|
|
442
|
+
}
|
|
418
443
|
const targetParent = resolveCwd(input);
|
|
419
444
|
const targetDir = resolve(targetParent, input.name);
|
|
420
445
|
if (existsSync(targetDir) && !input.force) {
|
|
@@ -440,6 +465,7 @@ export async function startMcpServer() {
|
|
|
440
465
|
arch: input.arch,
|
|
441
466
|
theme: input.theme,
|
|
442
467
|
css: input.cssFramework,
|
|
468
|
+
tauri: input.tauri,
|
|
443
469
|
yes: true, // 사전 검사를 마쳤으니 generator 의 confirm 프롬프트 우회
|
|
444
470
|
}),
|
|
445
471
|
);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "{{tauri_crate_name}}"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "{{project_name}} desktop shell"
|
|
5
|
+
authors = ["you"]
|
|
6
|
+
edition = "2021"
|
|
7
|
+
|
|
8
|
+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
9
|
+
|
|
10
|
+
[lib]
|
|
11
|
+
name = "{{tauri_crate_name}}_lib"
|
|
12
|
+
crate-type = ["staticlib", "cdylib", "rlib"]
|
|
13
|
+
|
|
14
|
+
[build-dependencies]
|
|
15
|
+
tauri-build = { version = "2", features = [] }
|
|
16
|
+
|
|
17
|
+
[dependencies]
|
|
18
|
+
tauri = { version = "2", features = [] }
|
|
19
|
+
tauri-plugin-opener = "2"
|
|
20
|
+
serde = { version = "1", features = ["derive"] }
|
|
21
|
+
serde_json = "1"
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# {{project_name}} — Tauri 데스크탑 셸
|
|
2
|
+
|
|
3
|
+
이 디렉토리는 Tauri 2.x 의 Rust 코드입니다. 부모 디렉토리의 vite SPA 가
|
|
4
|
+
프론트엔드, 이 디렉토리가 native 윈도우 셸.
|
|
5
|
+
|
|
6
|
+
## 첫 실행
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
# 부모 디렉토리에서 (vite 앱 루트)
|
|
10
|
+
pnpm install
|
|
11
|
+
pnpm tauri dev # Rust 처음 빌드는 5~10분 — 캐시되면 이후 5~10초
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Rust toolchain (`cargo`, `rustc`) 이 시스템에 설치되어 있어야 합니다. 없으면
|
|
15
|
+
https://rustup.rs/ 참고.
|
|
16
|
+
|
|
17
|
+
## 프로덕션 빌드 전 체크리스트
|
|
18
|
+
|
|
19
|
+
1. **Bundle identifier** — `tauri.conf.json` 의 `identifier: "app.{{tauri_crate_name}}.dev"` 를
|
|
20
|
+
실제 도메인 기반 unique ID 로 교체 (예: `com.yourcompany.{{tauri_crate_name}}`).
|
|
21
|
+
동일 ID 로 publish 된 다른 앱과 충돌 시 OS install 이 깨질 수 있음.
|
|
22
|
+
2. **Icons** — `tauri.conf.json` 의 `bundle.icon: []` 가 비어 있습니다. 프로덕션 빌드 시:
|
|
23
|
+
- 1024x1024 PNG 준비 (square, 투명 배경 권장)
|
|
24
|
+
- 부모 디렉토리에서 `pnpm tauri icon path/to/source.png` 실행 — `src-tauri/icons/` 에
|
|
25
|
+
플랫폼별 variants 자동 emit + `bundle.icon` 자동 채워짐
|
|
26
|
+
3. **Capabilities** — `capabilities/default.json` 은 최소 권한. fs / dialog / shell 등
|
|
27
|
+
확장 API 가 필요하면 https://v2.tauri.app/security/ 참고.
|
|
28
|
+
4. **Window 옵션** — `tauri.conf.json` 의 `app.windows[0]` 에 `decorations`, `transparent`,
|
|
29
|
+
`alwaysOnTop` 등 추가 가능.
|
|
30
|
+
|
|
31
|
+
## Rust 코드 추가
|
|
32
|
+
|
|
33
|
+
`src/lib.rs` 의 `invoke_handler![]` 안에 새 command 등록:
|
|
34
|
+
|
|
35
|
+
```rust
|
|
36
|
+
#[tauri::command]
|
|
37
|
+
fn my_command(name: &str) -> String {
|
|
38
|
+
format!("Hello, {}!", name)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// run() 안의 .invoke_handler 에:
|
|
42
|
+
.invoke_handler(tauri::generate_handler![my_command])
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
프론트엔드에서:
|
|
46
|
+
```ts
|
|
47
|
+
import { invoke } from '@tauri-apps/api/core';
|
|
48
|
+
const greeting = await invoke<string>('my_command', { name: 'World' });
|
|
49
|
+
```
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../gen/schemas/desktop-schema.json",
|
|
3
|
+
"identifier": "default",
|
|
4
|
+
"description": "기본 capability — 핵심 Tauri API 만 허용. 추가 권한 (fs / dialog / shell 등) 은 https://v2.tauri.app/security/ 참고해서 명시적 추가.",
|
|
5
|
+
"windows": [
|
|
6
|
+
"main"
|
|
7
|
+
],
|
|
8
|
+
"permissions": [
|
|
9
|
+
"core:default",
|
|
10
|
+
"opener:default"
|
|
11
|
+
]
|
|
12
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
|
2
|
+
pub fn run() {
|
|
3
|
+
tauri::Builder::default()
|
|
4
|
+
.plugin(tauri_plugin_opener::init())
|
|
5
|
+
.invoke_handler(tauri::generate_handler![])
|
|
6
|
+
.run(tauri::generate_context!())
|
|
7
|
+
.expect("error while running tauri application");
|
|
8
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://schema.tauri.app/config/2",
|
|
3
|
+
"productName": "{{project_name}}",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"identifier": "app.{{tauri_crate_name}}.dev",
|
|
6
|
+
"build": {
|
|
7
|
+
"beforeDevCommand": "pnpm dev",
|
|
8
|
+
"devUrl": "http://localhost:5173",
|
|
9
|
+
"beforeBuildCommand": "pnpm build",
|
|
10
|
+
"frontendDist": "../dist"
|
|
11
|
+
},
|
|
12
|
+
"app": {
|
|
13
|
+
"windows": [
|
|
14
|
+
{
|
|
15
|
+
"title": "{{project_name}}",
|
|
16
|
+
"width": 1200,
|
|
17
|
+
"height": 800
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"security": {
|
|
21
|
+
"csp": null
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"bundle": {
|
|
25
|
+
"active": true,
|
|
26
|
+
"targets": "all",
|
|
27
|
+
"icon": []
|
|
28
|
+
}
|
|
29
|
+
}
|