@teambit/application 1.0.108 → 1.0.109

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.
@@ -1,485 +0,0 @@
1
- import { MainRuntime, CLIMain, CLIAspect } from '@teambit/cli';
2
- import { compact, flatten, head } from 'lodash';
3
- import { AspectLoaderMain, AspectLoaderAspect } from '@teambit/aspect-loader';
4
- import { Slot, SlotRegistry, Harmony } from '@teambit/harmony';
5
- import WorkspaceAspect, { Workspace } from '@teambit/workspace';
6
- import { BitError } from '@teambit/bit-error';
7
- import WatcherAspect, { WatcherMain } from '@teambit/watcher';
8
- import { BuilderAspect, BuilderMain } from '@teambit/builder';
9
- import ScopeAspect, { ScopeMain } from '@teambit/scope';
10
- import { Logger, LoggerAspect, LoggerMain } from '@teambit/logger';
11
- import { EnvsAspect, EnvsMain } from '@teambit/envs';
12
- import ComponentAspect, { ComponentMain, ComponentID, Component } from '@teambit/component';
13
- import { ApplicationType } from './application-type';
14
- import { Application } from './application';
15
- import { DeploymentProvider } from './deployment-provider';
16
- import { AppNotFound } from './exceptions';
17
- import { ApplicationAspect } from './application.aspect';
18
- import { AppListCmdDeprecated } from './app-list.cmd';
19
- import { AppsBuildTask } from './build-application.task';
20
- import { RunCmd } from './run.cmd';
21
- import { AppService } from './application.service';
22
- import { AppCmd, AppListCmd } from './app.cmd';
23
- import { AppPlugin, BIT_APP_PATTERN } from './app.plugin';
24
- import { AppTypePlugin } from './app-type.plugin';
25
- import { AppContext } from './app-context';
26
- import { DeployTask } from './deploy.task';
27
-
28
- export type ApplicationTypeSlot = SlotRegistry<ApplicationType<unknown>[]>;
29
- export type ApplicationSlot = SlotRegistry<Application[]>;
30
- export type DeploymentProviderSlot = SlotRegistry<DeploymentProvider[]>;
31
-
32
- export type ApplicationAspectConfig = {
33
- /**
34
- * envs ids to load app types.
35
- */
36
- envs?: string[];
37
- };
38
-
39
- /**
40
- * Application meta data that is stored on the component on load if it's an application.
41
- */
42
- export type ApplicationMetadata = {
43
- appName: string;
44
- type?: string;
45
- };
46
-
47
- export type ServeAppOptions = {
48
- /**
49
- * default port range used to serve applications.
50
- */
51
- defaultPortRange?: [start: number, end: number];
52
-
53
- /**
54
- * determine whether to start the application in dev mode.
55
- */
56
- dev: boolean;
57
-
58
- /**
59
- * actively watch and compile the workspace (like the bit watch command)
60
- * @default true
61
- */
62
- watch?: boolean;
63
-
64
- /**
65
- * determine whether to start the application in server side mode.
66
- * @default false
67
- */
68
- ssr?: boolean;
69
-
70
- /**
71
- * exact port to run the app
72
- */
73
- port?: number;
74
- };
75
-
76
- export class ApplicationMain {
77
- constructor(
78
- private appSlot: ApplicationSlot,
79
- // TODO unused
80
- private appTypeSlot: ApplicationTypeSlot,
81
- private deploymentProviderSlot: DeploymentProviderSlot,
82
- private config: ApplicationAspectConfig,
83
- private envs: EnvsMain,
84
- private componentAspect: ComponentMain,
85
- private appService: AppService,
86
- private aspectLoader: AspectLoaderMain,
87
- private workspace: Workspace,
88
- private logger: Logger,
89
- private watcher: WatcherMain,
90
- private harmony: Harmony
91
- ) {}
92
-
93
- /**
94
- * register a new app.
95
- */
96
- registerApp(app: Application) {
97
- this.appSlot.register([app]);
98
- return this;
99
- }
100
-
101
- /**
102
- * list all registered apps.
103
- */
104
- listApps(): Application[] {
105
- return flatten(this.appSlot.values());
106
- }
107
-
108
- /**
109
- * map all apps by component ID.
110
- */
111
- mapApps() {
112
- return this.appSlot.toArray();
113
- }
114
-
115
- /**
116
- * list apps by a component id.
117
- */
118
- listAppsById(id?: ComponentID): Application[] | undefined {
119
- if (!id) return undefined;
120
- return this.appSlot.get(id.toString());
121
- }
122
-
123
- /**
124
- * get an application by a component id.
125
- */
126
- async getAppById(id: ComponentID) {
127
- const apps = await this.listAppsById(id);
128
- if (!apps) return undefined;
129
- return head(apps);
130
- }
131
-
132
- /**
133
- * calculate an application by a component.
134
- * This should be only used during the on component load slot
135
- */
136
- calculateAppByComponent(component: Component) {
137
- const apps = this.appSlot.get(component.id.toString());
138
- if (!apps) return undefined;
139
- return head(apps);
140
- }
141
-
142
- listAppTypes() {
143
- return flatten(this.appTypeSlot.values());
144
- }
145
-
146
- /**
147
- * @deprecated use `listAppsComponents` instead.
148
- * @returns
149
- */
150
- async listAppsFromComponents(): Promise<Component[]> {
151
- return this.listAppsComponents();
152
- }
153
-
154
- async listAppsComponents(): Promise<Component[]> {
155
- const components = await this.componentAspect.getHost().list();
156
- const appTypesPatterns = this.getAppPatterns();
157
- const appsComponents = components.filter((component) => this.hasAppTypePattern(component, appTypesPatterns));
158
- return appsComponents;
159
- }
160
-
161
- private hasAppTypePattern(component: Component, appTypesPatterns?: string[]): boolean {
162
- const patterns = appTypesPatterns || this.getAppPatterns();
163
- // has app plugin from registered types.
164
- const files = component.filesystem.byGlob(patterns);
165
- return !!files.length;
166
- }
167
-
168
- getAppPatterns() {
169
- const appTypes = this.listAppTypes();
170
- const appTypesPatterns = appTypes.map((appType) => {
171
- return this.getAppPattern(appType);
172
- });
173
-
174
- return appTypesPatterns.concat(BIT_APP_PATTERN);
175
- }
176
-
177
- async loadApps(): Promise<Application[]> {
178
- const apps = await this.listAppsComponents();
179
- const appTypesPatterns = this.getAppPatterns();
180
-
181
- const pluginsToLoad = apps.flatMap((appComponent) => {
182
- const files = appComponent.filesystem.byGlob(appTypesPatterns);
183
- return files.map((file) => file.path);
184
- });
185
-
186
- // const app = require(appPath);
187
- const appManifests = Promise.all(
188
- compact(
189
- pluginsToLoad.map(async (pluginPath) => {
190
- try {
191
- const isModule = await this.aspectLoader.isEsmModule(pluginPath);
192
- if (isModule) {
193
- const appManifest = await this.aspectLoader.loadEsm(pluginPath);
194
- return appManifest;
195
- }
196
- // eslint-disable-next-line
197
- const appManifest = require(pluginPath)?.default;
198
- return appManifest;
199
- } catch (err) {
200
- this.logger.error(`failed loading app manifest: ${pluginPath}`);
201
- return undefined;
202
- }
203
- })
204
- )
205
- );
206
-
207
- return appManifests;
208
- }
209
-
210
- async loadAppsFromComponent(component: Component, rootDir: string): Promise<Application[] | undefined> {
211
- const appTypesPatterns = this.getAppPatterns();
212
- const isApp = this.hasAppTypePattern(component, appTypesPatterns);
213
- if (!isApp) return undefined;
214
-
215
- const allPluginDefs = this.aspectLoader.getPluginDefs();
216
-
217
- const appsPluginDefs = allPluginDefs.filter((pluginDef) => {
218
- return appTypesPatterns.includes(pluginDef.pattern.toString());
219
- });
220
- // const fileResolver = this.aspectLoader.pluginFileResolver(component, rootDir);
221
-
222
- const plugins = this.aspectLoader.getPluginsFromDefs(component, rootDir, appsPluginDefs);
223
- let loadedPlugins;
224
- if (plugins.has()) {
225
- loadedPlugins = await plugins.load(MainRuntime.name);
226
- await this.aspectLoader.loadExtensionsByManifests([loadedPlugins], { seeders: [component.id.toString()] });
227
- }
228
-
229
- const listAppsById = this.listAppsById(component.id);
230
- return listAppsById;
231
- }
232
-
233
- /**
234
- * get an app.
235
- */
236
- getApp(appName: string, id?: ComponentID): Application | undefined {
237
- const apps = id ? this.listAppsById(id) : this.listApps();
238
- if (!apps) return undefined;
239
- return apps.find((app) => app.name === appName);
240
- }
241
-
242
- getAppByNameOrId(appNameOrId: string): Application | undefined {
243
- const byName = this.getApp(appNameOrId);
244
- if (byName) return byName;
245
- const byId = this.appSlot.get(appNameOrId);
246
- if (!byId || !byId.length) return undefined;
247
- if (byId.length > 1) {
248
- throw new BitError(
249
- `unable to figure out what app to retrieve. the id "${appNameOrId}" has more than one app. please use the app-name`
250
- );
251
- }
252
- return byId[0];
253
- }
254
-
255
- getAppPattern(appType: ApplicationType<unknown>) {
256
- if (appType.globPattern) return appType.globPattern;
257
- return `*.${appType.name}.*`;
258
- }
259
-
260
- /**
261
- * registers a new app and sets a plugin for it.
262
- */
263
- registerAppType<T>(...appTypes: Array<ApplicationType<T>>) {
264
- const plugins = appTypes.map((appType) => {
265
- return new AppTypePlugin(this.getAppPattern(appType), appType, this.appSlot);
266
- });
267
-
268
- this.aspectLoader.registerPlugins(plugins);
269
- this.appTypeSlot.register(appTypes);
270
- return this;
271
- }
272
-
273
- /**
274
- * get an app AspectId.
275
- */
276
- getAppAspect(appName: string): string | undefined {
277
- return this.appSlot.toArray().find(([, apps]) => apps.find((app) => app.name === appName))?.[0];
278
- }
279
-
280
- /**
281
- * get app to throw.
282
- */
283
- getAppOrThrow(appName: string): Application {
284
- const app = this.getAppByNameOrId(appName);
285
- if (!app) throw new AppNotFound(appName);
286
- return app;
287
- }
288
-
289
- defaultOpts: ServeAppOptions = {
290
- dev: false,
291
- ssr: false,
292
- watch: true,
293
- defaultPortRange: [3100, 3500],
294
- };
295
- private computeOptions(opts: Partial<ServeAppOptions> = {}) {
296
- return {
297
- ...this.defaultOpts,
298
- ...opts,
299
- };
300
- }
301
-
302
- async loadAppsToSlot() {
303
- const apps = await this.loadApps();
304
- this.appSlot.register(apps);
305
- return this;
306
- }
307
-
308
- async runApp(appName: string, options?: ServeAppOptions) {
309
- options = this.computeOptions(options);
310
- const app = this.getAppOrThrow(appName);
311
- const context = await this.createAppContext(app.name, options.port);
312
- if (!context) throw new AppNotFound(appName);
313
-
314
- const instance = await app.run(context);
315
- if (options.watch) {
316
- this.watcher
317
- .watch({
318
- preCompile: false,
319
- compile: true,
320
- })
321
- .catch((err) => {
322
- // don't throw an error, we don't want to break the "run" process
323
- this.logger.error(`compilation failed`, err);
324
- });
325
- }
326
-
327
- const isOldApi = typeof instance === 'number';
328
- const port = isOldApi ? instance : instance?.port;
329
-
330
- return { app, port, errors: undefined, isOldApi };
331
- }
332
-
333
- /**
334
- * get the component ID of a certain app.
335
- */
336
- async getAppIdOrThrow(appName: string) {
337
- const maybeApp = this.appSlot.toArray().find(([, apps]) => {
338
- return apps.find((app) => app.name === appName);
339
- });
340
-
341
- if (!maybeApp) throw new AppNotFound(appName);
342
-
343
- const host = this.componentAspect.getHost();
344
- return host.resolveComponentId(maybeApp[0]);
345
- }
346
-
347
- private async createAppContext(appName: string, port?: number): Promise<AppContext> {
348
- const host = this.componentAspect.getHost();
349
- // const components = await host.list();
350
- const id = await this.getAppIdOrThrow(appName);
351
- // const component = components.find((c) => c.id.isEqual(id));
352
- const component = await host.get(id);
353
- if (!component) throw new AppNotFound(appName);
354
-
355
- const env = await this.envs.createEnvironment([component]);
356
- const res = await env.run(this.appService);
357
- const context = res.results[0].data;
358
- if (!context) throw new AppNotFound(appName);
359
- const hostRootDir = await this.workspace.getComponentPackagePath(component);
360
- const workspaceComponentDir = this.workspace.componentDir(component.id);
361
-
362
- const appContext = new AppContext(
363
- appName,
364
- this.harmony,
365
- context.dev,
366
- component,
367
- this.workspace.path,
368
- context,
369
- hostRootDir,
370
- port,
371
- workspaceComponentDir
372
- );
373
- return appContext;
374
- }
375
-
376
- async createAppBuildContext(id: ComponentID, appName: string, capsuleRootDir: string, rootDir?: string) {
377
- const host = this.componentAspect.getHost();
378
- // const components = await host.list();
379
- // const component = components.find((c) => c.id.isEqual(id));
380
- const component = await host.get(id);
381
- if (!component) throw new AppNotFound(appName);
382
-
383
- const env = await this.envs.createEnvironment([component]);
384
- const res = await env.run(this.appService);
385
- const context = res.results[0].data;
386
- if (!context) throw new AppNotFound(appName);
387
-
388
- const appContext = new AppContext(
389
- appName,
390
- this.harmony,
391
- context.dev,
392
- component,
393
- capsuleRootDir,
394
- context,
395
- rootDir,
396
- undefined,
397
- undefined
398
- );
399
- return appContext;
400
- }
401
-
402
- static runtime = MainRuntime;
403
- static dependencies = [
404
- CLIAspect,
405
- LoggerAspect,
406
- BuilderAspect,
407
- EnvsAspect,
408
- ComponentAspect,
409
- AspectLoaderAspect,
410
- WorkspaceAspect,
411
- WatcherAspect,
412
- ScopeAspect,
413
- ];
414
-
415
- static slots = [
416
- Slot.withType<ApplicationType<unknown>[]>(),
417
- Slot.withType<Application[]>(),
418
- Slot.withType<DeploymentProvider[]>(),
419
- ];
420
-
421
- static async provider(
422
- [cli, loggerAspect, builder, envs, component, aspectLoader, workspace, watcher, scope]: [
423
- CLIMain,
424
- LoggerMain,
425
- BuilderMain,
426
- EnvsMain,
427
- ComponentMain,
428
- AspectLoaderMain,
429
- Workspace,
430
- WatcherMain,
431
- ScopeMain
432
- ],
433
- config: ApplicationAspectConfig,
434
- [appTypeSlot, appSlot, deploymentProviderSlot]: [ApplicationTypeSlot, ApplicationSlot, DeploymentProviderSlot],
435
- harmony: Harmony
436
- ) {
437
- const logger = loggerAspect.createLogger(ApplicationAspect.id);
438
- const appService = new AppService();
439
- const application = new ApplicationMain(
440
- appSlot,
441
- appTypeSlot,
442
- deploymentProviderSlot,
443
- config,
444
- envs,
445
- component,
446
- appService,
447
- aspectLoader,
448
- workspace,
449
- logger,
450
- watcher,
451
- harmony
452
- );
453
- appService.registerAppType = application.registerAppType.bind(application);
454
- const appCmd = new AppCmd();
455
- appCmd.commands = [new AppListCmd(application), new RunCmd(application, logger)];
456
- aspectLoader.registerPlugins([new AppPlugin(appSlot)]);
457
- builder.registerBuildTasks([new AppsBuildTask(application)]);
458
- builder.registerSnapTasks([new DeployTask(application, builder)]);
459
- builder.registerTagTasks([new DeployTask(application, builder)]);
460
- envs.registerService(appService);
461
- cli.registerGroup('apps', 'Applications');
462
- cli.register(new RunCmd(application, logger), new AppListCmdDeprecated(application), appCmd);
463
- // cli.registerOnStart(async () => {
464
- // await application.loadAppsToSlot();
465
- // });
466
- const calcAppOnLoad = async (loadedComponent): Promise<ApplicationMetadata | undefined> => {
467
- const app = application.calculateAppByComponent(loadedComponent);
468
- if (!app) return undefined;
469
- return {
470
- appName: app.name,
471
- type: app.applicationType,
472
- };
473
- };
474
- if (workspace) {
475
- workspace.registerOnComponentLoad(calcAppOnLoad);
476
- }
477
- if (scope) {
478
- scope.registerOnCompAspectReCalc(calcAppOnLoad);
479
- }
480
-
481
- return application;
482
- }
483
- }
484
-
485
- ApplicationAspect.addRuntime(ApplicationMain);
@@ -1,32 +0,0 @@
1
- import { EnvService, Env, EnvContext, ServiceTransformationMap, ExecutionContext } from '@teambit/envs';
2
- import { ApplicationType } from './application-type';
3
-
4
- type ApplicationTransformationMap = ServiceTransformationMap & {
5
- getAppTypes: () => ApplicationType<any>[];
6
- };
7
- export class AppService implements EnvService<any> {
8
- name = 'application';
9
- registerAppType: (...appType: Array<ApplicationType<any>>) => void;
10
-
11
- async run(context: ExecutionContext) {
12
- const appContext = Object.assign(context, {
13
- dev: true,
14
- errors: [],
15
- });
16
-
17
- return appContext;
18
- }
19
-
20
- transform(env: Env, context: EnvContext): ApplicationTransformationMap | undefined {
21
- // Old env
22
- if (!env?.apps) return undefined;
23
- const appTypesList = env.apps()(context);
24
- const appTypes = appTypesList.compute();
25
- this.registerAppType(...appTypes);
26
- return {
27
- getAppTypes: () => {
28
- return appTypes;
29
- },
30
- };
31
- }
32
- }
package/application.ts DELETED
@@ -1,41 +0,0 @@
1
- import { AppContext } from './app-context';
2
- import { AppDeployContext } from './app-deploy-context';
3
- import { AppBuildContext } from './app-build-context';
4
- import { AppBuildResult } from './app-build-result';
5
- import { ApplicationDeployment, ApplicationInstance } from './app-instance';
6
-
7
- export type DeployFn = (context: AppDeployContext) => Promise<ApplicationDeployment | void | undefined>;
8
-
9
- export type BuildFn = (context: AppBuildContext) => Promise<AppBuildResult>;
10
-
11
- export type AppResult = {
12
- port?: number;
13
- errors?: Error[];
14
- };
15
-
16
- export interface Application {
17
- /**
18
- * name of the application. e.g. ripple-ci.
19
- */
20
- name: string;
21
-
22
- /**
23
- * run the application.
24
- */
25
- run(context: AppContext): Promise<ApplicationInstance | number>;
26
-
27
- /**
28
- * build the application.
29
- */
30
- build?: BuildFn;
31
-
32
- /**
33
- * application deployment. this is a build task.
34
- */
35
- deploy?: DeployFn;
36
-
37
- /**
38
- * Type of the application
39
- */
40
- applicationType?: string;
41
- }
package/apps-env-type.ts DELETED
@@ -1,9 +0,0 @@
1
- import { EnvHandler } from '@teambit/envs';
2
- import { AppTypeList } from './app-type-list';
3
-
4
- export interface AppsEnv {
5
- /**
6
- * return a template list instance.
7
- */
8
- apps?(): EnvHandler<AppTypeList>;
9
- }