11/* eslint-env node */
22'use strict' ;
33
4- var path = require ( 'path' ) ;
4+ const path = require ( 'path' ) ;
5+ const fs = require ( 'fs' ) ;
56
6- var EventEmitter = require ( 'events' ) . EventEmitter ;
7- var mergeTrees = require ( 'broccoli-merge-trees' ) ;
8- var VersionChecker = require ( 'ember-cli-version-checker' ) ;
9- var FastBootExpressMiddleware = require ( 'fastboot-express-middleware' ) ;
10- var FastBoot = require ( 'fastboot' ) ;
11- var chalk = require ( 'chalk' ) ;
7+ const EventEmitter = require ( 'events' ) . EventEmitter ;
8+ const MergeTrees = require ( 'broccoli-merge-trees' ) ;
9+ const FastBootExpressMiddleware = require ( 'fastboot-express-middleware' ) ;
10+ const FastBoot = require ( 'fastboot' ) ;
11+ const chalk = require ( 'chalk' ) ;
1212
13- var patchEmberApp = require ( './lib/ext/patch-ember-app' ) ;
14- var fastbootAppModule = require ( './lib/utilities/fastboot-app-module' ) ;
13+ const fastbootAppModule = require ( './lib/utilities/fastboot-app-module' ) ;
14+ const FastBootConfig = require ( './lib/broccoli/fastboot-config' ) ;
15+ const migrateInitializers = require ( './lib/build-utilities/migrate-initializers' ) ;
1516
16- var filterInitializers = require ( 'fastboot-filter-initializers' ) ;
17- var FastBootBuild = require ( './lib/broccoli/fastboot-build' ) ;
17+ const Concat = require ( 'broccoli-concat' ) ;
18+ const Funnel = require ( 'broccoli-funnel' ) ;
19+ const p = require ( 'ember-cli-preprocess-registry/preprocessors' ) ;
20+ const existsSync = require ( 'exists-sync' ) ;
1821
1922/*
2023 * Main entrypoint for the Ember CLI addon.
2124 */
22-
2325module . exports = {
2426 name : 'ember-cli-fastboot' ,
2527
28+
2629 init ( ) {
2730 this . _super . init && this . _super . init . apply ( this , arguments ) ;
2831
32+ // TODO remove once serve PR is checked in
2933 this . emitter = new EventEmitter ( ) ;
3034 } ,
3135
36+ // TODO remove once serve PR is checked in
3237 includedCommands : function ( ) {
3338 return {
3439 'fastboot' : require ( './lib/commands/fastboot' ) ( this ) ,
35-
36- /* fastboot:build is deprecated and will be removed in a future version */
37- 'fastboot:build' : require ( './lib/commands/fastboot-build' )
3840 } ;
3941 } ,
4042
43+ // TODO remove once serve PR is checked in
4144 on : function ( ) {
4245 this . emitter . on . apply ( this . emitter , arguments ) ;
4346 } ,
4447
48+ // TODO remove once serve PR is checked in
4549 emit : function ( ) {
4650 this . emitter . emit . apply ( this . emitter , arguments ) ;
4751 } ,
4852
4953 /**
5054 * Called at the start of the build process to let the addon know it will be
51- * used. At this point, we can rely on the EMBER_CLI_FASTBOOT environment
52- * variable being set .
55+ * used. Sets the auto run on app to be false so that we create and route app
56+ * automatically only in browser .
5357 *
54- * Once we've determined which mode we're in (browser build or FastBoot build),
55- * we mixin additional Ember addon hooks appropriate to the current build target.
58+ * See: https://ember-cli.com/user-guide/#integration
5659 */
5760 included : function ( app ) {
58- patchEmberApp ( app ) ;
59- } ,
60-
61- config : function ( ) {
62- if ( this . app && this . app . options . __is_building_fastboot__ ) {
63- return { APP : { autoboot : false } } ;
64- }
61+ // set autoRun to false since we will conditionally include creating app when app files
62+ // is eval'd in app-boot
63+ app . options . autoRun = false ;
64+ // get the app registry object and app name so that we can build the fastboot
65+ // tree
66+ this . _appRegistry = app . registry ;
67+ this . _name = app . name ;
68+
69+ // set a environment variable to allow addons to use `fastboot-filter-initializers`
70+ // for old versions.
71+ process . env . FASTBOOT_NEW_BUILD = true ;
72+
73+ migrateInitializers ( this . project ) ;
6574 } ,
6675
6776 /**
@@ -79,83 +88,156 @@ module.exports = {
7988 }
8089
8190 if ( type === 'app-boot' ) {
82- return fastbootAppModule ( config . modulePrefix ) ;
91+ return fastbootAppModule ( config . modulePrefix , JSON . stringify ( config . APP || { } ) ) ;
8392 }
8493
85- if ( type === 'config-module' && this . app . options . __is_building_fastboot__ ) {
86- var linesToRemove = contents . length ;
87- while ( linesToRemove ) {
88- // Clear out the default config from ember-cli
89- contents . pop ( ) ;
90- linesToRemove -- ;
91- }
92-
93- return 'return FastBoot.config();' ;
94+ // if the fastboot addon is installed, we overwrite the config-module so that the config can be read
95+ // from meta tag for browser build and from Fastboot config for fastboot target
96+ if ( type === 'config-module' ) {
97+ const emberCliPath = path . join ( this . app . project . nodeModulesPath , 'ember-cli' ) ;
98+ contents . splice ( 0 , contents . length ) ;
99+ contents . push ( 'if (typeof FastBoot !== \'undefined\') {' ) ;
100+ contents . push ( 'return FastBoot.config();' ) ;
101+ contents . push ( '} else {' ) ;
102+ contents . push ( 'var prefix = \'' + config . modulePrefix + '\';' ) ;
103+ contents . push ( fs . readFileSync ( path . join ( emberCliPath , 'lib/broccoli/app-config-from-meta.js' ) ) ) ;
104+ contents . push ( '}' ) ;
105+ return ;
94106 }
95107 } ,
96108
97- treeForApp : function ( defaultTree ) {
98- var trees = [ defaultTree ] ;
109+ treeForFastBoot : function ( tree ) {
110+ let fastbootHtmlBarsTree ;
99111
112+ // check the ember-cli version and conditionally patch the DOM api
100113 if ( this . _getEmberVersion ( ) . lt ( '2.10.0-alpha.1' ) ) {
101- trees . push ( this . treeGenerator ( path . resolve ( this . root , 'app-lt-2-9' ) ) ) ;
114+ fastbootHtmlBarsTree = this . treeGenerator ( path . resolve ( __dirname , 'fastboot-app-lt-2-9' ) ) ;
115+ return tree ? new MergeTrees ( [ tree , fastbootHtmlBarsTree ] ) : fastbootHtmlBarsTree ;
102116 }
103117
104- return mergeTrees ( trees , { overwrite : true } ) ;
118+ return tree ;
105119 } ,
106120
107121 /**
108- * Filters out initializers and instance initializers that should only run in
109- * browser mode.
122+ * Function that builds the fastboot tree from all fastboot complaint addons
123+ * and project and transpiles it into appname-fastboot.js
110124 */
111- preconcatTree : function ( tree ) {
112- return filterInitializers ( tree , this . app . name ) ;
125+ _getFastbootTree : function ( ) {
126+ const appName = this . _name ;
127+ const nodeModulesPath = this . project . nodeModulesPath ;
128+
129+ let fastbootTrees = [ ] ;
130+ this . project . addons . forEach ( ( addon ) => {
131+ // walk through each addon and grab its fastboot tree
132+ const currentAddonFastbootPath = path . join ( nodeModulesPath , addon . name , 'fastboot' ) ;
133+ let fastbootTree ;
134+ if ( existsSync ( currentAddonFastbootPath ) ) {
135+ fastbootTree = this . treeGenerator ( currentAddonFastbootPath ) ;
136+ fastbootTrees . push ( fastbootTree ) ;
137+ }
138+
139+ // invoke addToFastBootTree for every addon
140+ if ( addon . treeForFastBoot ) {
141+ let additionalFastBootTree = addon . treeForFastBoot ( fastbootTree ) ;
142+ if ( additionalFastBootTree ) {
143+ fastbootTrees . push ( additionalFastBootTree ) ;
144+ }
145+ }
146+ } ) ;
147+
148+ // check the parent containing the fastboot directory
149+ const projectFastbootPath = path . join ( this . project . root , 'fastboot' ) ;
150+ if ( existsSync ( projectFastbootPath ) ) {
151+ let fastbootTree = this . treeGenerator ( projectFastbootPath ) ;
152+ fastbootTrees . push ( fastbootTree ) ;
153+ }
154+
155+ // transpile the fastboot JS tree
156+ let mergedFastBootTree = new MergeTrees ( fastbootTrees , {
157+ overwrite : true
158+ } ) ;
159+ let funneledFastbootTrees = new Funnel ( mergedFastBootTree , {
160+ destDir : appName
161+ } ) ;
162+ const processExtraTree = p . preprocessJs ( funneledFastbootTrees , '/' , this . _name , {
163+ registry : this . _appRegistry
164+ } ) ;
165+
166+ let fileAppName = path . basename ( this . app . options . outputPaths . app . js ) . split ( '.' ) [ 0 ] ;
167+ let finalFastbootTree = new Concat ( processExtraTree , {
168+ outputFile : 'assets/' + fileAppName + '-fastboot.js'
169+ } ) ;
170+
171+ return finalFastbootTree ;
172+ } ,
173+
174+ treeForPublic ( tree ) {
175+ let fastbootTree = this . _getFastbootTree ( ) ;
176+ let trees = [ ] ;
177+ if ( tree ) {
178+ trees . push ( tree ) ;
179+ }
180+ trees . push ( fastbootTree ) ;
181+
182+ let newTree = new MergeTrees ( trees ) ;
183+
184+ return newTree ;
113185 } ,
114186
115187 /**
116188 * After the entire Broccoli tree has been built for the `dist` directory,
117189 * adds the `fastboot-config.json` file to the root.
118190 *
119- * FASTBOOT_DISABLED is a pre 1.0 power user flag to
120- * disable the fastboot build while retaining the fastboot service.
121191 */
122192 postprocessTree : function ( type , tree ) {
123- if ( type === 'all' && ! process . env . FASTBOOT_DISABLED ) {
124- var fastbootTree = this . buildFastBootTree ( ) ;
193+ if ( type === 'all' ) {
194+ let fastbootConfigTree = this . _buildFastbootConfigTree ( tree ) ;
125195
126196 // Merge the package.json with the existing tree
127- return mergeTrees ( [ tree , fastbootTree ] , { overwrite : true } ) ;
197+ return new MergeTrees ( [ tree , fastbootConfigTree ] , { overwrite : true } ) ;
128198 }
129199
130200 return tree ;
131201 } ,
132202
133- buildFastBootTree : function ( ) {
134- var fastbootBuild = new FastBootBuild ( {
135- ui : this . ui ,
203+ _buildFastbootConfigTree : function ( tree ) {
204+ let env = this . app . env ;
205+ let config = this . project . config ( env ) ;
206+ let fastbootConfig = config . fastboot ;
207+ // do not boot the app automatically in fastboot. The instance is booted and
208+ // lives for the lifetime of the request.
209+ if ( 'APP' in config ) {
210+ config [ 'APP' ] [ 'autoboot' ] = false ;
211+ } else {
212+ config [ 'APP' ] = {
213+ 'autoboot' : false
214+ }
215+ }
216+
217+ return new FastBootConfig ( tree , {
136218 assetMapPath : this . assetMapPath ,
137219 project : this . project ,
138- app : this . app ,
139- parent : this . parent
220+ name : this . app . name ,
221+ outputPaths : this . app . options . outputPaths ,
222+ ui : this . ui ,
223+ fastbootAppConfig : fastbootConfig ,
224+ appConfig : config
140225 } ) ;
141-
142- return fastbootBuild . toTree ( ) ;
143226 } ,
144227
145228 serverMiddleware : function ( options ) {
146- var emberCliVersion = this . _getEmberCliVersion ( ) ;
147- var app = options . app ;
148- var options = options . options ;
229+ let emberCliVersion = this . _getEmberCliVersion ( ) ;
230+ let app = options . app ;
149231
150232 if ( emberCliVersion . gte ( '2.12.0-beta.1' ) ) {
151233 // only run the middleware when ember-cli version for app is above 2.12.0-beta.1 since
152234 // that version contains API to hook fastboot into ember-cli
153235
154236 app . use ( ( req , resp , next ) => {
155- var fastbootQueryParam = ( req . query . hasOwnProperty ( 'fastboot' ) && req . query . fastboot === 'false' ) ? false : true ;
156- var enableFastBootServe = ! process . env . FASTBOOT_DISABLED && fastbootQueryParam ;
157- var broccoliHeader = req . headers [ 'x-broccoli' ] ;
158- var outputPath = broccoliHeader [ 'outputPath' ] ;
237+ const fastbootQueryParam = ( req . query . hasOwnProperty ( 'fastboot' ) && req . query . fastboot === 'false' ) ? false : true ;
238+ const enableFastBootServe = ! process . env . FASTBOOT_DISABLED && fastbootQueryParam ;
239+ const broccoliHeader = req . headers [ 'x-broccoli' ] ;
240+ const outputPath = broccoliHeader [ 'outputPath' ] ;
159241
160242 if ( broccoliHeader [ 'url' ] === req . serveUrl && enableFastBootServe ) {
161243 // if it is a base page request, then have fastboot serve the base page
@@ -168,7 +250,7 @@ module.exports = {
168250 } ) ;
169251 }
170252
171- var fastbootMiddleware = FastBootExpressMiddleware ( {
253+ let fastbootMiddleware = FastBootExpressMiddleware ( {
172254 fastboot : this . fastboot
173255 } ) ;
174256
@@ -181,10 +263,12 @@ module.exports = {
181263 }
182264 } ,
183265
266+ // TODO remove once serve PR is checked in
184267 outputReady : function ( ) {
185268 this . emit ( 'outputReady' ) ;
186269 } ,
187270
271+ // TODO remove once serve PR is checked in
188272 postBuild : function ( result ) {
189273 this . emit ( 'postBuild' ) ;
190274 if ( this . fastboot ) {
@@ -199,16 +283,16 @@ module.exports = {
199283 } ,
200284
201285 _getEmberCliVersion : function ( ) {
202- var VersionChecker = require ( 'ember-cli-version-checker' ) ;
203- var checker = new VersionChecker ( this ) ;
286+ const VersionChecker = require ( 'ember-cli-version-checker' ) ;
287+ const checker = new VersionChecker ( this ) ;
204288
205289 return checker . for ( 'ember-cli' , 'npm' ) ;
206290 } ,
207291
208292 _getEmberVersion : function ( ) {
209- var VersionChecker = require ( 'ember-cli-version-checker' ) ;
210- var checker = new VersionChecker ( this ) ;
211- var emberVersionChecker = checker . for ( 'ember-source' , 'npm' ) ;
293+ const VersionChecker = require ( 'ember-cli-version-checker' ) ;
294+ const checker = new VersionChecker ( this ) ;
295+ const emberVersionChecker = checker . for ( 'ember-source' , 'npm' ) ;
212296
213297 if ( emberVersionChecker . version ) {
214298 return emberVersionChecker ;
0 commit comments