Skip to content

Develop & Deploy a Progressive Web Application

Yash Anand edited this page Apr 27, 2022 · 10 revisions

WIP

1. Introduction

This is a comprehensive guide to setup the foundation for a progressive web application. For now, it is based on boilerplate generated using ngX-Rocket. This guide not only covers development but also setting up a convenient CI/CD workflow, error reporting, analytics etc.

Angular ngX-Rocket

1.1 Why Angular?

Personally, I find the following to be the deciding factors in why I choose Angular as a framework

  • Speed of development
  • Opinionated and proven practices
  • Great tooling
  • Higher scalability than any other framework

1.2 Tools

2. Setup

Let's begin with generating the boilerplate, making some preliminary adjustments and setting up our environment.

2.1 Generate App

  1. Install ngX-Rocket
npm install -g generator-ngx-rocket
  1. Generate the app
ngx new

When asked, select configuration only as per the application's needs (also make sure you choose Jest & Puppeteer). Try not to select extra boilerplate code that you may never use.

Make sure you remove tslint.json in case it comes with the boilerplate as we will be using ESLint only.

2.2 Preliminary Refactoring

2.2.1 Refactor jest.config.js

Check my PR generator-ngx-rocket/#610

  1. Install ts-jest as a dev dependency
npm install ts-jest --save-dev
  1. To make sure jest auto generates module paths from tsconfig.json, replace the moduleNameMapper key in module.exports of jest.config.js with the one shown below and also add the require imports at the top of the file. Make sure the path to your tsconfig.json is correct.
// https://github.com/thymikee/jest-preset-angular#brief-explanation-of-config
const { pathsToModuleNameMapper } = require('ts-jest/utils');
// In the following statement, replace `./tsconfig` with the path to your `tsconfig` file
// which contains the path mapping (ie the `compilerOptions.paths` option):
const { compilerOptions } = require('./tsconfig');

module.exports = {
  ...
  moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, { prefix: '<rootDir>/' }),
  ...
};

2.2.2 Fix npx jest

Running tests via ng test should work well as the boilerplate code is configured to work with @angular-builders/jest:run. Though, if you try running npx jest directly, you might encounter errors. This is because we need to import 'jest-preset-angular/setup-jest' in in our setup-jest.ts but when you try adding this, ng test starts failing on the other hand because @angular-builders/jest:run is already configured to run the script. So if you want to run npx jest without disrupting any config files & ng test, just add some options

npx jest --setupFilesAfterEnv='jest-preset-angular/setup-jest' '<rootDir>/src/setup-jest.ts'

You can use the above CLI command, if you are configuring tests to be run in an IDE, for e.g. WebStorm, as it is more interactive; while ng test will still be functional if you're using it elsewhere, for e.g. in the CI.

2.2.3 Configure Prettier as an ESLint Rule

I personally prefer this as it makes prettier issues detectable as linting errors/warnings.

  1. Prettier comes packaged with the boilerplate generated by ngX-Rocket. Referring to the recommended configuration in the official readme
npm install -D eslint-plugin-prettier eslint-config-prettier
  1. Then you need to add plugin:prettier/recommended as the last extension in your .eslintrc
{
  "extends": ["plugin:prettier/recommended"]
}
  1. Create a new file .prettierrc if not already present in the root directory and set the following rules. Make sure you set the correct extension for the CSS preprocessor (if any) for your app, if it's not *.scss
{ 
  "singleQuote": true,
  "cursorOffset": -1,
  "trailingComma": "none",
  "overrides": [
    {
      "files": "*.scss",
      "options": {
        "singleQuote": false
      }
    },
    {
      "files": "*.component.html",
      "options": {
        "parser": "angular"
      }
    },
    {
      "files": "*.html",
      "options": {
        "parser": "html"
      }
    }
  ]
}
  1. Remove the Prettier configuration from package.json (if present) as we want to use .prettierrc instead.

2.2.4 Configure Prettier as a Stylelint Rule

  1. Referring to the recommended configuration in the official readme
npm install -D stylelint-prettier
  1. Replace the extends key in your .stylelintrc with the following
"extends": [
  "stylelint-prettier/recommended"
]
  1. Install postcss-scss
npm install -D postcss-scss
  1. Replace the lint script in package.json with the following
"lint": "ng lint && stylelint \"src/**/*.scss\" --custom-syntax postcss-scss",

2.2.5 Configure commit linting

We will be setting up git hooks using husky which comes installed with the boilerplate.

  1. Install commitlint as a dev dependency
npm install -D @commitlint/config-conventional @commitlint/cli
  1. Configure commitlint to use conventional config
echo "module.exports = { extends: ['@commitlint/config-conventional'] };" > commitlint.config.js
  1. Add the commit message hook
npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'

2.3 Deployment & Hosting

If you're a small team/individual developer, the setup may help you configure some simple CI/CD workflows. Alternatively, if you're a bigger team, you might want to configure a more robust & accommodating workflow.

2.3.1 Configure hosting using Firebase

Keeping ease of configuration in mind, we will be using Firebase Hosting as it allows for greater flexibility in terms of deployments than GitHub pages.

  1. Create a project on Firebase.
  2. Run firebase init and complete the questionnaire.

2.3.2 Improvise the Workflows