An opiniated Angular setup based on @angular/cli
Angular-Cli can help you start an Angular project very quickly.
But when you need a lot of external modules/libs and you've got to setup everything, everytime, it can be quite long and repetitive.
This setup has the following modules already installed and configured :
- Angular Material
- Material Design Icons
- Ng2 Translate
- Ngrx
- Store
- Effects
- StoreDevtools
If you don't know angular-cli, please read the doc.
I added one command to build the project as small as possible for production : yarn run prod
.
If you're new to ngrx [store | effects], it might help you get started. I've put a lot of comments and a folder called "pizzas" for demo/scaffolding.
Don't forget to install and take a look to Redux DevTools for state debugging.
The starter is pre-configured to generate a service-worker (thanks to angular-cli) and the only thing you need to do if you want your app to work offline, is to set serviceWorker
to true
in .angular-cli.json
.
The starter is pre-configured to use Chromium in headless mode. If you want to change that behavior, you can simply pass the browser of your choice in karma.conf.js
, property browsers
.
Before we start digging into the architecture of this project, you have to know that Prettier is already setup and thus, you can format all your .ts
and .scss
by simply running yarn run prettier:fix
. If you have a CI setup, you might want to run yarn run prettier:check
to make sure every file is correctly formatted.
Also, a pre-commit hook has been setup and before you commit something, it'll check if all the file are well formatted. If you want to disable that behavior, remove .git/hooks/pre-commit
and also the precommit
key in package.json
.
Of course, you can use your favorite editor/IDE. If you decide to use VSC, you might want to install Angular Language Service. It'll give you autocompletion and type checking into your HTML templates.
What you need to know to start with this template :
(all the code contains a lot of comments, so while reading the differents parts of this readme, I invite you to look the according files).
This is just the main scss
file where we can import the barrel from /src/styles
. Indeed, the goal here is to avoid listing all our scss
files into /.angular-cli.json
, in apps.styles
.
This is the main scss
barrel. In the styles folder, you might want to create other folders. If you do so, create a barrel /src/styles/themes/_themes.scss
where you import all the themes you need.
Put everything not related to a given component, that you may want to share across your app.
Thanks to material, you can define here your primary and accent colors. I've also added a $color-palette
which might be useful if you need other colors. You'll see why in next section.
Some utility classes. The main thing to notice here is the @mixin generate-colors
. For every color you've listed in the $color-palette
, it will generate the following css classes :
color-#{$name}-x#{$index}
, background-color-#{$name}-x#{$index}
, border-color-#{$name}-x#{$index}
and background-color-hover-#{$name}-x#{$index}:hover
. This way in your templates you can for example give a color to some text like that : <p class="color-orange-x1">some orange text</p>
.
You should take a look into the other classes too, just so you know they exists (eg full-width
, color-primary
, color-accent
, bold
, ...).
I am no expert in Material theming and I'm sure there are better solutions available. Feel free to make a PR or point to some good articles/documentation.
By default, there are 2 environments : Dev and prod. This is from @angular/cli
. Remember to always import in your app the environment.ts
, not environment.prod.ts
.
If you need to create others environments, create a file per environment and do not forget to list it in /src/.angular-cli.json
/ apps.environments
.
Based on previous works, I've added some useful variables :
production
(from@angular/cli
). You probably won't need it. The main use of this variable is to set angular to production mode or not (avoid the double cycle of change detection to make sure data haven't change. Useful only in dev mode)urlBackend
: Use it whenever you want to make an HTTP call to your APImock
: Wheter you want to use some mocks or fetch the real backend. To know more about that, take a look into/src/app/core/core.module.ts
where we use dependency injection to either have the real service or the mocked one based on this env variablehttpDelay
: When you havemock
set to true, it might be a good idea to simulate a small latency for your http requests (300~500ms)hashLocationStrategy
: Set it to true if you want to have your URLs in the old school mode :my-website/#/my/spa/routing
. By default set to false and thus your URLs won't have the#
and will look like that :my-website/my/spa/routing
debug
: You might use this variable to print (or not) some debug information in your app. This is different thanproduction
variable because you might want to display some debug in production too (eg if you create another environmente2e-prod
where you setproduction
to true, so your E2E tests run the same environment that the final one but you want the debug output in case something goes wrong)
Sometimes, you might want to have dynamic environment variables, loaded at runtime.
The main idea behind that is to be able to load it from a server, either from a given API or a simple .json
file. That way, you can avoid to compile your project multiple times for different environments.
How to use it: Add a json
file per required environment in /assets/runtime-environments
.
Then take a look into /app/core/runtime-environment.service.ts
. It's a simple guard from where you can handle some logic to let the app know which json
should be loaded. By default, it'll try to load /src/assets/runtime-environments/runtime-environment.json
.
Then into the app, use the RuntimeEnvironmentService
like that: constructor(private runEnv: RuntimeEnvironmentService) {}
. And you'll be able to access your environment variable: this.runEnv.environment
.
If you don't want that feature and keep your main route as fast as possible without being blocked while trying to fetch the json
file, just turn that feature off into the build environment /src/environments/environment*.ts
(set property loadRuntimeEnvironment
to false).
This feature has been turned off by default.
Folder where you can put all your static assets like pictures. There's also a i18n
folder with one file per language. Indeed, this template includes @ngx-translate
so you can easily have multi language support.
If you add a language file, to make it available in the UI you'll have to open /src/app/core/core.module.ts
and add it to the providers
list.
In every app, you need a "main" module (CF /src/main.ts
) so angular can bootstrap it. With @angular/cli
(and in general), it's called AppModule
. You'll find it here : /src/app/app.module.ts
.
I try to keep this module as simple as possible because if we need to run angular in a different environment (universal on server side or even in a web-worker), we might have to create another file (eg app.module.universal.ts
or app.module.webworker.ts
) which doesn't import the BrowserModule
. Then, in those files we would simply have to import our 3 modules : CoreModule
, SharedModule
and AppRoutingModule
.
Keep it simple : Don't touch it.
Everything you only want to import in your app only once. (It'll mainly be modules with providers). It's here that we load our (ngrx) store, the devTools, the translate module and our (ngrx) effects.
We'll also add our providers
here for simplicity.
Into the core
folder, you'll also find the injection-tokens.ts
. It's where you can create your tokens.
It's basically the folder where you'll put (nearly) all your code. With angular, your app will be splitted in (a lot of) components. I like to create a module (folder) per feature and if it's not something I'll re-use up to the tree of components, I nest it. For example, with an email application we could have :
|--src
|--app/
|--features/
|--login/
|--emails/
|--inbox/
|--newEmail/
|--contacts/
Sometimes, you'll have [components|directives|interfaces|helpers|services|...] that you might want to share across the whole app. You should group them into this SharedModule
under their common folder (components, directives, etc).
AppModule
: Shouldn't be imported anywhere else than/src/main.ts
. It's done so, you don't have to worry about this oneFeaturesModule
: Already imported into/src/app/app.routing.module.ts
and it's the only place where it should beSharedModule
: Import this module in every module you'll create deep down the tree of thefeatures
folder. For example,Material
is imported/exported intoSharedModule
and if you want to use anything fromMaterial
, just import it to the current module you're working on
If you have any questions about that setup, let me know by opening an issue and of course, if you see something that my be improved, feel free to make a pull request.