Skip to content

ekarpovs/ang-ssr-site-base

Repository files navigation

ANG-SSR-SITE-BASE

CircleCI tested with jest Angular Style Guide

ang-ssr-site-base is a client project for a site, based on: https://github.com/ng-seed/universal

Most significant changes and improvements:

  • Fixed state overloading after execution an each action.
  • Changed effects to avoid redurance backend calls.
  • Implemented real Login/Register with Authorization JWT token.
  • Implemented auth and routing via ngrx.
  • Implemented AuthInterceptor - adds the JWT token to the request's header.
  • Implemented HttpErrorInterceptor - provides searate handling of client and server sides HTTP errors.
  • Implemented TimeoutInterceptor - cancels HTTP requests after timeout.
  • Fixed (implemented) Create, Edit Delete a componemt behavior.
  • Changed application/ components layout for CSS grid usage.
  • Implemented backend (look at the api-side base project) for debug the application.

Application organization, providing the following features:

Built with Angular v7.x.x, bundled with Angular CLI.

You can find the project documentation here.

Table of contents

Prerequisites

Packages in this project depend on @angular v7.x.x. Older versions contain outdated dependencies, might produce errors.

Also, please ensure that you are using Typescript v3.1.x or higher.

Getting started

Installation

You can install ang-ssr-site-base by simply forking the repo:

# clone the repo
$ git clone https://github.com/ekarpovs/ang-ssr-site-base.git
$ cd ang-ssr-site-base

Setting up upstream repository

Once you have cloned the repo, you can follow these steps to allow sync changes made in this repo with your fork:

# set up `origin`
$ git remote set-url origin [your-fork-repo]

# set up `upstream` to sync future changes
$ git remote add upstream https://github.com/ekarpovs/ang-ssr-site-base.git

# verify the upstream repo specified for your fork
$ git remote -v
origin    https://github.com/YOUR_USERNAME/[your-fork-repo].git (fetch)
origin    https://github.com/YOUR_USERNAME/[your-fork-repo].git (push)
upstream  https://github.com/ekarpovs/ang-ssr-site-base.git (fetch)
upstream  https://github.com/ekarpovs/ang-ssr-site-base.git (push)

# initial push for the fork
$ git push

Now, you can create a new directory (ex: src/app/shared) to build your codebase out, while benefiting from the client framework located at the src/app/framework directory.

In order to merge the latest upstream changes, simply follow:

# fetch the latest upstream
$ git fetch upstream

# merge the upstream changes
$ git merge upstream/master

then handle any conflicts, and go on with building your app.

Development and builds

Below are the scripts to dev, build, and test this project:

Install dependencies

# use `yarn` to install the dependencies
$ yarn

Development servers

# dev server
$ ng serve

# dev server (HMR-enabled)
$ yarn start:hmr

# dev server (AoT compilation)
$ yarn start:prod

# dev server (SSR)
$ yarn start:ssr

# dev server (SSR & AoT compilation)
$ yarn start:ssr:prod

Build

# development build
$ ng build

# production build
$ ng build --prod

# development build (SSR)
$ yarn build:ssr

# production build (SSR)
$ yarn build:ssr:prod

The build artifacts will be stored in the dist/ directory.

Running tests

# run unit tests
$ yarn test

# run e2e tests
$ yarn e2e

CLI Scaffolding

The project currently performs CLI scaffolding using the official @schematics/angular collection and @ngrx/schematics collection.

@schematics/angular blueprints :

-_ class -_ component -_ directive -_ enum -_ guard -_ interface -_ module -_ pipe -* service

Example

# add module `domain`
$ ng g module domain
# create src/app/domain/domain.module.ts (183 bytes)

@ngrx/schematics blueprints :

-_ action -_ container -_ effect -_ entity -_ feature -_ reducer -* store

Initial store setup
# add store module
$ ng g m store --m app.module.ts
# CREATE src/app/store/store.module.ts (189 bytes)
# UPDATE src/app/app.module.ts (3525 bytes)

# add root state interface
# ng g i store/state
# CREATE src/app/store/state.ts (27 bytes)
Feature store module setup
# add module
$ ng g m store/domain/domain --flat
# CREATE src/app/store/domain/domain.module.ts (199 bytes)

# add entity
$ ng g en store/domain/domain/domain -m ../../domain/domain.module.ts
# CREATE src/app/store/domain/domain/domain.actions.ts (2254 bytes)
# CREATE src/app/store/domain/domain/domain.model.ts (42 bytes)
# CREATE src/app/store/domain/domain/domain.reducer.ts (1818 bytes)
# CREATE src/app/store/domain/domain/domain.reducer.spec.ts (326 bytes)
#UPDATE src/app/store/domain/domain.module.ts (355 bytes)

# add effects
$ ng g ef store/domain/domain/domain -m store/domain/domain.module.ts
# CREATE src/app/store/domain/domain/domain.effects.ts (185 bytes)
# CREATE src/app/store/domain/domain/domain.effects.spec.ts (589 bytes)
# UPDATE src/app/store/domain/domain.module.ts (506 bytes)

# add service
$ ng g s store/domain/domain/domain
# CREATE src/app/store/domain/domain/domain.service.spec.ts (333 bytes)
# CREATE src/app/store/domain/domain/domain.service.ts (135 bytes)
Container & child components setup
# add module `+domain/domain`
$ ng g m +domain/domain --flat
# CREATE src/app/+domain/domain.module.ts (188 bytes)

ng g m +domain/domain --flat


# add container component `+domain/domain/domain-container`
$ ng g co +domain/domain/domain-container --flat --state ../../store/domain/domain/domain.reducer.ts
# CREATE src/app/+domain/domain/domain-container.component.html (33 bytes)
# CREATE src/app/+domain/domain/domain-container.component.ts (432 bytes)
# CREATE src/app/+domain/domain/domain-container.component.scss (0 bytes)
# CREATE src/app/+domain/domain/domain-container.component.spec.ts (884 bytes)
# UPDATE src/app/+domain/domain.module.ts (829 bytes)

# add child component `+domain/domain`
$ ng g c +domain/domain -c OnPush
# CREATE src/app/+domain/domain/domain.component.html (23 bytes)
# CREATE src/app/+domain/domain/domain.component.spec.ts (614 bytes)
# CREATE src/app/+domain/domain/domain.component.ts (262 bytes)
# CREATE src/app/+domain/domain/domain.component.scss (0 bytes)
# UPDATE src/app/+domain/domain.module.ts (829 bytes)

# add container component `+domain/domain/domain-detail/domain-detail-container`
$ ng g co +domain/domain/domain-detail/domain-detail-container --flat --state ../../../store/domain/domain/domain.reducer.ts
# CREATE src/app/+domain/domain/domain-detail/domain-detail-container.component.html (40 bytes)
# CREATE src/app/+domain/domain/domain-detail/domain-detail-container.component.ts (462 bytes)
# CREATE src/app/+domain/domain/domain-detail/domain-detail-container.component.scss (0 bytes)
# CREATE src/app/+domain/domain/domain-detail/domain-detail-container.component.spec.ts (927 bytes)
# UPDATE src/app/+domain/domain.module.ts (946 bytes)

# add child component `+domain/domain-detail`
$ ng g c +domain/domain/domain-detail -c OnPush
# CREATE src/app/+domain/domain/domain-detail/domain-detail.component.html (30 bytes)
# CREATE src/app/+domain/domain/domain-detail/domain-detail.component.spec.ts (657 bytes)
# CREATE src/app/+domain/domain/domain-detail/domain-detail.component.ts (289 bytes)
# CREATE src/app/+domain/domain/domain-detail/domain-detail.component.scss (0 bytes)
# UPDATE src/app/+domain/domain.module.ts (946 bytes)

Directory structure

We use the component approach in this project, which is a standard for developing Angular apps and also a great way to ensure maintainable code by encapsulation of our behavior logic.

A component is basically a self contained app usually in a single file or a directory with each concern as a file: style, template, specs, and component class.

As an old convention, we use the + prefix for lazy-loaded modules. Please keep in mind that it does not change the router behavior, neither makes the directory unworkable. It's just a handy method to identify lazy-loaded modules by having a straight look at the directory structure.

universal/
 ├──.cache/                         * cache directory for ngx-cache
 |
 ├──.circleci/
 |   └──config.yml                  * CircleCI config
 |
 ├──.github/                        * issue & pr templates
 ├──coverage/                       * test coverage reports
 |
 ├──dist/                           * output directory to extract bundles
 |  ├──browser/                     * browser bundles
 |  └──server/                      * server bundles
 |
 ├──node_modules/                   * dependencies
 |
 ├──src/
 |   ├──app/                        * application code
 |   |   ├──+lazy-module/           * some LAZY module (attn to the `+` prefix for lazy-loaded modules)
 |   |   |  ...
 |   |   ├──framework/              * client framework
 |   |   ├──layout/                 * layout (app module)
 |   |   ├──library/                * application library (models, services, state management, etc.)
 |   |   ├──login/                  * login (app module)
 |   |   ├──shared/                 * shared codebase
 |   |   └──store/                  * state (ngrx) module
 |   └──assets/                     * static assets (scss, img, json, etc.)
 |   └──environments/               * environment settings
 |
 ├──tools/
 |   ├──build/                      * build config and scripts (webpack, etc.)
 |   ├──config/                     * config files for static-assets (stylelint, etc.)
 |   └──test/                       * test config
 |
 ├──.gitignore                      * GIT settings
 ├──.jshintrc                       * jshint config
 ├──angular.json                    * Angular CLI config
 ├──CHANGELOG.md                    * change log
 ├──CODE_OF_CONDUCT.md              * code of conduct
 ├──CONTRIBUTING.md                 * contributing info
 ├──LICENSE                         * software license
 ├──package.json                    * deps management
 ├──README.md                       * project information
 ├──server.ts                       * server code
 ├──stylelint.config.js             * stylelint config locator
 ├──test-report.xml                 * JUNIT test results
 ├──tsconfig.json                   * typescript config
 ├──tsconfig.server.json            * typescript config (for server build)
 ├──tsconfig.server-compile.json    * typescript config (for server compilation)
 ├──tsconfig.spec.json              * typescript config (for unit/e2e tests)
 ├──tslint.json                     * tslint config
 └──yarn.lock                       * deps lockfile

License

The MIT License (MIT)

Copyright (c) 2019 [Evgeny Karpovsky]

Known issues

  1. ngx-cache/fs-storage Error: EEXIST: file already exists, mkdir 'D:\Projects\vs-site.cache' at Object.mkdirSync (fs.js:768:3) at new FsStorageService (D:\Projects\vs-site\nodemodules@ngx-cache\fs-storage\bundles\ngx-cache-fs-storage.umd.js:131:20) at _createClass (D:\Projects\vs-site\node_modules@angular\core\bundles\core.umd.js:21284:24) at _createProviderInstance (D:\Projects\vs-site\node_modules@angular\core\bundles\core.umd.js:21256:30) at resolveNgModuleDep (D:\Projects\vs-site\node_modules@angular\core\bundles\core.umd.js:21220:25) at NgModuleRef.get (D:\Projects\vs-site\node_modules@angular\core\bundles\core.umd.js:21928:20) at new FsCacheService (D:\Projects\vs-site\node_modules@ngx-cache\platform-server\bundles\ngx-cache-platform-server.umd.js:41:39) at _createClass (D:\Projects\vs-site\node_modules@angular\core\bundles\core.umd.js:21286:24) at _createProviderInstance (D:\Projects\vs-site\node_modules@angular\core\bundles\core.umd.js:21256:30) at resolveNgModuleDep (D:\Projects\vs-site\node_modules@angular\core\bundles\core.umd.js:21220:25)