55 * Use of this source code is governed by an MIT-style license that can be
66 * found in the LICENSE file at https://angular.io/license
77 */
8- import { experimental , strings , normalize } from '@angular-devkit/core' ;
8+ import { strings , normalize , workspaces , join } from '@angular-devkit/core' ;
99import {
1010 apply ,
1111 chain ,
@@ -21,7 +21,6 @@ import {
2121 url ,
2222} from '@angular-devkit/schematics' ;
2323import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks' ;
24- import { getWorkspace } from '@schematics/angular/utility/config' ;
2524import { Schema as UniversalOptions } from './schema' ;
2625import {
2726 addPackageJsonDependency ,
@@ -30,44 +29,29 @@ import {
3029import { getProject } from '@schematics/angular/utility/project' ;
3130import { getProjectTargets } from '@schematics/angular/utility/project-targets' ;
3231import { InsertChange } from '@schematics/angular/utility/change' ;
33- import {
34- addSymbolToNgModuleMetadata ,
35- findNodes ,
36- insertAfterLastOccurrence ,
37- insertImport
38- } from '@schematics/angular/utility/ast-utils' ;
32+ import { getWorkspace , updateWorkspace } from '@schematics/angular/utility/workspace' ;
33+ import { findNodes , insertAfterLastOccurrence } from '@schematics/angular/utility/ast-utils' ;
3934import * as ts from 'typescript' ;
40- import { findAppServerModulePath , generateExport , getTsSourceFile , getTsSourceText } from './utils' ;
41- import { updateWorkspace } from '@schematics/angular/utility/workspace' ;
42-
43- // TODO(CaerusKaru): make these configurable
44- const BROWSER_DIST = 'dist/browser' ;
45- const SERVER_DIST = 'dist/server' ;
46-
47- function getClientProject (
48- host : Tree , options : UniversalOptions ,
49- ) : experimental . workspace . WorkspaceProject {
50- const workspace = getWorkspace ( host ) ;
51- const clientProject = workspace . projects [ options . clientProject ] ;
52- if ( ! clientProject ) {
53- throw new SchematicsException ( `Client app ${ options . clientProject } not found.` ) ;
35+ import { generateExport , getTsSourceFile , getTsSourceText } from './utils' ;
36+
37+ async function getClientProject ( host , projectName : string ) : Promise < workspaces . ProjectDefinition > {
38+ const workspace = await getWorkspace ( host ) ;
39+ const clientProject = workspace . projects . get ( projectName ) ;
40+
41+ if ( ! clientProject || clientProject . extensions . projectType !== 'application' ) {
42+ throw new SchematicsException ( `Universal requires a project type of "application".` ) ;
5443 }
5544
5645 return clientProject ;
5746}
5847
59- function addDependenciesAndScripts ( options : UniversalOptions ) : Rule {
48+ function addDependenciesAndScripts ( options : UniversalOptions , serverDist : string ) : Rule {
6049 return ( host : Tree ) => {
6150 addPackageJsonDependency ( host , {
6251 type : NodeDependencyType . Default ,
6352 name : '@nguniversal/hapi-engine' ,
6453 version : '0.0.0-PLACEHOLDER' ,
6554 } ) ;
66- addPackageJsonDependency ( host , {
67- type : NodeDependencyType . Default ,
68- name : '@nguniversal/module-map-ngfactory-loader' ,
69- version : '0.0.0-PLACEHOLDER' ,
70- } ) ;
7155 addPackageJsonDependency ( host , {
7256 type : NodeDependencyType . Default ,
7357 name : 'hapi' ,
@@ -100,23 +84,24 @@ function addDependenciesAndScripts(options: UniversalOptions): Rule {
10084 }
10185
10286 const pkg = JSON . parse ( buffer . toString ( ) ) ;
103-
104- pkg . scripts [ 'compile:server' ] = options . webpack ?
105- 'webpack --config webpack.server.config.js --progress --colors' :
106- `tsc -p ${ serverFileName } .tsconfig.json` ;
107- pkg . scripts [ 'serve:ssr' ] = `node dist/${ serverFileName } ` ;
108- pkg . scripts [ 'build:ssr' ] = 'npm run build:client-and-server-bundles && npm run compile:server' ;
109- pkg . scripts [ 'build:client-and-server-bundles' ] =
110- // tslint:disable:max-line-length
111- `ng build --prod && ng run ${ options . clientProject } :server:production --bundleDependencies all` ;
87+ pkg . scripts = {
88+ ...pkg . scripts ,
89+ 'compile:server' : options . webpack
90+ ? 'webpack --config webpack.server.config.js --progress --colors'
91+ : `tsc -p ${ serverFileName } .tsconfig.json` ,
92+ 'serve:ssr' : `node ${ serverDist . substr ( 1 ) } /${ serverFileName } ` ,
93+ 'build:ssr' : 'npm run build:client-and-server-bundles && npm run compile:server' ,
94+ // tslint:disable-next-line: max-line-length
95+ 'build:client-and-server-bundles' : `ng build --prod && ng run ${ options . clientProject } :server:production` ,
96+ } ;
11297
11398 host . overwrite ( pkgPath , JSON . stringify ( pkg , null , 2 ) ) ;
11499
115100 return host ;
116101 } ;
117102}
118103
119- function updateConfigFile ( options : UniversalOptions ) {
104+ function updateConfigFile ( options : UniversalOptions , browserDist : string , serverDist : string ) {
120105 return updateWorkspace ( ( workspace => {
121106 const clientProject = workspace . projects . get ( options . clientProject ) ;
122107 if ( clientProject ) {
@@ -132,58 +117,17 @@ function updateConfigFile(options: UniversalOptions) {
132117
133118 serverTarget . options = {
134119 ...serverTarget . options ,
135- outputPath : SERVER_DIST ,
120+ outputPath : serverDist ,
136121 } ;
137122
138123 buildTarget . options = {
139124 ...buildTarget . options ,
140- outputPath : BROWSER_DIST ,
125+ outputPath : browserDist ,
141126 } ;
142127 }
143128 } ) ) ;
144129}
145130
146- function addModuleMapLoader ( options : UniversalOptions ) : Rule {
147- return ( host : Tree ) => {
148- const clientProject = getProject ( host , options . clientProject ) ;
149- const clientTargets = getProjectTargets ( clientProject ) ;
150- if ( ! clientTargets . server ) {
151- // If they skipped Universal schematics and don't have a server target,
152- // just get out
153- return ;
154- }
155- const mainPath = normalize ( '/' + clientTargets . server . options . main ) ;
156- const appServerModuleRelativePath = findAppServerModulePath ( host , mainPath ) ;
157- const modulePath = normalize (
158- `/${ clientProject . root } /src/${ appServerModuleRelativePath } .ts` ) ;
159-
160- // Add the module map loader import
161- let moduleSource = getTsSourceFile ( host , modulePath ) ;
162- const importModule = 'ModuleMapLoaderModule' ;
163- const importPath = '@nguniversal/module-map-ngfactory-loader' ;
164- const moduleMapImportChange = insertImport ( moduleSource , modulePath , importModule ,
165- importPath ) as InsertChange ;
166- if ( moduleMapImportChange ) {
167- const recorder = host . beginUpdate ( modulePath ) ;
168- recorder . insertLeft ( moduleMapImportChange . pos , moduleMapImportChange . toAdd ) ;
169- host . commitUpdate ( recorder ) ;
170- }
171-
172- // Add the module map loader module to the imports
173- const importText = 'ModuleMapLoaderModule' ;
174- moduleSource = getTsSourceFile ( host , modulePath ) ;
175- const metadataChanges = addSymbolToNgModuleMetadata (
176- moduleSource , modulePath , 'imports' , importText ) ;
177- if ( metadataChanges ) {
178- const recorder = host . beginUpdate ( modulePath ) ;
179- metadataChanges . forEach ( ( change : InsertChange ) => {
180- recorder . insertRight ( change . pos , change . toAdd ) ;
181- } ) ;
182- host . commitUpdate ( recorder ) ;
183- }
184- } ;
185- }
186-
187131function addExports ( options : UniversalOptions ) : Rule {
188132 return ( host : Tree ) => {
189133 const clientProject = getProject ( host , options . clientProject ) ;
@@ -201,10 +145,8 @@ function addExports(options: UniversalOptions): Rule {
201145 const mainRecorder = host . beginUpdate ( mainPath ) ;
202146 const hapiEngineExport = generateExport ( mainSourceFile , [ 'ngHapiEngine' ] ,
203147 '@nguniversal/hapi-engine' ) ;
204- const moduleMapExport = generateExport ( mainSourceFile , [ 'provideModuleMap' ] ,
205- '@nguniversal/module-map-ngfactory-loader' ) ;
206148 const exports = findNodes ( mainSourceFile , ts . SyntaxKind . ExportDeclaration ) ;
207- const addedExports = `\n${ hapiEngineExport } \n${ moduleMapExport } \n ` ;
149+ const addedExports = `\n${ hapiEngineExport } \n` ;
208150 const exportChange = insertAfterLastOccurrence ( exports , addedExports , mainText ,
209151 0 ) as InsertChange ;
210152
@@ -214,11 +156,16 @@ function addExports(options: UniversalOptions): Rule {
214156}
215157
216158export default function ( options : UniversalOptions ) : Rule {
217- return ( host : Tree , context : SchematicContext ) => {
218- const clientProject = getClientProject ( host , options ) ;
219- if ( clientProject . projectType !== 'application' ) {
220- throw new SchematicsException ( `Universal requires a project type of "application".` ) ;
221- }
159+ return async ( host : Tree , context : SchematicContext ) => {
160+ // Generate new output paths
161+ const clientProject = await getClientProject ( host , options . clientProject ) ;
162+ const { options : buildOptions } = clientProject . targets . get ( 'build' ) ;
163+ const clientOutputPath = normalize (
164+ typeof buildOptions . outputPath === 'string' ? buildOptions . outputPath : 'dist'
165+ ) ;
166+
167+ const browserDist = join ( clientOutputPath , 'browser' ) ;
168+ const serverDist = join ( clientOutputPath , 'server' ) ;
222169
223170 if ( ! options . skipInstall ) {
224171 context . addTask ( new NodePackageInstallTask ( ) ) ;
@@ -232,18 +179,18 @@ export default function (options: UniversalOptions): Rule {
232179 ...strings ,
233180 ...options as object ,
234181 stripTsExtension : ( s : string ) => s . replace ( / \. t s $ / , '' ) ,
235- getBrowserDistDirectory : ( ) => BROWSER_DIST ,
236- getServerDistDirectory : ( ) => SERVER_DIST ,
182+ // remove the leading slashes
183+ getBrowserDistDirectory : ( ) => browserDist . substr ( 1 ) ,
184+ getServerDistDirectory : ( ) => serverDist . substr ( 1 ) ,
237185 } )
238186 ] ) ;
239187
240188 return chain ( [
241189 options . skipUniversal ?
242190 noop ( ) : externalSchematic ( '@schematics/angular' , 'universal' , options ) ,
243- updateConfigFile ( options ) ,
191+ updateConfigFile ( options , browserDist , serverDist ) ,
244192 mergeWith ( rootSource ) ,
245- addDependenciesAndScripts ( options ) ,
246- addModuleMapLoader ( options ) ,
193+ addDependenciesAndScripts ( options , serverDist ) ,
247194 addExports ( options ) ,
248195 ] ) ;
249196 } ;
0 commit comments