Repository: patrickmichalina/fusebox-angular-universal-starter Branch: master Commit: ab8c89e1f9c5 Files: 326 Total size: 381.1 KB Directory structure: gitextract_3ok5m6pt/ ├── .editorconfig ├── .firebaserc ├── .gitignore ├── .stylelintrc ├── .vscode/ │ ├── extensions.json │ └── settings.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── Procfile ├── README.md ├── app.json ├── circle.yml ├── codecov.yml ├── data/ │ ├── security.rules.json │ ├── seed.settings.json │ └── seed.superusers.json ├── docs/ │ ├── angular-universal.md │ ├── api-server.md │ └── openid-server.md ├── e2e-spec.json ├── firebase.json ├── fuse.ts ├── package.json ├── src/ │ ├── client/ │ │ ├── app/ │ │ │ ├── __snapshots__/ │ │ │ │ └── app.component.spec.ts.snap │ │ │ ├── about/ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── about.component.spec.ts.snap │ │ │ │ ├── about-routing.module.ts │ │ │ │ ├── about.component.e2e-spec.ts │ │ │ │ ├── about.component.html │ │ │ │ ├── about.component.scss │ │ │ │ ├── about.component.spec.ts │ │ │ │ ├── about.component.ts │ │ │ │ └── about.module.ts │ │ │ ├── account/ │ │ │ │ ├── account-routing.module.ts │ │ │ │ ├── account.component.html │ │ │ │ ├── account.component.scss │ │ │ │ ├── account.component.ts │ │ │ │ └── account.module.ts │ │ │ ├── admin/ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── admin.component.spec.ts.snap │ │ │ │ ├── admin-routing.module.ts │ │ │ │ ├── admin.component.e2e-spec.ts │ │ │ │ ├── admin.component.html │ │ │ │ ├── admin.component.scss │ │ │ │ ├── admin.component.spec.ts │ │ │ │ ├── admin.component.ts │ │ │ │ └── admin.module.ts │ │ │ ├── app-routing.module.ts │ │ │ ├── app.browser.module.ts │ │ │ ├── app.component.html │ │ │ ├── app.component.scss │ │ │ ├── app.component.spec.ts │ │ │ ├── app.component.ts │ │ │ ├── app.config.ts │ │ │ ├── app.module.ts │ │ │ ├── changelog/ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── changelog.component.spec.ts.snap │ │ │ │ ├── changelog-routing.module.ts │ │ │ │ ├── changelog.component.e2e-spec.ts │ │ │ │ ├── changelog.component.html │ │ │ │ ├── changelog.component.scss │ │ │ │ ├── changelog.component.spec.ts │ │ │ │ ├── changelog.component.ts │ │ │ │ └── changelog.module.ts │ │ │ ├── dashboard/ │ │ │ │ ├── dashboard-menu.ts │ │ │ │ ├── dashboard-routing.module.ts │ │ │ │ ├── dashboard.component.html │ │ │ │ ├── dashboard.component.scss │ │ │ │ ├── dashboard.component.ts │ │ │ │ ├── dashboard.module.ts │ │ │ │ ├── footer/ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── dashboard-page-footer.component.spec.ts.snap │ │ │ │ │ ├── dashboard-page-footer.component.html │ │ │ │ │ ├── dashboard-page-footer.component.scss │ │ │ │ │ ├── dashboard-page-footer.component.spec.ts │ │ │ │ │ └── dashboard-page-footer.component.ts │ │ │ │ ├── header/ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── dashboard-page-header.component.spec.ts.snap │ │ │ │ │ ├── dashboard-page-header.component.html │ │ │ │ │ ├── dashboard-page-header.component.scss │ │ │ │ │ ├── dashboard-page-header.component.spec.ts │ │ │ │ │ └── dashboard-page-header.component.ts │ │ │ │ ├── test/ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── test.component.spec.ts.snap │ │ │ │ │ ├── test-routing.module.ts │ │ │ │ │ ├── test.component.html │ │ │ │ │ ├── test.component.scss │ │ │ │ │ ├── test.component.spec.ts │ │ │ │ │ ├── test.component.ts │ │ │ │ │ ├── test.module.ts │ │ │ │ │ ├── test.service.ts │ │ │ │ │ ├── testChild/ │ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ │ └── testChild.component.spec.ts.snap │ │ │ │ │ │ ├── testChild.component.html │ │ │ │ │ │ ├── testChild.component.scss │ │ │ │ │ │ ├── testChild.component.spec.ts │ │ │ │ │ │ └── testChild.component.ts │ │ │ │ │ └── testChild1/ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── testChild1.component.spec.ts.snap │ │ │ │ │ ├── testChild1.component.html │ │ │ │ │ ├── testChild1.component.scss │ │ │ │ │ ├── testChild1.component.spec.ts │ │ │ │ │ └── testChild1.component.ts │ │ │ │ └── test1/ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── test1.component.spec.ts.snap │ │ │ │ ├── test1-routing.module.ts │ │ │ │ ├── test1.component.html │ │ │ │ ├── test1.component.scss │ │ │ │ ├── test1.component.spec.ts │ │ │ │ ├── test1.component.ts │ │ │ │ └── test1.module.ts │ │ │ ├── home/ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── home.component.spec.ts.snap │ │ │ │ ├── home-routing.module.ts │ │ │ │ ├── home.component.e2e-spec.ts │ │ │ │ ├── home.component.html │ │ │ │ ├── home.component.scss │ │ │ │ ├── home.component.spec.ts │ │ │ │ ├── home.component.ts │ │ │ │ └── home.module.ts │ │ │ ├── login/ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── login.component.spec.ts.snap │ │ │ │ ├── login-routing.module.ts │ │ │ │ ├── login.component.e2e-spec.ts │ │ │ │ ├── login.component.html │ │ │ │ ├── login.component.scss │ │ │ │ ├── login.component.spec.ts │ │ │ │ ├── login.component.ts │ │ │ │ └── login.module.ts │ │ │ ├── logout/ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── logout.component.spec.ts.snap │ │ │ │ ├── logout-routing.module.ts │ │ │ │ ├── logout.component.e2e-spec.ts │ │ │ │ ├── logout.component.html │ │ │ │ ├── logout.component.scss │ │ │ │ ├── logout.component.spec.ts │ │ │ │ ├── logout.component.ts │ │ │ │ └── logout.module.ts │ │ │ ├── not-found/ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── not-found.component.spec.ts.snap │ │ │ │ ├── not-found-routing.module.ts │ │ │ │ ├── not-found.component.e2e-spec.ts │ │ │ │ ├── not-found.component.html │ │ │ │ ├── not-found.component.scss │ │ │ │ ├── not-found.component.spec.ts │ │ │ │ ├── not-found.component.ts │ │ │ │ └── not-found.module.ts │ │ │ ├── pages/ │ │ │ │ ├── page-form/ │ │ │ │ │ ├── page-form.component.html │ │ │ │ │ ├── page-form.component.scss │ │ │ │ │ └── page-form.component.ts │ │ │ │ ├── pages-routing.module.ts │ │ │ │ ├── pages.component.html │ │ │ │ ├── pages.component.scss │ │ │ │ ├── pages.component.ts │ │ │ │ └── pages.module.ts │ │ │ ├── shared/ │ │ │ │ ├── cache-form/ │ │ │ │ │ ├── cache-form.component.html │ │ │ │ │ ├── cache-form.component.scss │ │ │ │ │ └── cache-form.component.ts │ │ │ │ ├── directives/ │ │ │ │ │ ├── avatar.directive.ts │ │ │ │ │ ├── click-outside.directive.ts │ │ │ │ │ ├── html-outlet.directive.ts │ │ │ │ │ └── social-button.directive.ts │ │ │ │ ├── http-cache-tag/ │ │ │ │ │ ├── http-cache-tag-interceptor.service.spec.ts │ │ │ │ │ ├── http-cache-tag-interceptor.service.ts │ │ │ │ │ └── http-cache-tag.module.ts │ │ │ │ ├── injection-form/ │ │ │ │ │ ├── injection-form.component.html │ │ │ │ │ ├── injection-form.component.scss │ │ │ │ │ └── injection-form.component.ts │ │ │ │ ├── key-value-form/ │ │ │ │ │ ├── key-value-form.component.html │ │ │ │ │ ├── key-value-form.component.scss │ │ │ │ │ └── key-value-form.component.ts │ │ │ │ ├── login-card/ │ │ │ │ │ ├── login-card.component.html │ │ │ │ │ ├── login-card.component.scss │ │ │ │ │ └── login-card.component.ts │ │ │ │ ├── material.module.ts │ │ │ │ ├── modal-confirmation/ │ │ │ │ │ ├── modal-confirmation.component.html │ │ │ │ │ ├── modal-confirmation.component.scss │ │ │ │ │ └── modal-confirmation.component.ts │ │ │ │ ├── navbar/ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── navbar.component.spec.ts.snap │ │ │ │ │ ├── navbar.component.html │ │ │ │ │ ├── navbar.component.scss │ │ │ │ │ ├── navbar.component.spec.ts │ │ │ │ │ ├── navbar.component.ts │ │ │ │ │ ├── navbar.service.spec.ts │ │ │ │ │ └── navbar.service.ts │ │ │ │ ├── pipes/ │ │ │ │ │ ├── key-value.pipe.ts │ │ │ │ │ ├── keys.pipe.ts │ │ │ │ │ └── sanitize-html.pipe.ts │ │ │ │ ├── quill-editor/ │ │ │ │ │ ├── quill-editor.component.html │ │ │ │ │ ├── quill-editor.component.scss │ │ │ │ │ └── quill-editor.component.ts │ │ │ │ ├── services/ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── error-handler.service.spec.ts.snap │ │ │ │ │ ├── adblock.service.spec.ts │ │ │ │ │ ├── adblock.service.ts │ │ │ │ │ ├── auth.service.ts │ │ │ │ │ ├── cookie.service.spec.ts │ │ │ │ │ ├── cookie.service.ts │ │ │ │ │ ├── environment.service.spec.ts │ │ │ │ │ ├── environment.service.ts │ │ │ │ │ ├── error-handler.service.spec.ts │ │ │ │ │ ├── error-handler.service.ts │ │ │ │ │ ├── firebase-database.service.ts │ │ │ │ │ ├── guard-admin.service.ts │ │ │ │ │ ├── guard-login.service.ts │ │ │ │ │ ├── http-config-interceptor.service.spec.ts │ │ │ │ │ ├── http-config-interceptor.service.ts │ │ │ │ │ ├── http-cookie-interceptor.service.spec.ts │ │ │ │ │ ├── http-cookie-interceptor.service.ts │ │ │ │ │ ├── injection.service.ts │ │ │ │ │ ├── logging.service.spec.ts │ │ │ │ │ ├── logging.service.ts │ │ │ │ │ ├── minifier.service.ts │ │ │ │ │ ├── platform.service.spec.ts │ │ │ │ │ ├── platform.service.ts │ │ │ │ │ ├── seo.service.ts │ │ │ │ │ ├── server-response.service.spec.ts │ │ │ │ │ ├── server-response.service.ts │ │ │ │ │ ├── setting.service.spec.ts │ │ │ │ │ ├── setting.service.ts │ │ │ │ │ └── web-socket.service.ts │ │ │ │ ├── shared.module.ts │ │ │ │ ├── style-injection-form/ │ │ │ │ │ ├── style-injection-form.component.html │ │ │ │ │ ├── style-injection-form.component.scss │ │ │ │ │ └── style-injection-form.component.ts │ │ │ │ └── web-app-installer/ │ │ │ │ ├── web-app-installer.component.html │ │ │ │ ├── web-app-installer.component.scss │ │ │ │ ├── web-app-installer.component.ts │ │ │ │ ├── web-app-installer.module.ts │ │ │ │ └── web-app-installer.service.ts │ │ │ ├── signup/ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── signup.component.spec.ts.snap │ │ │ │ ├── signup-routing.module.ts │ │ │ │ ├── signup.component.e2e-spec.ts │ │ │ │ ├── signup.component.html │ │ │ │ ├── signup.component.scss │ │ │ │ ├── signup.component.spec.ts │ │ │ │ ├── signup.component.ts │ │ │ │ └── signup.module.ts │ │ │ ├── unauthorized/ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── unauthorized.component.spec.ts.snap │ │ │ │ ├── unauthorized-routing.module.ts │ │ │ │ ├── unauthorized.component.html │ │ │ │ ├── unauthorized.component.scss │ │ │ │ ├── unauthorized.component.spec.ts │ │ │ │ ├── unauthorized.component.ts │ │ │ │ └── unauthorized.module.ts │ │ │ └── users/ │ │ │ ├── __snapshots__/ │ │ │ │ └── users.component.spec.ts.snap │ │ │ ├── users-routing.module.ts │ │ │ ├── users.component.html │ │ │ ├── users.component.scss │ │ │ ├── users.component.spec.ts │ │ │ ├── users.component.ts │ │ │ └── users.module.ts │ │ ├── index.html │ │ ├── main-prod.ts │ │ ├── main.aot-prod.ts │ │ ├── main.aot.ts │ │ ├── main.ts │ │ ├── ngsw.json │ │ ├── operators.ts │ │ ├── polyfills.ts │ │ └── styles/ │ │ ├── main.scss │ │ └── material2-app-themes.scss │ ├── server/ │ │ ├── api/ │ │ │ ├── api.spec.ts │ │ │ ├── controllers/ │ │ │ │ ├── index.ts │ │ │ │ ├── settings.controller.spec.ts │ │ │ │ └── settings.controller.ts │ │ │ ├── index.ts │ │ │ ├── middlewares/ │ │ │ │ ├── index.ts │ │ │ │ └── zone-error-handler.ts │ │ │ ├── repositories/ │ │ │ │ ├── index.ts │ │ │ │ ├── setting.repository.ts │ │ │ │ └── settings.ts │ │ │ ├── services/ │ │ │ │ ├── index.ts │ │ │ │ └── setting.service.ts │ │ │ └── test-helper.ts │ │ ├── server.angular-fire.service.ts │ │ ├── server.angular.module.ts │ │ ├── server.config.ts │ │ ├── server.sitemap.ts │ │ ├── server.ts │ │ ├── server.web-socket.ts │ │ └── service-account.json │ ├── testing/ │ │ ├── app-testing.module.ts │ │ ├── mock-cookie.service.ts │ │ ├── mock-environment.service.ts │ │ └── mock-firebase-database.service.ts │ ├── tsconfig.json │ └── tslint.json ├── tools/ │ ├── config/ │ │ ├── app.config.ts │ │ ├── build.ci.replace.ts │ │ ├── build.config.ts │ │ ├── build.interfaces.ts │ │ └── console.banner.256.txt │ ├── env/ │ │ ├── base.ts │ │ ├── dev.ts │ │ ├── e2e.ts │ │ └── prod.ts │ ├── manual-typings/ │ │ ├── README.md │ │ ├── project/ │ │ │ └── sample.package.d.ts │ │ └── seed/ │ │ ├── bunyan.d.ts │ │ ├── hash-files.d.ts │ │ ├── json.d.ts │ │ └── loglevel-std-streams.d.ts │ ├── plugins/ │ │ ├── ng-aot.ts │ │ ├── pwa-fused.ts │ │ └── web-index.ts │ ├── scripts/ │ │ ├── post-merge.sh │ │ └── replace.ts │ ├── tasks/ │ │ ├── index.ts │ │ ├── project/ │ │ │ └── sample.ts │ │ └── seed/ │ │ ├── assets.ts │ │ ├── banner.ts │ │ ├── changelog.ts │ │ ├── clean.ts │ │ ├── config.ts │ │ ├── favicons.ts │ │ ├── fonts.ts │ │ ├── index.copy.ts │ │ ├── index.minify.ts │ │ ├── lint.ts │ │ ├── mk-dist.ts │ │ ├── ngc.ts │ │ ├── ngsw-json.ts │ │ ├── ngsw-worker.min.ts │ │ ├── ngsw-worker.ts │ │ ├── ngsw.ts │ │ ├── sass.files.ts │ │ ├── sass.ts │ │ ├── serve.ts │ │ └── web.ts │ ├── test/ │ │ ├── jest.e2e-setup.ts │ │ ├── jest.mocks.ts │ │ └── jest.setup.ts │ ├── tslint-rules/ │ │ └── validateDecoratorsRule.ts │ └── web/ │ ├── ping.html │ └── robots.txt ├── tsconfig-aot.json ├── tsconfig-e2e.json └── tsconfig.json ================================================ FILE CONTENTS ================================================ ================================================ FILE: .editorconfig ================================================ # http://editorconfig.org root = true [*] charset = utf-8 indent_style = space indent_size = 2 end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true [*.md] insert_final_newline = false trim_trailing_whitespace = false ================================================ FILE: .firebaserc ================================================ { "projects": { "default": "fuse-angular-universal-s-67402" } } ================================================ FILE: .gitignore ================================================ # Logs logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* .DS_Store dist .env .fusebox # Runtime data pids *.pid *.seed *.pid.lock # Directory for instrumented libs generated by jscoverage/JSCover lib-cov # Coverage directory used by tools like istanbul coverage # nyc test coverage .nyc_output # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) .grunt # Bower dependency directory (https://bower.io/) bower_components # node-waf configuration .lock-wscript # Compiled binary addons (http://nodejs.org/api/addons.html) build/Release # Dependency directories node_modules/ jspm_packages/ # Typescript v1 declaration files typings/ # Optional npm cache directory .npm # Optional eslint cache .eslintcache # Optional REPL history .node_repl_history # Output of 'npm pack' *.tgz # Yarn Integrity file .yarn-integrity # dotenv environment variables file .env dist/ .DS_Store test-report.xml test-results.xml ngc .ngc .aot aot .e2e documentation src/config.json ================================================ FILE: .stylelintrc ================================================ { "rules": { "block-no-empty": null, "color-no-invalid-hex": true, "comment-empty-line-before": [ "always", { "ignore": ["stylelint-commands", "between-comments"] } ], "declaration-colon-space-after": "always", "indentation": 2, "max-empty-lines": 2, "unit-whitelist": ["em", "rem", "%", "px", "s", "ms", "vw", "vh", "deg"] } } ================================================ FILE: .vscode/extensions.json ================================================ { "recommendations": [ "msjsdiag.debugger-for-chrome", "michelemelluso.code-beautifier", "eg2.tslint", "eamodio.gitlens" ] } ================================================ FILE: .vscode/settings.json ================================================ // Place your settings in this file to overwrite default and user settings. { "editor.tabSize": 2, "beautify.tabSize": 2, "editor.insertSpaces": true, "autoimport.filesToScan": "src/**/*.{ts,tsx}", "typescript.tsdk": "node_modules/typescript/lib" } ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at patrickmichalina@mac.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ ================================================ FILE: CONTRIBUTING.md ================================================ # Contributing We love pull requests from everyone. By participating in this project, you agree to abide by our [code of conduct]. [code of conduct]: https://github.com/patrickmichalina/fusebox-angular-universal-starter/blob/master/CODE_OF_CONDUCT.md Fork, then clone the repo: git clone https://github.com/patrickmichalina/fusebox-angular-universal-starter Make sure the tests pass: npm test Make your change. Add tests for your change. Make the tests pass: npm test Push to your fork and [submit a pull request][pr]. [pr]: https://github.com/patrickmichalina/fusebox-angular-universal-starter/compare At this point you're waiting on us. We like to at least comment on pull requests within three business days (and, typically, one business day). We may suggest some changes or improvements or alternatives. Some things that will increase the chance that your pull request is accepted: * Write tests. * Write a [good commit message][commit]. [commit]: https://conventionalcommits.org ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2017 Patrick Michalina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: Procfile ================================================ web: node dist/server.js --prod ================================================ FILE: README.md ================================================ ## This project is archived and an improved version has been moved to [https://github.com/patrickmichalina/fusing-angular](https://github.com/patrickmichalina/fusing-angular) # Introduction [![CircleCI](https://circleci.com/gh/patrickmichalina/fusebox-angular-universal-starter.svg?style=shield)](https://circleci.com/gh/patrickmichalina/fusebox-angular-universal-starter) [![codecov](https://codecov.io/gh/patrickmichalina/fusebox-angular-universal-starter/branch/master/graph/badge.svg)](https://codecov.io/gh/patrickmichalina/fusebox-angular-universal-starter) [![dependencies Status](https://david-dm.org/patrickmichalina/fusebox-angular-universal-starter/status.svg)](https://david-dm.org/patrickmichalina/fusebox-angular-universal-starter) [![devDependencies Status](https://david-dm.org/patrickmichalina/fusebox-angular-universal-starter/dev-status.svg)](https://david-dm.org/patrickmichalina/fusebox-angular-universal-starter?type=dev) [![Greenkeeper badge](https://badges.greenkeeper.io/patrickmichalina/fusebox-angular-universal-starter.svg)](https://greenkeeper.io/) [![Angular Style Guide](https://mgechev.github.io/angular2-style-guide/images/badge.svg)](https://angular.io/styleguide) [![Fusebox-bundler](https://img.shields.io/badge/gitter-join%20chat%20%E2%86%92-brightgreen.svg)](https://gitter.im/fusebox-angular-universal-starter/Lobby) Provides an extremely fast seed project for the development of Angular Universal (isomorphic) projects. Check out the [live app](https://angular.patrickmichalina.com) # Project Goals This starter project is designed to get a basic application up and running with basic implementations of core features most applications need. It uses [Firebase](https://firebase.google.com) for the authentication and the database layers. Note: Firebase doesn't have official support for Angular Universal at this time. However, we have implemented some of the basic features to render and transfer server state to the browser. Once an official support is released, we will use that. # Features - [x] [Angular](https://github.com/angular/angular/blob/master/CHANGELOG.md) as the application framework - [x] [Angular Material](https://material.angular.io) as the UI language and component library - [x] [Angular Flex Layout](https://github.com/angular/flex-layout) for dynamic responsive layouts - [x] [FuseBox](http://fuse-box.org) as the TypeScript/JavaScript bundler - [x] [Jest](https://facebook.github.io/jest) for unit and component testing - [x] [Nightmare](https://github.com/segmentio/nightmare) for UI testing - [x] [Sparky](http://fuse-box.org/page/sparky) as the task runner - [x] Fully typed build tools using [TypeScript](https://www.typescriptlang.org) - [x] Production and development builds - [x] Manage your type definitions using [@types](https://www.npmjs.com/~types) - [x] Simple [Heroku](https://www.heroku.com) Deployment - [x] HttpStateTransfer for caching server responses on client boostrap (no flickering) - [x] CDN asset configuration - [x] Automatic sitemap generation - [x] [SCSS](http://sass-lang.com) support for professional grade CSS management - [x] [Brotli compression](https://github.com/google/brotli) with [gzip](http://www.gzip.org) fallback - [x] [CircleCI](https://circleci.com) unit testing support - [x] Full favicon icon generation for multiple devices derived from a single seed image - [x] SEO support for Title and Meta tags - [x] OG (Open Graph) tags for social sharing - [x] Simple Ad-Blocker detection service - [x] Vendor-agnostic analytics using [angulartics2](https://github.com/angulartics/angulartics2) - [x] Generic token based Authentication service with [JWT](https://jwt.io) cookie support. - [x] Both Client and Server build tasks - [x] Hot Module Reloading for faster browser reloads during client development - [ ] [Ahead-of-Time](https://angular.io/guide/aot-compiler) (AOT) compilation support - [x] [angular-tslint-rules](https://github.com/fulls1z3/angular-tslint-rules) as configuration preset for [TSLint](https://github.com/palantir/tslint) and [codelyzer](https://github.com/mgechev/codelyzer). - [x] Automatic static file cache invalidation - [x] [Lazy Loaded](https://angular-2-training-book.rangle.io/handout/modules/lazy-loading-module.html) modules - [x] Analyze bundle sizes by using [source-map-explorer](https://github.com/danvk/source-map-explorer) - [x] Support for [Angular Mobile Toolkit](https://mobile.angular.io) (Service Worker) - [x] [Tree-Shaking](https://angular.io/guide/aot-compiler) for production builds Built by [AngularUniversal.com](https://www.angularuniversal.com). For additional help please checkout our [services](https://www.angularuniversal.com/services) # Quick Start **Note that we strongly recommend node >= v7.0.0 and npm >= 4.0.0.** To start the seed use: ```bash $ git clone --depth 1 https://github.com/patrickmichalina/fusebox-angular-universal-starter $ cd fusebox-angular-universal-starter # Add Firebase Admin values to your project # in a ".env" file for local deveopment # in environment variables for other environments See [Environment Variables](#environment-variables) # install the project's dependencies $ npm install # start the Angular Universal server $ npm start # start the server while watching tests and updating app documentation $ npm run start.deving # start the Angular Universal server w/ AOT build step $ npm run start.aot # can also be called passing the parameter --aot # npm start --aot # start the application in Client only mode (not server driven), with HMR enabled $ npm run start.spa # start the server in production mode $ npm run start.prod ``` # Table of Contents * [Testing](#testing) * [Configuration](#configuration) * [Environment Variables](#environment-variables) * [@Types](#types) * [File Structure](#file-structure) * [Change Log](#change-log) * [License](#license) # Bundling Checkout how blazing fast bundling can be using FuseBox! ![fuse-box](https://thumbs.gfycat.com/WarmheartedUnfinishedHind-small.gif) # Testing ```bash # single test run $ npm test # single test with coverage results $ npm run test.coverage # continuous testing $ npm run test.watch # e2e testing (primarilly for CI builds) $ npm run test.e2e.ci # continuous e2e testing $ npm run test.e2e.watch ``` ![jest](https://thumbs.gfycat.com/CooperativeMammothEland-small.gif) # Configuration ```shell Coming Soon ``` # @Types When you include a module that doesn't include typings, you can include external type definitions using the npm @types repo. i.e, to have youtube api support, run this command in terminal: ```shell npm i -D @types/youtube @types/gapi @types/gapi.youtube ``` # Environment Variables ```bash # it is important to set the following environmental variables on your CI server (examples below) HOST : angular.patrickmichalina.com # the root origin of your application server CI : true # for Heroku Builds HEROKU : true # to build on heroku, ssl settings are setup using this flag NPM_CONFIG_PRODUCTION : false # to download all depenedencies on Heroku, including devDependencies # Firebase Admin SDK FB_SERVICE_ACCOUNT_PRIVATE_KEY_ID: Some_Secret FB_SERVICE_ACCOUNT_PRIVATE_KEY: Some_Secret FB_AUTH_KEY: Some_Secret ``` ## File Structure We use the component approach in our starter. This is the standard for developing Angular apps and a great way to ensure maintainable code ``` fusebox-angular-universal-starter/ ├──.fusebox/ * working folder for the js bundler ├──.vscode/ * Visual Studio Code settings ├──coverage/ * stores recent reporting of test coverage ├──dist/ * output files that represent the bundled application and its dependencies ├──node_modules/ * project depdendencies | ├──src/ | ├──client/ * client Angular code. (most your work should be done here) | └──server/ * server code | ├──tools/ | ├──config/ | | ├──app.config.ts * configuration interface for the web applications | | ├──build.config.ts * configuration values for the build system | | ├──build.interfaces.ts * configuration interfaces for the build system | | └──build.transformer.ts * build system config transform helper | | | ├──env/ | | ├──base.ts * base app configuration | | ├──dev.ts * dev app configuration | | ├──**.ts * arbitrary configuration called via the flag --env-config | | └──prod.ts * production app configuration | | | ├──scripts/ * misc. build helper scripts | ├──tasks/ * Sparky tasks | ├──test/ * testing system related configuration | └──web/ * static assets used for common web functions | ├──.gitignore * GIT settings ├──circl.yml * CirclCI configuration file ├──CODE_OF_CONDUCT.md * standard code of conduct information ├──codecov.yml * codecov.io configuration file ├──CONTRIBUTING.md * standard contributor information ├──fuse.ts * FuseBox entry point ├──LICENSE * software license ├──package-lock.json * what npm uses to manage it's dependencies ├──package.json * what npm uses to manage it's dependencies ├──Procfile * Heroku deployment setting ├──README.md * project information ├──test-report.xml * JUNIT test results ├──tsconfig-aot.json * typescript config for AOT build using @angular-cli (ngc) └──tsconfig.json * typescript config ``` # Change Log You can follow the [Angular change log here](https://github.com/angular/angular/blob/master/CHANGELOG.md). # License [MIT](https://github.com/patrickmichalina/fusebox-angular-universal-starter/blob/master/LICENSE) ================================================ FILE: app.json ================================================ { "name": "fusebox-angular-universal-star", "env": { "CI": { "required": true }, "HOST": { "required": true }, "HEROKU": { "required": true }, "NODE_MODULES_CACHE": { "required": true }, "NPM_CONFIG_PRODUCTION": { "required": true }, "HEROKU_APP_NAME": { "required": true }, "HEROKU_PARENT_APP_NAME": { "required": true }, "FB_SERVICE_ACCOUNT_PRIVATE_KEY": { "required": true }, "FB_SERVICE_ACCOUNT_PRIVATE_KEY_ID": { "required": true }, "FB_AUTH_KEY": { "required": true } } } ================================================ FILE: circle.yml ================================================ machine: node: version: 9.4.0 npm: version: 5.6.0 general: artifacts: - ./coverage - ./dist test: override: - npm run lint - npm run gen.config - npm run test.ci.before - node_modules/.bin/jest --ci --updateSnapshot --runInBand --coverage: environment: TEST_REPORT_PATH: $CIRCLE_TEST_REPORTS TEST_REPORT_FILENAME: test-results.xml - npm run test.ci.after post: - bash <(curl -s https://codecov.io/bash) - npm run semantic-release || true deployment: production: branch: master heroku: appname: fusebox-angular-universal-star ================================================ FILE: codecov.yml ================================================ codecov: allow_coverage_offsets: false ignore: - "tools" ================================================ FILE: data/security.rules.json ================================================ { "rules": { "site-settings": { ".read": "true", ".write": "root.child('users').child(auth.uid).child('roles/superadmin').val() === true" }, "posts": { ".read": "true", ".write": "true" }, "pages": { ".read": "true", ".write": "true", "blog": { "$document": { ".read": "true", ".write": "true" } } }, "users": { ".read": "auth != null && root.child('users').child(auth.uid).child('roles/superadmin').val() === true", "$uid": { ".read": "auth != null && auth.uid == $uid || root.child('users').child(auth.uid).child('roles/superadmin').val() === true", ".write": "auth != null && auth.uid == $uid || root.child('users').child(auth.uid).child('roles/superadmin').val() === true" } } } } ================================================ FILE: data/seed.settings.json ================================================ { "host": "http://localhost:8000", "og": { "title": "Fusebox Angular Universal Starter", "description": "Seed project for Angular Universal apps featuring Server-Side Rendering (SSR), FuseBox, dev/prod builds, Brotli/Gzip, SCSS, favicon generation, @types, unit testing w/ Jest, and sitemap generator. Created by Patrick Michalina", "image": "https://d3anl5a3ibkrdg.cloudfront.net/assets/favicons/android-chrome-512x512.png", "type": "website", "locale": "en_US" }, "firebase": { "appName": "fuse-angular-universal-starter", "config": { "apiKey": "AIzaSyDfE1owJZCbvasXieCKjMoGZddRhqcp7RM", "authDomain": "fuse-angular-universal-s-67402.firebaseapp.com", "databaseURL": "https://fuse-angular-universal-s-67402.firebaseio.com", "projectId": "fuse-angular-universal-s-67402", "storageBucket": "fuse-angular-universal-s-67402.appspot.com", "messagingSenderId": "883416191164" } }, "assets": { "userAvatarImage": "https://firebasestorage.googleapis.com/v0/b/fuse-angular-universal-s-67402.appspot.com/o/avatar.jpg?alt=media&token=9a153021-6e12-460b-9d87-40c2eed02c82" }, "tokens": { "facebookAppId": "117309532219749" }, "injections": [ { "inHead": true, "element": "link", "attributes": { "href": "/manifest.json", "rel": "manifest" } }, { "inHead": true, "element": "meta", "attributes": { "name": "theme-color", "content": "#2196F3" } }, { "inHead": false, "element": "link", "attributes": { "href": "https://fonts.googleapis.com/css?family=Roboto", "rel": "stylesheet", "type": "text/css", "media": "none", "onload": "if(media!=='all')media='all'" } }, { "inHead": true, "element": "meta", "attributes": { "name": "google-site-verification", "content": "RW-hcjXEgPMoy2NF8pTl8IEzP8gnj3cEZ6aF1HDUiOc" } }, { "inHead": true, "element": "script", "value": "window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;ga('create', 'UA-107089312-2', 'auto');", "attributes": { "type": "text/javascript" } }, { "inHead": false, "element": "script", "attributes": { "async": "true", "type": "text/javascript", "src": "https://www.google-analytics.com/analytics.js" } } ], "i18n": { "en": { "about": { "title": "About", "description": "See contact information and details about the Angular Universal seed at angular.patrickmichalina.com" }, "account": { "title": "Account", "description": "Update your profile and account settings" }, "dashboard": { "title": "Dashboard", "description": "An example dashboard page" }, "admin": { "title": "Admin", "description": "For application management" }, "changelog": { "title": "Changelog", "description": "Version history of the application" }, "home": { "title": "Home", "description": "A fullstack angular starter framework to quickly build mid-large scale web applications" }, "login": { "title": "Login", "description": "Login to your account now." }, "logout": { "title": "Logged Out", "description": "Come back again!" }, "search": { "title": "Search", "description": "Search for angular related projects on github, to showcase the flicker-free http state transfer of an Angular isomorphic application." }, "signup": { "title": "Signup", "description": "Sign up for an account with us. Create an account to start doing cool things with our application. It\"s easy to register" }, "not-found": { "title": "Not Found", "description": "The page you requested can not be found." } }, "jp": { "home": { "title": "こんにちは", "description": "" } } } } ================================================ FILE: data/seed.superusers.json ================================================ { "9BthHoxklbgCzP2vlFI3ZrNggrl1": { "roles": { "superadmin": true, "admin": true } } } ================================================ FILE: docs/angular-universal.md ================================================ # Universal "Gotchas" > When building Universal components in Angular 2 there are a few things to keep in mind. - **`window`**, **`document`**, **`navigator`**, and other browser types - _do not exist on the server_ - so using them, or any library that uses them (jQuery for example) will not work. You do have some options, if you truly need some of this functionality: - If you need to use them, consider limiting them to only your client and wrapping them situationally. You can use the Object injected using the PLATFORM_ID token to check whether the current platform is browser or server. ``` import { PlatformService } from '../services'; constructor(private platformService: PlatformService) { ... } ngOnInit() { if (this.platformService.isBrowser) { // Client only code. ... } if (this.platformService.isServer) { // Server only code. ... } } ``` - Try to *limit or* **avoid** using **`setTimeout`**. It will slow down the server-side rendering process. Make sure to remove them in the [`ngOnDestroy`](https://angular.io/docs/ts/latest/api/core/index/OnDestroy-class.html) method of your Components. - Also for RxJs timeouts, make sure to _cancel_ their stream on success, for they can slow down rendering as well. - **Don't manipulate the nativeElement directly**. Use the _Renderer2_. We do this to ensure that in any environment we're able to change our view. ``` constructor(element: ElementRef, renderer: Renderer2) { renderer.setStyle(element.nativeElement, 'font-size', 'x-large'); } ``` - The application runs XHR requests on the server & once again on the Client-side (when the application bootstraps) - Use a cache that's transferred from server to client (TODO: Point to the example) - Know the difference between attributes and properties in relation to the DOM. - Keep your directives stateless as much as possible. For stateful directives, you may need to provide an attribute that reflects the corresponding property with an initial string value such as url in img tag. For our native element the src attribute is reflected as the src property of the element type HTMLImageElement. ================================================ FILE: docs/api-server.md ================================================ # API This project includes an example API that can be split off into a standalone server. The goal of this API is to provide a set of commonly used endpoints that could apply to most modern web applications. This inclides things like: - Site Settings - Image Uploads - Tokens (login/logout) # Stack - [routing-controllers](https://github.com/pleerock/routing-controllers) Create structured, declarative and beautifully organized class-based controllers with heavy decorators usage in Express / Koa using TypeScript and Routing Controllers Framework. - [swagger-jsdoc]() Generates swagger doc based on JSDoc. - [swagger-ui-express]() Adds middleware to your express app to serve the Swagger UI bound to your Swagger document. This acts as living documentation for your API hosted from within your app. - [typedi]() Dependency Injection for TypeScript. # Structure The API has an opinionted structure in order to better sperate the various layers of the applications: - Controllers: gateway to the outside world, where users actually interact with the server - Services: internal tools that can be used in controllers, other services, or anywhere in the API - Repositories: data stores that are normally accessed via services - Middlewares: express server plugins ## Removing from the project ... TODO ================================================ FILE: docs/openid-server.md ================================================ # Identity Server This project includes an OpenID certifiec identity server that can be split off into a standalone OpenID server. ## Removing from the project ... TODO ================================================ FILE: e2e-spec.json ================================================ { "moduleFileExtensions": [ "ts", "js", "html" ], "testRegex": "(/__tests__/.*|\\.(test|e2e-spec))\\.(ts|js)$", "transform": { "^.+\\.tsx?$": "/node_modules/ts-jest/preprocessor.js" }, "globals": { "__TRANSFORM_HTML__": true, "__process_env__": {}, "ts-jest": { "tsConfigFile": "tsconfig.json" } } } ================================================ FILE: firebase.json ================================================ { "database": { "rules": "data/security.rules.json" } } ================================================ FILE: fuse.ts ================================================ import { Ng2TemplatePlugin } from 'ng2-fused'; import { argv } from 'yargs'; import { BUILD_CONFIG, ENV_CONFIG_INSTANCE, isProdBuild, typeHelper } from './tools/config/build.config'; import { WebIndexPlugin } from './tools/plugins/web-index'; import { init, reload, active } from 'browser-sync'; import { EnvPlugin, FuseBox, HTMLPlugin, JSONPlugin, RawPlugin, SassPlugin, Sparky, QuantumPlugin } from 'fuse-box'; import './tools/tasks'; const death = require('death') const isReachable = require('is-reachable'); const isAot = argv.aot; const isBuildServer = argv.ci; const baseEntry = isAot ? 'main.aot' : 'main'; const appBundleName = `js/app`; const vendorBundleName = `js/vendors`; const mainEntryFileName = isProdBuild ? `${baseEntry}-prod` : `${baseEntry}`; const vendorBundleInstructions = ` ~ client/${mainEntryFileName}.ts`; const appBundleInstructions = ` !> [client/${mainEntryFileName}.ts]`; const serverBundleInstructions = ' > [server/server.ts]'; if (isProdBuild) typeHelper() const baseOptions = { homeDir: './src', output: `${BUILD_CONFIG.outputDir}/$name.js`, plugins: [ Ng2TemplatePlugin(), ['*.component.html', RawPlugin()], ['*.component.scss', SassPlugin({ indentedSyntax: false, importer: true, sourceMap: false, outputStyle: 'compressed' } as any), RawPlugin()], JSONPlugin(), HTMLPlugin({ useDefault: false }) ] } const appOptions = { ...baseOptions, hash: isProdBuild, plugins: [ ...baseOptions.plugins, WebIndexPlugin({ bundles: [vendorBundleName, appBundleName], startingDocumentPath: 'dist/index.html', appElement: { name: 'pm-app', innerHTML: 'Loading....' }, additionalDeps: BUILD_CONFIG.dependencies as any[] }), isProdBuild && QuantumPlugin({ target: "universal", warnings: false, uglify: true, treeshake: true, bakeApiIntoBundle: vendorBundleName, processPolyfill: true }) ] } const serverOptions = { ...baseOptions, target: 'server', sourceMaps: false, plugins: [ EnvPlugin(ENV_CONFIG_INSTANCE), ...baseOptions.plugins ] } Sparky.task('build.universal', () => { const fuseApp = FuseBox.init(appOptions as any); const fuseServer = FuseBox.init(serverOptions as any); const path = isAot ? 'client/.aot/src/client/app' : 'client/app'; const serverBundle = fuseServer.bundle('server').instructions(serverBundleInstructions); const vendorBundle = fuseApp.bundle(`${vendorBundleName}`).instructions(vendorBundleInstructions) const appBundle = fuseApp .bundle(appBundleName) .splitConfig({ dest: 'js/modules' }) .instructions(`${appBundleInstructions} + [${path}/**/!(*.spec|*.e2e-spec|*.ngsummary|*.snap).*]`) if (!isBuildServer && !argv['build-only']) { const proxy = `${BUILD_CONFIG.host}:${BUILD_CONFIG.port}` vendorBundle.watch() appBundle.watch() return fuseApp.run().then(() => { serverBundle.watch('src/**').completed(proc => { typeHelper(false, false) proc.start(); isReachable(proxy).then(() => { active ? reload() : init({ port: BUILD_CONFIG.browserSyncPort, proxy }) }) death(function (signal: any, err: any) { proc.kill() process.exit() }) }) return fuseServer.run() }); } else { return fuseApp.run().then(() => fuseServer.run()) } }); ================================================ FILE: package.json ================================================ { "name": "fusebox-angular-universal-starter", "version": "0.0.0-development", "description": "Angular Universal starter build pipeline using FuseBox", "license": "MIT", "homepage": "https://angular.patrickmichalina.com", "repository": { "type": "git", "url": "https://github.com/patrickmichalina/fusebox-angular-universal-starter" }, "bugs": { "email": "patrickmichalina@mac.com", "url": "https://github.com/patrickmichalina/fusebox-angular-universal-starter/issues" }, "author": { "email": "patrickmichalina@mac.com", "name": "Patrick Michalina", "url": "https://patrickmichalina.com" }, "readme": "https://github.com/patrickmichalina/fusebox-angular-universal-starter/blob/master/README.md", "scripts": { "test": "npm run gen.config && jest", "test.ci": "npm run gen.config && jest --ci --updateSnapshot", "test.update": "npm run gen.config && jest --updateSnapshot", "test.coverage": "npm run gen.config && jest --coverage", "test.watch": "npm run gen.config && jest --watch", "test.ci.before": "greenkeeper-lockfile-update", "test.ci.after": "greenkeeper-lockfile-upload", "test.e2e": "npm run gen.config && jest -c e2e-spec.json", "test.e2e.ci": "npm run gen.config && npm run start.e2e && concurrently --kill-others --success first \"node dist/server.js --e2e --port 8000\" \"npm run test.e2e\"", "test.e2e.watch": "npm run gen.config && npm run start.e2e && concurrently --kill-others --success first --raw \"node dist/server.js --e2e\" \"jest -c e2e-spec.json --watch\" ", "start.mock.api": "json-server ./tools/test/db.json", "start.e2e": "ts-node fuse.ts serve --build-type prod --env-config e2e --ci --port 8000", "start": "ts-node fuse.ts serve --build-type dev --env-config dev", "start.deving": "concurrently \"npm run start\" \"npm run test.watch\" \"npm run compodoc\"", "start.spa": "ts-node fuse.ts serve --build-type dev --spa", "start.prod": "ts-node fuse.ts serve --build-type prod --env-config=prod", "start.prod.ci": "CI=true ts-node fuse.ts serve --build-type prod --env-config prod --ci --ci-vars", "heroku-postbuild": "npm run start.prod.ci", "source.tree.app": "ts-node fuse.ts build --build-only && source-map-explorer dist/js/app.js", "source.tree.server": "ts-node fuse.ts build --build-only && source-map-explorer dist/server.js", "compodoc": "./node_modules/.bin/compodoc -p tsconfig.json -t -s -w -o -r 8081 --theme readthedocs", "prepush": "npm run lint && npm test", "postmerge": "./tools/scripts/post-merge.sh || true", "semantic-release": "semantic-release pre && npm publish && semantic-release post", "lint": "ts-node fuse.ts lint --build-type prod", "postinstall": "./node_modules/.bin/ts-node fuse.ts clean", "firebase": "./node_modules/.bin/firebase", "firebase.update": "./node_modules/.bin/firebase deploy && npm run firebase.seed.superusers", "firebase.seed.site-settings": "./node_modules/.bin/firebase database:update /site-settings data/seed.settings.json -y", "firebase.seed.superusers": "./node_modules/.bin/firebase database:update /users data/seed.superusers.json -y", "gen.config": "ts-node fuse.ts config" }, "devDependencies": { "@compodoc/compodoc": "1.1.2", "@pwa/manifest": "1.0.0", "@types/body-parser": "1.16.8", "@types/browser-sync": "0.0.39", "@types/bunyan": "1.8.4", "@types/clean-css": "3.4.30", "@types/compression": "0.0.36", "@types/cookie-parser": "1.4.1", "@types/dotenv": "4.0.3", "@types/express": "4.11.1", "@types/getos": "3.0.0", "@types/glob": "5.0.35", "@types/html-minifier": "3.5.2", "@types/jest": "22.2.3", "@types/js-cookie": "2.1.0", "@types/jsdom": "11.0.4", "@types/memory-cache": "0.2.0", "@types/mkdirp": "0.5.2", "@types/ms": "0.7.30", "@types/nightmare": "2.10.3", "@types/node-sass": "3.10.32", "@types/object-hash": "1.2.0", "@types/quill": "1.3.6", "@types/request": "2.47.0", "@types/serve-favicon": "2.2.30", "@types/stacktrace-js": "0.0.32", "@types/string-hash": "1.1.1", "@types/supertest": "2.0.4", "@types/ws": "4.0.2", "@types/yargs": "11.0.0", "angular-tslint-rules": "1.2.1", "browser-sync": "2.23.6", "codelyzer": "4.2.1", "concurrently": "3.5.1", "condition-circle": "2.0.1", "conventional-changelog": "1.1.24", "death": "1.1.0", "favicons": "4.8.6", "firebase-tools": "3.17.6", "font-awesome": "4.7.0", "fuse-box": "3.0.2", "fuse-box-typechecker": "2.7.1", "glob": "7.1.2", "greenkeeper-lockfile": "1.14.0", "hash-files": "1.1.1", "html-minifier": "3.5.15", "husky": "0.14.3", "is-reachable": "2.4.0", "jest": "22.4.2", "jest-junit-reporter": "1.1.0", "jest-preset-angular": "5.2.1", "jsdom": "11.6.2", "last-release-git": "0.0.3", "mkdirp": "0.5.1", "ng2-fused": "0.5.1", "node-run-cmd": "1.0.1", "node-sass": "4.8.3", "opn": "5.3.0", "semantic-release": "15.1.7", "source-map-explorer": "1.5.0", "string-hash": "1.1.3", "superagent": "3.8.2", "svg2png": "4.1.1", "ts-jest": "22.4.3", "ts-node": "5.0.1", "tslint": "5.9.1", "tslint-immutable": "4.5.2", "typescript": "2.7.2", "uglify-es": "3.3.9" }, "dependencies": { "@angular/animations": "6.0.0-beta.7", "@angular/cdk": "5.1.1", "@angular/common": "6.0.0-beta.7", "@angular/compiler": "6.0.0-beta.7", "@angular/compiler-cli": "6.0.0-beta.7", "@angular/core": "6.0.0-beta.7", "@angular/flex-layout": "2.0.0-beta.12", "@angular/forms": "6.0.0-beta.7", "@angular/http": "6.0.0-beta.7", "@angular/material": "5.1.1", "@angular/platform-browser": "6.0.0-beta.7", "@angular/platform-browser-dynamic": "6.0.0-beta.7", "@angular/platform-server": "6.0.0-beta.7", "@angular/router": "6.0.0-beta.7", "@angular/service-worker": "6.0.0-beta.7", "@expo/bunyan": "1.8.10", "@nguniversal/common": "5.0.0", "@nguniversal/express-engine": "5.0.0", "@ngx-meta/core": "5.0.0", "angular2-jwt": "0.2.3", "angularfire2": "5.0.0-rc.6", "angulartics2": "5.1.2", "body-parser": "1.18.2", "bunyan-middleware": "0.8.0", "clean-css": "4.1.11", "compressible": "2.0.13", "compression": "1.7.2", "cookie-parser": "1.4.3", "core-js": "2.5.5", "cors": "2.8.4", "dotenv": "5.0.1", "express": "4.16.3", "express-minify-html": "0.12.0", "express-urlrewrite": "1.2.0", "firebase": "4.11.0", "firebase-admin": "5.10.0", "getos": "3.1.0", "hammerjs": "2.0.8", "js-cookie": "2.2.0", "markdown-to-html-pipe": "1.2.4", "ms": "2.1.1", "nightmare": "3.0.0", "object-hash": "1.3.0", "quill": "1.3.6", "reflect-metadata": "0.1.12", "request": "2.85.0", "routing-controllers": "0.7.7", "rxjs": "5.5.10", "serve-favicon": "2.4.5", "shrink-ray": "0.1.3", "sitemap-generator": "6.0.0", "stacktrace-js": "2.0.0", "supertest": "3.0.0", "swagger-jsdoc": "1.9.7", "swagger-ui-express": "3.0.8", "systemjs": "0.21.3", "ts-node": "5.0.1", "tsickle": "0.27.5", "typedi": "0.7.1", "url-parse": "1.3.0", "ws": "5.1.1", "xhr2": "0.1.4", "yargs": "11.0.0", "zone.js": "0.8.20" }, "engines": { "node": "= 9.4.0", "npm": "= 5.6.0" }, "release": { "branch": "master", "verifyConditions": "condition-circle", "getLastRelease": "last-release-git" }, "jest": { "preset": "jest-preset-angular", "moduleNameMapper": { "./client/operators": "/src/client/operators.ts" }, "setupTestFrameworkScriptFile": "./tools/test/jest.setup.ts", "testResultsProcessor": "./node_modules/jest-junit-reporter", "collectCoverageFrom": [ "src/client/app/**/*(*.service|*.component|*.pipe|*.directive|*.module).{ts,html}", "!src/client/app/shared/shared.module.ts", "src/server/**/**.{ts}" ], "globals": { "__TRANSFORM_HTML__": true, "__process_env__": {}, "ts-jest": { "tsConfigFile": "tsconfig.json" } } } } ================================================ FILE: src/client/app/__snapshots__/app.component.spec.ts.snap ================================================ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`App component should build without a problem 1`] = `