From cdf6df005a61c04042e1050f7959a6712d496f97 Mon Sep 17 00:00:00 2001 From: thomas Date: Sat, 7 Oct 2023 20:58:25 +0200 Subject: [PATCH] feat(challenge37): ngfor optimize big list --- README.md | 2 +- apps/performance/ngfor-biglist/.eslintrc.json | 36 ++++++++ apps/performance/ngfor-biglist/README.md | 13 +++ apps/performance/ngfor-biglist/project.json | 81 ++++++++++++++++++ .../ngfor-biglist/src/app/app.component.ts | 42 +++++++++ .../ngfor-biglist/src/app/app.config.ts | 6 ++ .../ngfor-biglist/src/app/generateList.ts | 15 ++++ .../ngfor-biglist/src/app/list.service.ts | 44 ++++++++++ .../src/app/person-list.component.ts | 30 +++++++ .../ngfor-biglist/src/app/person.model.ts | 4 + .../ngfor-biglist/src/assets/.gitkeep | 0 .../performance/ngfor-biglist/src/favicon.ico | Bin 0 -> 15086 bytes apps/performance/ngfor-biglist/src/index.html | 13 +++ apps/performance/ngfor-biglist/src/main.ts | 7 ++ .../performance/ngfor-biglist/src/styles.scss | 5 ++ .../ngfor-biglist/tailwind.config.js | 14 +++ .../ngfor-biglist/tsconfig.app.json | 10 +++ .../ngfor-biglist/tsconfig.editor.json | 7 ++ apps/performance/ngfor-biglist/tsconfig.json | 29 +++++++ challenge-number.json | 4 +- .../angular-performance/35-memoize.md | 2 +- .../angular-performance/36-ngfor-optimize.md | 3 +- .../angular-performance/37-ngfor-biglist.md | 55 ++++++++++++ docs/src/content/docs/index.mdx | 4 +- 24 files changed, 418 insertions(+), 8 deletions(-) create mode 100644 apps/performance/ngfor-biglist/.eslintrc.json create mode 100644 apps/performance/ngfor-biglist/README.md create mode 100644 apps/performance/ngfor-biglist/project.json create mode 100644 apps/performance/ngfor-biglist/src/app/app.component.ts create mode 100644 apps/performance/ngfor-biglist/src/app/app.config.ts create mode 100644 apps/performance/ngfor-biglist/src/app/generateList.ts create mode 100644 apps/performance/ngfor-biglist/src/app/list.service.ts create mode 100644 apps/performance/ngfor-biglist/src/app/person-list.component.ts create mode 100644 apps/performance/ngfor-biglist/src/app/person.model.ts create mode 100644 apps/performance/ngfor-biglist/src/assets/.gitkeep create mode 100644 apps/performance/ngfor-biglist/src/favicon.ico create mode 100644 apps/performance/ngfor-biglist/src/index.html create mode 100644 apps/performance/ngfor-biglist/src/main.ts create mode 100644 apps/performance/ngfor-biglist/src/styles.scss create mode 100644 apps/performance/ngfor-biglist/tailwind.config.js create mode 100644 apps/performance/ngfor-biglist/tsconfig.app.json create mode 100644 apps/performance/ngfor-biglist/tsconfig.editor.json create mode 100644 apps/performance/ngfor-biglist/tsconfig.json create mode 100644 docs/src/content/docs/challenges/angular-performance/37-ngfor-biglist.md diff --git a/README.md b/README.md index 6af1ff092..136070d07 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ If you would like to propose a challenge, this project is open source, so feel f ## Challenges -Check [all 36 challenges](https://angular-challenges.vercel.app/) +Check [all 37 challenges](https://angular-challenges.vercel.app/) ## Contributors ✨ diff --git a/apps/performance/ngfor-biglist/.eslintrc.json b/apps/performance/ngfor-biglist/.eslintrc.json new file mode 100644 index 000000000..bf8df1428 --- /dev/null +++ b/apps/performance/ngfor-biglist/.eslintrc.json @@ -0,0 +1,36 @@ +{ + "extends": ["../../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts"], + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "app", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "app", + "style": "kebab-case" + } + ] + }, + "extends": [ + "plugin:@nx/angular", + "plugin:@angular-eslint/template/process-inline-templates" + ] + }, + { + "files": ["*.html"], + "extends": ["plugin:@nx/angular-template"], + "rules": {} + } + ] +} diff --git a/apps/performance/ngfor-biglist/README.md b/apps/performance/ngfor-biglist/README.md new file mode 100644 index 000000000..e23cb226d --- /dev/null +++ b/apps/performance/ngfor-biglist/README.md @@ -0,0 +1,13 @@ +# NgFor optimize big list + +> Author: Thomas Laforge + +### Run Application + +```bash +npx nx serve performance-ngfor-biglist +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular-performance/37-ngfor-biglist/). diff --git a/apps/performance/ngfor-biglist/project.json b/apps/performance/ngfor-biglist/project.json new file mode 100644 index 000000000..e567b9b53 --- /dev/null +++ b/apps/performance/ngfor-biglist/project.json @@ -0,0 +1,81 @@ +{ + "name": "performance-ngfor-biglist", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/performance/ngfor-biglist/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/performance/ngfor-biglist", + "index": "apps/performance/ngfor-biglist/src/index.html", + "main": "apps/performance/ngfor-biglist/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/performance/ngfor-biglist/tsconfig.app.json", + "assets": [ + "apps/performance/ngfor-biglist/src/favicon.ico", + "apps/performance/ngfor-biglist/src/assets" + ], + "styles": ["apps/performance/ngfor-biglist/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "browserTarget": "performance-ngfor-biglist:build:production" + }, + "development": { + "browserTarget": "performance-ngfor-biglist:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "browserTarget": "performance-ngfor-biglist:build" + } + }, + "lint": { + "executor": "@nx/linter:eslint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": [ + "apps/performance/ngfor-biglist/**/*.ts", + "apps/performance/ngfor-biglist/**/*.html" + ] + } + } + } +} diff --git a/apps/performance/ngfor-biglist/src/app/app.component.ts b/apps/performance/ngfor-biglist/src/app/app.component.ts new file mode 100644 index 000000000..1baa61dab --- /dev/null +++ b/apps/performance/ngfor-biglist/src/app/app.component.ts @@ -0,0 +1,42 @@ +import { NgIf } from '@angular/common'; +import { Component, signal } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatInputModule } from '@angular/material/input'; +import { generateList } from './generateList'; +import { PersonService } from './list.service'; +import { PersonListComponent } from './person-list.component'; + +@Component({ + standalone: true, + imports: [ + NgIf, + PersonListComponent, + FormsModule, + MatFormFieldModule, + MatInputModule, + ], + providers: [PersonService], + selector: 'app-root', + template: ` + + + + `, + host: { + class: 'flex items-center flex-col gap-5', + }, +}) +export class AppComponent { + readonly persons = signal(generateList()); + readonly loadList = signal(false); + + label = ''; +} diff --git a/apps/performance/ngfor-biglist/src/app/app.config.ts b/apps/performance/ngfor-biglist/src/app/app.config.ts new file mode 100644 index 000000000..59198e627 --- /dev/null +++ b/apps/performance/ngfor-biglist/src/app/app.config.ts @@ -0,0 +1,6 @@ +import { ApplicationConfig } from '@angular/core'; +import { provideAnimations } from '@angular/platform-browser/animations'; + +export const appConfig: ApplicationConfig = { + providers: [provideAnimations()], +}; diff --git a/apps/performance/ngfor-biglist/src/app/generateList.ts b/apps/performance/ngfor-biglist/src/app/generateList.ts new file mode 100644 index 000000000..96bfb3722 --- /dev/null +++ b/apps/performance/ngfor-biglist/src/app/generateList.ts @@ -0,0 +1,15 @@ +import { randEmail, randFirstName } from '@ngneat/falso'; +import { Person } from './person.model'; + +export function generateList() { + const arr: Person[] = []; + + for (let i = 0; i < 100000; i++) { + arr.push({ + email: randEmail(), + name: randFirstName(), + }); + } + + return arr; +} diff --git a/apps/performance/ngfor-biglist/src/app/list.service.ts b/apps/performance/ngfor-biglist/src/app/list.service.ts new file mode 100644 index 000000000..e56bddef8 --- /dev/null +++ b/apps/performance/ngfor-biglist/src/app/list.service.ts @@ -0,0 +1,44 @@ +import { Injectable, inject, signal } from '@angular/core'; +import { randEmail, randFirstName } from '@ngneat/falso'; +import { generateList } from './generateList'; +import { Person } from './person.model'; + +@Injectable() +export class PersonService { + private readonly fakeBackend = inject(FakeBackendService); + readonly persons = signal([]); + + loadPersons() { + this.persons.set(generateList()); + } + + deletePerson(email: string) { + this.persons.set( + this.fakeBackend + .returnNewList(this.persons()) + .filter((p) => p.email !== email) + ); + } + + updatePerson(email: string) { + this.persons.set( + this.fakeBackend + .returnNewList(this.persons()) + .map((p) => (p.email === email ? { email, name: randFirstName() } : p)) + ); + } + + addPerson(name: string) { + this.persons.set([ + { email: randEmail(), name }, + ...this.fakeBackend.returnNewList(this.persons()), + ]); + } +} + +@Injectable({ providedIn: 'root' }) +export class FakeBackendService { + returnNewList = (input: Person[]): Person[] => [ + ...input.map((i) => ({ ...i })), + ]; +} diff --git a/apps/performance/ngfor-biglist/src/app/person-list.component.ts b/apps/performance/ngfor-biglist/src/app/person-list.component.ts new file mode 100644 index 000000000..e9bbb1785 --- /dev/null +++ b/apps/performance/ngfor-biglist/src/app/person-list.component.ts @@ -0,0 +1,30 @@ +import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; + +import { NgForTrackByModule } from '@angular-challenges/shared/directives'; +import { CommonModule } from '@angular/common'; +import { Person } from './person.model'; + +@Component({ + selector: 'app-person-list', + standalone: true, + imports: [CommonModule, NgForTrackByModule], + template: ` +
+
+
+

{{ person.name }}

+

{{ person.email }}

+
+
+
+ `, + host: { + class: 'w-full flex flex-col', + }, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class PersonListComponent { + @Input() persons: Person[] = []; +} diff --git a/apps/performance/ngfor-biglist/src/app/person.model.ts b/apps/performance/ngfor-biglist/src/app/person.model.ts new file mode 100644 index 000000000..0ccffbbf9 --- /dev/null +++ b/apps/performance/ngfor-biglist/src/app/person.model.ts @@ -0,0 +1,4 @@ +export interface Person { + email: string; + name: string; +} diff --git a/apps/performance/ngfor-biglist/src/assets/.gitkeep b/apps/performance/ngfor-biglist/src/assets/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/apps/performance/ngfor-biglist/src/favicon.ico b/apps/performance/ngfor-biglist/src/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..317ebcb2336e0833a22dddf0ab287849f26fda57 GIT binary patch literal 15086 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 + + + + performance-ngfor-biglist + + + + + + + + diff --git a/apps/performance/ngfor-biglist/src/main.ts b/apps/performance/ngfor-biglist/src/main.ts new file mode 100644 index 000000000..514c89a08 --- /dev/null +++ b/apps/performance/ngfor-biglist/src/main.ts @@ -0,0 +1,7 @@ +import { bootstrapApplication } from '@angular/platform-browser'; +import { appConfig } from './app/app.config'; +import { AppComponent } from './app/app.component'; + +bootstrapApplication(AppComponent, appConfig).catch((err) => + console.error(err) +); diff --git a/apps/performance/ngfor-biglist/src/styles.scss b/apps/performance/ngfor-biglist/src/styles.scss new file mode 100644 index 000000000..77e408aa8 --- /dev/null +++ b/apps/performance/ngfor-biglist/src/styles.scss @@ -0,0 +1,5 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +/* You can add global styles to this file, and also import other style files */ diff --git a/apps/performance/ngfor-biglist/tailwind.config.js b/apps/performance/ngfor-biglist/tailwind.config.js new file mode 100644 index 000000000..38183db2c --- /dev/null +++ b/apps/performance/ngfor-biglist/tailwind.config.js @@ -0,0 +1,14 @@ +const { createGlobPatternsForDependencies } = require('@nx/angular/tailwind'); +const { join } = require('path'); + +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + join(__dirname, 'src/**/!(*.stories|*.spec).{ts,html}'), + ...createGlobPatternsForDependencies(__dirname), + ], + theme: { + extend: {}, + }, + plugins: [], +}; diff --git a/apps/performance/ngfor-biglist/tsconfig.app.json b/apps/performance/ngfor-biglist/tsconfig.app.json new file mode 100644 index 000000000..58220429a --- /dev/null +++ b/apps/performance/ngfor-biglist/tsconfig.app.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "types": [] + }, + "files": ["src/main.ts"], + "include": ["src/**/*.d.ts"], + "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"] +} diff --git a/apps/performance/ngfor-biglist/tsconfig.editor.json b/apps/performance/ngfor-biglist/tsconfig.editor.json new file mode 100644 index 000000000..4ee639340 --- /dev/null +++ b/apps/performance/ngfor-biglist/tsconfig.editor.json @@ -0,0 +1,7 @@ +{ + "extends": "./tsconfig.json", + "include": ["src/**/*.ts"], + "compilerOptions": { + "types": [] + } +} diff --git a/apps/performance/ngfor-biglist/tsconfig.json b/apps/performance/ngfor-biglist/tsconfig.json new file mode 100644 index 000000000..51c7908c5 --- /dev/null +++ b/apps/performance/ngfor-biglist/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "target": "es2022", + "useDefineForClassFields": false, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.editor.json" + } + ], + "extends": "../../../tsconfig.base.json", + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/challenge-number.json b/challenge-number.json index a6d987c39..14d6f15fe 100644 --- a/challenge-number.json +++ b/challenge-number.json @@ -1,6 +1,6 @@ { - "total": 36, + "total": 37, "🟢": 13, - "🟠": 116, + "🟠": 117, "🔴": 207 } diff --git a/docs/src/content/docs/challenges/angular-performance/35-memoize.md b/docs/src/content/docs/challenges/angular-performance/35-memoize.md index 54fa6aacb..0c774bbc1 100644 --- a/docs/src/content/docs/challenges/angular-performance/35-memoize.md +++ b/docs/src/content/docs/challenges/angular-performance/35-memoize.md @@ -1,6 +1,6 @@ --- title: 🟢 Memoization -description: Challenge 35 is about learning +description: Challenge 35 is about learning how pure pipe works sidebar: order: 8 --- diff --git a/docs/src/content/docs/challenges/angular-performance/36-ngfor-optimize.md b/docs/src/content/docs/challenges/angular-performance/36-ngfor-optimize.md index 5fef237ff..8a043f10d 100644 --- a/docs/src/content/docs/challenges/angular-performance/36-ngfor-optimize.md +++ b/docs/src/content/docs/challenges/angular-performance/36-ngfor-optimize.md @@ -1,9 +1,8 @@ --- title: 🟢 NgFor Optimization -description: Challenge 36 is about ... +description: Challenge 36 is about learning how trackby works sidebar: order: 13 - badge: New ---
Challenge #36
diff --git a/docs/src/content/docs/challenges/angular-performance/37-ngfor-biglist.md b/docs/src/content/docs/challenges/angular-performance/37-ngfor-biglist.md new file mode 100644 index 000000000..c3691b75e --- /dev/null +++ b/docs/src/content/docs/challenges/angular-performance/37-ngfor-biglist.md @@ -0,0 +1,55 @@ +--- +title: 🟠 NgFor Optimization Big List +description: Challenge 37 is about learning how virtualization optimize big list rendering +sidebar: + order: 117 + badge: New +--- + +
Challenge #37
+ +## Information + +In this application, we can render a list of 100,000 individuals by clicking on the **loadList** button. If you open the Chrome developer panel by pressing **F12**, go to the Source tab, and expand the element to see the list, you will notice that all 100,000 elements are rendered in the DOM, even though we can only see about 20 elements in the viewport. This process takes a lot of time, which is why the application is very slow at displaying the list. + +We can use the Angular DevTool to profile our application and understand what is happening inside our application. I will show you how to do it inside the following video. + +:::note +If you don't know how to use it, read [the performance introduction page](/challenges/angular-performance/) first and come back after. +::: + +## Statement + +The goal of this challenge is to implement a better alternative to display big list of items. + +## Hints: + +
+ Hint 1 + +If you're unsure where to begin, I recommend reading the [Angular CDK virtualization documentation](https://material.angular.io/cdk/scrolling/overview) + +
+ +--- + +:::note +Start the project by running: `npx nx serve performance-ngfor-biglist`. +::: + +:::tip[Reminder] +Your PR title must start with Answer:37. +::: + + diff --git a/docs/src/content/docs/index.mdx b/docs/src/content/docs/index.mdx index 70e1f8627..082f1f097 100644 --- a/docs/src/content/docs/index.mdx +++ b/docs/src/content/docs/index.mdx @@ -23,8 +23,8 @@ hero: import { Card, CardGrid } from '@astrojs/starlight/components'; - - This repository gathers 36 Challenges related to Angular, Nx, RxJS, Ngrx and Typescript. + + This repository gathers 37 Challenges related to Angular, Nx, RxJS, Ngrx and Typescript. These challenges resolve around real-life issues or specific features to elevate your skills.