Skip to content

Commit

Permalink
Merge pull request #26 from FullStacksDev/angular-v19-etc
Browse files Browse the repository at this point in the history
Angular v19 upgrades and more
  • Loading branch information
jits authored Feb 8, 2025
2 parents 2bf23f1 + a945b5c commit d7e3634
Show file tree
Hide file tree
Showing 31 changed files with 5,389 additions and 5,142 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
- name: Set up pnpm
uses: pnpm/action-setup@v4
with:
version: 9
version: 10

- name: Set up Node.js
uses: actions/setup-node@v4
Expand Down
26 changes: 11 additions & 15 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ This isolation is important as Firebase Functions currently deploy ALL dependenc
>
> This does mean you have to manage, install and update dependencies separately, for each subfolder.
A VS Code workspace config is provided to work on both at the same time, in a single VS Code window. The workspace also provides settings and recommended extensions that will help your development experience.
A VS Code workspace config is provided to work on both subfolders at the same time, in a single VS Code window. The workspace also provides settings and recommended extensions that will help your development experience.

> [!TIP]
>
Expand All @@ -90,7 +90,7 @@ The `firebase/common` folder is the place for this shared common code. We recomm

> [!WARNING]
>
> It's highly recommended to only put types, interfaces and very simple utility functions here, and to not rely on any external libraries. Where you do want to rely on an external library (e.g. [type-fest](https://github.com/sindresorhus/type-fest/)) make sure the library is added to both the `app` and `firebase` `package.json` files.
> It's highly recommended to only put types, interfaces and very simple utility functions here, and to not rely on any external libraries. Where you do want to rely on an external library (e.g. [type-fest](https://github.com/sindresorhus/type-fest/)) make sure the library is added to both the `app` and `firebase` `package.json` files as well.
> [!TIP]
>
Expand Down Expand Up @@ -118,7 +118,7 @@ All data in the emulators is persisted to the `firebase/local` folder (on shutdo

| **:brain: Design decision** |
| :-- |
| Beyond local development, this base template assumes only one live Firebase project / environment (which you set up), as specified in the [`firebase/.firebaserc`](./firebase/.firebaserc) file.<br><br>We believe this is a good simple set-up to get you started, and for the first phase of your project (going from 0 to 1), after which you can always add intermediate environments for testing and less risky deploys / rollouts |
| Beyond local development, this base template assumes only one live Firebase project / environment (which you set up), as specified in the [`firebase/.firebaserc`](./firebase/.firebaserc) file.<br><br>We believe this is a good simple set-up to get you started, and for the first phase of your project (going from 0 to 1), after which you can always add a intermediate environment (aka 'staging') for testing and less risky deploys / rollouts |

This live project is your **production** environment — what your users will access, and where all your real data will live.

Expand Down Expand Up @@ -162,7 +162,7 @@ The [`./deploy`](./deploy) script in the root of the project is a simple script

| **:brain: Design decision** |
| :-- |
| We don't use [Angular modules (i.e. `@Module`)](https://angular.dev/guide/ngmodules) for our own code — we've chosen to go all-in on [Angular's recent **standalone** approach](https://angular.dev/guide/components/importing#standalone-components). So we only ever define (and prefer to import) standalone components, directives, etc.<br><br> The base template has configured the Angular CLI generator to always set the `standalone: true` flag on any components, directives, etc. you generate. |
| As of Angular v19, 'standalone' components, pipes and directives are the default (and thus no need for NgModules). We have also enabled the Angular-specific TypeScript flag `strictStandalone` to guard against the use of non-standalone bits. |

| **:brain: Design decision** |
| :-- |
Expand Down Expand Up @@ -222,7 +222,7 @@ We'll refer to these in the rest of the document.

> [!NOTE]
>
> There are some files at the root of the `/app` folder (not shown in the listing above) which we'll touch on in later sections. These include: `angular.json`, `prerendered-routes.txt`, `ngsw-config.json` and `tailwind.config.js`.
> There are some files at the root of the `/app` folder (not shown in the listing above) which we'll touch on in later sections. These include: `angular.json`, `prerendered-routes.txt`, and `ngsw-config.json`.
| **:brain: Design decision** |
| :-- |
Expand All @@ -240,7 +240,7 @@ We'll refer to these in the rest of the document.

The `data` folder is for (most) state management and data access services. Page and smart components go in the `feature` folder, whilst presentational components go in the `ui`folder. And the `util` folder is for standalone utilities.

This is a recommended folder structure based on [Nx's suggested library types](https://nx.dev/concepts/more-concepts/library-types).
This is a recommended folder structure based on [Nx's suggested library types](https://nx.dev/concepts/decisions/project-dependency-rules).

For features within the `shared` folder you should follow the same structure, except you probably won't need a `feature` subfolder within each shared feature since these are shared bits of code for use elsewhere.

Expand Down Expand Up @@ -321,25 +321,21 @@ Whilst on the topic of Firebase Hosting, we also set up some caching headers in

The core of a PWA config is the [`manifest.webmanifest`](./app/src/manifest.webmanifest) file, which defines the app's name, icons, colors, etc. This is used by the browser to provide a more "app-like" experience when the user adds the app to their home screen / app launcher (depending on device capabilities). This file follows the regular [PWA manifest](https://developer.mozilla.org/en-US/docs/Web/Manifest) spec. **You'll need to customize this file to specify your app's name and branding.**

For the Angular service worker, the [`app/ngsw-config.json`](./app/ngsw-config.json) file is the main configuration, determining how to cache assets, handle updates, etc ([docs](https://angular.io/guide/service-worker-config)).
For the Angular service worker, the [`app/ngsw-config.json`](./app/ngsw-config.json) file is the main configuration, determining how to cache assets, handle updates, etc ([docs](https://angular.dev/ecosystem/service-workers/config)).

The [`app/src/app/app.component.ts`](./app/src/app/app.component.ts) file contains the logic for the in-app update notification, which checks for updates to the app and prompts the user to reload when a new version is available.

> [!NOTE]
>
> Technically, a new "version" of an app is just a new build of assets, as defined by the `assetGroups` in the `ngsw-config.json` file. The service worker will automatically download (and cache) these new assets in the background and the trigger the in-app update notification.
> Technically, a new "version" of an app is just a new build of assets, as defined by the `assetGroups` in the `ngsw-config.json` file. The service worker will automatically download (and cache) these new assets in the background and the trigger the in-app update notification. We also use set `"applicationMaxAge": "30d"` to force the service worker to refetch assets every 30 days, just in case.
## [`app`] UI components and styling using Angular Material and Tailwind CSS

| **:brain: Design decision** |
| :-- |
| We use [Angular Material](https://material.angular.io/) (with Material 3) for UI components, and [Tailwind CSS](https://tailwindcss.com/) for styling. You can still create your own UI components or add in other libraries, if needed. You can also customize Tailwind CSS as you wish, by updating the [`app/tailwind.config.js`](./app/tailwind.config.js) config file. |
| We use [Angular Material](https://material.angular.io/) (with Material 3) for UI components, and [Tailwind CSS](https://tailwindcss.com/) for styling. You can still create your own UI components or add in other libraries, if needed. You can also customize Tailwind CSS as you wish, using v4's [CSS-first configuration](https://tailwindcss.com/blog/tailwindcss-v4#css-first-configuration). |

The [`app/src/styles.scss`](./app/src/styles.scss) file sets up both Angular Material (with a basic Material 3 theme with custom background and text colors) and Tailwind CSS styling. Here, we also provide styling overrides to make Angular Material work okay with the Tailwind CSS base styles.

> [!NOTE]
>
> We scope all Tailwind CSS and custom styles within the `#app` selector — we apply the `app` ID on the `<body>` element in the [`app/src/index.html`](./app/src/index.html) file and configure `tailwind.config.js` to place all Tailwind-specific styles within the `#app` selector, acting as a "namespace". When adding styles to the `styles.scss` file make sure to add them within the `#app` selector (already defined) to stick to this namespaced approach. This will hopefully allow for better overrides as you will have more specificity in your custom styles.
The [`app/src/styles.scss`](./app/src/styles.scss) file sets up both Angular Material (with a basic Material 3 theme with custom background and text colors) and Tailwind CSS styling. Styles are provided for headings and paragraphs (`h1`-`h6` and `p` tags) as Angular Material no longer provides these out of the box. We also provide styling overrides to make Angular Material work okay with the Tailwind CSS base styles.

You can import and use Angular Material components within your components as usual (see the [docs](https://material.angular.io/)). And you can use Tailwind CSS classes in your HTML and SCSS files as you wish (see the [docs](https://tailwindcss.com/docs)).

Expand Down Expand Up @@ -387,7 +383,7 @@ These return the underlying Firebase service instances provided by the Firebase

A critical component of any app that provides user-specific capabilities is authentication. The base template comes with an auth store, auth guard, login page, passwordless login flow and logout flow out of the box.

To use the auth store: inject the global `AuthStore` service into your component, service, directive, etc. using `inject(AuthStore)`. You then have access to the state of the auth store. Note that this auth store automatically connects to Firebase Authentication and listens for changes, when your app starts up.
To use the auth store: inject the global `AuthStore` service into your component, service, directive, etc. using `inject(AuthStore)`. You then have access to the state of the auth store. Note that this auth store automatically connects to Firebase Authentication and listens for changes when your app starts up.

To use the auth guard:

Expand Down
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ This template gives you an empty app skeleton, working end-to-end, with the foll
- Login flow using [Firebase Auth's Email Link](https://firebase.google.com/docs/auth/web/email-link-auth).
- Angular Material and Tailwind CSS, with styling overrides to make them work well together.
- Helpers to inject Firebase services into Angular components, services, etc.
- [RxFire](https://github.com/FirebaseExtended/rxfire) used for Observable wrappers for Firebase access in the frontend.
- [RxFire](https://github.com/FirebaseExtended/rxfire) for Observable wrappers for Firebase access in the frontend.
- Frontend logging using [consola](https://github.com/unjs/consola).
- VS Code, ESLint, Prettier, etc. all set up for a consistent and clean development experience.
- Continuous integration (CI) set up with GitHub Actions (for linting, tests and builds).
Expand All @@ -44,12 +44,12 @@ For more details see the [Architecture and design decisions](./ARCHITECTURE.md)
> Basic familiarity with the technologies and services listed is required to make the best of this tech stack and template.
- [Node.js](https://nodejs.org/en/) v20.x
- [TypeScript](https://www.typescriptlang.org/) v5.5
- [Angular](https://angular.dev/) v18.1
- [Angular Material](https://material.angular.io/) v18.1
- [Tailwind CSS](https://tailwindcss.com/) v3.4
- [NgRx Signals](https://ngrx.io/guide/signals) v18.0
- [RxFire](https://github.com/FirebaseExtended/rxfire)
- [TypeScript](https://www.typescriptlang.org/) v5.7
- [Angular](https://angular.dev/) v19.1
- [Angular Material](https://material.angular.io/) v19.1
- [Tailwind CSS](https://tailwindcss.com/) v4.0
- [NgRx Signals](https://ngrx.io/guide/signals) v19.0
- [RxFire](https://github.com/FirebaseExtended/rxfire) v6.1
- [Firebase](https://firebase.google.com/)
- [Hosting](https://firebase.google.com/products/hosting)
- [Authentication](https://firebase.google.com/products/auth)
Expand All @@ -63,7 +63,7 @@ For more details see the [Architecture and design decisions](./ARCHITECTURE.md)
- [Git](https://git-scm.com/) for version control.
- [GitHub](https://github.com/) for hosting the code and running the CI pipeline.
- [VS Code](https://code.visualstudio.com/) as the main editor.
- [pnpm](https://pnpm.io/) as the package manager and script runner.
- [pnpm](https://pnpm.io/) v10 as the package manager and script runner.
- [Angular CLI](https://angular.io/cli)
- [Firebase CLI](https://firebase.google.com/docs/cli)
- [Firebase Emulator Suite](https://firebase.google.com/docs/emulator-suite) for local Firebase services.
Expand Down
5 changes: 5 additions & 0 deletions app/.postcssrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"plugins": {
"@tailwindcss/postcss": {}
}
}
3 changes: 2 additions & 1 deletion app/angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
"routesFile": "prerendered-routes.txt"
},
"ssr": {
"entry": "server.ts"
"entry": "src/server.ts"
}
},
"configurations": {
Expand Down Expand Up @@ -119,6 +119,7 @@
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"builderMode": "application",
"polyfills": ["zone.js", "zone.js/testing"],
"tsConfig": "tsconfig.spec.json",
"inlineStyleLanguage": "scss",
Expand Down
1 change: 1 addition & 0 deletions app/ngsw-config.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"$schema": "./node_modules/@angular/service-worker/config/schema.json",
"index": "/index.csr.html",
"applicationMaxAge": "30d",
"assetGroups": [
{
"name": "app",
Expand Down
91 changes: 51 additions & 40 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,58 +15,69 @@
},
"engines": {
"node": "20",
"pnpm": "9"
"pnpm": "10"
},
"packageManager": "[email protected]",
"private": true,
"dependencies": {
"@angular/animations": "^18.2.12",
"@angular/cdk": "18.2.13",
"@angular/common": "^18.2.12",
"@angular/compiler": "^18.2.12",
"@angular/core": "^18.2.12",
"@angular/forms": "^18.2.12",
"@angular/material": "18.2.13",
"@angular/platform-browser": "^18.2.12",
"@angular/platform-browser-dynamic": "^18.2.12",
"@angular/platform-server": "^18.2.12",
"@angular/router": "^18.2.12",
"@angular/service-worker": "^18.2.12",
"@angular/ssr": "^18.2.12",
"@ngrx/operators": "^18.1.1",
"@ngrx/signals": "^18.1.1",
"consola": "^3.2.3",
"express": "^4.21.1",
"firebase": "^11.0.2",
"ngxtension": "^4.1.0",
"rxfire": "^6.0.6-canary.5cfad21",
"@angular/animations": "^19.1.5",
"@angular/cdk": "19.1.3",
"@angular/common": "^19.1.5",
"@angular/compiler": "^19.1.5",
"@angular/core": "^19.1.5",
"@angular/forms": "^19.1.5",
"@angular/material": "19.1.3",
"@angular/platform-browser": "^19.1.5",
"@angular/platform-browser-dynamic": "^19.1.5",
"@angular/platform-server": "^19.1.5",
"@angular/router": "^19.1.5",
"@angular/service-worker": "^19.1.5",
"@angular/ssr": "^19.1.6",
"@ngrx/operators": "^19.0.1",
"@ngrx/signals": "^19.0.1",
"consola": "^3.4.0",
"express": "^4.21.2",
"firebase": "^11.3.0",
"ngxtension": "^4.3.2",
"rxfire": "^6.1.0",
"rxjs": "~7.8.0",
"tslib": "^2.8.1",
"zone.js": "~0.14.10"
"zone.js": "~0.15.0"
},
"devDependencies": {
"@angular-devkit/build-angular": "^18.2.12",
"@angular/cli": "^18.2.12",
"@angular/compiler-cli": "^18.2.12",
"@ngrx/eslint-plugin": "^18.1.1",
"@types/express": "^4.17.17",
"@types/jasmine": "~5.1.0",
"@types/node": "^22.9.0",
"angular-eslint": "18.4.1",
"autoprefixer": "^10.4.20",
"eslint": "^9.15.0",
"eslint-config-prettier": "^9.1.0",
"jasmine-core": "~5.4.0",
"@angular-devkit/build-angular": "^19.1.6",
"@angular/cli": "^19.1.6",
"@angular/compiler-cli": "^19.1.5",
"@ngrx/eslint-plugin": "^19.0.1",
"@tailwindcss/postcss": "^4.0.0",
"@types/express": "^5.0.0",
"@types/jasmine": "~5.1.5",
"@types/node": "^22.13.1",
"angular-eslint": "^19.0.2",
"eslint": "^9.19.0",
"eslint-config-prettier": "^10.0.1",
"jasmine-core": "~5.5.0",
"karma": "~6.4.4",
"karma-chrome-launcher": "~3.2.0",
"karma-coverage": "~2.2.0",
"karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "~2.1.0",
"ng-mocks": "^14.13.1",
"ng-mocks": "^14.13.2",
"postcss": "^8.4.49",
"prettier": "^3.3.3",
"prettier-plugin-tailwindcss": "^0.6.8",
"tailwindcss": "^3.4.15",
"typescript": "~5.5.4",
"typescript-eslint": "^8.15.0"
"prettier": "^3.4.2",
"prettier-plugin-tailwindcss": "^0.6.11",
"tailwindcss": "^4.0.0",
"typescript": "~5.7.3",
"typescript-eslint": "^8.23.0"
},
"pnpm": {
"onlyBuiltDependencies": [
"protobufjs",
"nx",
"@parcel/watcher",
"esbuild",
"msgpackr-extract",
"lmdb"
]
}
}
Loading

0 comments on commit d7e3634

Please sign in to comment.