A rewrite of the WholeTale Dashboard in Angular 12+
This project was seeded from ng-seed/universal
For a short demonstration, see http://recordit.co/68UCeE5PU3
Packages in this project depend on @angular v12.x.x
. Older versions contain outdated dependencies, might produce errors.
Also, please ensure that you are using Typescript v4.3.x
or higher.
Optionally, Docker can be used to build and serve the application.
To run ngx-dashboard
, start by cloning the repo:
# clone the repo
$ git clone https://github.com/whole-tale/ngx-dashboard.git
$ cd ngx-dashboard/
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.
Docker can be used to build and serve the Angular source.
To build a Docker image capable of performing Angular builds, use the following command:
docker build -t wholetale/ng -f Dockerfile.build .
You can then run a development server using this Docker image:
docker run --name=ng-watch -itd -v $(pwd):/srv/app -w /srv/app wholetale/ng
You can check the logs of the development server by running:
docker logs -f ng-watch
To stop the server:
docker stop ng-watch && docker rm -f ng-watch
Docker can also be used to build and run the "production" version of the app.
To build the docker image, run the following command:
docker build -t bodom0015/ng-dashboard:wt .
This will build the Angular application in a customized node:carbon-slim
container, then copy the built files from the dist/
directory into a fresh nginx:stable-alpine
container.
This process ensures that our final production-ready image does not contain any unnecessary build tools, and will actively hinder us from manually performing modifications after the container is deployed.
Run the production image using the following command:
docker run -it bodom0015/ng-dashboard:wt
Optional: you can mount in -v /path/to/src/ngx-dashboard/dist:/usr/share/nginx/html/
. Note that in this case you will need to provide your own build container mounting the same /path/to/src/ngx-dashboard
that will produce the appropriate build output in dist/
.
Below are the scripts to dev, build, and test this seed project:
# use `yarn` to install the dependencies
$ yarn
# 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
# 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.
# run unit tests
$ yarn test
# run e2e tests
$ yarn e2e
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
# add module `todo`
$ ng g module todo
# create src/app/todo/todo.module.ts (183 bytes)
@ngrx/schematics
blueprints :
- action
- container
- effect
- entity
- feature
- reducer
- store
# 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)
# add module `store/todo/Todo`
$ ng g m store/todo/Todo --flat
# CREATE src/app/store/todo/todo.module.ts (196 bytes)
// TODO: remove
# add reducer `store/todo/todo`
$ ng g r store/todo/todo --spec false
# CREATE src/app/store/todo/todo.reducer.ts (247 bytes)
# add entity `store/todo/item/Item`
$ ng g en store/todo/item/Item -m ../../todo/todo.module.ts --reducers ../../store/todo.reducer.ts
# CREATE src/app/store/todo/item/item.actions.ts (2078 bytes)
# CREATE src/app/store/todo/item/item.model.ts (40 bytes)
# CREATE src/app/store/todo/item/item.reducer.ts (1746 bytes)
# CREATE src/app/store/todo/item/item.reducer.spec.ts (322 bytes)
# UPDATE src/app/store/todo/todo.module.ts (340 bytes)
# add effects `store/todo/item/Item`
$ ng g ef store/todo/item/Item -m +todo/todo.module.ts
# CREATE src/app/store/todo/item/item.effects.ts (183 bytes)
# CREATE src/app/store/todo/item/item.effects.spec.ts (577 bytes)
# UPDATE src/app/store/todo/todo.module.ts (489 bytes)
# add service `store/todo/Item`
$ ng g s store/todo/Item
# CREATE src/app/store/todo/item/item.service.spec.ts (323 bytes)
# CREATE src/app/store/todo/item/item.service.ts (133 bytes)
# add module `+todo/Todo`
$ ng g m +todo/Todo --flat
# CREATE src/app/+todo/todo.module.ts (188 bytes)
# add container component `+todo/item/item-container`
$ ng g co +todo/item/item-container --flat --state ../../store/todo/item/item.reducer.ts
# CREATE src/app/+todo/item/item-container.component.html (33 bytes)
# CREATE src/app/+todo/item/item-container.component.ts (432 bytes)
# CREATE src/app/+todo/item/item-container.component.scss (0 bytes)
# CREATE src/app/+todo/item/item-container.component.spec.ts (884 bytes)
# UPDATE src/app/+todo/todo.module.ts (829 bytes)
# add child component `+todo/item`
$ ng g c +todo/item -c OnPush
# CREATE src/app/+todo/item/item.component.html (23 bytes)
# CREATE src/app/+todo/item/item.component.spec.ts (614 bytes)
# CREATE src/app/+todo/item/item.component.ts (262 bytes)
# CREATE src/app/+todo/item/item.component.scss (0 bytes)
# UPDATE src/app/+todo/todo.module.ts (829 bytes)
# add container component `+todo/item/item-detail/item-detail-container`
$ ng g co +todo/item/item-detail/item-detail-container --flat --state ../../../store/todo/item/item.reducer.ts
# CREATE src/app/+todo/item/item-detail/item-detail-container.component.html (40 bytes)
# CREATE src/app/+todo/item/item-detail/item-detail-container.component.ts (462 bytes)
# CREATE src/app/+todo/item/item-detail/item-detail-container.component.scss (0 bytes)
# CREATE src/app/+todo/item/item-detail/item-detail-container.component.spec.ts (927 bytes)
# UPDATE src/app/+todo/todo.module.ts (946 bytes)
# add child component `+todo/item-detail`
$ ng g c +todo/item/item-detail -c OnPush
# CREATE src/app/+todo/item/item-detail/item-detail.component.html (30 bytes)
# CREATE src/app/+todo/item/item-detail/item-detail.component.spec.ts (657 bytes)
# CREATE src/app/+todo/item/item-detail/item-detail.component.ts (289 bytes)
# CREATE src/app/+todo/item/item-detail/item-detail.component.scss (0 bytes)
# UPDATE src/app/+todo/todo.module.ts (946 bytes)
We use the component approach in this seed 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
The MIT License (MIT)