Skip to content

Commit cee620b

Browse files
feat(appflow): support Capacitor only apps with ionic deploy manifest (#4641)
1 parent 6aad992 commit cee620b

File tree

2 files changed

+139
-5
lines changed

2 files changed

+139
-5
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { BaseConfig } from "@ionic/cli-framework";
2+
import lodash = require("lodash");
3+
4+
export interface CapacitorConfig {
5+
appId?: string;
6+
appName?: string;
7+
webDir?: string;
8+
server?: {
9+
url?: string;
10+
originalUrl?: string;
11+
};
12+
}
13+
14+
export interface CapacitorCLIConfig {
15+
android: {
16+
platformDirAbs: string;
17+
srcMainDirAbs: string;
18+
assetsDirAbs: string;
19+
};
20+
ios: {
21+
platformDirAbs: string;
22+
nativeTargetDirAbs: string;
23+
};
24+
app: {
25+
extConfig: CapacitorConfig;
26+
};
27+
}
28+
29+
export class CapacitorJSONConfig extends BaseConfig<CapacitorConfig> {
30+
constructor(p: string) {
31+
super(p, { spaces: "\t" });
32+
}
33+
34+
provideDefaults(config: CapacitorConfig): CapacitorConfig {
35+
return config;
36+
}
37+
38+
setServerUrl(url: string): void {
39+
const serverConfig = this.get("server") || {};
40+
41+
if (typeof serverConfig.url === "string") {
42+
serverConfig.originalUrl = serverConfig.url;
43+
}
44+
45+
serverConfig.url = url;
46+
47+
this.set("server", serverConfig);
48+
}
49+
50+
resetServerUrl(): void {
51+
const serverConfig = this.get("server") || {};
52+
53+
delete serverConfig.url;
54+
55+
if (serverConfig.originalUrl) {
56+
serverConfig.url = serverConfig.originalUrl;
57+
delete serverConfig.originalUrl;
58+
}
59+
60+
if (lodash.isEmpty(serverConfig)) {
61+
this.unset("server");
62+
} else {
63+
this.set("server", serverConfig);
64+
}
65+
}
66+
}

packages/@ionic/cli/src/commands/deploy/manifest.ts

Lines changed: 73 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,26 @@
11
import { MetadataGroup } from '@ionic/cli-framework';
2+
import { LOGGER_LEVELS } from '@ionic/cli-framework-output';
23
import { map } from '@ionic/utils-array';
3-
import { readdirp, stat, writeFile } from '@ionic/utils-fs';
4+
import { pathExists, readdirp, stat, writeFile } from '@ionic/utils-fs';
45
import { prettyPath } from '@ionic/utils-terminal';
56
import * as crypto from 'crypto';
67
import * as fs from 'fs';
8+
import lodash = require('lodash');
79
import * as path from 'path';
10+
import * as Debug from 'debug';
811

912
import { CommandMetadata } from '../../definitions';
1013
import { input } from '../../lib/color';
1114
import { FatalException } from '../../lib/errors';
15+
import { prependNodeModulesBinToPath, Shell } from '../../lib/shell';
16+
import { createDefaultLoggerHandlers, Logger } from '../../lib/utils/logger';
1217

18+
import { CapacitorCLIConfig, CapacitorConfig, CapacitorJSONConfig } from './capacitor';
1319
import { DeployCoreCommand } from './core';
1420

21+
const debug = Debug('ionic:commands:deploy:manifest');
22+
const CAPACITOR_CONFIG_JSON_FILE = 'capacitor.config.json';
23+
1524
interface DeployManifestItem {
1625
href: string;
1726
size: number;
@@ -20,21 +29,29 @@ interface DeployManifestItem {
2029

2130
export class DeployManifestCommand extends DeployCoreCommand {
2231
async getMetadata(): Promise<CommandMetadata> {
32+
// This command is set as type 'global' in order to support Capacitor apps without an ionic.config.json
2333
return {
2434
name: 'manifest',
25-
type: 'project',
35+
type: 'global',
2636
summary: 'Generates a manifest file for the deploy service from a built app directory',
2737
groups: [MetadataGroup.PAID],
2838
};
2939
}
3040

3141
async run(): Promise<void> {
32-
if (!this.project) {
42+
const capacitorConfig = await this.getCapacitorConfig();
43+
if (!this.project && !capacitorConfig) {
3344
throw new FatalException(`Cannot run ${input('ionic deploy manifest')} outside a project directory.`);
3445
}
35-
await this.requireNativeIntegration();
3646

37-
const buildDir = await this.project.getDistDir();
47+
let buildDir: string;
48+
if (this.project) {
49+
await this.requireNativeIntegration();
50+
buildDir = await this.project.getDistDir();
51+
} else {
52+
buildDir = capacitorConfig!.webDir ? capacitorConfig!.webDir : 'www';
53+
}
54+
3855
const manifest = await this.getFilesAndSizesAndHashesForGlobPattern(buildDir);
3956

4057
const manifestPath = path.resolve(buildDir, 'pro-manifest.json');
@@ -83,4 +100,55 @@ export class DeployManifestCommand extends DeployCoreCommand {
83100
})
84101
.join(' ');
85102
}
103+
104+
private getCapacitorConfigJsonPath(): string {
105+
return path.resolve(this.env.ctx.execPath, CAPACITOR_CONFIG_JSON_FILE);
106+
}
107+
108+
private getCapacitorCLIConfig = lodash.memoize(async (): Promise<CapacitorCLIConfig | undefined> => {
109+
// I had to create a new shell to force prependNodeModulesBinToPath.
110+
// If ionic.config.json is not present, then this.env.shell will not implement this, and the Capacitor command will fail.
111+
const args = ['config', '--json'];
112+
const log = new Logger({
113+
level: LOGGER_LEVELS.INFO,
114+
handlers: createDefaultLoggerHandlers(),
115+
});
116+
const shell = new Shell({ log }, { alterPath: p => { return prependNodeModulesBinToPath(this.env.ctx.execPath, p)} });
117+
118+
debug('Getting config with Capacitor CLI: %O', args);
119+
120+
const output = await shell.cmdinfo('capacitor', args);
121+
122+
if (!output) {
123+
debug('Could not get config from Capacitor CLI (probably old version)');
124+
return;
125+
}
126+
127+
return JSON.parse(output);
128+
});
129+
130+
private getCapacitorConfig = lodash.memoize(async (): Promise<CapacitorConfig | undefined> => {
131+
const cli = await this.getCapacitorCLIConfig();
132+
133+
if (cli) {
134+
debug('Loaded Capacitor config!');
135+
return cli.app.extConfig;
136+
}
137+
138+
// fallback to reading capacitor.config.json if it exists
139+
const confPath = this.getCapacitorConfigJsonPath();
140+
141+
if (!(await pathExists(confPath))) {
142+
debug('Capacitor config file does not exist at %O', confPath);
143+
debug('Failed to load Capacitor config');
144+
return;
145+
}
146+
147+
const conf = new CapacitorJSONConfig(confPath);
148+
const extConfig = conf.c;
149+
150+
debug('Loaded Capacitor config!');
151+
152+
return extConfig;
153+
});
86154
}

0 commit comments

Comments
 (0)