1
1
import { VERSION } from '@angular/cli' ;
2
2
import {
3
3
ApplicationOptions ,
4
- GenericAngularEnv ,
4
+ getWorkspace ,
5
+ NG_APP_NAME ,
5
6
normalizePath
6
7
} from '@bitdev/angular.dev-services.common' ;
8
+ import { AngularPreview } from '@bitdev/angular.dev-services.preview.preview' ;
7
9
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' ;
14
16
import { Component } from '@teambit/component' ;
15
- import { DependencyResolverMain } from '@teambit/dependency-resolver' ;
17
+ import { DependencyResolverAspect , DependencyResolverMain } from '@teambit/dependency-resolver' ;
16
18
import { EnvContext , EnvHandler } from '@teambit/envs' ;
17
19
import { CACHE_ROOT } from '@teambit/legacy/dist/constants' ;
18
- import { Logger } from '@teambit/logger' ;
19
20
import { Preview } from '@teambit/preview' ;
20
21
import { Port } from '@teambit/toolbox.network.get-port' ;
21
22
import { Workspace } from '@teambit/workspace' ;
@@ -35,34 +36,28 @@ const writeHash = new Map<string, string>();
35
36
36
37
export class AngularApp implements Application {
37
38
readonly name : string ;
38
-
39
- readonly preview : EnvHandler < Preview > ;
40
-
41
- readonly tempFolder : string ;
42
-
43
- readonly tsconfigPath : string ;
39
+ readonly idName : string ;
44
40
45
41
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
52
43
) {
53
- this . name = options . name ;
44
+ this . name = options . name || NG_APP_NAME ;
45
+ this . idName = `bitdev.angular/${ this . name } ` ;
46
+ }
54
47
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' ;
60
49
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 ;
63
56
}
64
57
65
- readonly publicDir = 'public' ;
58
+ private getTsconfigPath ( tempFolder : string ) : string {
59
+ return normalizePath ( join ( tempFolder , `tsconfig/tsconfig-${ Date . now ( ) } .json` ) ) ;
60
+ }
66
61
67
62
private getPublicDir ( artifactsDir : string ) {
68
63
return join ( artifactsDir , this . name ) ;
@@ -95,35 +90,33 @@ export class AngularApp implements Application {
95
90
} ) ;
96
91
}
97
92
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 } ) ;
103
96
104
97
return AngularPreview . from ( {
105
98
webpackServeTransformers : this . options . webpackServeTransformers ,
106
99
webpackBuildTransformers : this . options . webpackBuildTransformers ,
107
100
angularServeOptions,
108
101
angularBuildOptions,
109
- ngEnvOptions,
102
+ ngEnvOptions : this . options . ngEnvOptions ,
110
103
sourceRoot : this . options . sourceRoot ,
111
104
} ) ;
112
105
113
106
}
114
107
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 ;
117
110
118
111
// Add the paths to tsconfig to remap bit components to local folders
119
112
tsconfigJSON . compilerOptions . paths = tsconfigJSON . compilerOptions . paths || { } ;
120
113
bitCmps . forEach ( ( dep : Component ) => {
121
- let componentDir = this . workspace ?. componentDir ( dep . id , {
114
+ let componentDir = workspace ?. componentDir ( dep . id , {
122
115
ignoreVersion : true
123
116
} ) ;
124
117
if ( componentDir ) {
125
118
componentDir = normalizePath ( componentDir ) ;
126
- const pkgName = this . depsResolver . getPackageName ( dep ) ;
119
+ const pkgName = depsResolver . getPackageName ( dep ) ;
127
120
// TODO we should find a way to use the real entry file based on the component config because people can change it
128
121
if ( existsSync ( join ( componentDir , 'public-api.ts' ) ) ) {
129
122
tsconfigJSON . compilerOptions . paths [ pkgName ] = [ `${ componentDir } /public-api.ts` , `${ componentDir } ` ] ;
@@ -136,93 +129,114 @@ export class AngularApp implements Application {
136
129
tsconfigJSON . files . push ( serverEntry ) ;
137
130
}
138
131
139
- const tsconfigContent = expandIncludeExclude ( tsconfigJSON , this . tsconfigPath , [ appRootPath ] ) ;
132
+ const tsconfigContent = expandIncludeExclude ( tsconfigJSON , tsconfigPath , [ appRootPath ] ) ;
140
133
const hash = objectHash ( tsconfigContent ) ;
141
134
// 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 ) ;
145
138
}
146
139
}
147
140
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 ;
153
147
}
154
148
155
149
// 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 ) ;
158
156
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 , {
160
158
ignoreVersion : true
161
159
} ) ;
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 ) ;
166
166
167
167
if ( Number ( VERSION . major ) >= 16 ) {
168
168
await serveApplication ( {
169
169
angularOptions : {
170
170
...this . options . angularBuildOptions as ApplicationOptions ,
171
- tsConfig : this . tsconfigPath
171
+ tsConfig : tsconfigPath
172
172
} ,
173
173
sourceRoot : this . options . sourceRoot || 'src' ,
174
174
workspaceRoot : appRootPath ,
175
175
port,
176
- logger : this . logger ,
177
- tempFolder : this . tempFolder
176
+ logger : logger ,
177
+ tempFolder : tempFolder
178
178
} ) ;
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 ) ;
186
183
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 ) ;
190
186
}
191
187
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
+ } ;
196
192
}
197
193
198
194
async build ( context : AppBuildContext ) : Promise < AngularAppBuildResult > {
199
195
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 ) ;
200
199
const outputPath = this . getPublicDir ( context . artifactsDir ) ;
201
200
const appRootPath = capsule . path ;
202
- const tsconfigPath = join ( appRootPath , this . options . angularBuildOptions . tsConfig ) ;
201
+ const appTsconfigPath = join ( appRootPath , this . options . angularBuildOptions . tsConfig ) ;
203
202
const appOptions = this . options . angularBuildOptions as ApplicationOptions ;
204
203
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 ) ;
206
207
207
208
if ( ! this . options . bundler && Number ( VERSION . major ) >= 16 ) {
208
209
await buildApplication ( {
209
210
angularOptions : {
210
211
...appOptions ,
211
- tsConfig : this . tsconfigPath
212
+ tsConfig : tsconfigPath
212
213
} ,
213
214
outputPath,
214
215
sourceRoot : this . options . sourceRoot || 'src' ,
215
216
workspaceRoot : context . capsule . path ,
216
- logger : this . logger ,
217
- tempFolder : this . tempFolder ,
217
+ logger : logger ,
218
+ tempFolder : tempFolder ,
218
219
entryServer
219
220
} ) ;
220
221
} 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
+ }
222
232
await bundler . run ( ) ;
223
233
}
224
234
return {
225
235
publicDir : outputPath
226
236
} ;
227
237
}
238
+
239
+ static from ( options : AngularAppOptions ) : Application {
240
+ return new AngularApp ( options ) ;
241
+ }
228
242
}
0 commit comments