-
Notifications
You must be signed in to change notification settings - Fork 23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(core): integrated bootstrap #486
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from "./bootstrap/abstract-stark-main"; | ||
export * from "./bootstrap/stark-main.intf"; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
import { ApplicationRef, ComponentRef, enableProdMode, NgModuleRef } from "@angular/core"; | ||
import { disableDebugTools, enableDebugTools } from "@angular/platform-browser"; | ||
import { createNewHosts } from "@angularclass/hmr"; | ||
|
||
import { StarkMain } from "./stark-main.intf"; | ||
import {StarkEnvironment} from "../environment"; | ||
|
||
/** | ||
* Parent class for bootstrapping Stark applications. | ||
* It handles the DOMContentLoaded event of the Web browser in order to bootstrap the application. | ||
* This class also supports HMR in development mode. | ||
*/ | ||
export abstract class AbstractStarkMain implements StarkMain { | ||
protected constructor(protected environment: StarkEnvironment) { | ||
// no-op | ||
} | ||
|
||
/** | ||
* Must be implemented by children classes. Called within bootstrapDomReady (i.e., when the DOM has been loaded) | ||
*/ | ||
public abstract main: () => Promise<any>; | ||
|
||
public mainWrapper = (): void => { | ||
// written like this because otherwise "this" will not be captured :) | ||
// no need for the event listener after this | ||
document.removeEventListener("DOMContentLoaded", this.mainWrapper, false); | ||
|
||
this.initialize(); | ||
}; | ||
|
||
/** | ||
* Call the main() method and log an error in case of failure | ||
*/ | ||
private invokeMain(): void { | ||
// FIXME handle errors nicely (UX!) | ||
this.main().catch((err: any) => console.error(err)); | ||
|
||
// TODO reintroduce later | ||
// bootstrap the app as long as the app root element is there (it won't be there in case the browser is outdated) | ||
// if (document.getElementsByClassName("stark-app")[0]) { | ||
// // add anything relevant here | ||
// } else { | ||
// console.error("Could not bootstrap the App: unsupported browser."); | ||
// } | ||
} | ||
|
||
/** | ||
* Initialize by configuring HMR if it is enabled or normally instead. | ||
*/ | ||
protected initialize = (): void => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here about the definition of the method There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same reply |
||
if (ENV === "development" && this.environment.hmr) { | ||
if (module["hot"]) { | ||
this.bootstrapHmr(module, this.main); | ||
} else { | ||
console.error("HMR is not enabled for webpack-dev-server! This is most probably due to a bug in Stark."); | ||
} | ||
} else { | ||
this.invokeMain(); | ||
} | ||
}; | ||
|
||
/** | ||
* Call the main function once the DOM has loaded | ||
*/ | ||
protected bootstrapDomReady = (): void => { | ||
switch (document.readyState) { | ||
case "loading": | ||
document.addEventListener("DOMContentLoaded", this.mainWrapper, false); | ||
break; | ||
case "interactive": | ||
case "complete": | ||
default: | ||
this.initialize(); | ||
} | ||
}; | ||
|
||
/** | ||
* Bootstrap after document is ready | ||
*/ | ||
public bootstrap(): void { | ||
console.log(` | ||
NNNNNNNN NNNNNNNNBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBB | ||
N:::::::N N::::::NB::::::::::::::::B B::::::::::::::::B | ||
N::::::::N N::::::NB::::::BBBBBB:::::B B::::::BBBBBB:::::B | ||
N:::::::::N N::::::NBB:::::B B:::::BBB:::::B B:::::B | ||
N::::::::::N N::::::N B::::B B:::::B B::::B B:::::B | ||
N:::::::::::N N::::::N B::::B B:::::B B::::B B:::::B | ||
N:::::::N::::N N::::::N B::::BBBBBB:::::B B::::BBBBBB:::::B | ||
N::::::N N::::N N::::::N B:::::::::::::BB B:::::::::::::BB | ||
N::::::N N::::N:::::::N B::::BBBBBB:::::B B::::BBBBBB:::::B | ||
N::::::N N:::::::::::N B::::B B:::::B B::::B B:::::B | ||
N::::::N N::::::::::N B::::B B:::::B B::::B B:::::B | ||
N::::::N N:::::::::N B::::B B:::::B B::::B B:::::B | ||
N::::::N N::::::::NBB:::::BBBBBB::::::BBB:::::BBBBBB::::::B | ||
N::::::N N:::::::NB:::::::::::::::::B B:::::::::::::::::B | ||
N::::::N N::::::NB::::::::::::::::B B::::::::::::::::B | ||
NNNNNNNN NNNNNNNBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBB | ||
|
||
We need great software developers like you! https://jobs.nbb.be | ||
`); | ||
|
||
this.bootstrapDomReady(); | ||
} | ||
|
||
/** | ||
* Configure HMR | ||
* Code based on: https://github.com/angular/angular-cli/wiki/stories-configure-hmr | ||
* Reference: https://github.com/gdi2290/angular-hmr | ||
* @ignore | ||
*/ | ||
protected bootstrapHmr: Function = (module: any, bootstrap: () => Promise<NgModuleRef<any>>) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here about the definition of the method |
||
if(ENV === "development") { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is already checked at line 51. Maybe could we remove this check ? 😊 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Depends on how intelligent Webpack is for dead code removal. I didn't check the generated code though, I've added the check in the function just be be sure that the code would be dropped in production builds There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indeed, as @dsebastien said, this is needed so that webpack can remove the code inside this function. The other check (in line 51) makes sure that this function will not be called, but yet the function will still be there and so code that calls the |
||
console.log("Bootstrapping HMR"); | ||
let ngModule: NgModuleRef<any>; | ||
module.hot.accept(); | ||
bootstrap().then( | ||
(mod: NgModuleRef<any>) => (ngModule = mod), | ||
(reason: any) => console.error("HMR bootstrap: bootstrap failed due to ", reason) | ||
); | ||
|
||
module.hot.dispose(() => { | ||
const appRef: ApplicationRef = ngModule.injector.get(ApplicationRef); | ||
const elements: ComponentRef<any>[] = appRef.components.map((c: ComponentRef<any>) => c.location.nativeElement); | ||
const makeVisible: () => void = createNewHosts(elements); | ||
ngModule.destroy(); | ||
makeVisible(); | ||
}); | ||
} | ||
}; | ||
|
||
/** | ||
* Modify/decorate the NgModule instance created by Angular. | ||
* Adapt the configuration based on the current environment | ||
* @param moduleRef - NgModule instance created by Angular for a given platform. | ||
*/ | ||
public decorateModule = (moduleRef: NgModuleRef<any>): NgModuleRef<any> => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here about the definition of the method |
||
// written like this because otherwise "this" will not be captured :) | ||
if (this.environment.production) { | ||
console.log("Customizing configuration for production!"); | ||
enableProdMode(); | ||
disableDebugTools(); | ||
} else { | ||
console.log("Customizing configuration for development!"); | ||
|
||
// Ensure that we get detailed stack tracks during development (useful with node & Webpack) | ||
// Reference: http://stackoverflow.com/questions/7697038/more-than-10-lines-in-a-node-js-stack-error | ||
Error.stackTraceLimit = Infinity; | ||
require("zone.js/dist/long-stack-trace-zone"); | ||
|
||
// Enable Angular debug tools in the dev console | ||
// https://github.com/angular/angular/blob/86405345b781a9dc2438c0fbe3e9409245647019/TOOLS_JS.md | ||
const appRef: ApplicationRef = moduleRef.injector.get(ApplicationRef); | ||
const cmpRef: ComponentRef<any> = appRef.components[0]; | ||
enableDebugTools(cmpRef); | ||
|
||
const _ng: any = (<any>window).ng; | ||
(<any>window).ng.probe = _ng.probe; | ||
(<any>window).ng.coreTokens = _ng.coreTokens; | ||
} | ||
|
||
return moduleRef; | ||
}; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { NgModuleRef } from "@angular/core"; | ||
|
||
/** | ||
* Main entry point | ||
*/ | ||
export interface StarkMain { | ||
/** | ||
* Main function: responsible for starting the application. | ||
*/ | ||
main: () => Promise<any>; | ||
|
||
/** | ||
* Bootstrap the loading process. | ||
*/ | ||
bootstrap(): void; | ||
|
||
/** | ||
* Function to modify/decorate the module instance created by Angular for a given platform. | ||
* Useful to enable/disable some Angular specifics such as the debug tools. | ||
* @param moduleRef - NgModule instance created by Angular for a given platform. | ||
*/ | ||
decorateModule(moduleRef: NgModuleRef<any>): NgModuleRef<any>; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,18 @@ | ||
import { enableProdMode, NgModuleRef } from "@angular/core"; | ||
import { disableDebugTools } from "@angular/platform-browser"; | ||
import { StarkEnvironment } from "@nationalbankbelgium/stark-core"; | ||
import { NgModuleRef } from "@angular/core"; | ||
|
||
enableProdMode(); | ||
import { StarkEnvironment } from "@nationalbankbelgium/stark-core"; | ||
|
||
export const environment: StarkEnvironment = { | ||
production: true, | ||
hmr: false, | ||
|
||
ENV_PROVIDERS: [], | ||
/** | ||
* Angular debug tools in the dev console | ||
* https://github.com/angular/angular/blob/86405345b781a9dc2438c0fbe3e9409245647019/TOOLS_JS.md | ||
* @param modRef - NgModule Instance created by Angular for a given platform. | ||
* Customize the app module. | ||
* @param moduleRef - NgModule Instance created by Angular for a given platform. | ||
*/ | ||
decorateModuleRef(modRef: NgModuleRef<any>): NgModuleRef<any> { | ||
disableDebugTools(); | ||
return modRef; | ||
}, | ||
ENV_PROVIDERS: [] | ||
decorateModule(moduleRef: NgModuleRef<any>): NgModuleRef<any> { | ||
// perform any module customization needed for this specific environment here | ||
// and make sure to invoke this function by passing it the NgModule created by Angular | ||
return moduleRef; | ||
} | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You use different ways to define methods in this file, I think we should keep only one.
Could we have
instead of
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed to a lambda to capture "this", otherwise all calls to this would fail because they're made through a callback
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But I have in mind that there was another way to do it, just can't remember it though :p