6
6
* found in the LICENSE file at https://angular.io/license
7
7
*/
8
8
9
+ import { readFileSync , existsSync } from 'fs' ;
9
10
import * as browserSync from 'browser-sync' ;
10
11
import * as http from 'http' ;
11
12
import * as path from 'path' ;
@@ -17,6 +18,9 @@ import * as send from 'send';
17
18
* environment and on Windows (with a runfile manifest file).
18
19
*/
19
20
export class DevServer {
21
+ /** Cached content of the index.html. */
22
+ private _index : string | null = null ;
23
+
20
24
/** Instance of the browser-sync server. */
21
25
server = browserSync . create ( ) ;
22
26
@@ -38,7 +42,7 @@ export class DevServer {
38
42
private _historyApiFallback : boolean = false ) { }
39
43
40
44
/** Starts the server on the given port. */
41
- async start ( ) {
45
+ start ( ) {
42
46
return new Promise < void > ( ( resolve , reject ) => {
43
47
this . server . init ( this . options , ( err ) => {
44
48
if ( err ) {
@@ -82,30 +86,51 @@ export class DevServer {
82
86
// to the index: https://github.com/bripkens/connect-history-api-fallback#introduction
83
87
if ( this . _historyApiFallback && req . method === 'GET' && ! req . url . includes ( '.' ) &&
84
88
req . headers . accept && req . headers . accept . includes ( 'text/html' ) ) {
85
- req . url = '/index.html' ;
86
- }
89
+ res . end ( this . _getIndex ( ) ) ;
90
+ } else {
91
+ const resolvedPath = this . _resolveUrlFromRunfiles ( req . url ) ;
87
92
88
- const resolvedPath = this . _resolveUrlFromRunfiles ( req . url ) ;
93
+ if ( resolvedPath === null ) {
94
+ res . statusCode = 404 ;
95
+ res . end ( 'Page not found' ) ;
96
+ return ;
97
+ }
89
98
90
- if ( resolvedPath === null ) {
91
- res . statusCode = 404 ;
92
- res . end ( 'Page not found' ) ;
93
- return ;
99
+ send ( req , resolvedPath ) . pipe ( res ) ;
94
100
}
95
-
96
- send ( req , resolvedPath ) . pipe ( res ) ;
97
101
}
98
102
99
103
/** Resolves a given URL from the runfiles using the corresponding manifest path. */
100
104
private _resolveUrlFromRunfiles ( url : string ) : string | null {
101
105
for ( let rootPath of this . _rootPaths ) {
102
106
try {
103
107
return require . resolve ( path . posix . join ( rootPath , getManifestPath ( url ) ) ) ;
104
- } catch {
105
- }
108
+ } catch { }
106
109
}
107
110
return null ;
108
111
}
112
+
113
+ /** Gets the content of the index.html. */
114
+ private _getIndex ( ) : string {
115
+ if ( ! this . _index ) {
116
+ const indexPath = this . _resolveUrlFromRunfiles ( '/index.html' ) ;
117
+
118
+ if ( ! indexPath ) {
119
+ throw Error ( 'Could not resolve dev server index.html' ) ;
120
+ }
121
+
122
+ // We support specifying a variables.json file next to the index.html which will be inlined
123
+ // into the dev app as a `script` tag. It is used to pass in environment-specific variables.
124
+ const varsPath = path . join ( path . dirname ( indexPath ) , 'variables.json' ) ;
125
+ const scriptTag = '<script>window.DEV_APP_VARIABLES = ' +
126
+ ( existsSync ( varsPath ) ? readFileSync ( varsPath , 'utf8' ) : '{}' ) + ';</script>' ;
127
+ const content = readFileSync ( indexPath , 'utf8' ) ;
128
+ const headIndex = content . indexOf ( '</head>' ) ;
129
+ this . _index = content . slice ( 0 , headIndex ) + scriptTag + content . slice ( headIndex ) ;
130
+ }
131
+
132
+ return this . _index ;
133
+ }
109
134
}
110
135
111
136
/** Gets the manifest path for a given url */
0 commit comments