@proj-airi/cap-vite 0.9.0-alpha.7 → 0.9.0-alpha.8

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/README.md CHANGED
@@ -5,13 +5,17 @@ CLI for [Capacitor](https://capacitorjs.com/) live-reload development using Vite
5
5
  ## Usage
6
6
 
7
7
  ```bash
8
- pnpm cap-vite ios <DEVICE_ID_OR_SIMULATOR_NAME>
9
- pnpm cap-vite android <DEVICE_ID_OR_SIMULATOR_NAME>
8
+ pnpm cap-vite ios --target <DEVICE_ID_OR_SIMULATOR_NAME>
9
+ pnpm cap-vite android --target <DEVICE_ID_OR_SIMULATOR_NAME>
10
+ pnpm cap-vite ios --target <DEVICE_ID_OR_SIMULATOR_NAME> -- --scheme AIRI
11
+ pnpm cap-vite android --target <DEVICE_ID_OR_SIMULATOR_NAME> -- --flavor release
10
12
  # Or
11
13
  CAPACITOR_DEVICE_ID=<DEVICE_ID_OR_SIMULATOR_NAME> pnpm cap-vite ios
12
14
  CAPACITOR_DEVICE_ID=<DEVICE_ID_OR_SIMULATOR_NAME> pnpm cap-vite android
13
15
  ```
14
16
 
17
+ - Arguments after `--` are forwarded to `cap run`, example: `pnpm cap-vite ios --target <DEVICE_ID_OR_SIMULATOR_NAME> -- --scheme AIRI` will run `cap run ios --target <DEVICE_ID_OR_SIMULATOR_NAME> --scheme AIRI`.
18
+
15
19
  You can see the list of available devices and simulators by running `pnpm exec cap run ios --list` or `pnpm exec cap run android --list`.
16
20
 
17
21
  ## Capacitor Configuration
package/dist/bin/run.mjs CHANGED
@@ -1,17 +1,45 @@
1
1
  #!/usr/bin/env node
2
2
  import { runCapVite } from "../index.mjs";
3
3
  import process from "node:process";
4
+ import { cac } from "cac";
4
5
 
6
+ //#region src/cli.ts
7
+ const usage = "cap-vite <ios|android> [--target <DEVICE_ID_OR_SIMULATOR_NAME>] [-- <cap args...>]";
8
+ function createCapViteCli() {
9
+ const cli = cac("cap-vite");
10
+ cli.help();
11
+ cli.command("<platform>", "Run Capacitor with a Vite dev server").usage(usage).option("--target <target>", "Set the Capacitor device target").example("cap-vite ios --target \"iPhone 16 Pro\" -- --scheme AIRI").example("CAPACITOR_DEVICE_ID=emulator-5554 cap-vite android -- --flavor release");
12
+ return cli;
13
+ }
14
+ function parseCapViteCliArgs(argv, env = process.env) {
15
+ const cli = createCapViteCli();
16
+ const parsed = cli.parse([
17
+ "node",
18
+ "cap-vite",
19
+ ...argv
20
+ ], { run: false });
21
+ if (cli.options.help) return null;
22
+ cli.matchedCommand?.checkUnknownOptions();
23
+ cli.matchedCommand?.checkOptionValue();
24
+ cli.matchedCommand?.checkRequiredArgs();
25
+ if (parsed.args.length > 1) throw new Error(usage);
26
+ const platform = parsed.args[0];
27
+ if (platform !== "android" && platform !== "ios") throw new Error(usage);
28
+ const target = typeof parsed.options.target === "string" ? parsed.options.target : env.CAPACITOR_DEVICE_ID;
29
+ if (!target) throw new Error(usage);
30
+ return {
31
+ capArgs: Array.isArray(parsed.options["--"]) ? parsed.options["--"] : [],
32
+ platform,
33
+ target
34
+ };
35
+ }
36
+
37
+ //#endregion
5
38
  //#region src/bin/run.ts
6
39
  async function main() {
7
- const platform = process.argv[2];
8
- const deviceId = process.env.CAPACITOR_DEVICE_ID || process.argv[3];
9
- if (!deviceId) throw new Error("Usage: cap-vite <ios|android> <DEVICE_ID_OR_SIMULATOR_NAME>");
10
- if (platform !== "android" && platform !== "ios") {
11
- process.stderr.write("Usage: cap-vite <ios|android> <DEVICE_ID_OR_SIMULATOR_NAME>\n");
12
- process.exit(1);
13
- }
14
- await runCapVite(platform, deviceId);
40
+ const parsed = parseCapViteCliArgs(process.argv.slice(2));
41
+ if (!parsed) return;
42
+ await runCapVite(parsed.platform, parsed.target, { capArgs: parsed.capArgs });
15
43
  }
16
44
  main().catch((error) => {
17
45
  process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
@@ -1 +1 @@
1
- {"version":3,"file":"run.mjs","names":[],"sources":["../../src/bin/run.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport process from 'node:process'\n\nimport { runCapVite } from '..'\n\nasync function main() {\n const platform = process.argv[2]\n const deviceId = process.env.CAPACITOR_DEVICE_ID || process.argv[3]\n if (!deviceId) {\n throw new Error('Usage: cap-vite <ios|android> <DEVICE_ID_OR_SIMULATOR_NAME>')\n }\n\n if (platform !== 'android' && platform !== 'ios') {\n process.stderr.write('Usage: cap-vite <ios|android> <DEVICE_ID_OR_SIMULATOR_NAME>\\n')\n process.exit(1)\n }\n\n await runCapVite(platform, deviceId)\n}\n\nvoid main().catch((error) => {\n process.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`)\n process.exit(1)\n})\n"],"mappings":";;;;;AAMA,eAAe,OAAO;CACpB,MAAM,WAAW,QAAQ,KAAK;CAC9B,MAAM,WAAW,QAAQ,IAAI,uBAAuB,QAAQ,KAAK;AACjE,KAAI,CAAC,SACH,OAAM,IAAI,MAAM,8DAA8D;AAGhF,KAAI,aAAa,aAAa,aAAa,OAAO;AAChD,UAAQ,OAAO,MAAM,gEAAgE;AACrF,UAAQ,KAAK,EAAE;;AAGjB,OAAM,WAAW,UAAU,SAAS;;AAGjC,MAAM,CAAC,OAAO,UAAU;AAC3B,SAAQ,OAAO,MAAM,GAAG,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,CAAC,IAAI;AACnF,SAAQ,KAAK,EAAE;EACf"}
1
+ {"version":3,"file":"run.mjs","names":[],"sources":["../../src/cli.ts","../../src/bin/run.ts"],"sourcesContent":["import type { CapacitorPlatform } from '.'\n\nimport process from 'node:process'\n\nimport { cac } from 'cac'\n\nexport interface ParsedCapViteCliArgs {\n capArgs: string[]\n platform: CapacitorPlatform\n target: string\n}\n\nconst usage = 'cap-vite <ios|android> [--target <DEVICE_ID_OR_SIMULATOR_NAME>] [-- <cap args...>]'\n\nfunction createCapViteCli() {\n const cli = cac('cap-vite')\n\n cli.help()\n cli\n .command('<platform>', 'Run Capacitor with a Vite dev server')\n .usage(usage)\n .option('--target <target>', 'Set the Capacitor device target')\n .example('cap-vite ios --target \"iPhone 16 Pro\" -- --scheme AIRI')\n .example('CAPACITOR_DEVICE_ID=emulator-5554 cap-vite android -- --flavor release')\n\n return cli\n}\n\nexport function parseCapViteCliArgs(\n argv: string[],\n env: NodeJS.ProcessEnv = process.env,\n): ParsedCapViteCliArgs | null {\n const cli = createCapViteCli()\n const parsed = cli.parse(['node', 'cap-vite', ...argv], { run: false })\n\n if (cli.options.help) {\n return null\n }\n\n cli.matchedCommand?.checkUnknownOptions()\n cli.matchedCommand?.checkOptionValue()\n cli.matchedCommand?.checkRequiredArgs()\n\n if (parsed.args.length > 1) {\n throw new Error(usage)\n }\n\n const platform = parsed.args[0]\n if (platform !== 'android' && platform !== 'ios') {\n throw new Error(usage)\n }\n\n const target = typeof parsed.options.target === 'string' ? parsed.options.target : env.CAPACITOR_DEVICE_ID\n if (!target) {\n throw new Error(usage)\n }\n\n return {\n capArgs: Array.isArray(parsed.options['--']) ? parsed.options['--'] : [],\n platform,\n target,\n }\n}\n","#!/usr/bin/env node\n\nimport process from 'node:process'\n\nimport { runCapVite } from '..'\nimport { parseCapViteCliArgs } from '../cli'\n\nasync function main() {\n const parsed = parseCapViteCliArgs(process.argv.slice(2))\n if (!parsed) {\n return\n }\n\n await runCapVite(parsed.platform, parsed.target, { capArgs: parsed.capArgs })\n}\n\nvoid main().catch((error) => {\n process.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`)\n process.exit(1)\n})\n"],"mappings":";;;;;;AAYA,MAAM,QAAQ;AAEd,SAAS,mBAAmB;CAC1B,MAAM,MAAM,IAAI,WAAW;AAE3B,KAAI,MAAM;AACV,KACG,QAAQ,cAAc,uCAAuC,CAC7D,MAAM,MAAM,CACZ,OAAO,qBAAqB,kCAAkC,CAC9D,QAAQ,2DAAyD,CACjE,QAAQ,yEAAyE;AAEpF,QAAO;;AAGT,SAAgB,oBACd,MACA,MAAyB,QAAQ,KACJ;CAC7B,MAAM,MAAM,kBAAkB;CAC9B,MAAM,SAAS,IAAI,MAAM;EAAC;EAAQ;EAAY,GAAG;EAAK,EAAE,EAAE,KAAK,OAAO,CAAC;AAEvE,KAAI,IAAI,QAAQ,KACd,QAAO;AAGT,KAAI,gBAAgB,qBAAqB;AACzC,KAAI,gBAAgB,kBAAkB;AACtC,KAAI,gBAAgB,mBAAmB;AAEvC,KAAI,OAAO,KAAK,SAAS,EACvB,OAAM,IAAI,MAAM,MAAM;CAGxB,MAAM,WAAW,OAAO,KAAK;AAC7B,KAAI,aAAa,aAAa,aAAa,MACzC,OAAM,IAAI,MAAM,MAAM;CAGxB,MAAM,SAAS,OAAO,OAAO,QAAQ,WAAW,WAAW,OAAO,QAAQ,SAAS,IAAI;AACvF,KAAI,CAAC,OACH,OAAM,IAAI,MAAM,MAAM;AAGxB,QAAO;EACL,SAAS,MAAM,QAAQ,OAAO,QAAQ,MAAM,GAAG,OAAO,QAAQ,QAAQ,EAAE;EACxE;EACA;EACD;;;;;ACtDH,eAAe,OAAO;CACpB,MAAM,SAAS,oBAAoB,QAAQ,KAAK,MAAM,EAAE,CAAC;AACzD,KAAI,CAAC,OACH;AAGF,OAAM,WAAW,OAAO,UAAU,OAAO,QAAQ,EAAE,SAAS,OAAO,SAAS,CAAC;;AAG1E,MAAM,CAAC,OAAO,UAAU;AAC3B,SAAQ,OAAO,MAAM,GAAG,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,CAAC,IAAI;AACnF,SAAQ,KAAK,EAAE;EACf"}
package/dist/index.d.mts CHANGED
@@ -1,10 +1,11 @@
1
1
  //#region src/index.d.ts
2
2
  type CapacitorPlatform = 'android' | 'ios';
3
3
  interface RunCapViteOptions {
4
+ capArgs?: string[];
4
5
  cwd?: string;
5
6
  debounceMs?: number;
6
7
  }
7
- declare function runCapVite(platform: CapacitorPlatform, deviceId: string, options?: RunCapViteOptions): Promise<void>;
8
+ declare function runCapVite(platform: CapacitorPlatform, target: string, options?: RunCapViteOptions): Promise<void>;
8
9
  //#endregion
9
10
  export { CapacitorPlatform, RunCapViteOptions, runCapVite };
10
11
  //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs CHANGED
@@ -82,12 +82,15 @@ async function stopCapProcess(current) {
82
82
  await current;
83
83
  } catch {}
84
84
  }
85
- function startCapProcess(cwd, platform, deviceId, url) {
85
+ function startCapProcess(cwd, platform, target, url, capArgs) {
86
+ console.info("\n----------------------\n");
87
+ console.info("Running cap run", platform, "--target", target, ...capArgs);
86
88
  return x("cap", [
87
89
  "run",
88
90
  platform,
89
91
  "--target",
90
- deviceId
92
+ target,
93
+ ...capArgs
91
94
  ], {
92
95
  persist: true,
93
96
  throwOnError: false,
@@ -98,7 +101,8 @@ function startCapProcess(cwd, platform, deviceId, url) {
98
101
  }
99
102
  });
100
103
  }
101
- async function runCapVite(platform, deviceId, options = {}) {
104
+ async function runCapVite(platform, target, options = {}) {
105
+ const capArgs = options.capArgs ?? [];
102
106
  const cwd = resolve(options.cwd ?? process.cwd());
103
107
  const debounceMs = options.debounceMs ?? 300;
104
108
  const server = await createServer({
@@ -109,7 +113,7 @@ async function runCapVite(platform, deviceId, options = {}) {
109
113
  server.printUrls();
110
114
  const url = pickServerUrl(server);
111
115
  const logger = server.config.logger;
112
- let currentCapProcess = startCapProcess(cwd, platform, deviceId, url);
116
+ let currentCapProcess = startCapProcess(cwd, platform, target, url, capArgs);
113
117
  let restartTimer;
114
118
  let shuttingDown = false;
115
119
  async function restartCapProcess(reason) {
@@ -118,7 +122,7 @@ async function runCapVite(platform, deviceId, options = {}) {
118
122
  const previous = currentCapProcess;
119
123
  currentCapProcess = void 0;
120
124
  await stopCapProcess(previous);
121
- currentCapProcess = startCapProcess(cwd, platform, deviceId, url);
125
+ currentCapProcess = startCapProcess(cwd, platform, target, url, capArgs);
122
126
  }
123
127
  const onWatcherEvent = (_event, file) => {
124
128
  if (!shouldRestartForNativeChange(file, platform, cwd)) return;
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type { Result } from 'tinyexec'\nimport type { ViteDevServer } from 'vite'\n\nimport process from 'node:process'\n\nimport { basename, extname, relative, resolve, sep } from 'node:path'\n\nimport { x } from 'tinyexec'\nimport { createServer } from 'vite'\n\nexport type CapacitorPlatform = 'android' | 'ios'\n\nexport interface RunCapViteOptions {\n cwd?: string\n debounceMs?: number\n}\n\nconst nativeExtensionsByPlatform: Record<CapacitorPlatform, Set<string>> = {\n ios: new Set([\n '.entitlements',\n '.h',\n '.hpp',\n '.m',\n '.mm',\n '.pbxproj',\n '.plist',\n '.storyboard',\n '.strings',\n '.swift',\n '.xcodeproj',\n '.xcconfig',\n '.xcscheme',\n '.xib',\n ]),\n android: new Set([\n '.gradle',\n '.java',\n '.json',\n '.kts',\n '.kt',\n '.properties',\n '.xml',\n ]),\n}\n\nconst nativeNamesByPlatform: Record<CapacitorPlatform, Set<string>> = {\n ios: new Set([\n 'Podfile',\n 'Podfile.lock',\n 'project.pbxproj',\n ]),\n android: new Set([\n 'AndroidManifest.xml',\n 'build.gradle',\n 'build.gradle.kts',\n 'gradle.properties',\n 'settings.gradle',\n 'settings.gradle.kts',\n ]),\n}\n\nconst ignoredNames = new Set([\n 'capacitor.config.json',\n])\n\nconst ignoredPathSegments = new Set([\n '.gradle',\n 'DerivedData',\n 'Pods',\n 'build',\n 'xcuserdata',\n])\n\nconst ignoredPathPrefixesByPlatform: Record<CapacitorPlatform, string[][]> = {\n ios: [\n ['App', 'CapApp-SPM'],\n ],\n android: [],\n}\n\nfunction pickServerUrl(server: ViteDevServer): URL {\n const url = server.resolvedUrls?.network?.[0] ?? server.resolvedUrls?.local?.[0]\n\n if (!url) {\n throw new Error('Vite did not expose a reachable dev server URL.')\n }\n\n const resolved = new URL(url)\n\n return resolved\n}\n\nfunction shouldRestartForNativeChange(file: string, platform: CapacitorPlatform, cwd: string): boolean {\n const absoluteFile = resolve(cwd, file)\n const platformRoot = resolve(cwd, platform)\n\n if (!absoluteFile.startsWith(`${platformRoot}${sep}`) && absoluteFile !== platformRoot) {\n return false\n }\n\n const fileName = basename(absoluteFile)\n\n if (ignoredNames.has(fileName)) {\n return false\n }\n\n const segments = absoluteFile.split(sep)\n if (segments.some(segment => ignoredPathSegments.has(segment))) {\n return false\n }\n\n const relativeFile = relative(platformRoot, absoluteFile)\n const relativeSegments = relativeFile.split(sep).filter(Boolean)\n\n if (ignoredPathPrefixesByPlatform[platform].some(prefix =>\n prefix.every((segment, index) => relativeSegments[index] === segment),\n )) {\n // NOTICE: Capacitor regenerates ios/App/CapApp-SPM/Package.swift during `cap run`.\n // Treating that generated tree as a native source change causes an infinite restart loop.\n return false\n }\n\n if (nativeNamesByPlatform[platform].has(fileName)) {\n return true\n }\n\n return nativeExtensionsByPlatform[platform].has(extname(fileName).toLowerCase())\n}\n\nasync function stopCapProcess(current: Result | undefined) {\n if (!current) {\n return\n }\n\n current.kill('SIGINT')\n\n try {\n await current\n }\n catch {\n // tinyexec rejects on interrupted exits when the child was stopped for a restart.\n }\n}\n\nfunction startCapProcess(cwd: string, platform: CapacitorPlatform, deviceId: string, url: URL) {\n return x('cap', ['run', platform, '--target', deviceId], { persist: true, throwOnError: false, nodeOptions: { cwd, stdio: 'inherit', env: { CAPACITOR_DEV_SERVER_URL: url.toString() } } })\n}\n\nexport async function runCapVite(\n platform: CapacitorPlatform,\n deviceId: string,\n options: RunCapViteOptions = {},\n): Promise<void> {\n const cwd = resolve(options.cwd ?? process.cwd())\n const debounceMs = options.debounceMs ?? 300\n const server = await createServer({\n clearScreen: false,\n root: cwd,\n })\n\n await server.listen()\n server.printUrls()\n\n const url = pickServerUrl(server)\n const logger = server.config.logger\n\n let currentCapProcess: Result | undefined = startCapProcess(cwd, platform, deviceId, url)\n let restartTimer: NodeJS.Timeout | undefined\n let shuttingDown = false\n\n async function restartCapProcess(reason: string) {\n if (shuttingDown) {\n return\n }\n\n logger.info(`[cap-vite] ${reason}. Re-running cap run ${platform}.`)\n const previous = currentCapProcess\n currentCapProcess = undefined\n await stopCapProcess(previous)\n currentCapProcess = startCapProcess(cwd, platform, deviceId, url)\n }\n\n const onWatcherEvent = (_event: string, file: string) => {\n if (!shouldRestartForNativeChange(file, platform, cwd)) {\n return\n }\n\n clearTimeout(restartTimer)\n restartTimer = setTimeout(() => {\n void restartCapProcess(`native file changed: ${resolve(cwd, file)}`)\n }, debounceMs)\n }\n\n const shutdown = async (exitCode: number) => {\n if (shuttingDown) {\n return\n }\n\n shuttingDown = true\n clearTimeout(restartTimer)\n server.watcher.off('all', onWatcherEvent)\n await server.watcher.unwatch(platform)\n await server.close()\n await stopCapProcess(currentCapProcess)\n process.exit(exitCode)\n }\n\n server.watcher.add(platform)\n server.watcher.on('all', onWatcherEvent)\n\n process.once('SIGINT', () => {\n void shutdown(0)\n })\n process.once('SIGTERM', () => {\n void shutdown(0)\n })\n}\n"],"mappings":";;;;;;AAiBA,MAAM,6BAAqE;CACzE,KAAK,IAAI,IAAI;EACX;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC;CACF,SAAS,IAAI,IAAI;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC;CACH;AAED,MAAM,wBAAgE;CACpE,KAAK,IAAI,IAAI;EACX;EACA;EACA;EACD,CAAC;CACF,SAAS,IAAI,IAAI;EACf;EACA;EACA;EACA;EACA;EACA;EACD,CAAC;CACH;AAED,MAAM,eAAe,IAAI,IAAI,CAC3B,wBACD,CAAC;AAEF,MAAM,sBAAsB,IAAI,IAAI;CAClC;CACA;CACA;CACA;CACA;CACD,CAAC;AAEF,MAAM,gCAAuE;CAC3E,KAAK,CACH,CAAC,OAAO,aAAa,CACtB;CACD,SAAS,EAAE;CACZ;AAED,SAAS,cAAc,QAA4B;CACjD,MAAM,MAAM,OAAO,cAAc,UAAU,MAAM,OAAO,cAAc,QAAQ;AAE9E,KAAI,CAAC,IACH,OAAM,IAAI,MAAM,kDAAkD;AAKpE,QAFiB,IAAI,IAAI,IAAI;;AAK/B,SAAS,6BAA6B,MAAc,UAA6B,KAAsB;CACrG,MAAM,eAAe,QAAQ,KAAK,KAAK;CACvC,MAAM,eAAe,QAAQ,KAAK,SAAS;AAE3C,KAAI,CAAC,aAAa,WAAW,GAAG,eAAe,MAAM,IAAI,iBAAiB,aACxE,QAAO;CAGT,MAAM,WAAW,SAAS,aAAa;AAEvC,KAAI,aAAa,IAAI,SAAS,CAC5B,QAAO;AAIT,KADiB,aAAa,MAAM,IAAI,CAC3B,MAAK,YAAW,oBAAoB,IAAI,QAAQ,CAAC,CAC5D,QAAO;CAIT,MAAM,mBADe,SAAS,cAAc,aAAa,CACnB,MAAM,IAAI,CAAC,OAAO,QAAQ;AAEhE,KAAI,8BAA8B,UAAU,MAAK,WAC/C,OAAO,OAAO,SAAS,UAAU,iBAAiB,WAAW,QAAQ,CACtE,CAGC,QAAO;AAGT,KAAI,sBAAsB,UAAU,IAAI,SAAS,CAC/C,QAAO;AAGT,QAAO,2BAA2B,UAAU,IAAI,QAAQ,SAAS,CAAC,aAAa,CAAC;;AAGlF,eAAe,eAAe,SAA6B;AACzD,KAAI,CAAC,QACH;AAGF,SAAQ,KAAK,SAAS;AAEtB,KAAI;AACF,QAAM;SAEF;;AAKR,SAAS,gBAAgB,KAAa,UAA6B,UAAkB,KAAU;AAC7F,QAAO,EAAE,OAAO;EAAC;EAAO;EAAU;EAAY;EAAS,EAAE;EAAE,SAAS;EAAM,cAAc;EAAO,aAAa;GAAE;GAAK,OAAO;GAAW,KAAK,EAAE,0BAA0B,IAAI,UAAU,EAAE;GAAE;EAAE,CAAC;;AAG7L,eAAsB,WACpB,UACA,UACA,UAA6B,EAAE,EAChB;CACf,MAAM,MAAM,QAAQ,QAAQ,OAAO,QAAQ,KAAK,CAAC;CACjD,MAAM,aAAa,QAAQ,cAAc;CACzC,MAAM,SAAS,MAAM,aAAa;EAChC,aAAa;EACb,MAAM;EACP,CAAC;AAEF,OAAM,OAAO,QAAQ;AACrB,QAAO,WAAW;CAElB,MAAM,MAAM,cAAc,OAAO;CACjC,MAAM,SAAS,OAAO,OAAO;CAE7B,IAAI,oBAAwC,gBAAgB,KAAK,UAAU,UAAU,IAAI;CACzF,IAAI;CACJ,IAAI,eAAe;CAEnB,eAAe,kBAAkB,QAAgB;AAC/C,MAAI,aACF;AAGF,SAAO,KAAK,cAAc,OAAO,uBAAuB,SAAS,GAAG;EACpE,MAAM,WAAW;AACjB,sBAAoB;AACpB,QAAM,eAAe,SAAS;AAC9B,sBAAoB,gBAAgB,KAAK,UAAU,UAAU,IAAI;;CAGnE,MAAM,kBAAkB,QAAgB,SAAiB;AACvD,MAAI,CAAC,6BAA6B,MAAM,UAAU,IAAI,CACpD;AAGF,eAAa,aAAa;AAC1B,iBAAe,iBAAiB;AAC9B,GAAK,kBAAkB,wBAAwB,QAAQ,KAAK,KAAK,GAAG;KACnE,WAAW;;CAGhB,MAAM,WAAW,OAAO,aAAqB;AAC3C,MAAI,aACF;AAGF,iBAAe;AACf,eAAa,aAAa;AAC1B,SAAO,QAAQ,IAAI,OAAO,eAAe;AACzC,QAAM,OAAO,QAAQ,QAAQ,SAAS;AACtC,QAAM,OAAO,OAAO;AACpB,QAAM,eAAe,kBAAkB;AACvC,UAAQ,KAAK,SAAS;;AAGxB,QAAO,QAAQ,IAAI,SAAS;AAC5B,QAAO,QAAQ,GAAG,OAAO,eAAe;AAExC,SAAQ,KAAK,gBAAgB;AAC3B,EAAK,SAAS,EAAE;GAChB;AACF,SAAQ,KAAK,iBAAiB;AAC5B,EAAK,SAAS,EAAE;GAChB"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type { Result } from 'tinyexec'\nimport type { ViteDevServer } from 'vite'\n\nimport process from 'node:process'\n\nimport { basename, extname, relative, resolve, sep } from 'node:path'\n\nimport { x } from 'tinyexec'\nimport { createServer } from 'vite'\n\nexport type CapacitorPlatform = 'android' | 'ios'\n\nexport interface RunCapViteOptions {\n capArgs?: string[]\n cwd?: string\n debounceMs?: number\n}\n\nconst nativeExtensionsByPlatform: Record<CapacitorPlatform, Set<string>> = {\n ios: new Set([\n '.entitlements',\n '.h',\n '.hpp',\n '.m',\n '.mm',\n '.pbxproj',\n '.plist',\n '.storyboard',\n '.strings',\n '.swift',\n '.xcodeproj',\n '.xcconfig',\n '.xcscheme',\n '.xib',\n ]),\n android: new Set([\n '.gradle',\n '.java',\n '.json',\n '.kts',\n '.kt',\n '.properties',\n '.xml',\n ]),\n}\n\nconst nativeNamesByPlatform: Record<CapacitorPlatform, Set<string>> = {\n ios: new Set([\n 'Podfile',\n 'Podfile.lock',\n 'project.pbxproj',\n ]),\n android: new Set([\n 'AndroidManifest.xml',\n 'build.gradle',\n 'build.gradle.kts',\n 'gradle.properties',\n 'settings.gradle',\n 'settings.gradle.kts',\n ]),\n}\n\nconst ignoredNames = new Set([\n 'capacitor.config.json',\n])\n\nconst ignoredPathSegments = new Set([\n '.gradle',\n 'DerivedData',\n 'Pods',\n 'build',\n 'xcuserdata',\n])\n\nconst ignoredPathPrefixesByPlatform: Record<CapacitorPlatform, string[][]> = {\n ios: [\n ['App', 'CapApp-SPM'],\n ],\n android: [],\n}\n\nfunction pickServerUrl(server: ViteDevServer): URL {\n const url = server.resolvedUrls?.network?.[0] ?? server.resolvedUrls?.local?.[0]\n\n if (!url) {\n throw new Error('Vite did not expose a reachable dev server URL.')\n }\n\n const resolved = new URL(url)\n\n return resolved\n}\n\nfunction shouldRestartForNativeChange(file: string, platform: CapacitorPlatform, cwd: string): boolean {\n const absoluteFile = resolve(cwd, file)\n const platformRoot = resolve(cwd, platform)\n\n if (!absoluteFile.startsWith(`${platformRoot}${sep}`) && absoluteFile !== platformRoot) {\n return false\n }\n\n const fileName = basename(absoluteFile)\n\n if (ignoredNames.has(fileName)) {\n return false\n }\n\n const segments = absoluteFile.split(sep)\n if (segments.some(segment => ignoredPathSegments.has(segment))) {\n return false\n }\n\n const relativeFile = relative(platformRoot, absoluteFile)\n const relativeSegments = relativeFile.split(sep).filter(Boolean)\n\n if (ignoredPathPrefixesByPlatform[platform].some(prefix =>\n prefix.every((segment, index) => relativeSegments[index] === segment),\n )) {\n // NOTICE: Capacitor regenerates ios/App/CapApp-SPM/Package.swift during `cap run`.\n // Treating that generated tree as a native source change causes an infinite restart loop.\n return false\n }\n\n if (nativeNamesByPlatform[platform].has(fileName)) {\n return true\n }\n\n return nativeExtensionsByPlatform[platform].has(extname(fileName).toLowerCase())\n}\n\nasync function stopCapProcess(current: Result | undefined) {\n if (!current) {\n return\n }\n\n current.kill('SIGINT')\n\n try {\n await current\n }\n catch {\n // tinyexec rejects on interrupted exits when the child was stopped for a restart.\n }\n}\n\nfunction startCapProcess(cwd: string, platform: CapacitorPlatform, target: string, url: URL, capArgs: string[]) {\n console.info('\\n----------------------\\n')\n console.info('Running cap run', platform, '--target', target, ...capArgs)\n return x('cap', ['run', platform, '--target', target, ...capArgs], { persist: true, throwOnError: false, nodeOptions: { cwd, stdio: 'inherit', env: { CAPACITOR_DEV_SERVER_URL: url.toString() } } })\n}\n\nexport async function runCapVite(\n platform: CapacitorPlatform,\n target: string,\n options: RunCapViteOptions = {},\n): Promise<void> {\n const capArgs = options.capArgs ?? []\n const cwd = resolve(options.cwd ?? process.cwd())\n const debounceMs = options.debounceMs ?? 300\n const server = await createServer({\n clearScreen: false,\n root: cwd,\n })\n\n await server.listen()\n server.printUrls()\n\n const url = pickServerUrl(server)\n const logger = server.config.logger\n\n let currentCapProcess: Result | undefined = startCapProcess(cwd, platform, target, url, capArgs)\n let restartTimer: NodeJS.Timeout | undefined\n let shuttingDown = false\n\n async function restartCapProcess(reason: string) {\n if (shuttingDown) {\n return\n }\n\n logger.info(`[cap-vite] ${reason}. Re-running cap run ${platform}.`)\n const previous = currentCapProcess\n currentCapProcess = undefined\n await stopCapProcess(previous)\n currentCapProcess = startCapProcess(cwd, platform, target, url, capArgs)\n }\n\n const onWatcherEvent = (_event: string, file: string) => {\n if (!shouldRestartForNativeChange(file, platform, cwd)) {\n return\n }\n\n clearTimeout(restartTimer)\n restartTimer = setTimeout(() => {\n void restartCapProcess(`native file changed: ${resolve(cwd, file)}`)\n }, debounceMs)\n }\n\n const shutdown = async (exitCode: number) => {\n if (shuttingDown) {\n return\n }\n\n shuttingDown = true\n clearTimeout(restartTimer)\n server.watcher.off('all', onWatcherEvent)\n await server.watcher.unwatch(platform)\n await server.close()\n await stopCapProcess(currentCapProcess)\n process.exit(exitCode)\n }\n\n server.watcher.add(platform)\n server.watcher.on('all', onWatcherEvent)\n\n process.once('SIGINT', () => {\n void shutdown(0)\n })\n process.once('SIGTERM', () => {\n void shutdown(0)\n })\n}\n"],"mappings":";;;;;;AAkBA,MAAM,6BAAqE;CACzE,KAAK,IAAI,IAAI;EACX;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC;CACF,SAAS,IAAI,IAAI;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC;CACH;AAED,MAAM,wBAAgE;CACpE,KAAK,IAAI,IAAI;EACX;EACA;EACA;EACD,CAAC;CACF,SAAS,IAAI,IAAI;EACf;EACA;EACA;EACA;EACA;EACA;EACD,CAAC;CACH;AAED,MAAM,eAAe,IAAI,IAAI,CAC3B,wBACD,CAAC;AAEF,MAAM,sBAAsB,IAAI,IAAI;CAClC;CACA;CACA;CACA;CACA;CACD,CAAC;AAEF,MAAM,gCAAuE;CAC3E,KAAK,CACH,CAAC,OAAO,aAAa,CACtB;CACD,SAAS,EAAE;CACZ;AAED,SAAS,cAAc,QAA4B;CACjD,MAAM,MAAM,OAAO,cAAc,UAAU,MAAM,OAAO,cAAc,QAAQ;AAE9E,KAAI,CAAC,IACH,OAAM,IAAI,MAAM,kDAAkD;AAKpE,QAFiB,IAAI,IAAI,IAAI;;AAK/B,SAAS,6BAA6B,MAAc,UAA6B,KAAsB;CACrG,MAAM,eAAe,QAAQ,KAAK,KAAK;CACvC,MAAM,eAAe,QAAQ,KAAK,SAAS;AAE3C,KAAI,CAAC,aAAa,WAAW,GAAG,eAAe,MAAM,IAAI,iBAAiB,aACxE,QAAO;CAGT,MAAM,WAAW,SAAS,aAAa;AAEvC,KAAI,aAAa,IAAI,SAAS,CAC5B,QAAO;AAIT,KADiB,aAAa,MAAM,IAAI,CAC3B,MAAK,YAAW,oBAAoB,IAAI,QAAQ,CAAC,CAC5D,QAAO;CAIT,MAAM,mBADe,SAAS,cAAc,aAAa,CACnB,MAAM,IAAI,CAAC,OAAO,QAAQ;AAEhE,KAAI,8BAA8B,UAAU,MAAK,WAC/C,OAAO,OAAO,SAAS,UAAU,iBAAiB,WAAW,QAAQ,CACtE,CAGC,QAAO;AAGT,KAAI,sBAAsB,UAAU,IAAI,SAAS,CAC/C,QAAO;AAGT,QAAO,2BAA2B,UAAU,IAAI,QAAQ,SAAS,CAAC,aAAa,CAAC;;AAGlF,eAAe,eAAe,SAA6B;AACzD,KAAI,CAAC,QACH;AAGF,SAAQ,KAAK,SAAS;AAEtB,KAAI;AACF,QAAM;SAEF;;AAKR,SAAS,gBAAgB,KAAa,UAA6B,QAAgB,KAAU,SAAmB;AAC9G,SAAQ,KAAK,6BAA6B;AAC1C,SAAQ,KAAK,mBAAmB,UAAU,YAAY,QAAQ,GAAG,QAAQ;AACzE,QAAO,EAAE,OAAO;EAAC;EAAO;EAAU;EAAY;EAAQ,GAAG;EAAQ,EAAE;EAAE,SAAS;EAAM,cAAc;EAAO,aAAa;GAAE;GAAK,OAAO;GAAW,KAAK,EAAE,0BAA0B,IAAI,UAAU,EAAE;GAAE;EAAE,CAAC;;AAGvM,eAAsB,WACpB,UACA,QACA,UAA6B,EAAE,EAChB;CACf,MAAM,UAAU,QAAQ,WAAW,EAAE;CACrC,MAAM,MAAM,QAAQ,QAAQ,OAAO,QAAQ,KAAK,CAAC;CACjD,MAAM,aAAa,QAAQ,cAAc;CACzC,MAAM,SAAS,MAAM,aAAa;EAChC,aAAa;EACb,MAAM;EACP,CAAC;AAEF,OAAM,OAAO,QAAQ;AACrB,QAAO,WAAW;CAElB,MAAM,MAAM,cAAc,OAAO;CACjC,MAAM,SAAS,OAAO,OAAO;CAE7B,IAAI,oBAAwC,gBAAgB,KAAK,UAAU,QAAQ,KAAK,QAAQ;CAChG,IAAI;CACJ,IAAI,eAAe;CAEnB,eAAe,kBAAkB,QAAgB;AAC/C,MAAI,aACF;AAGF,SAAO,KAAK,cAAc,OAAO,uBAAuB,SAAS,GAAG;EACpE,MAAM,WAAW;AACjB,sBAAoB;AACpB,QAAM,eAAe,SAAS;AAC9B,sBAAoB,gBAAgB,KAAK,UAAU,QAAQ,KAAK,QAAQ;;CAG1E,MAAM,kBAAkB,QAAgB,SAAiB;AACvD,MAAI,CAAC,6BAA6B,MAAM,UAAU,IAAI,CACpD;AAGF,eAAa,aAAa;AAC1B,iBAAe,iBAAiB;AAC9B,GAAK,kBAAkB,wBAAwB,QAAQ,KAAK,KAAK,GAAG;KACnE,WAAW;;CAGhB,MAAM,WAAW,OAAO,aAAqB;AAC3C,MAAI,aACF;AAGF,iBAAe;AACf,eAAa,aAAa;AAC1B,SAAO,QAAQ,IAAI,OAAO,eAAe;AACzC,QAAM,OAAO,QAAQ,QAAQ,SAAS;AACtC,QAAM,OAAO,OAAO;AACpB,QAAM,eAAe,kBAAkB;AACvC,UAAQ,KAAK,SAAS;;AAGxB,QAAO,QAAQ,IAAI,SAAS;AAC5B,QAAO,QAAQ,GAAG,OAAO,eAAe;AAExC,SAAQ,KAAK,gBAAgB;AAC3B,EAAK,SAAS,EAAE;GAChB;AACF,SAAQ,KAAK,iBAAiB;AAC5B,EAAK,SAAS,EAAE;GAChB"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@proj-airi/cap-vite",
3
3
  "type": "module",
4
- "version": "0.9.0-alpha.7",
4
+ "version": "0.9.0-alpha.8",
5
5
  "description": "CLI that starts a Vite dev server and runs Capacitor live reload",
6
6
  "author": {
7
7
  "name": "Moeru AI Project AIRI Team",
@@ -35,10 +35,12 @@
35
35
  "vite": "^7.0.0 || ^8.0.0-beta.0"
36
36
  },
37
37
  "dependencies": {
38
+ "cac": "^6.7.14",
38
39
  "tinyexec": "^1.0.2"
39
40
  },
40
41
  "scripts": {
41
42
  "build": "tsdown",
43
+ "test": "vitest run",
42
44
  "typecheck": "tsc --noEmit"
43
45
  }
44
46
  }