by @tomastrajan from AngularExperts.io
In this exercise were going to explore Angular CLI
- Learn how to execute Angular CLI commands and how to get and use
--help
for given command - Create new Angular workspace
- Learn how to use Angular schematics
- Create application in the workspace
- Run the application (and options)
- Build the application (and options)
- Test the application (and options)
- Lint the application (and options)
- Analyze the application (bundle and dependency graph)
- Explore workspace configuration
- Add Prettier support
- Remove default placeholder content
- Add Angular Material component framework & Tailwind CSS
- Setup IDE to run prettier with key shortcut (usually
CTRL ALT SHIFT P
in Webstorm /SHIFT ALT F
in VS Code) - Setup IDE expand to level 1, 2, 3, 4, 5 keyboard shortcuts
- Setup IDE shortcut to refresh workspace (from disk, useful when CLI creates / changes files in the workspace)
- Eslint working in the IDE (may need manual setup and selecting of the
working directory
) - (part of exercise) Pre-configure most commonly used schematics like
component
,directive
, ... - NPM troubleshooting, try to run
npm i <package-name> --registry https://registry.npmjs.org
in case of issues
- Run
ng version
to confirm version of your global Angular CLI (should be 15). If not, please update it usingnpm i -g @angular/cli@latest
. - Run
ng version
command to see all the available Angular CLI commands - Try running
ng <some-command> --help
(please useng new --help
) as we're not in Angular workspace yet
- Workspaces are created using
ng new
command, but before we execute it explore available options - Run
ng new exercise-angular-cli
command with options that disable the creation of an initial application--create-application false
, sets--style
toscss
, enablesrouting
and setsprefix
tomy-org
and--strict
for TypeScript strictness preset (hint: useng new --help
to see what are the exact options to achieve this) - Once done, explore the generated workspace folder in your console and inspect the generated files in your IDE (eg
cd exercise-angular-cli
)
- Once in an Angular workspace we can start using Angular schematics to scaffold code instead of writing it manually
- Schematics are executed using
ng generate --help
(orng g --help
), running this command will give us list of all available schematics (hint: you might need to enable / disable Angular CLI anonymous stats reporting when running a command for the first time in a new workspace) - Similarly, to Angular CLI we can explore schematics option using
ng g <scheamtic-name> --help
- Application in a workspace can be generated using Angular schematics
- Explore options of
application
schematics using--help
flag - Create an application with name
product-app
and following options: enabledstandalone
,routing
,scss
style andmy-org
prefix andstrict
TypeScript preset and disabledssr
(or you could decline it using the prompt if not specified) - Once done explore what was generated inside your IDE
- Once we created our application we can run it in two ways, first being
ng serve
(and second beingnpm start
, check that script in thepackage.json
file) - Open browser at
https://localhost:4200
to see the application running - Adjust the
start
script in thepackage.json
file by adding--open
flag, stop running app and restart it usingnpm start
- Once running open your browsers DEV tools and explore the network tab about what kind of files represent the application and check their size (refresh application once the tab was opened)
- Add new
start:prod
script to yourpackage.json
file and add both--open
and--configuration production
flags (--prod
flag was used in previous versions), stop running app and restart it usingnpm run start:prod
(notice therun
keyword, every script besidesstart
andtest
have to userun
- Once running open your browsers DEV tools and explore the network tab about what kind of files represent the application and check their size (the new
esbuild
based builder doesn't really optimize that well for serve even withproduction
configuration, but it's great for build speed, we're going to see actual production bundle size in the build step...)
- Serving application is great for the development purposes, but we have to build artifacts to deploy to production
- Build application using
ng build
(ornpm run build
, notice therun
keyword, every script besidesstart
andtest
have to userun
) - Once done explore the
dist
folder - Add new
build:dev
script to yourpackage.json
file and add--configuration development
flags, and build your application again usingnpm run build:dev
- Once done explore the
dist
folder - What other difference besides the size of the files was between the DEV and the PROD mode and what is its purpose?
- Explore options of
ng build
script using--help
flag
By default, Angular comes with Karma based testing out of the box, but it is possible to use Jest or other testing frameworks...
Angular now even comes with the official, but still experimental Jest
support, but the main downside is that it doesn't
support running of the individual tests in IDEs or with help of -- file-pattern
flag, so for now, we're going to use plain Jest with jest-preset-angular
package.
- Remove Karma with
npm un karma karma-chrome-launcher karma-coverage karma-jasmine karma-jasmine-html-reporter
- Install Jest and related packages
npm i -D jest jest-environment-jsdom jest-preset-angular @types/jest
- In the
projects/product-app/
addjest.config.js
file with the following content
module.exports = {
preset: 'jest-preset-angular',
setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
globalSetup: 'jest-preset-angular/global-setup',
};
- In the
projects/product-app/
addjest.setup.ts
file with the following content
import 'jest-preset-angular/setup-jest';
- In the
package.json
file adjusttest
script tojest --config projects/product-app/jest.config.js
- Try the setup by running
npm t
and see the tests pass - Adjust your
test:watch
script inpackage.json
withnpm run test -- --watch
content (the--
is a way to pipe additional args to the predefined npm script) - Try running
npm run test:watch
and see the tests running in watch mode, try some of the provided controls likep
orq
- Try breaking a test by changing
toEqual('product-app');
in theapp.component.spec.ts
to something else and see the test fail - Check out the new test output and try changing tests a couple of times
- (Optional) Set up E2E (end-to-end) tests using
ng add @cypress/schematic
and agree to all CLI prompts.- Once done, in the
angular.json
file, in theprojects.product-app.architect.e2e.options
, add the"configFile": "projects/product-app/cypress.config.ts",
. - After that, in the
projects/product-app/cypress.config.ts
file, inside thee2e
property, addspecPattern: '**/cypress/e2e/**/*.cy.ts',
andsupportFile: '**/cypress/support/e2e.ts',
. - Then, in the
projects/product-app/cypress/tsconfig.json
file, adjust"extends": "../tsconfig.json",
to"extends": "../tsconfig.app.json",
. - Finally, run
ng e2e
and try to fix first out-of-the-box test.
- Once done, in the
- Try to run
ng lint
what happens? - Proceed with offered installation of the
eslint
. - Once done, run
ng lint
again and check out the new output - in case we previously added the Cypress e2e testing, going to fix the linting error inline the file by using comment
// eslint-disable-next-line @typescript-eslint/no-namespace
in the listed file) - Try adding
<button>Test</button>
to theapp.component.html
and runng lint
again - There won't be any linting error reported, but using buttons without
type
attribute is a bad practice (accidental form submission) so let's add a new lint rule to prevent it - Add
"parser": "@angular-eslint/template-parser",
property into overrides for both.ts
and.html
files in the root.eslintrc.json
file - The add
"@angular-eslint/template/button-has-type": "error"
(into therules
object) into overrides for both.ts
and.html
files in the root.eslintrc.json
file - Run
ng lint
again and see the new error - Fix the error by adding
type="button"
to the button and runng lint
again
It usually makes sense to create dedicated ci
npm script in package json which will execute all the tests when project is built in the CI environment, such a command can look like "ci": "npm run lint && npm run test && npm run build"
...
Analyzing application can come in handy when debugging produced bundle size...
- Install
npm install -D esbuild-visualizer source-map-explorer http-server
- Add
"analyze": "ng build --stats-json --output-hashing none --named-chunks && esbuild-visualizer --template treemap --metadata dist/product-app/stats.json --filename dist/product-app/analyse/index.html && http-server -o -c-1 ./dist/product-app/analyse/"
to yourpackage.json
file - Try to run the
analyze
command and explore the website in opened tab - Add
"analyze:sme": "ng build --source-map --output-hashing none --named-chunks && source-map-explorer dist/product-app/browser/*.js --html dist/product-app/sme/index.html && http-server -o -c-1 ./dist/product-app/sme/"
- Try to run the
analyze:sme
command and explore the website in opened tab - Another way is to upload
stats.json
file to official Esbuild Bundle Analyzer website and explore the bundle size there
Our workspace setup is pretty much done, let's see how it looks like and what can be configured...
- Open
angular.json
file in the workspace root, it represents the main descriptor and configuration of the whole workspace - Depending on your IDE, try to collapse
projects
property - Our workspace currently has only one project (
product-app
), a single workspace can host multiple apps and libraries, in case we have multiple projects we can specify which one we want to build, test or serve it using--project
flag so for example we could useng build --project some-other-app
- Inside of
product-app
you can findarchitect
property withbuild
property and finallyconfiguration
property, here you can see what options are applied by default with theproduction
configuration (it is possible to define your own custom configurations which then can be activated using--configuration <my-config>
flag when running commands) - Find
budgets
in thebuild
configuration, this feature enables your build to fail if the size of the bundle crosses specified threshold, try to set it lower and runnpm run build
to see it fail... (hint: reduce warning to0.1mb
and error to0.2mb
for theinitial
bundle type) After that, revert the budget to default values to prevent your build from failing in the future.
- Explore the
cli
property at the bottom of theangular.json
file. Depending on your completion of previous optional tasks for eslint / cypress you might seeschematicCollections
property which contains an array of registered schematics collections. Make sure that the@schematics/angular
is the first item of this array if it exists. - Explore the
schematics
property of theproduct-app
, here you can set schematics defaults so let's say if you always wanted to use components with inline templates instead of separate HTML file you could specify it here instead of always writingng generate component some-component --inline-template
- Try to use code completing (of your IDE) inside of schematics configuration, and you should get hints about all the available options. Notice that the configuration is per schematics collection so if you switched your first collection to
"@cypress/schematic"
then you would need to set options for that schematics too. - Configure schematic options for generating components to always generate standalone component, use "OnPush" change detection strategy and display block as a default
:host
style, then try to generate a new example componentng g c example
, then see thestandalone
andOnPush
flags set in the generated component as well as:host
styles. - Then delete the component
- Running schematics in CLI is great, but in real projects, the paths may get long and tedious to type correctly, that's why it's much better to run schematics with the help of IDE integration, for example in Webstorm (and IDEA), it is possible to right-click a folder, select
New
andAngular Schematic
and then select the schematic you want to run. - Try to run
component
schematic using this method and see how it's much easier to use than typing the command in the terminal - It can be a great idea to bind
Angular Schematics
command to a dedicated key shortcut in the IDE to make its use even more seamless!
Prettier is amazing frontend tooling package which enables an autoformatting of your source code and lets you focus on developing features instead!
- Install
prettier
as a dev dependencynpm i -D
- Create
.prettierrc
file in the workspace root and add the following content
{
"singleQuote": true
}
-
Try to go to any source file in the
product-app
, (egapp.component.ts
) and break formatting, then depending on IDE try to run prettier- Intellij IDEA - press
CTRL ALT SHIFT P
(check your plugins and configuration if it doesn't work...) - VS Code - install prettier extension, and then it should be available with
SHIFT ALT F
- Intellij IDEA - press
-
Add
format:write
script to yourpackage.json
file withprettier \"projects/**/*.{ts,scss,json,html,js}\" --write
content (careful with the escaped quotes, copying and pasting might not work correctly) -
Add
format:test
script to yourpackage.json
file withprettier \"projects/**/*.{ts,scss,json,html,js}\" --list-different
content -
Try running the
format:test
followed by theformat:write
and again followed byformat:test
, all the errors should be gone!
As we might have noticed, running freshly generated application comes with some default content which gives us some pointers about the next steps. That being said we need to get rid of it to start developing our own features.
- Open the
app.component.html
file and delete all its content. - Add
<h1>{{title}} app is running!</h1>
instead - Open the
app.component.spec.ts
file and change the test to expect correct string based on our latest change as theh1
content... - Try to run tests using
npm test
Angular Material is the "official" component framework developed by the Angular team and open source collaborators, as such it represents a great starting point for developing beautiful Angular applications ( alternative options being other 3rd party component frameworks or your own custom framework, but that takes LOTS of time, skill and dedication...)
Setting up Angular Material is relatively simple and includes a couple of steps and choices to be made on the way...
Luckily, Angular CLI and Angular Schematics support automation of this process using ng add
command!
-
Run
ng add --help
to see available options, thecollection
stands for the package to be added and in our case that will be@angular/material
-
Run
ng add @angular/material
, the package will be installed and the Angular Schematics will prompt us for some required options that we didn't provide with the command -
Choose
Indigo/Pink
theme -
Confirm setup of global Angular Material typography styles
-
Confirm include and enable Angular Material browser animations
-
Once done, the command line will inform us about what changes have been made by running the
ng add
schematics, let's explore these files...app.config.ts
- theprovideAnimationsAsync()
was addedindex.html
- schematics added links to fonts used by Angular Material and themat-typography
class on the<body>
tagstyles.scss
- font configurationangular.json
- the indigo/pink pre-built theme is included in thestyles: []
array
-
All this setup executed seamlessly with the power of Angular Schematics, pretty epic! Remember, many popular 3rd party libraries come with the
ng add
support simplifying the setup and usage dramatically! -
Run application using
npm start
to see howmat-typography
affected the fonts -
Let's install Tailwind CSS dependencies with
npm install -D tailwindcss postcss autoprefixer
-
And run
npx tailwind init
, after that, add'./projects/product-app/**/*.{html,ts}',
in thecontent: []
array of the generatedtailwind.config.js
file -
Now we need to enable Tailwind classes by adding following to the start of the
styles.scss
file (global styles)...
@tailwind base;
@tailwind components;
@tailwind utilities;
// Tailwind CSS workarounds (for Angular Material)
.mat-mdc-form-field.mat-mdc-form-field.mat-mdc-form-field.mat-mdc-form-field.mat-mdc-form-field
.mdc-notched-outline__notch {
border-right-style: hidden;
}
- Tailwind CSS is amazing for creation of responsive layouts and has lots of great helpers for layouts, sizing, ...
- Try to use Tailwind classes like
!text-4xl
ortext-blue-700
on the<h1>
tag in theapp.component.html
file and see the changes in the browser
- Why do we generate workspace with
--create-application false
and what are the benefits of this approach? - What's the difference between bundle files produced by the build in production and development mode (besides the size) and what is the purpose of it?
- What's the best way to pass additional arguments to existing npm scripts? (to avoid duplication)
- What is the purpose of the
budgets
specified in theangular.json
file and why should we always use them? - What's the difference between root
styles.scss
file,styles
array in theangular.json
file andstyleUrls
property in the component metadata?