Skip to content

Commit 3c70e87

Browse files
committed
feat(start): better multi-app support
- Introduces `root` key for projects in multi-app - Ability to use `ionic start` within a multi-app configured project. - Removes single-app style `ionic.config.json` from downloaded template - Configures existing multi-app `ionic.config.json` with new project - Integration w/ Angular and lerna is not perfect... additional commands and configuration is still needed.
1 parent dc3f2a5 commit 3c70e87

File tree

6 files changed

+45
-17
lines changed

6 files changed

+45
-17
lines changed

packages/ionic/src/commands/start.ts

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@ import * as Debug from 'debug';
88
import * as lodash from 'lodash';
99
import * as path from 'path';
1010

11-
import { CommandInstanceInfo, CommandLineInputs, CommandLineOptions, CommandMetadata, CommandPreRun, ResolvedStarterTemplate, StarterManifest, StarterTemplate } from '../definitions';
11+
import { PROJECT_FILE } from '../constants';
12+
import { CommandInstanceInfo, CommandLineInputs, CommandLineOptions, CommandMetadata, CommandPreRun, IProject, ProjectType, ResolvedStarterTemplate, StarterManifest, StarterTemplate } from '../definitions';
1213
import { getProject } from '../lib';
1314
import { Command } from '../lib/command';
1415
import { FatalException } from '../lib/errors';
1516
import { runCommand } from '../lib/executor';
17+
import { createProjectFromType } from '../lib/project';
1618
import { prependNodeModulesBinToPath } from '../lib/shell';
1719
import { emoji } from '../lib/utils/emoji';
1820

@@ -28,7 +30,7 @@ interface CommonAppSchema {
2830
interface NewAppSchema extends CommonAppSchema {
2931
cloned: false;
3032
name: string;
31-
type: string;
33+
type: ProjectType;
3234
template: string;
3335
}
3436

@@ -198,7 +200,7 @@ ${chalk.cyan('[1]')}: ${chalk.bold('https://ionicframework.com/docs/cli/starters
198200
options['git'] = true;
199201
}
200202

201-
if (this.project) {
203+
if (this.project && !this.project.name) {
202204
const confirm = await this.env.prompt({
203205
type: 'confirm',
204206
name: 'confirm',
@@ -358,7 +360,7 @@ ${chalk.cyan('[1]')}: ${chalk.bold('https://ionicframework.com/docs/cli/starters
358360
this.schema = {
359361
cloned,
360362
name: inputs[0],
361-
type: projectType,
363+
type: projectType as ProjectType,
362364
template: inputs[1],
363365
projectId,
364366
projectDir,
@@ -428,21 +430,32 @@ ${chalk.cyan('[1]')}: ${chalk.bold('https://ionicframework.com/docs/cli/starters
428430
await this.downloadStarterTemplate(projectDir, starterTemplate);
429431
}
430432

433+
let project: IProject | undefined;
434+
435+
if (this.project && this.project.name && !this.schema.cloned) {
436+
// We're in a multi-app setup, so the new config file isn't wanted.
437+
await unlink(path.resolve(projectDir, 'ionic.config.json'));
438+
439+
project = await createProjectFromType(path.resolve(this.project.rootDirectory, PROJECT_FILE), projectId, this.env, this.schema.type);
440+
project.config.set('type', this.schema.type);
441+
project.config.set('root', path.relative(this.project.rootDirectory, projectDir));
442+
} else {
443+
project = await getProject(projectDir, undefined, this.env);
444+
}
445+
431446
// start is weird, once the project directory is created, it becomes a
432447
// "project" command and so we replace the `Project` instance that was
433448
// autogenerated when the CLI booted up. This has worked thus far?
434-
this.namespace.root.project = await getProject(projectDir, undefined, this.env);
449+
this.namespace.root.project = project;
435450

436451
if (!this.project) {
437452
throw new FatalException('Error while loading new project. Please report this error!');
438453
}
439454

440455
this.env.shell.alterPath = p => prependNodeModulesBinToPath(projectDir, p);
441456

442-
const shellOptions = { cwd: projectDir, stdio: 'inherit' };
443-
444457
if (!this.schema.cloned) {
445-
if (!options['cordova'] && !options['capacitor']) {
458+
if (typeof options['cordova'] === 'undefined' && !options['capacitor']) {
446459
const confirm = await this.env.prompt({
447460
type: 'confirm',
448461
name: 'confirm',
@@ -464,9 +477,12 @@ ${chalk.cyan('[1]')}: ${chalk.bold('https://ionicframework.com/docs/cli/starters
464477
}
465478

466479
await this.project.personalize({ name: this.schema.name, projectId, packageId });
480+
467481
this.env.log.nl();
468482
}
469483

484+
const shellOptions = { cwd: projectDir, stdio: 'inherit' };
485+
470486
if (options['deps']) {
471487
this.env.log.msg('Installing dependencies may take several minutes.');
472488
this.env.log.rawmsg(await getIonicDevAppText());

packages/ionic/src/definitions.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ export interface IProjectConfig {
232232
name: string;
233233
type?: ProjectType;
234234
pro_id?: string;
235+
root?: string;
235236

236237
readonly integrations: ProjectIntegrations;
237238
readonly hooks?: Record<HookName, string | string[] | undefined>;
@@ -242,16 +243,17 @@ export interface IProjectConfig {
242243
};
243244
}
244245

245-
export interface MultiProjectConfig {
246+
export interface IMultiProjectConfig {
246247
defaultProject?: string;
247248
projects: {
248249
[key: string]: IProjectConfig | undefined;
249250
};
250251
}
251252

252-
export type ProjectFile = IProjectConfig | MultiProjectConfig;
253+
export type ProjectFile = IProjectConfig | IMultiProjectConfig;
253254

254255
export interface IProject {
256+
readonly rootDirectory: string;
255257
readonly directory: string;
256258
readonly filePath: string;
257259
readonly name?: string;

packages/ionic/src/guards.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ import {
1313
GithubRepo,
1414
GithubRepoAssociation,
1515
ICommand,
16+
IMultiProjectConfig,
1617
IProjectConfig,
1718
IntegrationName,
1819
Login,
19-
MultiProjectConfig,
2020
Org,
2121
Response,
2222
SSHKey,
@@ -284,7 +284,7 @@ export function isProjectConfig(configFile: any): configFile is IProjectConfig {
284284
&& typeof configFile.projects === 'undefined';
285285
}
286286

287-
export function isMultiProjectConfig(configFile: any): configFile is MultiProjectConfig {
287+
export function isMultiProjectConfig(configFile: any): configFile is IMultiProjectConfig {
288288
return configFile
289289
&& typeof configFile.name === 'undefined'
290290
&& typeof configFile.projects === 'object';

packages/ionic/src/lib/project/angular/build.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ class AngularBuildCLI extends BuildCLI<AngularBuildOptions> {
117117
const integration = this.e.project.requireIntegration('cordova');
118118
args.platform = options.platform;
119119

120-
if (this.e.project.directory !== integration.root) {
120+
if (this.e.project.rootDirectory !== integration.root) {
121121
args.cordovaBasePath = integration.root;
122122
}
123123

packages/ionic/src/lib/project/angular/serve.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ export class AngularServeCLI extends ServeCLI<AngularServeOptions> {
148148
const integration = this.e.project.requireIntegration('cordova');
149149
args.platform = options.platform;
150150

151-
if (this.e.project.directory !== integration.root) {
151+
if (this.e.project.rootDirectory !== integration.root) {
152152
args.cordovaBasePath = integration.root;
153153
}
154154

packages/ionic/src/lib/project/index.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ export interface ProjectDeps {
138138
}
139139

140140
export abstract class Project implements IProject {
141-
readonly directory: string;
141+
readonly rootDirectory: string;
142142
abstract readonly type: ProjectType;
143143
protected originalConfigFile?: { [key: string]: any };
144144

@@ -157,7 +157,17 @@ export abstract class Project implements IProject {
157157

158158
protected readonly e: ProjectDeps
159159
) {
160-
this.directory = path.dirname(filePath);
160+
this.rootDirectory = path.dirname(filePath);
161+
}
162+
163+
get directory(): string {
164+
const root = this.config.get('root');
165+
166+
if (!root) {
167+
return this.rootDirectory;
168+
}
169+
170+
return path.resolve(this.rootDirectory, root);
161171
}
162172

163173
get config(): ProjectConfig {
@@ -317,7 +327,7 @@ export abstract class Project implements IProject {
317327
if (integration) {
318328
return {
319329
enabled: integration.enabled !== false,
320-
root: integration.root === undefined ? this.directory : path.resolve(this.directory, integration.root),
330+
root: integration.root === undefined ? this.directory : path.resolve(this.rootDirectory, integration.root),
321331
};
322332
}
323333
}

0 commit comments

Comments
 (0)