@proj-airi/cap-vite 0.9.0-alpha.10
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 +21 -0
- package/README.md +61 -0
- package/dist/bin/run.d.mts +1 -0
- package/dist/bin/run.mjs +56 -0
- package/dist/bin/run.mjs.map +1 -0
- package/dist/index.d.mts +22 -0
- package/dist/index.mjs +110 -0
- package/dist/index.mjs.map +1 -0
- package/dist/native-B_RstP1a.mjs +97 -0
- package/dist/native-B_RstP1a.mjs.map +1 -0
- package/dist/vite-plugin.d.mts +10 -0
- package/dist/vite-plugin.mjs +86 -0
- package/dist/vite-plugin.mjs.map +1 -0
- package/dist/vite-wrapper-config.d.mts +7 -0
- package/dist/vite-wrapper-config.mjs +24 -0
- package/dist/vite-wrapper-config.mjs.map +1 -0
- package/package.json +46 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-PRESENT Neko Ayaka
|
|
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,61 @@
|
|
|
1
|
+
# @proj-airi/cap-vite
|
|
2
|
+
|
|
3
|
+
CLI for [Capacitor](https://capacitorjs.com/) live-reload development using Vite.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
cap-vite [vite args...] -- <ios|android> [cap run args...]
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Examples:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pnpm exec cap-vite -- ios --target <DEVICE_ID_OR_SIMULATOR_NAME>
|
|
15
|
+
pnpm exec cap-vite -- --host 0.0.0.0 --port 5173 -- android --target <DEVICE_ID_OR_SIMULATOR_NAME> --flavor release
|
|
16
|
+
CAPACITOR_DEVICE_ID=<DEVICE_ID_OR_SIMULATOR_NAME> pnpm exec cap-vite -- ios
|
|
17
|
+
pnpm -F @proj-airi/stage-pocket run dev:ios -- --target <DEVICE_ID_OR_SIMULATOR_NAME>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
- Arguments before `--` are forwarded to `vite`.
|
|
21
|
+
- Arguments after `--` are forwarded to `cap run`.
|
|
22
|
+
- If `CAPACITOR_DEVICE_ID` is set and `cap run` args do not contain `--target`, `cap-vite` injects `--target <CAPACITOR_DEVICE_ID>` automatically.
|
|
23
|
+
- `cap-vite` always launches the Vite dev server. Do not pass `vite dev` or `vite serve` as extra args.
|
|
24
|
+
|
|
25
|
+
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`.
|
|
26
|
+
|
|
27
|
+
## Capacitor Configuration
|
|
28
|
+
|
|
29
|
+
You need to set `server.url` in `capacitor.config.ts` to the env variable `CAPACITOR_DEV_SERVER_URL`, then the cli will handle rest for you.
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
const serverURL = env.CAPACITOR_DEV_SERVER_URL
|
|
33
|
+
const isCleartext = serverURL?.startsWith('http://') ?? false
|
|
34
|
+
|
|
35
|
+
const config: CapacitorConfig = {
|
|
36
|
+
appId: 'com.example.app',
|
|
37
|
+
appName: 'Example App',
|
|
38
|
+
webDir: 'dist',
|
|
39
|
+
server: serverURL
|
|
40
|
+
? {
|
|
41
|
+
url: serverURL,
|
|
42
|
+
cleartext: isCleartext,
|
|
43
|
+
}
|
|
44
|
+
: undefined,
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export default config
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Why we need this?
|
|
51
|
+
|
|
52
|
+
- No need to care what `server.url` should be, it will be automatically set to the correct value.
|
|
53
|
+
- Rerun native app when native code changes, you won't forget to start it.
|
|
54
|
+
- No need to open two terminals to run the project, you can run it with one command.
|
|
55
|
+
|
|
56
|
+
## Architecture Notes
|
|
57
|
+
|
|
58
|
+
- Vite arguments are left to the real Vite CLI instead of being reimplemented inside `cap-vite`.
|
|
59
|
+
- `cap-vite` injects a wrapper config so it can append its own Vite plugin without editing the user's existing `vite.config.*`.
|
|
60
|
+
- The injected plugin reads `server.resolvedUrls`, starts `cap run`, and restarts it when files under the native platform directory change.
|
|
61
|
+
- `cap-vite` only splits the two argument groups and passes the `cap run` arguments into the injected plugin through environment variables.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
package/dist/bin/run.mjs
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { runCapVite } from "../index.mjs";
|
|
3
|
+
import process from "node:process";
|
|
4
|
+
|
|
5
|
+
//#region src/cli.ts
|
|
6
|
+
const usage = "cap-vite [vite args...] -- <ios|android> [cap run args...]";
|
|
7
|
+
const helpText = [
|
|
8
|
+
"Run a Vite dev server and forward a second argument group to `cap run`.",
|
|
9
|
+
"",
|
|
10
|
+
"Usage:",
|
|
11
|
+
` ${usage}`,
|
|
12
|
+
"",
|
|
13
|
+
"Examples:",
|
|
14
|
+
" cap-vite -- ios --target \"iPhone 16 Pro\"",
|
|
15
|
+
" cap-vite --host 0.0.0.0 --port 5173 -- android --target emulator-5554 --flavor release",
|
|
16
|
+
"",
|
|
17
|
+
"Notes:",
|
|
18
|
+
" Arguments before `--` are forwarded to Vite.",
|
|
19
|
+
" Arguments after `--` are forwarded to `cap run`."
|
|
20
|
+
].join("\n");
|
|
21
|
+
function getCapViteCliHelpText() {
|
|
22
|
+
return helpText;
|
|
23
|
+
}
|
|
24
|
+
function parseCapViteCliArgs(argv) {
|
|
25
|
+
if (argv.length === 1 && (argv[0] === "--help" || argv[0] === "-h")) return null;
|
|
26
|
+
const separatorIndex = argv.indexOf("--");
|
|
27
|
+
if (separatorIndex === -1) throw new Error(usage);
|
|
28
|
+
const capArgs = argv.slice(separatorIndex + 1);
|
|
29
|
+
if (capArgs.length === 0) throw new Error(usage);
|
|
30
|
+
const platform = capArgs[0];
|
|
31
|
+
if (platform !== "android" && platform !== "ios") throw new Error(usage);
|
|
32
|
+
return {
|
|
33
|
+
capArgs,
|
|
34
|
+
viteArgs: argv.slice(0, separatorIndex)
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
//#endregion
|
|
39
|
+
//#region src/bin/run.ts
|
|
40
|
+
async function main() {
|
|
41
|
+
const parsed = parseCapViteCliArgs(process.argv.slice(2));
|
|
42
|
+
if (!parsed) {
|
|
43
|
+
process.stdout.write(`${getCapViteCliHelpText()}\n`);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const result = await runCapVite(parsed.viteArgs, parsed.capArgs);
|
|
47
|
+
if (typeof result.exitCode === "number") process.exitCode = result.exitCode;
|
|
48
|
+
}
|
|
49
|
+
main().catch((error) => {
|
|
50
|
+
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
//#endregion
|
|
55
|
+
export { };
|
|
56
|
+
//# sourceMappingURL=run.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.mjs","names":[],"sources":["../../src/cli.ts","../../src/bin/run.ts"],"sourcesContent":["const usage = 'cap-vite [vite args...] -- <ios|android> [cap run args...]'\n\nconst helpText = [\n 'Run a Vite dev server and forward a second argument group to `cap run`.',\n '',\n 'Usage:',\n ` ${usage}`,\n '',\n 'Examples:',\n ' cap-vite -- ios --target \"iPhone 16 Pro\"',\n ' cap-vite --host 0.0.0.0 --port 5173 -- android --target emulator-5554 --flavor release',\n '',\n 'Notes:',\n ' Arguments before `--` are forwarded to Vite.',\n ' Arguments after `--` are forwarded to `cap run`.',\n].join('\\n')\n\nexport interface ParsedCapViteCliArgs {\n capArgs: string[]\n viteArgs: string[]\n}\n\nexport function getCapViteCliHelpText(): string {\n return helpText\n}\n\nexport function getCapViteCliUsage(): string {\n return usage\n}\n\nexport function parseCapViteCliArgs(argv: string[]): ParsedCapViteCliArgs | null {\n if (argv.length === 1 && (argv[0] === '--help' || argv[0] === '-h')) {\n return null\n }\n\n const separatorIndex = argv.indexOf('--')\n if (separatorIndex === -1) {\n throw new Error(usage)\n }\n\n const capArgs = argv.slice(separatorIndex + 1)\n if (capArgs.length === 0) {\n throw new Error(usage)\n }\n\n const platform = capArgs[0]\n if (platform !== 'android' && platform !== 'ios') {\n throw new Error(usage)\n }\n\n return {\n capArgs,\n viteArgs: argv.slice(0, separatorIndex),\n }\n}\n","#!/usr/bin/env node\n\nimport process from 'node:process'\n\nimport { runCapVite } from '..'\nimport { getCapViteCliHelpText, parseCapViteCliArgs } from '../cli'\n\nasync function main() {\n const parsed = parseCapViteCliArgs(process.argv.slice(2))\n if (!parsed) {\n process.stdout.write(`${getCapViteCliHelpText()}\\n`)\n return\n }\n\n const result = await runCapVite(parsed.viteArgs, parsed.capArgs)\n if (typeof result.exitCode === 'number') {\n process.exitCode = result.exitCode\n }\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":";;;;;AAAA,MAAM,QAAQ;AAEd,MAAM,WAAW;CACf;CACA;CACA;CACA,KAAK;CACL;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC,KAAK,KAAK;AAOZ,SAAgB,wBAAgC;AAC9C,QAAO;;AAOT,SAAgB,oBAAoB,MAA6C;AAC/E,KAAI,KAAK,WAAW,MAAM,KAAK,OAAO,YAAY,KAAK,OAAO,MAC5D,QAAO;CAGT,MAAM,iBAAiB,KAAK,QAAQ,KAAK;AACzC,KAAI,mBAAmB,GACrB,OAAM,IAAI,MAAM,MAAM;CAGxB,MAAM,UAAU,KAAK,MAAM,iBAAiB,EAAE;AAC9C,KAAI,QAAQ,WAAW,EACrB,OAAM,IAAI,MAAM,MAAM;CAGxB,MAAM,WAAW,QAAQ;AACzB,KAAI,aAAa,aAAa,aAAa,MACzC,OAAM,IAAI,MAAM,MAAM;AAGxB,QAAO;EACL;EACA,UAAU,KAAK,MAAM,GAAG,eAAe;EACxC;;;;;AC9CH,eAAe,OAAO;CACpB,MAAM,SAAS,oBAAoB,QAAQ,KAAK,MAAM,EAAE,CAAC;AACzD,KAAI,CAAC,QAAQ;AACX,UAAQ,OAAO,MAAM,GAAG,uBAAuB,CAAC,IAAI;AACpD;;CAGF,MAAM,SAAS,MAAM,WAAW,OAAO,UAAU,OAAO,QAAQ;AAChE,KAAI,OAAO,OAAO,aAAa,SAC7B,SAAQ,WAAW,OAAO;;AAIzB,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
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Output } from "tinyexec";
|
|
2
|
+
import "vite";
|
|
3
|
+
|
|
4
|
+
//#region src/native.d.ts
|
|
5
|
+
type CapacitorPlatform = 'android' | 'ios';
|
|
6
|
+
//#endregion
|
|
7
|
+
//#region src/index.d.ts
|
|
8
|
+
interface RunCapViteOptions {
|
|
9
|
+
cwd?: string;
|
|
10
|
+
}
|
|
11
|
+
interface PreparedViteLaunch {
|
|
12
|
+
baseConfigFile?: string;
|
|
13
|
+
configLoader?: 'bundle' | 'native' | 'runner';
|
|
14
|
+
projectRoot: string;
|
|
15
|
+
viteArgs: string[];
|
|
16
|
+
wrapperConfigFile: string;
|
|
17
|
+
}
|
|
18
|
+
declare function prepareCapViteLaunch(viteArgs: string[], cwd?: string): PreparedViteLaunch;
|
|
19
|
+
declare function runCapVite(viteArgs: string[], capArgs: string[], options?: RunCapViteOptions): Promise<Output>;
|
|
20
|
+
//#endregion
|
|
21
|
+
export { type CapacitorPlatform, RunCapViteOptions, prepareCapViteLaunch, runCapVite };
|
|
22
|
+
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { t as parseCapacitorPlatform } from "./native-B_RstP1a.mjs";
|
|
2
|
+
import process from "node:process";
|
|
3
|
+
import { extname, resolve } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { x } from "tinyexec";
|
|
6
|
+
|
|
7
|
+
//#region src/index.ts
|
|
8
|
+
function resolveWrapperConfigFile() {
|
|
9
|
+
const wrapperExtension = extname(fileURLToPath(import.meta.url)) === ".ts" ? ".ts" : ".mjs";
|
|
10
|
+
return fileURLToPath(new URL(`./vite-wrapper-config${wrapperExtension}`, import.meta.url));
|
|
11
|
+
}
|
|
12
|
+
function parseViteConfigLoader(value) {
|
|
13
|
+
if (value === "bundle" || value === "native" || value === "runner") return value;
|
|
14
|
+
}
|
|
15
|
+
function resolveConfigPath(cwd, value) {
|
|
16
|
+
return resolve(cwd, value);
|
|
17
|
+
}
|
|
18
|
+
function readRequiredOptionValue(viteArgs, index, optionName) {
|
|
19
|
+
const value = viteArgs[index + 1];
|
|
20
|
+
if (!value) throw new Error(`Missing value for \`${optionName}\`.`);
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
function parseConfigArg(viteArgs, index, cwd) {
|
|
24
|
+
const arg = viteArgs[index];
|
|
25
|
+
if (arg === "--config" || arg === "-c") return {
|
|
26
|
+
baseConfigFile: resolveConfigPath(cwd, readRequiredOptionValue(viteArgs, index, "--config")),
|
|
27
|
+
consumedArgs: 2,
|
|
28
|
+
forwardedArgs: []
|
|
29
|
+
};
|
|
30
|
+
if (arg.startsWith("--config=")) return {
|
|
31
|
+
baseConfigFile: resolveConfigPath(cwd, arg.slice(9)),
|
|
32
|
+
consumedArgs: 1,
|
|
33
|
+
forwardedArgs: []
|
|
34
|
+
};
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
function parseConfigLoaderArg(viteArgs, index) {
|
|
38
|
+
const arg = viteArgs[index];
|
|
39
|
+
if (arg === "--configLoader") {
|
|
40
|
+
const value = readRequiredOptionValue(viteArgs, index, "--configLoader");
|
|
41
|
+
return {
|
|
42
|
+
configLoader: parseViteConfigLoader(value),
|
|
43
|
+
consumedArgs: 2,
|
|
44
|
+
forwardedArgs: [arg, value]
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
if (arg.startsWith("--configLoader=")) return {
|
|
48
|
+
configLoader: parseViteConfigLoader(arg.slice(15)),
|
|
49
|
+
consumedArgs: 1,
|
|
50
|
+
forwardedArgs: [arg]
|
|
51
|
+
};
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
function parseViteArg(viteArgs, index, cwd) {
|
|
55
|
+
return parseConfigArg(viteArgs, index, cwd) ?? parseConfigLoaderArg(viteArgs, index) ?? {
|
|
56
|
+
consumedArgs: 1,
|
|
57
|
+
forwardedArgs: [viteArgs[index]]
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function resolveProjectRoot(viteArgs, cwd) {
|
|
61
|
+
const firstArg = viteArgs[0];
|
|
62
|
+
return firstArg && !firstArg.startsWith("-") ? resolve(cwd, firstArg) : cwd;
|
|
63
|
+
}
|
|
64
|
+
function prepareCapViteLaunch(viteArgs, cwd = process.cwd()) {
|
|
65
|
+
const resolvedCwd = resolve(cwd);
|
|
66
|
+
const projectRoot = resolveProjectRoot(viteArgs, resolvedCwd);
|
|
67
|
+
let baseConfigFile;
|
|
68
|
+
let configLoader;
|
|
69
|
+
const forwardedViteArgs = [];
|
|
70
|
+
for (let index = 0; index < viteArgs.length;) {
|
|
71
|
+
const parsedArg = parseViteArg(viteArgs, index, resolvedCwd);
|
|
72
|
+
baseConfigFile = parsedArg.baseConfigFile ?? baseConfigFile;
|
|
73
|
+
configLoader = parsedArg.configLoader ?? configLoader;
|
|
74
|
+
forwardedViteArgs.push(...parsedArg.forwardedArgs);
|
|
75
|
+
index += parsedArg.consumedArgs;
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
baseConfigFile,
|
|
79
|
+
configLoader,
|
|
80
|
+
projectRoot,
|
|
81
|
+
viteArgs: forwardedViteArgs,
|
|
82
|
+
wrapperConfigFile: resolveWrapperConfigFile()
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
async function runCapVite(viteArgs, capArgs, options = {}) {
|
|
86
|
+
if (!parseCapacitorPlatform(capArgs[0])) throw new Error("The first `cap run` argument must be `ios` or `android`.");
|
|
87
|
+
const cwd = resolve(options.cwd ?? process.cwd());
|
|
88
|
+
const prepared = prepareCapViteLaunch(viteArgs, cwd);
|
|
89
|
+
return await x("vite", [
|
|
90
|
+
"--config",
|
|
91
|
+
prepared.wrapperConfigFile,
|
|
92
|
+
...prepared.viteArgs
|
|
93
|
+
], {
|
|
94
|
+
throwOnError: false,
|
|
95
|
+
nodeOptions: {
|
|
96
|
+
cwd,
|
|
97
|
+
env: {
|
|
98
|
+
CAP_VITE_BASE_CONFIG: prepared.baseConfigFile ?? "",
|
|
99
|
+
CAP_VITE_CAP_ARGS_JSON: JSON.stringify(capArgs),
|
|
100
|
+
CAP_VITE_CONFIG_LOADER: prepared.configLoader ?? "",
|
|
101
|
+
CAP_VITE_ROOT: prepared.projectRoot
|
|
102
|
+
},
|
|
103
|
+
stdio: "inherit"
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
//#endregion
|
|
109
|
+
export { prepareCapViteLaunch, runCapVite };
|
|
110
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type { Output } from 'tinyexec'\n\nimport process from 'node:process'\n\nimport { extname, resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nimport { x } from 'tinyexec'\n\nimport { parseCapacitorPlatform } from './native'\n\nexport type { CapacitorPlatform } from './native'\n\nexport interface RunCapViteOptions {\n cwd?: string\n}\n\ninterface PreparedViteLaunch {\n baseConfigFile?: string\n configLoader?: 'bundle' | 'native' | 'runner'\n projectRoot: string\n viteArgs: string[]\n wrapperConfigFile: string\n}\n\ninterface ParsedViteArg {\n baseConfigFile?: string\n configLoader?: 'bundle' | 'native' | 'runner'\n consumedArgs: number\n forwardedArgs: string[]\n}\n\nfunction resolveWrapperConfigFile(): string {\n const currentModulePath = fileURLToPath(import.meta.url)\n const wrapperExtension = extname(currentModulePath) === '.ts' ? '.ts' : '.mjs'\n return fileURLToPath(new URL(`./vite-wrapper-config${wrapperExtension}`, import.meta.url))\n}\n\nfunction parseViteConfigLoader(value: string | undefined): 'bundle' | 'native' | 'runner' | undefined {\n if (value === 'bundle' || value === 'native' || value === 'runner') {\n return value\n }\n\n return undefined\n}\n\nfunction resolveConfigPath(cwd: string, value: string): string {\n return resolve(cwd, value)\n}\n\nfunction readRequiredOptionValue(viteArgs: string[], index: number, optionName: string): string {\n const value = viteArgs[index + 1]\n if (!value) {\n throw new Error(`Missing value for \\`${optionName}\\`.`)\n }\n\n return value\n}\n\nfunction parseConfigArg(viteArgs: string[], index: number, cwd: string): ParsedViteArg | null {\n const arg = viteArgs[index]\n\n // NOTICE: Vite only accepts one `--config` entrypoint. cap-vite consumes that slot\n // for its wrapper config, then loads the user config from inside the wrapper.\n if (arg === '--config' || arg === '-c') {\n return {\n baseConfigFile: resolveConfigPath(cwd, readRequiredOptionValue(viteArgs, index, '--config')),\n consumedArgs: 2,\n forwardedArgs: [],\n }\n }\n\n if (arg.startsWith('--config=')) {\n return {\n baseConfigFile: resolveConfigPath(cwd, arg.slice('--config='.length)),\n consumedArgs: 1,\n forwardedArgs: [],\n }\n }\n\n return null\n}\n\nfunction parseConfigLoaderArg(viteArgs: string[], index: number): ParsedViteArg | null {\n const arg = viteArgs[index]\n\n if (arg === '--configLoader') {\n const value = readRequiredOptionValue(viteArgs, index, '--configLoader')\n\n return {\n configLoader: parseViteConfigLoader(value),\n consumedArgs: 2,\n forwardedArgs: [arg, value],\n }\n }\n\n if (arg.startsWith('--configLoader=')) {\n return {\n configLoader: parseViteConfigLoader(arg.slice('--configLoader='.length)),\n consumedArgs: 1,\n forwardedArgs: [arg],\n }\n }\n\n return null\n}\n\nfunction parseViteArg(viteArgs: string[], index: number, cwd: string): ParsedViteArg {\n return parseConfigArg(viteArgs, index, cwd)\n ?? parseConfigLoaderArg(viteArgs, index)\n ?? {\n consumedArgs: 1,\n forwardedArgs: [viteArgs[index]],\n }\n}\n\nfunction resolveProjectRoot(viteArgs: string[], cwd: string): string {\n const firstArg = viteArgs[0]\n\n return firstArg && !firstArg.startsWith('-')\n ? resolve(cwd, firstArg)\n : cwd\n}\n\nexport function prepareCapViteLaunch(viteArgs: string[], cwd: string = process.cwd()): PreparedViteLaunch {\n const resolvedCwd = resolve(cwd)\n const projectRoot = resolveProjectRoot(viteArgs, resolvedCwd)\n\n let baseConfigFile: string | undefined\n let configLoader: 'bundle' | 'native' | 'runner' | undefined\n const forwardedViteArgs: string[] = []\n\n for (let index = 0; index < viteArgs.length;) {\n const parsedArg = parseViteArg(viteArgs, index, resolvedCwd)\n\n baseConfigFile = parsedArg.baseConfigFile ?? baseConfigFile\n configLoader = parsedArg.configLoader ?? configLoader\n forwardedViteArgs.push(...parsedArg.forwardedArgs)\n index += parsedArg.consumedArgs\n }\n\n return {\n baseConfigFile,\n configLoader,\n projectRoot,\n viteArgs: forwardedViteArgs,\n wrapperConfigFile: resolveWrapperConfigFile(),\n }\n}\n\nexport async function runCapVite(\n viteArgs: string[],\n capArgs: string[],\n options: RunCapViteOptions = {},\n): Promise<Output> {\n if (!parseCapacitorPlatform(capArgs[0])) {\n throw new Error('The first `cap run` argument must be `ios` or `android`.')\n }\n\n const cwd = resolve(options.cwd ?? process.cwd())\n const prepared = prepareCapViteLaunch(viteArgs, cwd)\n\n return await x('vite', ['--config', prepared.wrapperConfigFile, ...prepared.viteArgs], {\n throwOnError: false,\n nodeOptions: {\n cwd,\n env: {\n CAP_VITE_BASE_CONFIG: prepared.baseConfigFile ?? '',\n CAP_VITE_CAP_ARGS_JSON: JSON.stringify(capArgs),\n CAP_VITE_CONFIG_LOADER: prepared.configLoader ?? '',\n CAP_VITE_ROOT: prepared.projectRoot,\n },\n stdio: 'inherit',\n },\n })\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
import { basename, extname, relative, resolve, sep } from "node:path";
|
|
3
|
+
|
|
4
|
+
//#region src/native.ts
|
|
5
|
+
const nativeExtensionsByPlatform = {
|
|
6
|
+
ios: new Set([
|
|
7
|
+
".entitlements",
|
|
8
|
+
".h",
|
|
9
|
+
".hpp",
|
|
10
|
+
".m",
|
|
11
|
+
".mm",
|
|
12
|
+
".pbxproj",
|
|
13
|
+
".plist",
|
|
14
|
+
".storyboard",
|
|
15
|
+
".strings",
|
|
16
|
+
".swift",
|
|
17
|
+
".xcodeproj",
|
|
18
|
+
".xcconfig",
|
|
19
|
+
".xcscheme",
|
|
20
|
+
".xib"
|
|
21
|
+
]),
|
|
22
|
+
android: new Set([
|
|
23
|
+
".gradle",
|
|
24
|
+
".java",
|
|
25
|
+
".json",
|
|
26
|
+
".kts",
|
|
27
|
+
".kt",
|
|
28
|
+
".properties",
|
|
29
|
+
".xml"
|
|
30
|
+
])
|
|
31
|
+
};
|
|
32
|
+
const nativeNamesByPlatform = {
|
|
33
|
+
ios: new Set([
|
|
34
|
+
"Podfile",
|
|
35
|
+
"Podfile.lock",
|
|
36
|
+
"project.pbxproj"
|
|
37
|
+
]),
|
|
38
|
+
android: new Set([
|
|
39
|
+
"AndroidManifest.xml",
|
|
40
|
+
"build.gradle",
|
|
41
|
+
"build.gradle.kts",
|
|
42
|
+
"gradle.properties",
|
|
43
|
+
"settings.gradle",
|
|
44
|
+
"settings.gradle.kts"
|
|
45
|
+
])
|
|
46
|
+
};
|
|
47
|
+
const ignoredNames = new Set(["capacitor.config.json"]);
|
|
48
|
+
const ignoredPathSegments = new Set([
|
|
49
|
+
".gradle",
|
|
50
|
+
"DerivedData",
|
|
51
|
+
"Pods",
|
|
52
|
+
"build",
|
|
53
|
+
"xcuserdata"
|
|
54
|
+
]);
|
|
55
|
+
const ignoredPathPrefixesByPlatform = {
|
|
56
|
+
ios: [["App", "CapApp-SPM"]],
|
|
57
|
+
android: []
|
|
58
|
+
};
|
|
59
|
+
function parseCapacitorPlatform(value) {
|
|
60
|
+
return value === "android" || value === "ios" ? value : null;
|
|
61
|
+
}
|
|
62
|
+
function hasCapacitorTargetArg(capArgs) {
|
|
63
|
+
return capArgs.some((arg, index) => arg === "--target" || index > 0 && arg.startsWith("--target="));
|
|
64
|
+
}
|
|
65
|
+
function resolveCapRunArgs(capArgs, env = process.env) {
|
|
66
|
+
if (capArgs.length === 0 || hasCapacitorTargetArg(capArgs)) return capArgs;
|
|
67
|
+
const target = env.CAPACITOR_DEVICE_ID;
|
|
68
|
+
if (!target) return capArgs;
|
|
69
|
+
const [platform, ...rest] = capArgs;
|
|
70
|
+
return [
|
|
71
|
+
platform,
|
|
72
|
+
"--target",
|
|
73
|
+
target,
|
|
74
|
+
...rest
|
|
75
|
+
];
|
|
76
|
+
}
|
|
77
|
+
function pickServerUrl(server) {
|
|
78
|
+
const url = server.resolvedUrls?.network?.[0] ?? server.resolvedUrls?.local?.[0];
|
|
79
|
+
if (!url) throw new Error("Vite did not expose a reachable dev server URL.");
|
|
80
|
+
return new URL(url);
|
|
81
|
+
}
|
|
82
|
+
function shouldRestartForNativeChange(file, platform, cwd) {
|
|
83
|
+
const absoluteFile = resolve(cwd, file);
|
|
84
|
+
const platformRoot = resolve(cwd, platform);
|
|
85
|
+
if (!absoluteFile.startsWith(`${platformRoot}${sep}`) && absoluteFile !== platformRoot) return false;
|
|
86
|
+
const fileName = basename(absoluteFile);
|
|
87
|
+
if (ignoredNames.has(fileName)) return false;
|
|
88
|
+
if (absoluteFile.split(sep).some((segment) => ignoredPathSegments.has(segment))) return false;
|
|
89
|
+
const relativeSegments = relative(platformRoot, absoluteFile).split(sep).filter(Boolean);
|
|
90
|
+
if (ignoredPathPrefixesByPlatform[platform].some((prefix) => prefix.every((segment, index) => relativeSegments[index] === segment))) return false;
|
|
91
|
+
if (nativeNamesByPlatform[platform].has(fileName)) return true;
|
|
92
|
+
return nativeExtensionsByPlatform[platform].has(extname(fileName).toLowerCase());
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
//#endregion
|
|
96
|
+
export { shouldRestartForNativeChange as i, pickServerUrl as n, resolveCapRunArgs as r, parseCapacitorPlatform as t };
|
|
97
|
+
//# sourceMappingURL=native-B_RstP1a.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"native-B_RstP1a.mjs","names":[],"sources":["../src/native.ts"],"sourcesContent":["import type { ViteDevServer } from 'vite'\n\nimport process from 'node:process'\n\nimport { basename, extname, relative, resolve, sep } from 'node:path'\n\nexport type CapacitorPlatform = 'android' | 'ios'\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\nexport function parseCapacitorPlatform(value: string | undefined): CapacitorPlatform | null {\n return value === 'android' || value === 'ios' ? value : null\n}\n\nexport function hasCapacitorTargetArg(capArgs: string[]): boolean {\n return capArgs.some((arg, index) => arg === '--target' || (index > 0 && arg.startsWith('--target=')))\n}\n\nexport function resolveCapRunArgs(capArgs: string[], env: NodeJS.ProcessEnv = process.env): string[] {\n if (capArgs.length === 0 || hasCapacitorTargetArg(capArgs)) {\n return capArgs\n }\n\n const target = env.CAPACITOR_DEVICE_ID\n if (!target) {\n return capArgs\n }\n\n const [platform, ...rest] = capArgs\n\n return [platform, '--target', target, ...rest]\n}\n\nexport function pickServerUrl(server: Pick<ViteDevServer, 'resolvedUrls'>): 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 return new URL(url)\n}\n\nexport function 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"],"mappings":";;;;AAQA,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,SAAgB,uBAAuB,OAAqD;AAC1F,QAAO,UAAU,aAAa,UAAU,QAAQ,QAAQ;;AAG1D,SAAgB,sBAAsB,SAA4B;AAChE,QAAO,QAAQ,MAAM,KAAK,UAAU,QAAQ,cAAe,QAAQ,KAAK,IAAI,WAAW,YAAY,CAAE;;AAGvG,SAAgB,kBAAkB,SAAmB,MAAyB,QAAQ,KAAe;AACnG,KAAI,QAAQ,WAAW,KAAK,sBAAsB,QAAQ,CACxD,QAAO;CAGT,MAAM,SAAS,IAAI;AACnB,KAAI,CAAC,OACH,QAAO;CAGT,MAAM,CAAC,UAAU,GAAG,QAAQ;AAE5B,QAAO;EAAC;EAAU;EAAY;EAAQ,GAAG;EAAK;;AAGhD,SAAgB,cAAc,QAAkD;CAC9E,MAAM,MAAM,OAAO,cAAc,UAAU,MAAM,OAAO,cAAc,QAAQ;AAE9E,KAAI,CAAC,IACH,OAAM,IAAI,MAAM,kDAAkD;AAGpE,QAAO,IAAI,IAAI,IAAI;;AAGrB,SAAgB,6BAA6B,MAAc,UAA6B,KAAsB;CAC5G,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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Plugin } from "vite";
|
|
2
|
+
|
|
3
|
+
//#region src/vite-plugin.d.ts
|
|
4
|
+
interface CapVitePluginOptions {
|
|
5
|
+
capArgs: string[];
|
|
6
|
+
}
|
|
7
|
+
declare function capVitePlugin(options: CapVitePluginOptions): Plugin;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { CapVitePluginOptions, capVitePlugin };
|
|
10
|
+
//# sourceMappingURL=vite-plugin.d.mts.map
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { i as shouldRestartForNativeChange, n as pickServerUrl, r as resolveCapRunArgs, t as parseCapacitorPlatform } from "./native-B_RstP1a.mjs";
|
|
2
|
+
import process from "node:process";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
import { x } from "tinyexec";
|
|
5
|
+
|
|
6
|
+
//#region src/vite-plugin.ts
|
|
7
|
+
async function stopCapProcess(current) {
|
|
8
|
+
if (!current) return;
|
|
9
|
+
current.kill("SIGINT");
|
|
10
|
+
try {
|
|
11
|
+
await current;
|
|
12
|
+
} catch {}
|
|
13
|
+
}
|
|
14
|
+
function startCapProcess(cwd, capArgs, url) {
|
|
15
|
+
console.info("\n----------------------\n");
|
|
16
|
+
console.info("Running cap run", ...capArgs);
|
|
17
|
+
return x("cap", ["run", ...capArgs], {
|
|
18
|
+
throwOnError: false,
|
|
19
|
+
nodeOptions: {
|
|
20
|
+
cwd,
|
|
21
|
+
env: { CAPACITOR_DEV_SERVER_URL: url.toString() },
|
|
22
|
+
stdio: "inherit"
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
function capVitePlugin(options) {
|
|
27
|
+
const resolvedCapArgs = resolveCapRunArgs(options.capArgs);
|
|
28
|
+
const platform = parseCapacitorPlatform(resolvedCapArgs[0]);
|
|
29
|
+
if (!platform) throw new Error("The first `cap run` argument must be `ios` or `android`.");
|
|
30
|
+
return {
|
|
31
|
+
apply: "serve",
|
|
32
|
+
name: "cap-vite:run-capacitor",
|
|
33
|
+
configureServer(server) {
|
|
34
|
+
const cwd = resolve(server.config.root);
|
|
35
|
+
const platformRoot = resolve(cwd, platform);
|
|
36
|
+
const debounceMs = 300;
|
|
37
|
+
const logger = server.config.logger;
|
|
38
|
+
let currentCapProcess;
|
|
39
|
+
let shuttingDown = false;
|
|
40
|
+
let restartTimer;
|
|
41
|
+
const start = () => {
|
|
42
|
+
currentCapProcess = startCapProcess(cwd, resolvedCapArgs, pickServerUrl(server));
|
|
43
|
+
};
|
|
44
|
+
const restartCapProcess = async (reason) => {
|
|
45
|
+
if (shuttingDown) return;
|
|
46
|
+
logger.info(`[cap-vite] ${reason}. Re-running cap run ${platform}.`);
|
|
47
|
+
const previous = currentCapProcess;
|
|
48
|
+
currentCapProcess = void 0;
|
|
49
|
+
await stopCapProcess(previous);
|
|
50
|
+
start();
|
|
51
|
+
};
|
|
52
|
+
const onWatcherEvent = (_event, file) => {
|
|
53
|
+
if (!shouldRestartForNativeChange(file, platform, cwd)) return;
|
|
54
|
+
clearTimeout(restartTimer);
|
|
55
|
+
restartTimer = setTimeout(() => {
|
|
56
|
+
restartCapProcess(`native file changed: ${resolve(cwd, file)}`);
|
|
57
|
+
}, debounceMs);
|
|
58
|
+
};
|
|
59
|
+
const shutdown = async () => {
|
|
60
|
+
if (shuttingDown) return;
|
|
61
|
+
shuttingDown = true;
|
|
62
|
+
clearTimeout(restartTimer);
|
|
63
|
+
server.watcher.off("all", onWatcherEvent);
|
|
64
|
+
await server.watcher.unwatch(platformRoot);
|
|
65
|
+
await stopCapProcess(currentCapProcess);
|
|
66
|
+
};
|
|
67
|
+
server.watcher.add(platformRoot);
|
|
68
|
+
server.watcher.on("all", onWatcherEvent);
|
|
69
|
+
server.httpServer?.once("listening", () => {
|
|
70
|
+
try {
|
|
71
|
+
start();
|
|
72
|
+
} catch (error) {
|
|
73
|
+
logger.error(`[cap-vite] ${error instanceof Error ? error.message : String(error)}`);
|
|
74
|
+
shutdown();
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
server.httpServer?.once("close", shutdown);
|
|
78
|
+
process.once("SIGINT", shutdown);
|
|
79
|
+
process.once("SIGTERM", shutdown);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
//#endregion
|
|
85
|
+
export { capVitePlugin };
|
|
86
|
+
//# sourceMappingURL=vite-plugin.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vite-plugin.mjs","names":[],"sources":["../src/vite-plugin.ts"],"sourcesContent":["import type { Result } from 'tinyexec'\nimport type { Plugin } from 'vite'\n\nimport process from 'node:process'\n\nimport { resolve } from 'node:path'\n\nimport { x } from 'tinyexec'\n\nimport { parseCapacitorPlatform, pickServerUrl, resolveCapRunArgs, shouldRestartForNativeChange } from './native'\n\nexport interface CapVitePluginOptions {\n capArgs: string[]\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 when a process is stopped during a restart.\n }\n}\n\nfunction startCapProcess(cwd: string, capArgs: string[], url: URL) {\n console.info('\\n----------------------\\n')\n console.info('Running cap run', ...capArgs)\n\n return x('cap', ['run', ...capArgs], {\n throwOnError: false,\n nodeOptions: {\n cwd,\n env: {\n CAPACITOR_DEV_SERVER_URL: url.toString(),\n },\n stdio: 'inherit',\n },\n })\n}\n\nexport function capVitePlugin(options: CapVitePluginOptions): Plugin {\n const resolvedCapArgs = resolveCapRunArgs(options.capArgs)\n const platform = parseCapacitorPlatform(resolvedCapArgs[0])\n if (!platform) {\n throw new Error('The first `cap run` argument must be `ios` or `android`.')\n }\n\n return {\n apply: 'serve',\n name: 'cap-vite:run-capacitor',\n configureServer(server) {\n const cwd = resolve(server.config.root)\n const platformRoot = resolve(cwd, platform)\n const debounceMs = 300\n const logger = server.config.logger\n\n let currentCapProcess: Result | undefined\n let shuttingDown = false\n let restartTimer: NodeJS.Timeout | undefined\n\n const start = () => {\n const url = pickServerUrl(server)\n currentCapProcess = startCapProcess(cwd, resolvedCapArgs, url)\n }\n\n const restartCapProcess = async (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 start()\n }\n\n const onWatcherEvent = (_event, file) => {\n if (!shouldRestartForNativeChange(file, platform, cwd)) {\n return\n }\n\n clearTimeout(restartTimer)\n restartTimer = setTimeout(() => {\n restartCapProcess(`native file changed: ${resolve(cwd, file)}`)\n }, debounceMs)\n }\n\n const shutdown = async () => {\n if (shuttingDown) {\n return\n }\n\n shuttingDown = true\n clearTimeout(restartTimer)\n server.watcher.off('all', onWatcherEvent)\n await server.watcher.unwatch(platformRoot)\n await stopCapProcess(currentCapProcess)\n }\n\n server.watcher.add(platformRoot)\n server.watcher.on('all', onWatcherEvent)\n\n server.httpServer?.once('listening', () => {\n try {\n start()\n }\n catch (error) {\n logger.error(`[cap-vite] ${error instanceof Error ? error.message : String(error)}`)\n shutdown()\n }\n })\n server.httpServer?.once('close', shutdown)\n process.once('SIGINT', shutdown)\n process.once('SIGTERM', shutdown)\n },\n }\n}\n"],"mappings":";;;;;;AAeA,eAAe,eAAe,SAA6B;AACzD,KAAI,CAAC,QACH;AAGF,SAAQ,KAAK,SAAS;AAEtB,KAAI;AACF,QAAM;SAEF;;AAKR,SAAS,gBAAgB,KAAa,SAAmB,KAAU;AACjE,SAAQ,KAAK,6BAA6B;AAC1C,SAAQ,KAAK,mBAAmB,GAAG,QAAQ;AAE3C,QAAO,EAAE,OAAO,CAAC,OAAO,GAAG,QAAQ,EAAE;EACnC,cAAc;EACd,aAAa;GACX;GACA,KAAK,EACH,0BAA0B,IAAI,UAAU,EACzC;GACD,OAAO;GACR;EACF,CAAC;;AAGJ,SAAgB,cAAc,SAAuC;CACnE,MAAM,kBAAkB,kBAAkB,QAAQ,QAAQ;CAC1D,MAAM,WAAW,uBAAuB,gBAAgB,GAAG;AAC3D,KAAI,CAAC,SACH,OAAM,IAAI,MAAM,2DAA2D;AAG7E,QAAO;EACL,OAAO;EACP,MAAM;EACN,gBAAgB,QAAQ;GACtB,MAAM,MAAM,QAAQ,OAAO,OAAO,KAAK;GACvC,MAAM,eAAe,QAAQ,KAAK,SAAS;GAC3C,MAAM,aAAa;GACnB,MAAM,SAAS,OAAO,OAAO;GAE7B,IAAI;GACJ,IAAI,eAAe;GACnB,IAAI;GAEJ,MAAM,cAAc;AAElB,wBAAoB,gBAAgB,KAAK,iBAD7B,cAAc,OAAO,CAC6B;;GAGhE,MAAM,oBAAoB,OAAO,WAAmB;AAClD,QAAI,aACF;AAGF,WAAO,KAAK,cAAc,OAAO,uBAAuB,SAAS,GAAG;IACpE,MAAM,WAAW;AACjB,wBAAoB;AACpB,UAAM,eAAe,SAAS;AAC9B,WAAO;;GAGT,MAAM,kBAAkB,QAAQ,SAAS;AACvC,QAAI,CAAC,6BAA6B,MAAM,UAAU,IAAI,CACpD;AAGF,iBAAa,aAAa;AAC1B,mBAAe,iBAAiB;AAC9B,uBAAkB,wBAAwB,QAAQ,KAAK,KAAK,GAAG;OAC9D,WAAW;;GAGhB,MAAM,WAAW,YAAY;AAC3B,QAAI,aACF;AAGF,mBAAe;AACf,iBAAa,aAAa;AAC1B,WAAO,QAAQ,IAAI,OAAO,eAAe;AACzC,UAAM,OAAO,QAAQ,QAAQ,aAAa;AAC1C,UAAM,eAAe,kBAAkB;;AAGzC,UAAO,QAAQ,IAAI,aAAa;AAChC,UAAO,QAAQ,GAAG,OAAO,eAAe;AAExC,UAAO,YAAY,KAAK,mBAAmB;AACzC,QAAI;AACF,YAAO;aAEF,OAAO;AACZ,YAAO,MAAM,cAAc,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,GAAG;AACpF,eAAU;;KAEZ;AACF,UAAO,YAAY,KAAK,SAAS,SAAS;AAC1C,WAAQ,KAAK,UAAU,SAAS;AAChC,WAAQ,KAAK,WAAW,SAAS;;EAEpC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { capVitePlugin } from "./vite-plugin.mjs";
|
|
2
|
+
import process from "node:process";
|
|
3
|
+
import { defineConfig, loadConfigFromFile, mergeConfig } from "vite";
|
|
4
|
+
|
|
5
|
+
//#region src/vite-wrapper-config.ts
|
|
6
|
+
function parseCapArgs() {
|
|
7
|
+
const value = process.env.CAP_VITE_CAP_ARGS_JSON;
|
|
8
|
+
if (!value) return [];
|
|
9
|
+
const parsed = JSON.parse(value);
|
|
10
|
+
if (!Array.isArray(parsed) || parsed.some((arg) => typeof arg !== "string")) throw new Error("CAP_VITE_CAP_ARGS_JSON must be a JSON string array.");
|
|
11
|
+
return parsed;
|
|
12
|
+
}
|
|
13
|
+
function parseConfigLoader() {
|
|
14
|
+
const value = process.env.CAP_VITE_CONFIG_LOADER;
|
|
15
|
+
if (value === "bundle" || value === "native" || value === "runner") return value;
|
|
16
|
+
}
|
|
17
|
+
var vite_wrapper_config_default = defineConfig(async (env) => {
|
|
18
|
+
const root = process.env.CAP_VITE_ROOT ?? process.cwd();
|
|
19
|
+
return mergeConfig((await loadConfigFromFile(env, process.env.CAP_VITE_BASE_CONFIG || void 0, root, void 0, void 0, parseConfigLoader()))?.config ?? {}, { plugins: [capVitePlugin({ capArgs: parseCapArgs() })] });
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
//#endregion
|
|
23
|
+
export { vite_wrapper_config_default as default };
|
|
24
|
+
//# sourceMappingURL=vite-wrapper-config.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vite-wrapper-config.mjs","names":[],"sources":["../src/vite-wrapper-config.ts"],"sourcesContent":["import process from 'node:process'\n\nimport { defineConfig, loadConfigFromFile, mergeConfig } from 'vite'\n\nimport { capVitePlugin } from './vite-plugin'\n\nfunction parseCapArgs(): string[] {\n const value = process.env.CAP_VITE_CAP_ARGS_JSON\n if (!value) {\n return []\n }\n\n const parsed = JSON.parse(value)\n if (!Array.isArray(parsed) || parsed.some(arg => typeof arg !== 'string')) {\n throw new Error('CAP_VITE_CAP_ARGS_JSON must be a JSON string array.')\n }\n\n return parsed\n}\n\nfunction parseConfigLoader(): 'bundle' | 'native' | 'runner' | undefined {\n const value = process.env.CAP_VITE_CONFIG_LOADER\n if (value === 'bundle' || value === 'native' || value === 'runner') {\n return value\n }\n\n return undefined\n}\n\nexport default defineConfig(async (env) => {\n const root = process.env.CAP_VITE_ROOT ?? process.cwd()\n const baseConfigFile = process.env.CAP_VITE_BASE_CONFIG || undefined\n const configLoader = parseConfigLoader()\n\n const loaded = await loadConfigFromFile(\n env,\n baseConfigFile,\n root,\n undefined,\n undefined,\n configLoader,\n )\n\n return mergeConfig(loaded?.config ?? {}, {\n plugins: [\n capVitePlugin({\n capArgs: parseCapArgs(),\n }),\n ],\n })\n})\n"],"mappings":";;;;;AAMA,SAAS,eAAyB;CAChC,MAAM,QAAQ,QAAQ,IAAI;AAC1B,KAAI,CAAC,MACH,QAAO,EAAE;CAGX,MAAM,SAAS,KAAK,MAAM,MAAM;AAChC,KAAI,CAAC,MAAM,QAAQ,OAAO,IAAI,OAAO,MAAK,QAAO,OAAO,QAAQ,SAAS,CACvE,OAAM,IAAI,MAAM,sDAAsD;AAGxE,QAAO;;AAGT,SAAS,oBAAgE;CACvE,MAAM,QAAQ,QAAQ,IAAI;AAC1B,KAAI,UAAU,YAAY,UAAU,YAAY,UAAU,SACxD,QAAO;;AAMX,kCAAe,aAAa,OAAO,QAAQ;CACzC,MAAM,OAAO,QAAQ,IAAI,iBAAiB,QAAQ,KAAK;AAavD,QAAO,aATQ,MAAM,mBACnB,KAJqB,QAAQ,IAAI,wBAAwB,QAMzD,MACA,QACA,QAPmB,mBAAmB,CASvC,GAE0B,UAAU,EAAE,EAAE,EACvC,SAAS,CACP,cAAc,EACZ,SAAS,cAAc,EACxB,CAAC,CACH,EACF,CAAC;EACF"}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@proj-airi/cap-vite",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.9.0-alpha.10",
|
|
5
|
+
"description": "CLI that starts a Vite dev server and runs Capacitor live reload",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "Moeru AI Project AIRI Team",
|
|
8
|
+
"email": "airi@moeru.ai",
|
|
9
|
+
"url": "https://github.com/moeru-ai"
|
|
10
|
+
},
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "https://github.com/moeru-ai/airi.git",
|
|
15
|
+
"directory": "packages/cap-vite"
|
|
16
|
+
},
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./dist/index.d.mts",
|
|
20
|
+
"default": "./dist/index.mjs"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"main": "./dist/index.mjs",
|
|
24
|
+
"types": "./dist/index.d.mts",
|
|
25
|
+
"bin": {
|
|
26
|
+
"cap-vite": "./dist/bin/run.mjs"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"README.md",
|
|
30
|
+
"dist",
|
|
31
|
+
"package.json"
|
|
32
|
+
],
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"@capacitor/cli": "^8.0.0",
|
|
35
|
+
"vite": "^7.0.0 || ^8.0.0-beta.0"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"cac": "^6.7.14",
|
|
39
|
+
"tinyexec": "^1.0.2"
|
|
40
|
+
},
|
|
41
|
+
"scripts": {
|
|
42
|
+
"build": "tsdown",
|
|
43
|
+
"test": "vitest run",
|
|
44
|
+
"typecheck": "tsc --noEmit"
|
|
45
|
+
}
|
|
46
|
+
}
|