Skip to content

Commit 0e5b546

Browse files
committed
feat: use new app type format
1 parent 3639292 commit 0e5b546

File tree

24 files changed

+219
-206
lines changed

24 files changed

+219
-206
lines changed

angular/app-types/angular-app-type/angular-app-options.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
AngularEnvOptions,
23
ApplicationOptions,
34
BrowserOptions,
45
DevServerOptions
@@ -52,4 +53,9 @@ export type AngularAppOptions = {
5253
* Angular options for `bit run`
5354
*/
5455
angularServeOptions: (BrowserOptions & DevServerOptions) | (ApplicationOptions & DevServerOptions);
56+
57+
/**
58+
* Env-specific options depending on the version of Angular used.
59+
*/
60+
ngEnvOptions: AngularEnvOptions;
5561
};
Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,27 @@
1-
import { GenericAngularEnv, getWorkspace, NG_APP_NAME } from '@bitdev/angular.dev-services.common';
1+
import { NG_APP_NAME } from '@bitdev/angular.dev-services.common';
22
import { Application, ApplicationType } from '@teambit/application';
3-
import { DependencyResolverAspect, DependencyResolverMain } from '@teambit/dependency-resolver';
4-
import { EnvContext, EnvHandler } from '@teambit/envs';
5-
import { Logger } from '@teambit/logger';
6-
import { Workspace } from '@teambit/workspace';
3+
import { EnvHandler } from '@teambit/envs';
74
import { AngularAppOptions } from './angular-app-options';
85
import { AngularApp } from './angular.application';
96

107
interface AngularAppTypeOptions {
118
name?: string;
12-
angularEnv: GenericAngularEnv;
139
}
1410

1511
export class AngularAppType implements ApplicationType<AngularAppOptions> {
16-
constructor(readonly name: string, private angularEnv: GenericAngularEnv, private context: EnvContext, private depsResolver: DependencyResolverMain, private logger: Logger, private workspace?: Workspace) {
17-
}
12+
constructor(readonly name: string) {}
1813

1914
createApp(options: AngularAppOptions): Application {
20-
return new AngularApp(
21-
this.angularEnv,
22-
this.context,
23-
options,
24-
this.depsResolver,
25-
this.logger,
26-
this.workspace
27-
);
15+
return new AngularApp({
16+
...options,
17+
name: this.name
18+
});
2819
}
2920

3021
static from(options: AngularAppTypeOptions): EnvHandler<AngularAppType> {
31-
return (context: EnvContext) => {
22+
return () => {
3223
const name = options.name || NG_APP_NAME;
33-
const depsResolver = context.getAspect<DependencyResolverMain>(DependencyResolverAspect.id);
34-
const workspace = getWorkspace(context);
35-
const logger = context.createLogger(name);
36-
return new AngularAppType(name, options.angularEnv, context, depsResolver, logger, workspace);
24+
return new AngularAppType(name);
3725
};
3826
}
3927
}
Lines changed: 93 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
11
import { VERSION } from '@angular/cli';
22
import {
33
ApplicationOptions,
4-
GenericAngularEnv,
4+
getWorkspace,
5+
NG_APP_NAME,
56
normalizePath
67
} from '@bitdev/angular.dev-services.common';
8+
import { AngularPreview } from '@bitdev/angular.dev-services.preview.preview';
79
import {
8-
AngularPreview,
9-
BundlerProvider,
10-
DevServerProvider
11-
} from '@bitdev/angular.dev-services.preview.preview';
12-
import { AppBuildContext, AppContext, Application } from '@teambit/application';
13-
import { Bundler, BundlerContext, DevServer, DevServerContext } from '@teambit/bundler';
10+
AppBuildContext,
11+
AppContext,
12+
Application,
13+
ApplicationInstance
14+
} from '@teambit/application';
15+
import { Bundler, BundlerContext, DevServerContext } from '@teambit/bundler';
1416
import { Component } from '@teambit/component';
15-
import { DependencyResolverMain } from '@teambit/dependency-resolver';
17+
import { DependencyResolverAspect, DependencyResolverMain } from '@teambit/dependency-resolver';
1618
import { EnvContext, EnvHandler } from '@teambit/envs';
1719
import { CACHE_ROOT } from '@teambit/legacy/dist/constants';
18-
import { Logger } from '@teambit/logger';
1920
import { Preview } from '@teambit/preview';
2021
import { Port } from '@teambit/toolbox.network.get-port';
2122
import { Workspace } from '@teambit/workspace';
@@ -35,34 +36,28 @@ const writeHash = new Map<string, string>();
3536

3637
export class AngularApp implements Application {
3738
readonly name: string;
38-
39-
readonly preview: EnvHandler<Preview>;
40-
41-
readonly tempFolder: string;
42-
43-
readonly tsconfigPath: string;
39+
readonly idName: string;
4440

4541
constructor(
46-
private angularEnv: GenericAngularEnv,
47-
private envContext: EnvContext,
48-
readonly options: AngularAppOptions,
49-
private depsResolver: DependencyResolverMain,
50-
private logger: Logger,
51-
private workspace?: Workspace
42+
readonly options: AngularAppOptions
5243
) {
53-
this.name = options.name;
44+
this.name = options.name || NG_APP_NAME;
45+
this.idName = `bitdev.angular/${ this.name }`;
46+
}
5447

55-
const idName = `bitdev.angular/${ this.name }`;
56-
this.tempFolder = workspace?.getTempDir(idName) || join(CACHE_ROOT, idName);
57-
if (!existsSync(this.tempFolder)) {
58-
mkdirSync(this.tempFolder, { recursive: true });
59-
}
48+
readonly publicDir = 'public';
6049

61-
this.tsconfigPath = normalizePath(join(this.tempFolder, `tsconfig/tsconfig-${ Date.now() }.json`));
62-
this.preview = this.getPreview();
50+
private getTempFolder(workspace?: Workspace): string {
51+
const tempFolder = workspace?.getTempDir(this.idName) || join(CACHE_ROOT, this.idName);
52+
if (!existsSync(tempFolder)) {
53+
mkdirSync(tempFolder, { recursive: true });
54+
}
55+
return tempFolder;
6356
}
6457

65-
readonly publicDir = 'public';
58+
private getTsconfigPath(tempFolder: string): string {
59+
return normalizePath(join(tempFolder, `tsconfig/tsconfig-${ Date.now() }.json`));
60+
}
6661

6762
private getPublicDir(artifactsDir: string) {
6863
return join(artifactsDir, this.name);
@@ -95,35 +90,33 @@ export class AngularApp implements Application {
9590
});
9691
}
9792

98-
private getPreview(): EnvHandler<Preview> {
99-
const ngEnvOptions = this.angularEnv.getNgEnvOptions();
100-
101-
const angularServeOptions: any = Object.assign(cloneDeep(this.options.angularServeOptions), { tsConfig: this.tsconfigPath });
102-
const angularBuildOptions: any = Object.assign(cloneDeep(this.options.angularBuildOptions), { tsConfig: this.tsconfigPath });
93+
private getPreview(tsconfigPath: string): EnvHandler<Preview> {
94+
const angularServeOptions: any = Object.assign(cloneDeep(this.options.angularServeOptions), { tsConfig: tsconfigPath });
95+
const angularBuildOptions: any = Object.assign(cloneDeep(this.options.angularBuildOptions), { tsConfig: tsconfigPath });
10396

10497
return AngularPreview.from({
10598
webpackServeTransformers: this.options.webpackServeTransformers,
10699
webpackBuildTransformers: this.options.webpackBuildTransformers,
107100
angularServeOptions,
108101
angularBuildOptions,
109-
ngEnvOptions,
102+
ngEnvOptions: this.options.ngEnvOptions,
110103
sourceRoot: this.options.sourceRoot,
111104
});
112105

113106
}
114107

115-
private generateTsConfig(bitCmps: Component[], appRootPath: string, tsconfigPath: string, serverEntry?: string): void {
116-
const tsconfigJSON: JsonObject = readConfigFile(tsconfigPath, sys.readFile).config;
108+
private generateTsConfig(bitCmps: Component[], appRootPath: string, appTsconfigPath: string, tsconfigPath: string, depsResolver: DependencyResolverMain, workspace?: Workspace, serverEntry?: string): void {
109+
const tsconfigJSON: JsonObject = readConfigFile(appTsconfigPath, sys.readFile).config;
117110

118111
// Add the paths to tsconfig to remap bit components to local folders
119112
tsconfigJSON.compilerOptions.paths = tsconfigJSON.compilerOptions.paths || {};
120113
bitCmps.forEach((dep: Component) => {
121-
let componentDir = this.workspace?.componentDir(dep.id, {
114+
let componentDir = workspace?.componentDir(dep.id, {
122115
ignoreVersion: true
123116
});
124117
if (componentDir) {
125118
componentDir = normalizePath(componentDir);
126-
const pkgName = this.depsResolver.getPackageName(dep);
119+
const pkgName = depsResolver.getPackageName(dep);
127120
// TODO we should find a way to use the real entry file based on the component config because people can change it
128121
if (existsSync(join(componentDir, 'public-api.ts'))) {
129122
tsconfigJSON.compilerOptions.paths[pkgName] = [`${ componentDir }/public-api.ts`, `${ componentDir }`];
@@ -136,93 +129,114 @@ export class AngularApp implements Application {
136129
tsconfigJSON.files.push(serverEntry);
137130
}
138131

139-
const tsconfigContent = expandIncludeExclude(tsconfigJSON, this.tsconfigPath, [appRootPath]);
132+
const tsconfigContent = expandIncludeExclude(tsconfigJSON, tsconfigPath, [appRootPath]);
140133
const hash = objectHash(tsconfigContent);
141134
// write only if link has changed (prevents triggering fs watches)
142-
if (writeHash.get(this.tsconfigPath) !== hash) {
143-
outputJsonSync(this.tsconfigPath, tsconfigContent, { spaces: 2 });
144-
writeHash.set(this.tsconfigPath, hash);
135+
if (writeHash.get(tsconfigPath) !== hash) {
136+
outputJsonSync(tsconfigPath, tsconfigContent, { spaces: 2 });
137+
writeHash.set(tsconfigPath, hash);
145138
}
146139
}
147140

148-
async getDevServer(context: AppContext, appRootPath: string): Promise<DevServer> {
149-
const devServerContext = this.getDevServerContext(context, appRootPath);
150-
const preview = this.preview(this.envContext);
151-
152-
return preview.getDevServer(devServerContext)(this.envContext);
141+
/**
142+
* Transform the app context into env context to make typescript happy.
143+
* Technically, we only use methods that exist in both interfaces, so it's fine.
144+
*/
145+
private getEnvContext(context: AppContext | AppBuildContext): EnvContext {
146+
return context as any as EnvContext;
153147
}
154148

155149
// TODO: fix return type once bit has a new stable version
156-
async run(context: AppContext): Promise<any> {
157-
assert(this.workspace, 'Workspace is not defined');
150+
async run(context: AppContext): Promise<ApplicationInstance> {
151+
const depsResolver = context.getAspect<DependencyResolverMain>(DependencyResolverAspect.id);
152+
assert(depsResolver, 'Dependency resolver is not defined');
153+
const workspace = getWorkspace(context);
154+
assert(workspace, 'Workspace is not defined');
155+
const logger = context.createLogger(this.name);
158156
const port = context.port || (await Port.getPortFromRange(this.options.portRange || [3000, 4000]));
159-
const appRootPath = this.workspace.componentDir(context.appComponent.id, {
157+
const appRootPath = workspace.componentDir(context.appComponent.id, {
160158
ignoreVersion: true
161159
});
162-
const tsconfigPath = join(appRootPath, this.options.angularServeOptions.tsConfig);
163-
const workspaceCmpsIDs = await this.workspace.listIds();
164-
const bitCmps = await this.workspace.getMany(workspaceCmpsIDs);
165-
this.generateTsConfig(bitCmps, appRootPath, tsconfigPath);
160+
const appTsconfigPath = join(appRootPath, this.options.angularServeOptions.tsConfig);
161+
const workspaceCmpsIDs = await workspace.listIds();
162+
const bitCmps = await workspace.getMany(workspaceCmpsIDs);
163+
const tempFolder = this.getTempFolder(workspace);
164+
const tsconfigPath = this.getTsconfigPath(tempFolder);
165+
this.generateTsConfig(bitCmps, appRootPath, appTsconfigPath, tsconfigPath, depsResolver, workspace);
166166

167167
if (Number(VERSION.major) >= 16) {
168168
await serveApplication({
169169
angularOptions: {
170170
...this.options.angularBuildOptions as ApplicationOptions,
171-
tsConfig: this.tsconfigPath
171+
tsConfig: tsconfigPath
172172
},
173173
sourceRoot: this.options.sourceRoot || 'src',
174174
workspaceRoot: appRootPath,
175175
port,
176-
logger: this.logger,
177-
tempFolder: this.tempFolder
176+
logger: logger,
177+
tempFolder: tempFolder
178178
});
179-
return port;
180-
}
181-
182-
const devServer = await this.getDevServer(context, appRootPath);
183-
await devServer.listen(port);
184-
return port;
185-
}
179+
} else {
180+
const devServerContext = this.getDevServerContext(context, appRootPath);
181+
const envContext = this.getEnvContext(context);
182+
const preview = this.getPreview(tsconfigPath)(envContext);
186183

187-
async getBundler(context: AppBuildContext): Promise<Bundler> {
188-
if (this.options.bundler) {
189-
return this.options.bundler;
184+
const devServer = await preview.getDevServer(devServerContext)(envContext);
185+
await devServer.listen(port);
190186
}
191187

192-
const bundlerContext = this.getBundlerContext(context);
193-
const preview = this.preview(this.envContext);
194-
195-
return preview.getBundler(bundlerContext)(this.envContext);
188+
return {
189+
appName: this.name,
190+
port
191+
};
196192
}
197193

198194
async build(context: AppBuildContext): Promise<AngularAppBuildResult> {
199195
const { capsule } = context;
196+
const depsResolver = context.getAspect<DependencyResolverMain>(DependencyResolverAspect.id);
197+
assert(depsResolver, 'Dependency resolver is not defined');
198+
const logger = context.createLogger(this.name);
200199
const outputPath = this.getPublicDir(context.artifactsDir);
201200
const appRootPath = capsule.path;
202-
const tsconfigPath = join(appRootPath, this.options.angularBuildOptions.tsConfig);
201+
const appTsconfigPath = join(appRootPath, this.options.angularBuildOptions.tsConfig);
203202
const appOptions = this.options.angularBuildOptions as ApplicationOptions;
204203
const entryServer = appOptions.ssr && Number(VERSION.major) >= 17 ? './entry.server.ts' : undefined;
205-
this.generateTsConfig([capsule.component], appRootPath, tsconfigPath, entryServer);
204+
const tempFolder = this.getTempFolder();
205+
const tsconfigPath = this.getTsconfigPath(tempFolder);
206+
this.generateTsConfig([capsule.component], appRootPath, appTsconfigPath, tsconfigPath, depsResolver, undefined, entryServer);
206207

207208
if (!this.options.bundler && Number(VERSION.major) >= 16) {
208209
await buildApplication({
209210
angularOptions: {
210211
...appOptions,
211-
tsConfig: this.tsconfigPath
212+
tsConfig: tsconfigPath
212213
},
213214
outputPath,
214215
sourceRoot: this.options.sourceRoot || 'src',
215216
workspaceRoot: context.capsule.path,
216-
logger: this.logger,
217-
tempFolder: this.tempFolder,
217+
logger: logger,
218+
tempFolder: tempFolder,
218219
entryServer
219220
});
220221
} else {
221-
const bundler = await this.getBundler(context);
222+
let bundler: Bundler;
223+
if (this.options.bundler) {
224+
bundler = this.options.bundler;
225+
} else {
226+
const bundlerContext = this.getBundlerContext(context);
227+
const envContext = this.getEnvContext(context);
228+
const preview = this.getPreview(tsconfigPath)(envContext);
229+
230+
bundler = await preview.getBundler(bundlerContext)(envContext);
231+
}
222232
await bundler.run();
223233
}
224234
return {
225235
publicDir: outputPath
226236
};
227237
}
238+
239+
static from(options: AngularAppOptions): Application {
240+
return new AngularApp(options);
241+
}
228242
}

angular/app-types/angular-app-type/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ export { AngularAppType } from './angular.app-type';
22
export type { AngularDeployContext } from './deploy-context';
33
export type { AngularAppOptions } from './angular-app-options';
44
export { NG_APP_NAME, NG_APP_PATTERN } from '@bitdev/angular.dev-services.common';
5+
export { AngularApp } from './angular.application';

angular/devkit/common/utils.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import normalize from 'normalize-path';
1414
import objectHash from 'object-hash';
1515
import { dirname, join, posix, resolve } from 'path';
1616

17-
export const NG_APP_NAME = 'ng-app';
17+
export const NG_APP_NAME = 'bit-app';
1818
export const NG_APP_PATTERN = `*.${ NG_APP_NAME }.*`;
1919

2020
export enum BundlerSetup {
@@ -33,7 +33,7 @@ export function componentIsApp(component: Component, application: ApplicationMai
3333
/**
3434
* Returns the workspace instance from the context, if it's available, or undefined otherwise.
3535
*/
36-
export function getWorkspace(context: EnvContext): Workspace | undefined {
36+
export function getWorkspace(context: EnvContext | AppContext): Workspace | undefined {
3737
// TODO: replace this try catch with context.hasAspect once it's available from harmony
3838
try {
3939
return context.getAspect<Workspace>(WorkspaceAspect.id);
@@ -115,7 +115,7 @@ export function cmpIdToPkgName(componentId: ComponentID) {
115115
return `@${ partsToJoin.join('.') }`;
116116
}
117117

118-
export function isBuildContext(context: DevServerContext | BundlerContext): context is BundlerContext {
118+
export function isBuildContext(context: any): context is BundlerContext {
119119
return (context as BundlerContext).capsuleNetwork !== undefined;
120120
}
121121

@@ -169,7 +169,7 @@ export function generateTsConfig(
169169
* Generates the tsconfig to load the preview app with compositions dynamically.
170170
*/
171171
export function writeTsconfig(
172-
context: DevServerContext | BundlerContext,
172+
context: DevServerContext | BundlerContext | AppContext | AppBuildContext,
173173
rootPath: string,
174174
tempFolder: string,
175175
application: ApplicationMain,

angular/devkit/preview/preview/angular-preview.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,8 @@ export class AngularPreview implements Preview {
139139
getDevEnvId() {
140140
const objToHash = {
141141
webpack: this.ngEnvOptions.webpackModulePath,
142-
webpackDevServer: this.ngEnvOptions.webpackDevServerModulePath
142+
webpackDevServer: this.ngEnvOptions.webpackDevServerModulePath,
143+
transformers: this.webpackServeTransformers
143144
};
144145
return objectHash(objToHash);
145146
}

0 commit comments

Comments
 (0)