├── .husky
├── .gitignore
├── commit-msg
└── pre-commit
├── projects
├── demo-integrations
│ ├── cypress
│ │ ├── fixtures
│ │ │ └── example.json
│ │ ├── support
│ │ │ ├── e2e.ts
│ │ │ └── command.ts
│ │ ├── tests
│ │ │ └── ssr
│ │ │ │ └── ssr.cy.ts
│ │ └── plugins
│ │ │ └── index.js
│ ├── tsconfig.json
│ └── cypress.config.ts
└── demo
│ ├── src
│ ├── test-setup.ts
│ ├── app
│ │ ├── modules
│ │ │ ├── lazy
│ │ │ │ ├── lazy.template.html
│ │ │ │ ├── lazy.component.ts
│ │ │ │ └── lazy.module.ts
│ │ │ └── static
│ │ │ │ ├── static.template.html
│ │ │ │ ├── static.module.ts
│ │ │ │ └── static.component.ts
│ │ ├── app.component.ts
│ │ ├── app.component.html
│ │ ├── app.server.module.ts
│ │ ├── app.component.spec.ts
│ │ ├── app.browser.module.ts
│ │ └── app.routes.ts
│ ├── environments
│ │ ├── environment.ts
│ │ └── environment.prod.ts
│ ├── polyfills.ts
│ ├── favicon.ico
│ ├── styles.css
│ ├── main.server.ts
│ ├── main.browser.ts
│ └── index.html
│ ├── tsconfig.json
│ ├── tsconfig.spec.json
│ ├── tsconfig.app.json
│ ├── tsconfig.server.json
│ ├── jest.config.js
│ ├── .gitignore
│ ├── server.ts
│ └── project.json
├── .prettierignore
├── commitlint.config.js
├── jest.preset.js
├── .npmrc
├── .browserslistrc
├── angular.json
├── scripts
├── helpers
│ ├── get-last-major-version.ts
│ ├── check-prettier-changes.ts
│ ├── get-all-versions.ts
│ ├── execute.ts
│ ├── colored-log.ts
│ └── argv.ts
├── postchangelog.ts
├── syncVersions.js
└── npm-publish.ts
├── tsconfig.json
├── CHANGELOG.md
├── stylelint.config.js
├── tsconfig.spec.json
├── .editorconfig
├── tsconfig.eslint.json
├── .github
├── workflows
│ ├── build.yml
│ ├── lint.yml
│ ├── test.yml
│ ├── deploy.yml
│ └── e2e.yml
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── PULL_REQUEST_TEMPLATE.md
└── actions
│ └── nodejs
│ └── action.yml
├── prettier.config.js
├── .eslintrc.js
├── codecov.yml
├── .gitignore
├── CONTRIBUTING.md
├── tsconfig.base.json
├── nx.json
├── CODE_OF_CONDUCT.md
├── README.md
├── renovate.json
├── package.json
└── LICENSE
/.husky/.gitignore:
--------------------------------------------------------------------------------
1 | _
2 |
--------------------------------------------------------------------------------
/projects/demo-integrations/cypress/fixtures/example.json:
--------------------------------------------------------------------------------
1 | {}
2 |
--------------------------------------------------------------------------------
/projects/demo-integrations/cypress/support/e2e.ts:
--------------------------------------------------------------------------------
1 | import './command';
2 |
--------------------------------------------------------------------------------
/projects/demo/src/test-setup.ts:
--------------------------------------------------------------------------------
1 | import 'jest-preset-angular/setup-jest';
2 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | **/dist/**
2 | **/coverage/**
3 | package-lock.json
4 | .husky
5 |
--------------------------------------------------------------------------------
/projects/demo/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json"
3 | }
4 |
--------------------------------------------------------------------------------
/projects/demo/src/app/modules/lazy/lazy.template.html:
--------------------------------------------------------------------------------
1 |
This is a lazy route
2 |
--------------------------------------------------------------------------------
/commitlint.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {extends: ['@commitlint/config-conventional']};
2 |
--------------------------------------------------------------------------------
/projects/demo/src/app/modules/static/static.template.html:
--------------------------------------------------------------------------------
1 | This is a static route
2 |
--------------------------------------------------------------------------------
/jest.preset.js:
--------------------------------------------------------------------------------
1 | const nxPreset = require('@nrwl/jest/preset');
2 |
3 | module.exports = {...nxPreset};
4 |
--------------------------------------------------------------------------------
/projects/demo/src/environments/environment.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: false,
3 | };
4 |
--------------------------------------------------------------------------------
/projects/demo/src/environments/environment.prod.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: true,
3 | };
4 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | legacy-peer-deps=true
2 | engine-strict=false
3 | lockfileVersion=2
4 | ignore-engines=true
5 | loglevel=error
6 |
--------------------------------------------------------------------------------
/projects/demo/src/polyfills.ts:
--------------------------------------------------------------------------------
1 | import 'core-js/es6/reflect';
2 | import 'core-js/es7/reflect';
3 | import 'zone.js';
4 |
--------------------------------------------------------------------------------
/.husky/commit-msg:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # shellcheck disable=SC1090
3 | . "$(dirname "$0")/_/husky.sh"
4 |
5 | npx commitlint --edit $1
6 |
--------------------------------------------------------------------------------
/projects/demo/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tinkoff/angular-open-source-starter/HEAD/projects/demo/src/favicon.ico
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # shellcheck disable=SC1090
3 | . "$(dirname "$0")/_/husky.sh"
4 |
5 | npx lint-staged
6 | npm run typecheck
7 |
--------------------------------------------------------------------------------
/.browserslistrc:
--------------------------------------------------------------------------------
1 | # we only want es2015 compliant browsers https://caniuse.com/#feat=es6
2 | # just use one as representative for all
3 |
4 | supports es6-module
5 |
--------------------------------------------------------------------------------
/angular.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3 | "version": 2,
4 | "projects": {
5 | "demo": "projects/demo"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/projects/demo/src/styles.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: -apple-system, 'BlinkMacSystemFont', 'Segoe UI', system-ui, 'Roboto', 'Helvetica Neue', sans-serif;
3 | color: #333;
4 | margin: 0;
5 | }
6 |
--------------------------------------------------------------------------------
/scripts/helpers/get-last-major-version.ts:
--------------------------------------------------------------------------------
1 | export function getLastMajorVersion(versions: string[], currentMajor: number): number {
2 | return Math.max(...versions.map(x => parseInt(x)), currentMajor);
3 | }
4 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | // TODO after update all "@nrwl/*"-packages to 13.8.6+:
2 | // 1. Drop this file
3 | // 2. Rename "tsconfig.base.json" => "tsconfig.json"
4 | {
5 | "extends": "./tsconfig.base.json"
6 | }
7 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to this project will be documented in this file. See
4 | [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
5 |
--------------------------------------------------------------------------------
/projects/demo/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import {Component} from '@angular/core';
2 |
3 | @Component({
4 | selector: 'my-app',
5 | templateUrl: './app.component.html',
6 | })
7 | export class AppComponent {}
8 |
--------------------------------------------------------------------------------
/projects/demo/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.spec.json",
3 | "include": ["**/*.spec.ts", "**/*.d.ts"],
4 | "compilerOptions": {
5 | "esModuleInterop": true
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/projects/demo/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/app"
5 | },
6 | "files": ["./src/main.browser.ts", "./src/polyfills.ts"]
7 | }
8 |
--------------------------------------------------------------------------------
/stylelint.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: ['@tinkoff/stylelint-config/less', '@tinkoff/stylelint-config/angular'],
3 | ignoreFiles: ['**/demo/**', '**/dist/**', '**/coverage/**', '**/node_modules/**'],
4 | };
5 |
--------------------------------------------------------------------------------
/scripts/helpers/check-prettier-changes.ts:
--------------------------------------------------------------------------------
1 | import {execute} from './execute';
2 |
3 | export function checkPrettierChanges(pattern = `**/*.{json,md}`): void {
4 | execute(`prettier '${pattern}' --write`);
5 | execute(`git add .`, {stdio: `inherit`});
6 | }
7 |
--------------------------------------------------------------------------------
/projects/demo/src/app/modules/static/static.module.ts:
--------------------------------------------------------------------------------
1 | import {NgModule} from '@angular/core';
2 |
3 | import {StaticComponent} from './static.component';
4 |
5 | @NgModule({declarations: [StaticComponent], exports: [StaticComponent]})
6 | export class StaticModule {}
7 |
--------------------------------------------------------------------------------
/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "./out-tsc/spec",
5 | "module": "esnext",
6 | "types": ["jest"]
7 | },
8 | "exclude": ["**/schematics/**/*", "projects/demo-integrations"]
9 | }
10 |
--------------------------------------------------------------------------------
/projects/demo/src/app/modules/lazy/lazy.component.ts:
--------------------------------------------------------------------------------
1 | import {ChangeDetectionStrategy, Component} from '@angular/core';
2 |
3 | @Component({
4 | selector: 'lazy',
5 | templateUrl: './lazy.template.html',
6 | changeDetection: ChangeDetectionStrategy.OnPush,
7 | })
8 | export class LazyComponent {}
9 |
--------------------------------------------------------------------------------
/projects/demo/src/app/modules/static/static.component.ts:
--------------------------------------------------------------------------------
1 | import {ChangeDetectionStrategy, Component} from '@angular/core';
2 |
3 | @Component({
4 | selector: 'static',
5 | templateUrl: './static.template.html',
6 | changeDetection: ChangeDetectionStrategy.OnPush,
7 | })
8 | export class StaticComponent {}
9 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 4
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.md]
12 | max_line_length = off
13 | trim_trailing_whitespace = false
14 |
--------------------------------------------------------------------------------
/projects/demo-integrations/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "typeRoots": ["../../node_modules/@types", "../../node_modules/cypress/types"],
5 | "types": ["cypress", "node"]
6 | },
7 | "include": ["./cypress/**/*.ts"],
8 | "exclude": []
9 | }
10 |
--------------------------------------------------------------------------------
/tsconfig.eslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "rootDir": ".",
5 | "baseUrl": ".",
6 | "strict": false,
7 | "incremental": true
8 | },
9 | "include": ["projects", "scripts"],
10 | "exclude": ["**/node_modules", "**/schematics/**", "**/.*/", "*.js"]
11 | }
12 |
--------------------------------------------------------------------------------
/projects/demo/src/main.server.ts:
--------------------------------------------------------------------------------
1 | import {enableProdMode} from '@angular/core';
2 |
3 | import {environment} from './environments/environment';
4 |
5 | if (environment.production) {
6 | enableProdMode();
7 | }
8 |
9 | export {AppServerModule} from './app/app.server.module';
10 | export {renderModule, renderModuleFactory} from '@angular/platform-server';
11 |
--------------------------------------------------------------------------------
/projects/demo/tsconfig.server.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "./dist/out-tsc-server",
5 | "target": "es2016",
6 | "types": ["node"]
7 | },
8 | "files": ["src/main.server.ts", "server.ts"],
9 | "angularCompilerOptions": {
10 | "entryModule": "./src/app/app.server.module#AppServerModule"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Build
2 | on: [pull_request]
3 |
4 | jobs:
5 | build:
6 | runs-on: ubuntu-latest
7 | steps:
8 | - uses: actions/checkout@v2
9 | - name: Setup Node.js and Cache
10 | uses: ./.github/actions/nodejs
11 |
12 | - name: Build demo
13 | run: npm run build
14 |
15 | concurrency:
16 | group: build-${{ github.head_ref }}
17 | cancel-in-progress: true
18 |
--------------------------------------------------------------------------------
/scripts/helpers/get-all-versions.ts:
--------------------------------------------------------------------------------
1 | import {execute} from './execute';
2 |
3 | export function getAllVersions(name: string): string[] {
4 | try {
5 | const versions: string[] | string = JSON.parse(
6 | execute(`npm view ${name} versions --json || echo "[]"`, {}),
7 | );
8 |
9 | return Array.isArray(versions) ? versions : [versions];
10 | } catch {
11 | return [];
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/scripts/postchangelog.ts:
--------------------------------------------------------------------------------
1 | import {checkPrettierChanges} from './helpers/check-prettier-changes';
2 |
3 | (function main(): void {
4 | /**
5 | * We need to automatically format changes by prettier
6 | * after the CHANGELOG is generated before commit and push
7 | *
8 | * postbump lifecycle script is executed just
9 | * before information is written to CHANGELOG.md
10 | */
11 | checkPrettierChanges();
12 | })();
13 |
--------------------------------------------------------------------------------
/projects/demo/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
2 | Import from your library in this demo project as if you were using it as an
3 | NPM package
4 |
5 |
6 |
10 | Static component
11 |
12 | Lazy component
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/scripts/helpers/execute.ts:
--------------------------------------------------------------------------------
1 | import {CommonExecOptions, execSync} from 'child_process';
2 |
3 | import {infoLog} from './colored-log';
4 |
5 | export function execute(shell: string, options?: Partial): string {
6 | infoLog(`ᐅ ${shell}`);
7 |
8 | return execSync(
9 | shell,
10 | options ?? {
11 | stdio: `inherit`,
12 | encoding: `utf8`,
13 | },
14 | )
15 | ?.toString()
16 | .trim();
17 | }
18 |
--------------------------------------------------------------------------------
/prettier.config.js:
--------------------------------------------------------------------------------
1 | const base = require('@tinkoff/prettier-config/angular');
2 |
3 | module.exports = {
4 | ...base,
5 | singleAttributePerLine: true,
6 | overrides: [
7 | ...base.overrides,
8 | {
9 | files: ['*.js', '*.ts'],
10 | options: {printWidth: 90, parser: 'typescript'},
11 | },
12 | {
13 | files: '*.html',
14 | options: {printWidth: 80, parser: 'angular'},
15 | },
16 | ],
17 | };
18 |
--------------------------------------------------------------------------------
/projects/demo/src/app/app.server.module.ts:
--------------------------------------------------------------------------------
1 | import {NgModule} from '@angular/core';
2 | import {ServerModule} from '@angular/platform-server';
3 | import {UNIVERSAL_PROVIDERS} from '@ng-web-apis/universal';
4 |
5 | import {AppBrowserModule} from './app.browser.module';
6 | import {AppComponent} from './app.component';
7 |
8 | @NgModule({
9 | imports: [AppBrowserModule, ServerModule],
10 | bootstrap: [AppComponent],
11 | providers: UNIVERSAL_PROVIDERS,
12 | })
13 | export class AppServerModule {}
14 |
--------------------------------------------------------------------------------
/projects/demo/src/app/modules/lazy/lazy.module.ts:
--------------------------------------------------------------------------------
1 | import {NgModule} from '@angular/core';
2 | import {RouterModule, Routes} from '@angular/router';
3 |
4 | import {LazyComponent} from './lazy.component';
5 |
6 | export const routes: Routes = [
7 | {
8 | path: '',
9 | component: LazyComponent,
10 | },
11 | ];
12 |
13 | @NgModule({
14 | imports: [RouterModule.forChild(routes)],
15 | declarations: [LazyComponent],
16 | exports: [LazyComponent],
17 | })
18 | export class LazyModule {}
19 |
--------------------------------------------------------------------------------
/.github/workflows/lint.yml:
--------------------------------------------------------------------------------
1 | name: Lint
2 | on: [pull_request]
3 |
4 | jobs:
5 | lint:
6 | runs-on: ubuntu-latest
7 | steps:
8 | - uses: actions/checkout@v2
9 | - name: Setup Node.js and Cache
10 | uses: ./.github/actions/nodejs
11 |
12 | - name: Lint check
13 | run: |
14 | npm run typecheck
15 | npm run format -- --check
16 | npm run stylelint
17 | npm run lint
18 |
19 | concurrency:
20 | group: lint-${{ github.head_ref }}
21 | cancel-in-progress: true
22 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @type {import('eslint').Linter.Config}
3 | */
4 | module.exports = {
5 | root: true,
6 | extends: [
7 | '@tinkoff/eslint-config-angular',
8 | '@tinkoff/eslint-config-angular/html',
9 | '@tinkoff/eslint-config-angular/rxjs',
10 | ],
11 | ignorePatterns: ['projects/**/test.ts', '*.json', '*.less', '*.md', '*.js'],
12 | parser: '@typescript-eslint/parser',
13 | parserOptions: {
14 | ecmaVersion: 2020,
15 | sourceType: 'module',
16 | project: [require.resolve('./tsconfig.eslint.json')],
17 | },
18 | };
19 |
--------------------------------------------------------------------------------
/codecov.yml:
--------------------------------------------------------------------------------
1 | codecov:
2 | branch: main
3 | notify:
4 | require_ci_to_pass: no
5 |
6 | coverage:
7 | # This value is used to customize the visible color range in Codecov.
8 | # The first number represents the red, and the second represents green.
9 | # You can change the range of colors by adjusting this configuration.
10 | range: 50..100 # by default 70..100
11 | round: down
12 | precision: 2
13 |
14 | # Disable codecov/patch check
15 | status:
16 | project:
17 | default:
18 | enabled: false
19 | patch:
20 | default:
21 | enabled: false
22 |
--------------------------------------------------------------------------------
/scripts/helpers/colored-log.ts:
--------------------------------------------------------------------------------
1 | export function processLog(message: string): void {
2 | console.info('\x1b[36m%s\x1b[0m', message);
3 | }
4 |
5 | export function errorLog(message: string): void {
6 | console.info('\x1B[31m%s\x1B[0m', message);
7 | }
8 |
9 | export function successLog(message: string): void {
10 | console.info('\x1B[32m%s\x1B[0m', message);
11 | }
12 |
13 | export function infoLog(message: string): void {
14 | console.info('\x1B[34m%s\x1B[0m', message);
15 | }
16 |
17 | export function titleLog(message: string): void {
18 | console.info('\x1b[35m', message);
19 | }
20 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Tests
2 | on:
3 | pull_request:
4 | push:
5 | branches:
6 | - main
7 |
8 | jobs:
9 | tests:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: actions/checkout@v2
13 | - name: Setup Node.js and Cache
14 | uses: ./.github/actions/nodejs
15 |
16 | - name: Run tests
17 | run: npm run test -- --coverage
18 |
19 | - uses: codecov/codecov-action@v2
20 | with:
21 | directory: ./coverage
22 | flags: summary
23 | name: demo
24 |
25 | concurrency:
26 | group: test-${{ github.head_ref }}
27 | cancel-in-progress: true
28 |
--------------------------------------------------------------------------------
/projects/demo-integrations/cypress/tests/ssr/ssr.cy.ts:
--------------------------------------------------------------------------------
1 | describe('Server side rendering', () => {
2 | const baseUrl: string = Cypress.config('baseUrl') ?? '/';
3 |
4 | it('should serve statics and favicon.ico', () => {
5 | cy.request(`${baseUrl}/favicon.ico`).its('status').should('equal', 200);
6 | });
7 |
8 | it('should successfully render static url', () => {
9 | cy.request(baseUrl).its('body').should('include', 'This is a static route');
10 | });
11 |
12 | it('should successfully render lazy url', () => {
13 | cy.request(`${baseUrl}/lazy`)
14 | .its('body')
15 | .should('include', 'This is a lazy route');
16 | });
17 | });
18 |
--------------------------------------------------------------------------------
/.github/workflows/deploy.yml:
--------------------------------------------------------------------------------
1 | name: Deploy
2 | on:
3 | push:
4 | branches:
5 | - main
6 |
7 | jobs:
8 | deploy:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - uses: actions/checkout@v2
12 | - name: Setup Node.js and Cache
13 | uses: ./.github/actions/nodejs
14 |
15 | - name: Build demo
16 | run: npx nx build-gh-pages
17 |
18 | - name: Deploy
19 | uses: JamesIves/github-pages-deploy-action@v4.2.5
20 | with:
21 | branch: gh-pages
22 | folder: dist/demo/browser
23 | silent: false
24 | clean: true
25 |
26 | concurrency:
27 | group: deploy-${{ github.head_ref }}
28 | cancel-in-progress: true
29 |
--------------------------------------------------------------------------------
/projects/demo/src/main.browser.ts:
--------------------------------------------------------------------------------
1 | import './polyfills';
2 |
3 | import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
4 |
5 | import {AppBrowserModule} from './app/app.browser.module';
6 |
7 | document.addEventListener('DOMContentLoaded', () => {
8 | platformBrowserDynamic()
9 | .bootstrapModule(AppBrowserModule)
10 | .then(ref => {
11 | const windowRef: any = window;
12 |
13 | // Ensure Angular destroys itself on hot reloads for Stackblitz
14 | if (windowRef['ngRef']) {
15 | windowRef['ngRef'].destroy();
16 | }
17 |
18 | windowRef['ngRef'] = ref;
19 | })
20 | .catch(console.error);
21 | });
22 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 🐞 Bug report
3 | about: Create a report to help us improve
4 | title: '[BUG] '
5 | labels: ''
6 | ---
7 |
8 | # 🐞 Bug report
9 |
10 | ### Description
11 |
12 |
13 |
14 | ### Reproduction
15 |
16 |
17 |
18 | http://www.stackblitz.com/...
19 |
20 | ### Expected behavior
21 |
22 |
23 |
24 | ### Versions
25 |
26 | - OS: [e.g. iOS]
27 | - Browser [e.g. chrome, safari]
28 | - Angular [e.g. 8]
29 |
30 | ### Additional context
31 |
32 |
33 |
--------------------------------------------------------------------------------
/projects/demo/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | displayName: 'demo',
3 | preset: '../../jest.preset.js',
4 | setupFilesAfterEnv: ['/src/test-setup.ts'],
5 | globals: {
6 | 'ts-jest': {
7 | tsconfig: '/tsconfig.spec.json',
8 | stringifyContentPathRegex: '\\.(html|svg)$',
9 | },
10 | },
11 | coverageDirectory: '../../coverage/projects/demo',
12 | transform: {
13 | '^.+\\.(ts|js|html)$': 'jest-preset-angular',
14 | },
15 | snapshotSerializers: [
16 | 'jest-preset-angular/build/serializers/no-ng-attributes',
17 | 'jest-preset-angular/build/serializers/ng-snapshot',
18 | 'jest-preset-angular/build/serializers/html-comment',
19 | ],
20 | };
21 |
--------------------------------------------------------------------------------
/projects/demo/.gitignore:
--------------------------------------------------------------------------------
1 | # compiled output
2 | /dist
3 | /tmp
4 | /out-tsc
5 | # Only exists if Bazel was run
6 | /bazel-out
7 |
8 | # dependencies
9 | /node_modules
10 |
11 | # profiling files
12 | chrome-profiler-events.json
13 | speed-measure-plugin.json
14 |
15 | # IDEs and editors
16 | /.idea
17 | .project
18 | .classpath
19 | .c9/
20 | *.launch
21 | .settings/
22 | *.sublime-workspace
23 |
24 | # IDE - VSCode
25 | .vscode/*
26 | !.vscode/settings.json
27 | !.vscode/tasks.json
28 | !.vscode/launch.json
29 | !.vscode/extensions.json
30 | .history/*
31 |
32 | # misc
33 | /.sass-cache
34 | /connect.lock
35 | /coverage
36 | /libpeerconnection.log
37 | npm-debug.log
38 | yarn-error.log
39 | testem.log
40 | /typings
41 |
42 | # System Files
43 | .DS_Store
44 | Thumbs.db
45 |
--------------------------------------------------------------------------------
/projects/demo-integrations/cypress.config.ts:
--------------------------------------------------------------------------------
1 | import {defineConfig} from 'cypress';
2 |
3 | export const CYPRESS_CONFIG: Cypress.ConfigOptions = {
4 | video: false,
5 | fixturesFolder: 'cypress/fixtures',
6 | viewportWidth: 1440,
7 | viewportHeight: 900,
8 | responseTimeout: 60000,
9 | pageLoadTimeout: 120000,
10 | defaultCommandTimeout: 10000,
11 | e2e: {
12 | // We've imported your old cypress plugins here.
13 | // You may want to clean this up later by importing these.
14 | setupNodeEvents(on, config) {
15 | return require('./cypress/plugins/index.js')(on, config);
16 | },
17 | baseUrl: 'http://localhost:4200',
18 | specPattern: 'cypress/tests/**/*.cy.ts',
19 | },
20 | };
21 |
22 | export default defineConfig(CYPRESS_CONFIG);
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # compiled output
2 | /dist
3 | /tmp
4 | /out-tsc
5 | # Only exists if Bazel was run
6 | /bazel-out
7 |
8 | # dependencies
9 | /node_modules
10 |
11 | # profiling files
12 | chrome-profiler-events.json
13 | speed-measure-plugin.json
14 |
15 | # IDEs and editors
16 | /.idea
17 | .project
18 | .classpath
19 | .c9/
20 | *.launch
21 | .settings/
22 | *.sublime-workspace
23 |
24 | # IDE - VSCode
25 | .vscode/*
26 | !.vscode/settings.json
27 | !.vscode/tasks.json
28 | !.vscode/launch.json
29 | !.vscode/extensions.json
30 | .history/*
31 |
32 | # misc
33 | /.sass-cache
34 | /connect.lock
35 | /coverage
36 | /libpeerconnection.log
37 | npm-debug.log
38 | yarn-error.log
39 | testem.log
40 | /typings
41 |
42 | # System Files
43 | .DS_Store
44 | Thumbs.db
45 |
46 | # cypress
47 | **/cypress/**/screenshots/**
48 |
49 | .ssl
50 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## PR Checklist
2 |
3 | Please check if your PR fulfills the following requirements:
4 |
5 | - [ ] The commit message follows [Conventional Commits](https://www.conventionalcommits.org/en/)
6 | - [ ] Tests for the changes have been added (for bug fixes / features)
7 | - [ ] Docs have been added / updated (for bug fixes / features)
8 |
9 | ## PR Type
10 |
11 | What kind of change does this PR introduce?
12 |
13 | - [ ] Bugfix
14 | - [ ] Feature
15 | - [ ] Refactoring
16 | - [ ] Code style update
17 | - [ ] Build or CI related changes
18 | - [ ] Documentation content changes
19 |
20 | ## What is the current behavior?
21 |
22 | Closes #
23 |
24 | ## What is the new behavior?
25 |
26 | ## Does this PR introduce a breaking change?
27 |
28 | - [ ] Yes
29 | - [ ] No
30 |
--------------------------------------------------------------------------------
/projects/demo/src/app/app.component.spec.ts:
--------------------------------------------------------------------------------
1 | import {APP_BASE_HREF} from '@angular/common';
2 | import {TestBed} from '@angular/core/testing';
3 | import {Router} from '@angular/router';
4 |
5 | import {AppBrowserModule} from './app.browser.module';
6 | import {AppComponent} from './app.component';
7 |
8 | describe('Test dummy', () => {
9 | let component: AppComponent;
10 |
11 | beforeEach(() => {
12 | TestBed.configureTestingModule({
13 | imports: [AppBrowserModule],
14 | providers: [{provide: APP_BASE_HREF, useValue: '/'}],
15 | });
16 |
17 | component = TestBed.createComponent(AppComponent);
18 | });
19 |
20 | it('AppComponent compiles properly', () => {
21 | TestBed.inject(Router).navigate(['/lazy']);
22 |
23 | expect(component).toBeTruthy();
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 🚀 Feature request
3 | about: Suggest an idea for this project
4 | title: '[FEATURE]'
5 | labels: ''
6 | ---
7 |
8 | # 🚀 Feature request
9 |
10 | ### Is your feature request related to a problem?
11 |
12 |
13 | I'm always frustrated when...
14 |
15 | ### Describe the solution you'd like
16 |
17 |
18 |
19 |
20 | ### Describe alternatives you've considered
21 |
22 |
23 |
24 |
25 | ### Additional context
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/projects/demo/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
13 |
17 |
21 |
25 |
26 | Angular open source starter
27 |
28 |
29 | Loading...
30 |
31 |
32 |
--------------------------------------------------------------------------------
/projects/demo-integrations/cypress/plugins/index.js:
--------------------------------------------------------------------------------
1 | const {CYPRESS_CONFIG} = require('./../../cypress.config');
2 |
3 | module.exports = on => {
4 | on('before:browser:launch', (browser, launchOptions) => {
5 | if (browser.name === 'chrome') {
6 | launchOptions.args.push(
7 | `--window-size=${CYPRESS_CONFIG.viewportWidth},${CYPRESS_CONFIG.viewportHeight}`,
8 | );
9 | launchOptions.args.push('--force-device-scale-factor=2');
10 | launchOptions.args.push('--high-dpi-support=1');
11 | launchOptions.args.push('--disable-dev-shm-usage');
12 | launchOptions.args.push('--incognito');
13 | }
14 |
15 | if (browser.isHeadless) {
16 | launchOptions.args.push('--disable-gpu');
17 | }
18 |
19 | return launchOptions;
20 | });
21 | };
22 |
--------------------------------------------------------------------------------
/projects/demo/src/app/app.browser.module.ts:
--------------------------------------------------------------------------------
1 | import {LocationStrategy, PathLocationStrategy} from '@angular/common';
2 | import {NgModule} from '@angular/core';
3 | import {BrowserModule} from '@angular/platform-browser';
4 |
5 | import {AppComponent} from './app.component';
6 | import {AppRoutingModule} from './app.routes';
7 | import {StaticModule} from './modules/static/static.module';
8 |
9 | @NgModule({
10 | bootstrap: [AppComponent],
11 | imports: [
12 | BrowserModule.withServerTransition({
13 | appId: 'demo',
14 | }),
15 | AppRoutingModule,
16 | StaticModule,
17 | ],
18 | declarations: [AppComponent],
19 | providers: [
20 | {
21 | provide: LocationStrategy,
22 | useClass: PathLocationStrategy,
23 | },
24 | ],
25 | })
26 | export class AppBrowserModule {}
27 |
--------------------------------------------------------------------------------
/scripts/syncVersions.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const glob = require('glob');
3 | const JSON_INDENTATION_LEVEL = 4;
4 | const {version} = require('../package.json');
5 |
6 | // Sync libraries package.json versions with main package.json
7 | syncVersions('projects');
8 |
9 | function syncVersions(root) {
10 | glob(root + '/**/package.json', (_, files) => {
11 | files.forEach(file => {
12 | const packageJson = JSON.parse(fs.readFileSync(file));
13 |
14 | fs.writeFileSync(
15 | file,
16 | JSON.stringify(
17 | {
18 | ...packageJson,
19 | version,
20 | },
21 | null,
22 | JSON_INDENTATION_LEVEL,
23 | ),
24 | );
25 | });
26 | });
27 | }
28 |
--------------------------------------------------------------------------------
/projects/demo/src/app/app.routes.ts:
--------------------------------------------------------------------------------
1 | import {NgModule} from '@angular/core';
2 | import {RouterModule, Routes} from '@angular/router';
3 |
4 | import {StaticComponent} from './modules/static/static.component';
5 |
6 | export const appRoutes: Routes = [
7 | {
8 | path: '',
9 | component: StaticComponent,
10 | },
11 | {
12 | path: 'lazy',
13 | loadChildren: () => import(`./modules/lazy/lazy.module`).then(m => m.LazyModule),
14 | },
15 | {
16 | path: '**',
17 | redirectTo: '',
18 | },
19 | ];
20 |
21 | @NgModule({
22 | imports: [
23 | RouterModule.forRoot(appRoutes, {
24 | initialNavigation: 'enabledBlocking',
25 | relativeLinkResolution: 'corrected',
26 | scrollPositionRestoration: 'enabled',
27 | }),
28 | ],
29 | exports: [RouterModule],
30 | })
31 | export class AppRoutingModule {}
32 |
--------------------------------------------------------------------------------
/projects/demo-integrations/cypress/support/command.ts:
--------------------------------------------------------------------------------
1 | // ***********************************************
2 | // This example commands.js shows you how to
3 | // create various custom commands and overwrite
4 | // existing commands.
5 | //
6 | // For more comprehensive examples of custom
7 | // commands please read more here:
8 | // https://on.cypress.io/custom-commands
9 | // ***********************************************
10 | //
11 | //
12 | // -- This is a parent command --
13 | // Cypress.Commands.add('login', (email, password) => { ... })
14 | //
15 | //
16 | // -- This is a child command --
17 | // Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
18 | //
19 | //
20 | // -- This is a dual command --
21 | // Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
22 | //
23 | //
24 | // -- This will overwrite an existing command --
25 | // Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
26 |
--------------------------------------------------------------------------------
/scripts/helpers/argv.ts:
--------------------------------------------------------------------------------
1 | import * as process from 'process';
2 |
3 | import {processLog} from './colored-log';
4 |
5 | export function getValueByFlag(flag: string, fallback: T): T {
6 | const index = findIndexFlag(flag);
7 |
8 | if (index === -1) {
9 | return fallback;
10 | }
11 |
12 | const [parsedFlag, parsedValue] = process.argv[index].split(`=`) ?? [];
13 | const value =
14 | stringifier(parsedValue) ??
15 | (process.argv[index + 1].startsWith(`-`)
16 | ? fallback
17 | : stringifier(process.argv[index + 1]) ?? fallback);
18 |
19 | processLog(`parsed flags: \n${[parsedFlag, value].join(`=`)}`);
20 |
21 | return value as T;
22 | }
23 |
24 | export function hasFlag(flag: string): boolean {
25 | return findIndexFlag(flag) !== -1;
26 | }
27 |
28 | export function findIndexFlag(flag: string): number {
29 | return process.argv.findIndex(arg => arg === flag || arg.split(`=`)[0] === flag);
30 | }
31 |
32 | export function stringifier(value?: string): string | undefined {
33 | return value === `undefined` || value === `null` ? undefined : value;
34 | }
35 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | > Thank you for considering contributing to our project. Your help if very welcome!
4 |
5 | When contributing, it's better to first discuss the change you wish to make via issue, email, or any other method with
6 | the owners of this repository before making a change.
7 |
8 | All members of our community are expected to follow our [Code of Conduct](CODE_OF_CONDUCT.md). Please make sure you are
9 | welcoming and friendly in all of our spaces.
10 |
11 | ## Getting started
12 |
13 | In order to make your contribution please make a fork of the repository. After you've pulled the code, follow these
14 | steps to kick-start the development:
15 |
16 | 1. Run `npm ci` to install dependencies
17 | 2. Run `npm start` to launch demo project where you could test your changes
18 | 3. Use following commands to ensure code quality
19 |
20 | ```
21 | npm run lint
22 | npm run build
23 | npm run test
24 | ```
25 |
26 | ## Pull Request Process
27 |
28 | 1. We follow [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0-beta.4/) in our commit messages, i.e.
29 | `feat(core): improve typing`
30 | 2. Update [README.md](README.md) to reflect changes related to public API and everything relevant
31 | 3. Make sure you cover all code changes with unit tests
32 | 4. When you are ready, create Pull Request of your fork into original repository
33 |
--------------------------------------------------------------------------------
/tsconfig.base.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": false,
3 | "angularCompilerOptions": {
4 | "enableIvy": true,
5 | "preserveWhitespaces": false,
6 | "annotateForClosureCompiler": false,
7 | "skipTemplateCodegen": true,
8 | "strictMetadataEmit": true,
9 | "fullTemplateTypeCheck": true,
10 | "strictInjectionParameters": true,
11 | "enableResourceInlining": true,
12 | "strictLiteralTypes": true,
13 | "strictInputTypes": true
14 | },
15 | "compilerOptions": {
16 | "baseUrl": "./",
17 | "outDir": "./dist/out-tsc",
18 | "sourceMap": true,
19 | "declaration": false,
20 | "module": "es2020",
21 | "moduleResolution": "node",
22 | "experimentalDecorators": true,
23 | "importHelpers": true,
24 | "strict": true,
25 | "noFallthroughCasesInSwitch": true,
26 | "noImplicitReturns": true,
27 | "noUnusedParameters": true,
28 | "noUnusedLocals": true,
29 | "target": "es2015",
30 | "typeRoots": ["node_modules/@types"],
31 | "lib": ["es2018", "dom"],
32 | "paths": {}
33 | },
34 | "ts-node": {
35 | "files": true,
36 | "transpileOnly": true,
37 | "compilerOptions": {
38 | "types": ["node"],
39 | "module": "commonjs"
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/.github/workflows/e2e.yml:
--------------------------------------------------------------------------------
1 | name: E2E
2 | on: [pull_request]
3 |
4 | jobs:
5 | e2e:
6 | runs-on: ubuntu-latest
7 | env:
8 | CYPRESS_CACHE_FOLDER: ./node_modules/cache-cypress
9 | UNIVERSAL_SERVER: http://localhost:4000
10 | STATIC_SERVER: http://localhost:8080
11 | steps:
12 | - uses: actions/checkout@v2
13 | - name: Setup Node.js and Cache
14 | uses: ./.github/actions/nodejs
15 |
16 | - name: Build demo
17 | run: npm run build
18 |
19 | - name: Prerender demo
20 | run: npm run build:prerender
21 |
22 | - name: Serving static files
23 | run: |
24 | npm run serve:prerender & sleep 5
25 | curl -X GET -I -f "${{ env.STATIC_SERVER }}"
26 |
27 | - name: Run cypress / ssr / prerender
28 | run: npm run cy:run -- --spec "**/ssr/*.cy.ts" --config baseUrl="${{ env.STATIC_SERVER }}"
29 |
30 | - name: Build ssr server
31 | run: npm run build:ssr
32 |
33 | - name: Serving ssr server
34 | run: |
35 | npm run serve:ssr & sleep 5
36 | curl -X GET -I -f "${{ env.UNIVERSAL_SERVER }}"
37 |
38 | - name: Run cypress / ssr / universal
39 | run: npm run cy:run -- --spec "**/ssr/*.cy.ts" --config baseUrl="${{ env.UNIVERSAL_SERVER }}"
40 |
41 | concurrency:
42 | group: integration-e2e-${{ github.head_ref }}
43 | cancel-in-progress: true
44 |
--------------------------------------------------------------------------------
/nx.json:
--------------------------------------------------------------------------------
1 | {
2 | "implicitDependencies": {
3 | "angular.json": "*",
4 | "package.json": {
5 | "dependencies": "*",
6 | "devDependencies": "*"
7 | },
8 | ".eslintrc.js": "*",
9 | "nx.json": "*",
10 | "karma.*.js": "*",
11 | "tsconfig.*.json": "*",
12 | "tsconfig.json": "*"
13 | },
14 | "npmScope": "angular-open-source-starter",
15 | "tasksRunnerOptions": {
16 | "default": {
17 | "runner": "@nrwl/nx-cloud",
18 | "options": {
19 | "cacheableOperations": ["build", "test", "lint"],
20 | "parallel": 1
21 | }
22 | }
23 | },
24 | "affected": {
25 | "defaultBase": "origin/main"
26 | },
27 | "workspaceLayout": {
28 | "libsDir": "projects",
29 | "appsDir": "projects"
30 | },
31 | "defaultProject": "demo",
32 | "generators": {
33 | "@nrwl/js:library": {
34 | "buildable": true,
35 | "strict": true,
36 | "linter": "none",
37 | "unitTestRunner": "jest",
38 | "config": "project"
39 | },
40 | "@nrwl/angular:library": {
41 | "buildable": true,
42 | "compilationMode": "partial",
43 | "linter": "none",
44 | "unitTestRunner": "jest",
45 | "strict": true,
46 | "skipModule": true,
47 | "standaloneConfig": true
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/scripts/npm-publish.ts:
--------------------------------------------------------------------------------
1 | import {execSync} from 'child_process';
2 | import {resolve} from 'path';
3 |
4 | import {getValueByFlag} from './helpers/argv';
5 | import {errorLog, infoLog, processLog, successLog} from './helpers/colored-log';
6 | import {getAllVersions} from './helpers/get-all-versions';
7 | import {getLastMajorVersion} from './helpers/get-last-major-version';
8 |
9 | const isDryRun =
10 | getValueByFlag<'true' | 'false' | 'undefined'>(`--dry-run`, `false`) === `true`;
11 | const path = getValueByFlag(`--path`, ``);
12 |
13 | (async function main(): Promise {
14 | const packageJson = await import(resolve(path, `package.json`));
15 | const versions: string[] = getAllVersions(packageJson.name);
16 |
17 | if (versions.includes(packageJson.version) && !isDryRun) {
18 | errorLog(`${packageJson.name}@${packageJson.version} is already published`);
19 |
20 | return;
21 | }
22 |
23 | infoLog(`name: ${packageJson.name}`);
24 | infoLog(`version: ${packageJson.version}`);
25 |
26 | const dry = isDryRun ? `--dry-run` : ``;
27 | const tag = makeTag(packageJson.version, versions);
28 | const command = `npm publish ${path} ${tag} ${dry} --access public`;
29 |
30 | processLog(command);
31 | execSync(command, {stdio: `inherit`, encoding: `utf8`});
32 | successLog(`+${packageJson.name}@${packageJson.version} is published successfully`);
33 | })();
34 |
35 | function makeTag(version: string, versions: string[]): string {
36 | const currentMajor = parseInt(version);
37 | const maxMajorVersion = getLastMajorVersion(versions, currentMajor);
38 | const tagFlag = maxMajorVersion > currentMajor ? `--tag v${currentMajor}-lts` : ``;
39 |
40 | return version.includes(`rc`) ? `--tag next` : tagFlag;
41 | }
42 |
--------------------------------------------------------------------------------
/.github/actions/nodejs/action.yml:
--------------------------------------------------------------------------------
1 | name: Action for Node.js
2 | description: Node.js setup cache
3 |
4 | inputs:
5 | node-version:
6 | description: Node.js version
7 | required: false
8 | default: 16.x
9 |
10 | runs:
11 | using: composite
12 | steps:
13 | - name: Use Node.js ${{ inputs.node-version }}
14 | uses: actions/setup-node@v3
15 | with:
16 | node-version: ${{ inputs.node-version }}
17 | registry-url: 'https://registry.npmjs.org'
18 |
19 | - name: Restore node_modules from cache
20 | id: cache-node-modules
21 | uses: actions/cache@v3
22 | with:
23 | path: |
24 | **/node_modules
25 | !**/node_modules/.cache
26 | key: modules-cache__nodejs-${{ inputs.node-version }}__${{ hashfiles('**/package-lock.json') }}
27 |
28 | - name: Restore from cache of builds
29 | id: build-cache
30 | if: steps.cache-node-modules.outputs.cache-hit == 'true'
31 | uses: actions/cache@v3
32 | with:
33 | path: |
34 | **/node_modules/.cache
35 | key: builds-cache-hash__${{ hashFiles('**/package-lock.json') }}-${{ github.ref }}
36 | restore-keys: builds-cache__nodejs-${{ inputs.node-version }}__${{ hashFiles('**/package-lock.json') }}
37 |
38 | - name: Restore from global NPM cache
39 | if: steps.cache-node-modules.outputs.cache-hit != 'true'
40 | uses: actions/cache@v3
41 | with:
42 | path: ~/.npm
43 | key: npm-cache__nodejs-${{ inputs.node-version }}__${{ hashFiles('**/package-lock.json') }}
44 | restore-keys: npm-cache-hash__
45 |
46 | - run: npm ci
47 | env:
48 | CYPRESS_CACHE_FOLDER: ./node_modules/cache-cypress
49 | if: steps.cache-node-modules.outputs.cache-hit != 'true'
50 | shell: bash
51 |
52 | - name: environment
53 | shell: bash
54 | run: |
55 | node -v
56 | npm -v
57 |
--------------------------------------------------------------------------------
/projects/demo/server.ts:
--------------------------------------------------------------------------------
1 | import '@ng-web-apis/universal/mocks';
2 | import 'zone.js/node';
3 |
4 | import {APP_BASE_HREF} from '@angular/common';
5 | import {provideLocation, provideUserAgent} from '@ng-web-apis/universal';
6 | import {ngExpressEngine} from '@nguniversal/express-engine';
7 | import * as express from 'express';
8 | import {Express} from 'express';
9 | import {existsSync} from 'fs';
10 | import {join} from 'path';
11 |
12 | import {AppServerModule} from './src/main.server';
13 |
14 | // The Express app is exported so that it can be used by serverless Functions.
15 | export function app(): Express {
16 | const server = express();
17 | const distFolder = join(process.cwd(), 'dist/demo/browser');
18 | const indexHtml = existsSync(join(distFolder, 'index.original.html'))
19 | ? 'index.original.html'
20 | : 'index';
21 |
22 | // Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
23 | server.engine(
24 | 'html',
25 | ngExpressEngine({
26 | bootstrap: AppServerModule,
27 | }) as any,
28 | );
29 |
30 | server.set('view engine', 'html');
31 | server.set('views', distFolder);
32 |
33 | // Example Express Rest API endpoints
34 | // server.get('/api/**', (req, res) => { });
35 | // Serve static files from /browser
36 | server.get(
37 | '*.*',
38 | express.static(distFolder, {
39 | maxAge: '1y',
40 | }),
41 | );
42 |
43 | // All regular routes use the Universal engine
44 | server.get('*', (req, res) => {
45 | res.render(indexHtml, {
46 | req,
47 | providers: [
48 | {provide: APP_BASE_HREF, useValue: req.baseUrl},
49 | provideLocation(req),
50 | provideUserAgent(req),
51 | ],
52 | });
53 | });
54 |
55 | return server;
56 | }
57 |
58 | function run() {
59 | const port = process.env.PORT || 4000;
60 |
61 | // Start up the Node server
62 | const server = app();
63 |
64 | server.listen(port, () => {
65 | console.info(`Node Express server listening on http://localhost:${port}`);
66 | });
67 | }
68 |
69 | // Webpack will replace 'require' with '__webpack_require__'
70 | // '__non_webpack_require__' is a proxy to Node 'require'
71 | // The below code is to ensure that the server is run only when not requiring the bundle.
72 | declare const __non_webpack_require__: NodeRequire;
73 | const mainModule = __non_webpack_require__.main;
74 | const moduleFilename = (mainModule && mainModule.filename) || '';
75 |
76 | if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {
77 | run();
78 | }
79 |
80 | export * from './src/main.server';
81 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making
6 | participation in our project and our community a harassment-free experience for everyone, regardless of age, body size,
7 | disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education,
8 | socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
9 |
10 | ## Our Standards
11 |
12 | Examples of behavior that contributes to creating a positive environment include:
13 |
14 | - Using welcoming and inclusive language
15 | - Being respectful of differing viewpoints and experiences
16 | - Gracefully accepting constructive criticism
17 | - Focusing on what is best for the community
18 | - Showing empathy towards other community members
19 |
20 | Examples of unacceptable behavior by participants include:
21 |
22 | - The use of sexualized language or imagery and unwelcome sexual attention or advances
23 | - Trolling, insulting/derogatory comments, and personal or political attacks
24 | - Public or private harassment
25 | - Publishing others' private information, such as a physical or electronic address, without explicit permission
26 | - Other conduct which could reasonably be considered inappropriate in a professional setting
27 |
28 | ## Our Responsibilities
29 |
30 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take
31 | appropriate and fair corrective action in response to any instances of unacceptable behavior.
32 |
33 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits,
34 | issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any
35 | contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
36 |
37 | ## Scope
38 |
39 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the
40 | project or its community. Examples of representing a project or community include using an official project e-mail
41 | address, posting via an official social media account, or acting as an appointed representative at an online or offline
42 | event. Representation of a project may be further defined and clarified by project maintainers.
43 |
44 | ## Enforcement
45 |
46 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at
47 | [INSERT YOUR EMAIL HERE]. All complaints will be reviewed and investigated and will result in a response that is deemed
48 | necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to
49 | the reporter of an incident. Further details of specific enforcement policies may be posted separately.
50 |
51 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent
52 | repercussions as determined by other members of the project's leadership.
53 |
54 | ## Attribution
55 |
56 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at
57 | https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
58 |
59 | [homepage]: https://www.contributor-covenant.org
60 |
61 | For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq
62 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Angular Open-source Starter
2 |
3 | [](https://github.com/Tinkoff/angular-open-source-starter/actions/workflows/deploy.yml)
4 | [](https://github.com/Tinkoff/angular-open-source-starter/actions/workflows/test.yml)
5 | [](https://codecov.io/gh/Tinkoff/angular-open-source-starter)
6 | [](https://tinkoff.github.io/angular-open-source-starter/)
7 |
8 | ## How to use
9 |
10 | > This is a starter project for creating open-source libraries for Angular. It is a full-fledged Angular workspace with
11 | > demo application and easy library addition. It is designed to be used for open-sourcing libraries on GitHub and has
12 | > everything you'd need ready for CI, code coverage, SSR testing, StackBlitz demo deployment and more.
13 |
14 | 1. Run `npm ci` to install everything
15 |
16 | 2. Use search to replace all mentions of `angular-open-source-starter` with your new library name (`npmScope` inside
17 | `nx.json`, matadata of the root `package.json`, root `README.md` etc.)
18 |
19 | 3. Create basic file structure via [Nx-generators](https://nx.dev/plugin-features/use-code-generators):
20 |
21 | - `nx g @nrwl/js:library [your-library-name]` - create Typescript library. See
22 | [available options](https://nx.dev/packages/js/generators/library#options).
23 | - `nx g @nrwl/angular:library [your-library-name]` - create Angular library. See
24 | [available options](https://nx.dev/packages/angular/generators/library#options).
25 |
26 | 4. Fill in `projects/[your-library-name]/package.json` metadata for your newly generated library
27 |
28 | 5. Add your email at [INSERT YOUR EMAIL HERE] in `CODE_OF_CONDUCT.md`
29 |
30 | 6. Update `LICENSE` file according to your preferences
31 |
32 | 7. Update root `package.json` metadata to represent your project
33 |
34 | 8. Code your library and create demo for it
35 |
36 | ## Cool features
37 |
38 | - [x] Versioning is ready for you with following simple commands:
39 |
40 | ```json
41 | {
42 | "release": "standard-version",
43 | "release:patch": "npm run release -- --release-as patch",
44 | "release:minor": "npm run release -- --release-as minor",
45 | "release:major": "npm run release -- --release-as major",
46 | "publish": "nx run-many --target build --all --exclude=demo && nx run-many --target publish --all"
47 | }
48 | ```
49 |
50 | Just use [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0-beta.4/) format and `CHANGELOG.md` will be
51 | automatically generated on releases by
52 | [Standard Version](https://github.com/conventional-changelog/standard-version#standard-version).
53 |
54 | - [x] This project has Angular Universal — you can easily test your library with SSR and Prerender:
55 |
56 | `npm run serve:dev:ssr` or `npm run build:prerender && npm run serve:prerender`
57 |
58 | - [x] CI and code coverage are ready, GitHub Action checks that packages build, test and lint correctly. It also sends
59 | test results to [Codecov](https://about.codecov.io).
60 |
61 | - [x] Precommit checks, prettier, linter and all that jazz is there.
62 |
63 | - [x] You can also deploy your demo to [StackBlitz](https://stackblitz.com) with no hustle, just use link in the
64 | following format:
65 |
66 | https://stackblitz.com/github/[User|Organization]/[Repository]/tree/main/projects/demo
67 |
68 | - [x] You can add more libraries using the same [Nx-generators](https://nx.dev/plugin-features/use-code-generators) to
69 | create a whole Angular Workspace with multiple libraries. Versioning and publishing is configured that they are
70 | released simultaneously like Angular packages.
71 |
72 | ## Infrastructure
73 |
74 | - [x] GitHub Actions
75 | - [x] Node.js 16+, npm 8+
76 | - [x] Angular 12+
77 | - [x] TypeScript 4+
78 | - [x] Prettier 2.6+
79 | - [x] Stylelint 14+
80 | - [x] ESLint 7+
81 | - [x] Husky 7+
82 | - [x] Cypress 10+
83 | - [x] Jest 27+
84 | - [x] Nx 13+
85 |
86 | ## Badge
87 |
88 | Show that your project is based off of our starter
89 |
90 | [](https://github.com/Tinkoff/angular-open-source-starter)
91 |
92 | ```md
93 | [](https://github.com/Tinkoff/angular-open-source-starter)
94 | ```
95 |
--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3 | "enabled": true,
4 | "automerge": true,
5 | "pinVersions": true,
6 | "rangeStrategy": "bump",
7 | "branchPrefix": "renovate/",
8 | "timezone": "Europe/Moscow",
9 | "semanticCommits": "enabled",
10 | "masterIssueApproval": false,
11 | "separateMajorMinor": true,
12 | "separateMinorPatch": false,
13 | "dependencyDashboard": false,
14 | "dependencyDashboardApproval": false,
15 | "semanticPrefix": "build",
16 | "rebaseWhen": "auto",
17 | "labels": ["renovate"],
18 | "baseBranches": ["master"],
19 | "digest": {"enabled": false},
20 | "pinDigests": false,
21 | "includePaths": ["package.json", "**/package.json", "!node_modules/**"],
22 | "packageRules": [
23 | {
24 | "matchUpdateTypes": ["minor", "patch"],
25 | "matchPackagePatterns": ["*"],
26 | "groupName": "all dependencies (minor/patch)",
27 | "groupSlug": "all-minor-patch"
28 | },
29 | {
30 | "matchUpdateTypes": ["major"],
31 | "labels": ["renovate", "major"],
32 | "automerge": false
33 | },
34 | {
35 | "matchUpdateTypes": ["minor", "patch"],
36 | "labels": ["renovate", "minor/patch"],
37 | "automerge": true
38 | },
39 | {
40 | "depTypeList": ["engines", "peerDependencies"],
41 | "enabled": false
42 | },
43 | {
44 | "matchPackagePatterns": ["^rxjs.*"],
45 | "groupSlug": "rxjs",
46 | "groupName": "rxjs dependencies"
47 | },
48 | {
49 | "matchPackagePatterns": ["^prettier"],
50 | "groupSlug": "prettier",
51 | "groupName": "prettier dependencies"
52 | },
53 | {
54 | "matchPackagePatterns": [
55 | "^@angular/.*",
56 | "^@angular-devkit/.*",
57 | "^@schematics/.*",
58 | "^@angular/cdk$",
59 | "^@angular/cli$",
60 | "^@angular/cdk-experimental$",
61 | "^@angular/flex-layout$",
62 | "^@angular/material$",
63 | "^@angular-builders/.*",
64 | "^ng-packagr$",
65 | "^zone.js"
66 | ],
67 | "groupSlug": "angular",
68 | "groupName": "angular dependencies"
69 | },
70 | {
71 | "matchPackagePatterns": ["^class-transformer$"],
72 | "groupSlug": "class-transformer",
73 | "groupName": "class-transformer dependencies"
74 | },
75 | {
76 | "matchPackagePatterns": ["^@nrwl/.*"],
77 | "groupSlug": "nrwl",
78 | "groupName": "nrwl dependencies"
79 | },
80 | {
81 | "matchPackagePatterns": ["^@commitlint/.*"],
82 | "groupSlug": "commitlint",
83 | "groupName": "commitlint dependencies"
84 | },
85 | {
86 | "matchPackagePatterns": ["^@sentry/.*"],
87 | "groupSlug": "sentry",
88 | "groupName": "sentry dependencies"
89 | },
90 | {
91 | "matchPackagePatterns": ["^@ngx-translate/.*"],
92 | "groupSlug": "ngx-translate",
93 | "groupName": "ngx-translate dependencies"
94 | },
95 | {
96 | "matchPackagePatterns": [
97 | "^@types/eslint$",
98 | "^@angular-eslint/.*",
99 | "^@angular-ru/eslint.*",
100 | "^@typescript-eslint/.*",
101 | "^eslint.*"
102 | ],
103 | "groupSlug": "eslint",
104 | "groupName": "eslint dependencies"
105 | },
106 | {
107 | "matchPackagePatterns": ["^@types/jest$", "^jest.*", "^ts-jest$", "^jest-preset-angular$"],
108 | "groupSlug": "jest",
109 | "groupName": "jest dependencies"
110 | },
111 | {
112 | "matchPackagePatterns": ["@types/karma.*", "^karma.*"],
113 | "groupSlug": "karma",
114 | "groupName": "karma dependencies"
115 | },
116 | {
117 | "matchPackagePatterns": ["@types/jasmine", "@types/jasmine*", "^jasmine.*"],
118 | "groupSlug": "jasmine",
119 | "groupName": "jasmine dependencies"
120 | },
121 | {
122 | "matchPackagePatterns": ["@types/node"],
123 | "groupSlug": "nodejs",
124 | "groupName": "nodejs dependencies"
125 | },
126 | {
127 | "matchPackagePatterns": ["^typescript", "^tslib"],
128 | "groupSlug": "typescript",
129 | "groupName": "typescript dependencies"
130 | }
131 | ]
132 | }
133 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@tinkoff/angular-open-source-starter",
3 | "version": "0.0.0",
4 | "description": "This is a template project to develop, create and open-source Angular libraries with demos",
5 | "keywords": [
6 | "angular",
7 | "ng",
8 | "workspace",
9 | "library",
10 | "starter",
11 | "tinkoff"
12 | ],
13 | "homepage": "https://github.com/tinkoff/angular-open-source-starter#README",
14 | "bugs": "https://github.com/tinkoff/angular-open-source-starter/issues",
15 | "repository": "https://github.com/tinkoff/angular-open-source-starter",
16 | "license": "Apache-2.0",
17 | "author": {
18 | "name": "Roman Sedov",
19 | "email": "79601794011@ya.ru",
20 | "url": "http://marsibarsi.me/"
21 | },
22 | "contributors": [
23 | "Alex Inkin ",
24 | "Maksim Ivanov "
25 | ],
26 | "scripts": {
27 | "postinstall": "husky install && ngcc --async",
28 | "*** Workflow ***": "",
29 | "start": "nx run demo:serve",
30 | "build": "nx run demo:build:production",
31 | "test": "nx test",
32 | "*** Format ***": "",
33 | "lint": "eslint .",
34 | "format": "prettier '**/*.{svg,yml,js,ts,html,md,less,json}'",
35 | "stylelint": "stylelint '**/*.{less,css}'",
36 | "typecheck": "tsc --noEmit --skipLibCheck --incremental false --tsBuildInfoFile null --project tsconfig.spec.json",
37 | "*** SSR ***": "",
38 | "serve:dev:ssr": "nx run demo:serve-ssr",
39 | "serve:ssr": "node dist/demo/server/main.js",
40 | "serve:prerender": "http-server dist/demo/browser",
41 | "build:ssr": "nx run demo:server:production",
42 | "build:prerender": "nx run demo:prerender:production",
43 | "*** Cypress ***": "",
44 | "cy:open": "cypress open --project ./projects/demo-integrations/",
45 | "cy:run": "cypress run --project ./projects/demo-integrations/",
46 | "*** Release ***": "",
47 | "release": "standard-version -a --no-verify",
48 | "release:patch": "npm run release -- --release-as patch",
49 | "release:minor": "npm run release -- --release-as minor",
50 | "release:major": "npm run release -- --release-as major",
51 | "publish": "nx run-many --target build --all --exclude=demo && nx run-many --target publish --all"
52 | },
53 | "lint-staged": {
54 | "*.{js,ts,html,md,less,json}": [
55 | "npm run lint -- --fix",
56 | "prettier --write",
57 | "git add"
58 | ],
59 | "*.less": [
60 | "stylelint --fix",
61 | "git add"
62 | ]
63 | },
64 | "dependencies": {
65 | "@angular/animations": "^12.2.16",
66 | "@angular/common": "^12.2.16",
67 | "@angular/compiler": "^12.2.16",
68 | "@angular/core": "^12.2.16",
69 | "@angular/forms": "^12.2.16",
70 | "@angular/platform-browser": "^12.2.16",
71 | "@angular/platform-browser-dynamic": "^12.2.16",
72 | "@angular/platform-server": "^12.2.16",
73 | "@angular/router": "^12.2.16",
74 | "@ng-web-apis/common": "^2.0.0",
75 | "@ng-web-apis/universal": "^2.0.0",
76 | "@nguniversal/express-engine": "^12.1.3",
77 | "core-js": "^2.6.12",
78 | "express": "^4.17.3",
79 | "rxjs": "~6.6.7",
80 | "tslib": "^2.0.0",
81 | "zone.js": "~0.11.5"
82 | },
83 | "devDependencies": {
84 | "@angular-devkit/build-angular": "~12.2.17",
85 | "@angular-devkit/core": "^12.2.17",
86 | "@angular-devkit/schematics": "^12.2.17",
87 | "@angular-devkit/schematics-cli": "~0.901.13",
88 | "@angular/cli": "^12.2.17",
89 | "@angular/compiler-cli": "^12.2.16",
90 | "@angular/language-service": "^12.2.16",
91 | "@commitlint/cli": "^16.2.3",
92 | "@commitlint/config-conventional": "^16.2.1",
93 | "@nguniversal/builders": "^12.1.3",
94 | "@nrwl/angular": "13.1.4",
95 | "@nrwl/cli": "13.1.4",
96 | "@nrwl/eslint-plugin-nx": "13.1.4",
97 | "@nrwl/jest": "13.1.4",
98 | "@nrwl/js": "13.3.0",
99 | "@nrwl/node": "13.1.4",
100 | "@nrwl/nx-cloud": "13.1.4",
101 | "@nrwl/tao": "13.1.4",
102 | "@nrwl/workspace": "13.1.4",
103 | "@tinkoff/eslint-config": "^1.36.1",
104 | "@tinkoff/eslint-config-angular": "^1.36.1",
105 | "@tinkoff/prettier-config": "^1.32.1",
106 | "@tinkoff/stylelint-config": "^1.30.0",
107 | "@types/estree": "^0.0.51",
108 | "@types/express": "^4.17.13",
109 | "@types/jest": "^27.4.1",
110 | "@types/node": "17.0.23",
111 | "cypress": "^10.11.0",
112 | "http-server": "^14.1.0",
113 | "husky": "^7.0.4",
114 | "jest": "^27.5.1",
115 | "jest-preset-angular": "^11.1.1",
116 | "lint-staged": "^12.3.7",
117 | "ng-packagr": "^12.2.7",
118 | "prettier": "^2.6.2",
119 | "standard-version": "^9.3.2",
120 | "ts-jest": "27.0.5",
121 | "ts-node": "^10.7.0",
122 | "tsutils": "^3.21.0",
123 | "typescript": "~4.3.5"
124 | },
125 | "engines": {
126 | "node": ">= 14",
127 | "npm": ">= 7",
128 | "yarn": "Please use npm instead of yarn to install dependencies"
129 | },
130 | "standard-version": {
131 | "scripts": {
132 | "postchangelog": "ts-node ./scripts/postchangelog.ts",
133 | "postbump": "node scripts/syncVersions.js && git add **/package.json"
134 | }
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/projects/demo/project.json:
--------------------------------------------------------------------------------
1 | {
2 | "projectType": "application",
3 | "generators": {},
4 | "root": "projects/demo",
5 | "sourceRoot": "projects/demo/src",
6 | "prefix": "app",
7 | "targets": {
8 | "build": {
9 | "executor": "@angular-devkit/build-angular:browser",
10 | "options": {
11 | "baseHref": "/",
12 | "outputPath": "dist/demo/browser",
13 | "index": "projects/demo/src/index.html",
14 | "main": "projects/demo/src/main.browser.ts",
15 | "polyfills": "projects/demo/src/polyfills.ts",
16 | "tsConfig": "projects/demo/tsconfig.app.json",
17 | "aot": false,
18 | "assets": ["projects/demo/src/favicon.ico"],
19 | "styles": ["projects/demo/src/styles.css"],
20 | "scripts": [],
21 | "vendorChunk": true,
22 | "extractLicenses": false,
23 | "buildOptimizer": false,
24 | "sourceMap": true,
25 | "optimization": false,
26 | "namedChunks": true
27 | },
28 | "configurations": {
29 | "production": {
30 | "fileReplacements": [
31 | {
32 | "replace": "projects/demo/src/environments/environment.ts",
33 | "with": "projects/demo/src/environments/environment.prod.ts"
34 | }
35 | ],
36 | "optimization": true,
37 | "outputHashing": "all",
38 | "sourceMap": false,
39 | "namedChunks": false,
40 | "aot": true,
41 | "extractLicenses": true,
42 | "vendorChunk": false,
43 | "buildOptimizer": true,
44 | "budgets": [
45 | {
46 | "type": "initial",
47 | "maximumWarning": "2mb",
48 | "maximumError": "5mb"
49 | }
50 | ]
51 | },
52 | "development": {}
53 | },
54 | "defaultConfiguration": "production"
55 | },
56 | "build-gh-pages": {
57 | "executor": "@nrwl/workspace:run-commands",
58 | "options": {
59 | "parallel": false,
60 | "commands": [
61 | "echo 'Github pages require special baseHref + 404.html'",
62 | "echo 'Read more: https://angular.io/guide/deployment#deploy-to-github-pages'",
63 | "echo ------",
64 | "nx build --base-href='/angular-open-source-starter/'",
65 | "cp dist/demo/browser/index.html dist/demo/browser/404.html"
66 | ]
67 | }
68 | },
69 | "serve": {
70 | "executor": "@angular-devkit/build-angular:dev-server",
71 | "options": {
72 | "browserTarget": "demo:build",
73 | "sslCert": ".ssl/localhost.pem",
74 | "sslKey": ".ssl/localhost-key.pem"
75 | },
76 | "configurations": {
77 | "production": {
78 | "browserTarget": "demo:build:production"
79 | },
80 | "development": {
81 | "browserTarget": "demo:build:development"
82 | }
83 | },
84 | "defaultConfiguration": "development"
85 | },
86 | "serve-ip": {
87 | "builder": "@nrwl/workspace:run-commands",
88 | "options": {
89 | "command": "nx serve --open --host 0.0.0.0 --disable-host-check"
90 | }
91 | },
92 | "serve-ssl": {
93 | "builder": "@nrwl/workspace:run-commands",
94 | "options": {
95 | "parallel": false,
96 | "commands": [
97 | "echo \"mkcert is a simple tool for making locally-trusted development certificates\"",
98 | "echo \"Read about installation and more: https://github.com/FiloSottile/mkcert\"",
99 | "echo ------",
100 | "mkcert -install",
101 | "mkdir -p .ssl",
102 | "mkcert -key-file .ssl/localhost-key.pem -cert-file .ssl/localhost.pem localhost 127.0.0.1 ::1",
103 | "nx serve --ssl"
104 | ]
105 | }
106 | },
107 | "test": {
108 | "executor": "@nrwl/jest:jest",
109 | "outputs": ["coverage/projects/demo"],
110 | "options": {
111 | "jestConfig": "projects/demo/jest.config.js",
112 | "passWithNoTests": true
113 | }
114 | },
115 | "server": {
116 | "executor": "@angular-devkit/build-angular:server",
117 | "options": {
118 | "outputPath": "dist/demo/server",
119 | "main": "projects/demo/server.ts",
120 | "tsConfig": "projects/demo/tsconfig.server.json",
121 | "sourceMap": true,
122 | "optimization": false
123 | },
124 | "configurations": {
125 | "production": {
126 | "outputHashing": "media",
127 | "sourceMap": false,
128 | "optimization": true
129 | },
130 | "development": {}
131 | },
132 | "defaultConfiguration": "production"
133 | },
134 | "serve-ssr": {
135 | "executor": "@nguniversal/builders:ssr-dev-server",
136 | "options": {
137 | "browserTarget": "demo:build",
138 | "serverTarget": "demo:server"
139 | },
140 | "configurations": {
141 | "production": {
142 | "browserTarget": "demo:build:production",
143 | "serverTarget": "demo:server:production"
144 | },
145 | "development": {
146 | "serverTarget": "demo:server:development",
147 | "browserTarget": "demo:build:development"
148 | }
149 | },
150 | "defaultConfiguration": "development"
151 | },
152 | "prerender": {
153 | "executor": "@nguniversal/builders:prerender",
154 | "options": {
155 | "browserTarget": "demo:build:production",
156 | "serverTarget": "demo:server:production",
157 | "routes": ["/"]
158 | },
159 | "configurations": {
160 | "production": {}
161 | }
162 | }
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | Copyright 2019 Tinkoff Bank
179 |
180 | Licensed under the Apache License, Version 2.0 (the "License");
181 | you may not use this file except in compliance with the License.
182 | You may obtain a copy of the License at
183 |
184 | http://www.apache.org/licenses/LICENSE-2.0
185 |
186 | Unless required by applicable law or agreed to in writing, software
187 | distributed under the License is distributed on an "AS IS" BASIS,
188 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
189 | See the License for the specific language governing permissions and
190 | limitations under the License.
--------------------------------------------------------------------------------