Some advice and some tips for using CLI when you work with Angular

Tram Ho

Developing Angular application with Angular CLI is a very interesting experience! The Angular development team has provided us with a great CLI that supports almost everything needed for any project. The project structure is standardized with full testing capabilities (both unit and e2e testing),
code scaffolding, production grade build with support for using specific configurations of each environment. It is a dream come true and saves a lot of time for every new project. Although the Angular CLI works very well from the beginning, we need to know and apply it and practice before we can use them to make our projects even better!

What will I say in this article?

  1. Best structure for Core, Shared and lazy-loaded Feature modules
  2. Use aliases for directories in the application and environment to support cleaner imports
  3. Why and how to use Sass and Angular Material
  4. How to set up a good production build
  5. Say goodbye to PhantomJS and use Headless Chrome (testing)

1. A little architecture

OK, because we created our new project using Angular CLI but now continue? Should we continue to create our services and components into some random directories? How do we structure our project?

A good guide to follow is to divide our application into at least three different Core, Shared and Feature modules (we will probably need more than one Feature module).


All services must have one and only one version per application (singleton services) should be implemented here. Typical examples might be authentication service or user service. Consider an example of CoreModule implementation.


All “dumb” components and pipes should be done here. These components do not import and inject services from the core or features in their constructors. Chungs will get all the data even though the properties in the template of the component use them. All this shows the fact that SharedModule does not have any dependencies on the rest of our application. This is also the perfect place to import and re-export Angular Material components.

How to prepare project structure with Angular CLI

We can create Core and Shared modules right after creating a new project. That way, we will be prepared to create additional components and services from the beginning. Run the core module generator. Then create index.ts file in core folder and re-export CoreModule itself. We will re-export the public services needed throughout the application during further development. That being done, we can do the same for shared modules.


We will create many feature modules for every feature independent of our application. Feature modules should only import services from CoreModule. If feature module A needs to import service from feature module B, then consider moving that service into the core.

In some cases, the need for services is only shared by some features and it makes no sense to move them to the core. In that case, we can create shared feature modules as described later in this article.

The general rule is to try to create features that do not depend on any other features only on services provided by CoreModule and components provided by SharedModule. This will keep our code clean, maintainable and expandable with new features. It also reduces the effort required for restructuring. If properly followed, we will be confident that changes to a feature cannot affect or disrupt the rest of our application.


We should lazy load our feature modules whenever possible. Theoretically only one feature module should be loaded synchronously during the application startup to display the original content. Every other feature module should be lazy loading after the user triggered navigation.

2. Aliases for applications and environments

Our application folder and environment aliases will allow us to perform clear and consistent import throughout our entire application. Considering the hypothesis, but the usual situation. We are working on a component that is located three directories deep in feature A and we want to import the service from the core two directories deep. This will lead the import statement to look like import {SomeService} from ‘../../../core/subpackage1/subpackage2/some.service’.

Definitely not the cleanest import ever…

And what’s worse, whenever we want to change the location of any of these two files, our import statement will be corrupted. Compare that to the much shorter import {SomeService} from ” @app / core”. Seems better right?

To be able to use aliases, we have to add baseUrl and pathsthat attributes to our tsconfig.jso file like this.

We are also adding alias @env so we can easily access environment variables from anywhere in our application using the same import statement {environment} from ” @env / environment”. It will work for all specified environments because it will automatically resolve the correct environment file based on the –env flag passed to ng build . With our paths, we can now import env and service like this:

You may have noticed that we are importing entities (like SomeSingletonServicet in the example above) directly from @app / core instead of @app /core/some-package/some-singleton.service. This may be due to re-exporting all public entities in the main index.ts file. We create an index.ts file for the package (folder) and they look like this:

In most applications, components and services of specific feature modules will usually only have access to services from CoreModule and components from SharedModule. Sometimes this may not be enough to address specific businesses and we will also need some types of “shared feature modules”, which provide functionality for a limited subset of other feature modules.

In this case, we will end up with something like import { SomeService } from '@app/shared-feature'; Similar to core, shared-feature is also accessed by @app alias.

3. Use Sass

Sass is a type preprocessor that provides support for favorite things like variables (although css will soon receive variables), functions, mixins, etc.Sass is also required to use the effect. Official Angular Material Components library with extensive theming capabilities. It is safe to assume that using Sass is the default choice for most projects. To use Sass, we must create our project using the ng new tron Angular CLI command with the --style scss flag. This sets up most of the required configuration. One thing that is not added by default is stylePreprocessorOptions with includePaths and we can set it manually with the original values "./" and the optional “./themes” option.

This our editor finds imported symbols and enhances the developer experience with the completion code of Angular Material variables and functions.

4. “PROD” build

Projects created by the Angular CLI only come with a very simple ng build script. To create production grade artifacts, we have to do a little bit of customization on our own. We add "build:prod": "ng build --target production --build-optimizer --vendor-chunk" to our package.json script.

Target Production

This is a flag that allows you to shrink your code. Along with it, there will be many other flags to accompany, many useful build flags often come with default values ​​when running the command. Eg:

  • --environment prod – use file for environment variables.
  • --aot – allow Ahead-of-Time compilation. This will become a default setting in future versions of Angular CLI, but in Angular 6 we have to manually enable this option.
  • --output-hashing all – hash contents of generated file and appends the hash to the file name to facilitate browser cache (any changes to the file content will result in different hash functions and thus submit The browser must download the new version of the file)
  • --extract-css true extracts all css into its own style-sheet file
  • --sourcemaps false disables the creation of source maps
  • --named-chunks false disables the use of human readable names for chunk and uses numbers instead

Other useful flags

  • --build-optimizer new feature leads to smaller bundles but construction time is much longer so use with caution! (should also be enabled by default in the future)
  • --vendor-chunk – extract all endor (library) code into separate chunk Also check official docs for other available configuration flags that may be helpful in your personal project.

5. Phantom JS is obsolete! Headless Chrome will be an alternative!

PhantomJS is a headless browser for running frontend testing on CI servers and many dev machines. While still fine, support for modern ECMAScript features has been delayed. Moreover, its non-standard behavior causes headaches in many cases, when the operations are performed locally without any problems but they still fail in the CI environment. Fortunately, we don’t have to deal with it anymore! As the official document says:

Headless Chrome is shipping in Chrome 59. It’s a way to run the Chrome browser in a headless environment. Essentially, running Chrome without chrome! It brings all modern web platform features provided by Chromium and the Blink rendering engine to the command line.

Great! So how can we use it in our Angular CLI project? We added the --browser ChromeHeadless flag to the ng test to use: ng test --browser ChromeHeadless --single-run and the ng test --browser ChromeHeadless in the package.json file in our project, quite simple. Right?


For users (Intellij IDEA, Webstorm) Intellij IDEA will not always find all links by default, this will result in many red error marks and crippled code completion is paralyzed. Fortunately, the solution is very simple. Just select the src folder and mark it as Sources Root.


In this article, I have mentioned some things you should do in an angular project, as well as learn more useful flags when using angular CLI, hope that you can apply it to your project. yourself. Thank you for reading this article.

Reference source:

Chia sẻ bài viết ngay

Nguồn bài viết : Viblo