challenge 53 big signal performance (#904)

* feat: challenge 52 big signal performance

* fix: update to 53
This commit is contained in:
Laforge Thomas
2024-06-11 17:28:14 +02:00
committed by GitHub
parent ecc7c8d36c
commit c02c41a606
28 changed files with 453 additions and 16 deletions

View File

@@ -24,7 +24,7 @@ If you would like to propose a challenge, this project is open source, so feel f
## Challenges ## Challenges
Check [all 52 challenges](https://angular-challenges.vercel.app/) Check [all 53 challenges](https://angular-challenges.vercel.app/)
## Contributors ✨ ## Contributors ✨

View File

@@ -0,0 +1,19 @@
{
"extends": ["../../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts"],
"extends": [
"plugin:@nx/angular",
"plugin:@angular-eslint/template/process-inline-templates"
],
"rules": {}
},
{
"files": ["*.html"],
"extends": ["plugin:@nx/angular-template"],
"rules": {}
}
]
}

View File

@@ -0,0 +1,13 @@
# Big Signal Performance
> author: thomas-laforge
### Run Application
```bash
npx nx serve signal-big-signal-performance
```
### Documentation and Instruction
Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/signal/52-big-signal-performance/).

View File

@@ -0,0 +1,72 @@
{
"name": "signal-big-signal-performance",
"$schema": "../../../node_modules/nx/schemas/project-schema.json",
"projectType": "application",
"prefix": "app",
"sourceRoot": "apps/signal/53-big-signal-performance/src",
"tags": [],
"targets": {
"build": {
"executor": "@angular-devkit/build-angular:application",
"outputs": ["{options.outputPath}"],
"options": {
"outputPath": "dist/apps/signal/53-big-signal-performance",
"index": "apps/signal/53-big-signal-performance/src/index.html",
"browser": "apps/signal/53-big-signal-performance/src/main.ts",
"polyfills": ["zone.js"],
"tsConfig": "apps/signal/53-big-signal-performance/tsconfig.app.json",
"inlineStyleLanguage": "scss",
"assets": [
"apps/signal/53-big-signal-performance/src/favicon.ico",
"apps/signal/53-big-signal-performance/src/assets"
],
"styles": ["apps/signal/53-big-signal-performance/src/styles.scss"],
"scripts": []
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "500kb",
"maximumError": "1mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "2kb",
"maximumError": "4kb"
}
],
"outputHashing": "all"
},
"development": {
"optimization": false,
"extractLicenses": false,
"sourceMap": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"executor": "@angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"buildTarget": "signal-big-signal-performance:build:production"
},
"development": {
"buildTarget": "signal-big-signal-performance:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"executor": "@angular-devkit/build-angular:extract-i18n",
"options": {
"buildTarget": "signal-big-signal-performance:build"
}
},
"lint": {
"executor": "@nx/eslint:lint"
}
}
}

View File

@@ -0,0 +1,21 @@
import { CDFlashingDirective } from '@angular-challenges/shared/directives';
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
import { UserStore } from './user.service';
@Component({
selector: 'address-user',
standalone: true,
template: `
<div cd-flash class="m-4 block border border-gray-500 p-4">
Address:
<div>Street: {{ userService.user().address.street }}</div>
<div>ZipCode: {{ userService.user().address.zipCode }}</div>
<div>City: {{ userService.user().address.city }}</div>
</div>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CDFlashingDirective],
})
export class AddressComponent {
userService = inject(UserStore);
}

View File

@@ -0,0 +1,27 @@
import { Component } from '@angular/core';
import { AddressComponent } from './address.component';
import { JobComponent } from './job.component';
import { NameComponent } from './name.component';
import { NoteComponent } from './note.component';
import { UserFormComponent } from './user-form.component';
@Component({
standalone: true,
selector: 'app-root',
template: `
<name />
<address-user />
<job />
<note />
<user-form />
`,
styles: [''],
imports: [
JobComponent,
NameComponent,
AddressComponent,
NoteComponent,
UserFormComponent,
],
})
export class AppComponent {}

View File

@@ -0,0 +1,5 @@
import { ApplicationConfig } from '@angular/core';
export const appConfig: ApplicationConfig = {
providers: [],
};

View File

@@ -0,0 +1,20 @@
import { CDFlashingDirective } from '@angular-challenges/shared/directives';
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
import { UserStore } from './user.service';
@Component({
selector: 'job',
standalone: true,
template: `
<div cd-flash class="m-4 block border border-gray-500 p-4">
Job:
<div>title: {{ userService.user().title }}</div>
<div>salary: {{ userService.user().salary }}</div>
</div>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CDFlashingDirective],
})
export class JobComponent {
userService = inject(UserStore);
}

View File

@@ -0,0 +1,18 @@
import { CDFlashingDirective } from '@angular-challenges/shared/directives';
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
import { UserStore } from './user.service';
@Component({
selector: 'name',
standalone: true,
template: `
<div cd-flash class="m-4 block border border-gray-500 p-4">
Name: {{ userService.user().name }}
</div>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CDFlashingDirective],
})
export class NameComponent {
userService = inject(UserStore);
}

View File

@@ -0,0 +1,18 @@
import { CDFlashingDirective } from '@angular-challenges/shared/directives';
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
import { UserStore } from './user.service';
@Component({
selector: 'note',
standalone: true,
template: `
<div cd-flash class="m-4 block border border-gray-500 p-4">
Note: {{ userService.user().note }}
</div>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CDFlashingDirective],
})
export class NoteComponent {
userService = inject(UserStore);
}

View File

@@ -0,0 +1,100 @@
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
import { UserStore } from './user.service';
@Component({
selector: 'user-form',
standalone: true,
imports: [ReactiveFormsModule],
template: `
<form [formGroup]="form" (ngSubmit)="submit()" class="flex flex-col gap-4">
<div>
Name:
<input
class="rounded-md border border-gray-400"
formControlName="name" />
</div>
<div>
Address:
<div>
street:
<input
class="rounded-md border border-gray-400"
formControlName="street" />
</div>
<div>
zipCode:
<input
class="rounded-md border border-gray-400"
formControlName="zipCode" />
</div>
<div>
city:
<input
class="rounded-md border border-gray-400"
formControlName="city" />
</div>
</div>
<div>
note:
<input
class="rounded-md border border-gray-400"
formControlName="note" />
</div>
<div>
title:
<input
class="rounded-md border border-gray-400"
formControlName="title" />
</div>
<div>
salary:
<input
class="rounded-md border border-gray-400"
formControlName="salary" />
</div>
<button class="w-fit border p-2">Submit</button>
</form>
`,
host: {
class: 'block border border-gray-500 p-4 pt-10 m-4',
},
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class UserFormComponent {
userStore = inject(UserStore);
form = new FormGroup({
name: new FormControl(this.userStore.user().name, { nonNullable: true }),
street: new FormControl(this.userStore.user().address.street, {
nonNullable: true,
}),
zipCode: new FormControl(this.userStore.user().address.zipCode, {
nonNullable: true,
}),
city: new FormControl(this.userStore.user().address.city, {
nonNullable: true,
}),
note: new FormControl(this.userStore.user().note, { nonNullable: true }),
title: new FormControl(this.userStore.user().title, { nonNullable: true }),
salary: new FormControl(this.userStore.user().salary, {
nonNullable: true,
}),
});
submit() {
this.userStore.user.update((u) => ({
...u,
name: this.form.getRawValue().name,
address: {
...u.address,
street: this.form.getRawValue().street,
zipCode: this.form.getRawValue().zipCode,
city: this.form.getRawValue().city,
},
note: this.form.getRawValue().note,
title: this.form.getRawValue().title,
salary: this.form.getRawValue().salary,
}));
}
}

View File

@@ -0,0 +1,16 @@
import { Injectable, signal } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class UserStore {
user = signal({
name: 'Bob',
address: {
street: '',
zipCode: '',
city: '',
},
note: '',
title: '',
salary: 0,
});
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>signal-big-signal-performance</title>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
</head>
<body>
<app-root></app-root>
</body>
</html>

View File

@@ -0,0 +1,7 @@
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { appConfig } from './app/app.config';
bootstrapApplication(AppComponent, appConfig).catch((err) =>
console.error(err),
);

View File

@@ -0,0 +1,5 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
/* You can add global styles to this file, and also import other style files */

View File

@@ -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: [],
};

View File

@@ -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"]
}

View File

@@ -0,0 +1,6 @@
{
"extends": "./tsconfig.json",
"include": ["src/**/*.ts"],
"compilerOptions": {},
"exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"]
}

View File

@@ -0,0 +1,30 @@
{
"compilerOptions": {
"target": "es2022",
"useDefineForClassFields": false,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
},
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.editor.json"
},
{
"path": "./tsconfig.app.json"
}
],
"extends": "../../../tsconfig.base.json",
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"strictTemplates": true
}
}

View File

@@ -1,6 +1,6 @@
{ {
"total": 52, "total": 53,
"🟢": 21, "🟢": 21,
"🟠": 121, "🟠": 122,
"🔴": 209 "🔴": 209
} }

View File

@@ -0,0 +1,23 @@
---
title: 🟠 Big Signal Performance
description: Challenge 53 is about performance while using big signal object
author: thomas-laforge
contributors:
- tomalaforge
challengeNumber: 53
command: signal-big-signal-performance
sidebar:
order: 122
badge: New
---
## Information
In this challenge, you can imagine a big application where you store your user state inside a service and you use this service to use your user anywhere in your application.
The issue is when you update one property of your user, the entire application is updating.
I added the `CDFlashingDirective` to vizualise when one component is rerendering.
## Statement
With Signal, you can now be more fine-grained in what the UI is rerendering. The goal of this challenge is to understand why everything is rerendering and you refactor the application to be more performante.

View File

@@ -13,7 +13,7 @@ hero:
icon: right-arrow icon: right-arrow
variant: primary variant: primary
- text: Ir al Desafío más reciente - text: Ir al Desafío más reciente
link: /es/challenges/angular/52-lazy-load-component/ link: /es/challenges/signal/53-big-signal-performance/
icon: rocket icon: rocket
- text: Dar una estrella - text: Dar una estrella
link: https://github.com/tomalaforge/angular-challenges link: https://github.com/tomalaforge/angular-challenges
@@ -26,8 +26,8 @@ import MyIcon from '../../../components/MyIcon.astro';
import SubscriptionForm from '../../../components/SubscriptionForm.astro'; import SubscriptionForm from '../../../components/SubscriptionForm.astro';
<CardGrid> <CardGrid>
<Card title="52 Desafíos"> <Card title="53 Desafíos">
Este repositorio contiene 52 Desafíos relacionados con <b>Angular</b>, <b>Nx</b>, <b>RxJS</b>, <b>Ngrx</b> y <b>Typescript</b>. Este repositorio contiene 53 Desafíos relacionados con <b>Angular</b>, <b>Nx</b>, <b>RxJS</b>, <b>Ngrx</b> y <b>Typescript</b>.
Estos desafíos se resuelven en torno a problemas de la vida real o características específicas para mejorar tus habilidades. Estos desafíos se resuelven en torno a problemas de la vida real o características específicas para mejorar tus habilidades.
</Card> </Card>

View File

@@ -13,7 +13,7 @@ hero:
icon: right-arrow icon: right-arrow
variant: primary variant: primary
- text: Aller au dernier Challenge - text: Aller au dernier Challenge
link: /fr/challenges/angular/52-lazy-load-component/ link: /fr/challenges/signal/53-big-signal-performance/
icon: rocket icon: rocket
- text: Donne une étoile - text: Donne une étoile
link: https://github.com/tomalaforge/angular-challenges link: https://github.com/tomalaforge/angular-challenges
@@ -26,8 +26,8 @@ import MyIcon from '../../../components/MyIcon.astro';
import SubscriptionForm from '../../../components/SubscriptionForm.astro'; import SubscriptionForm from '../../../components/SubscriptionForm.astro';
<CardGrid> <CardGrid>
<Card title="52 Défis"> <Card title="53 Défis">
Ce répertoire rassemble 52 Défis liés à <b>Angular</b>, <b>Nx</b>, <b>RxJS</b>, <b>Ngrx</b> et <b>Typescript</b>. Ces défis portent sur des problèmes réels ou des fonctionnalités spécifiques pour améliorer vos compétences. Ce répertoire rassemble 53 Défis liés à <b>Angular</b>, <b>Nx</b>, <b>RxJS</b>, <b>Ngrx</b> et <b>Typescript</b>. Ces défis portent sur des problèmes réels ou des fonctionnalités spécifiques pour améliorer vos compétences.
</Card> </Card>
<Card title="Subscribe to get notify of latest challenges"> <Card title="Subscribe to get notify of latest challenges">

View File

@@ -13,7 +13,7 @@ hero:
icon: right-arrow icon: right-arrow
variant: primary variant: primary
- text: Go to the latest Challenge - text: Go to the latest Challenge
link: /challenges/angular/52-lazy-load-component link: /challenges/signal/53-big-signal-performance/
icon: rocket icon: rocket
- text: Give a star - text: Give a star
link: https://github.com/tomalaforge/angular-challenges link: https://github.com/tomalaforge/angular-challenges

View File

@@ -13,7 +13,7 @@ hero:
icon: right-arrow icon: right-arrow
variant: primary variant: primary
- text: Ir para o desafio mais recente - text: Ir para o desafio mais recente
link: /pt/challenges/angular/52-lazy-load-component/ link: /pt/challenges/signal/53-big-signal-performance/
icon: rocket icon: rocket
- text: Dar uma estrela - text: Dar uma estrela
link: https://github.com/tomalaforge/angular-challenges link: https://github.com/tomalaforge/angular-challenges
@@ -26,8 +26,8 @@ import MyIcon from '../../../components/MyIcon.astro';
import SubscriptionForm from '../../../components/SubscriptionForm.astro'; import SubscriptionForm from '../../../components/SubscriptionForm.astro';
<CardGrid> <CardGrid>
<Card title="52 Desafios"> <Card title="53 Desafios">
Este repositório possui 52 Desafios relacionados a <b>Angular</b>, <b>Nx</b>, <b>RxJS</b>, Este repositório possui 53 Desafios relacionados a <b>Angular</b>, <b>Nx</b>, <b>RxJS</b>,
<b>Ngrx</b> e <b>Typescript</b>. <b>Ngrx</b> e <b>Typescript</b>.
Esses desafios são voltados para problemas reais ou funcionalidades específicas afim de Esses desafios são voltados para problemas reais ou funcionalidades específicas afim de
melhorar suas habilidades. melhorar suas habilidades.

View File

@@ -13,7 +13,7 @@ hero:
icon: right-arrow icon: right-arrow
variant: primary variant: primary
- text: Перейти к последней задаче - text: Перейти к последней задаче
link: /ru/challenges/angular/52-lazy-load-component/ link: /ru/challenges/signal/53-big-signal-performance/
icon: rocket icon: rocket
- text: Добавить звезду - text: Добавить звезду
link: https://github.com/tomalaforge/angular-challenges link: https://github.com/tomalaforge/angular-challenges
@@ -26,8 +26,8 @@ import MyIcon from '../../../components/MyIcon.astro';
import SubscriptionForm from '../../../components/SubscriptionForm.astro'; import SubscriptionForm from '../../../components/SubscriptionForm.astro';
<CardGrid> <CardGrid>
<Card title="51 испытаний"> <Card title="53 испытаний">
Этот репозиторий содержит 51 испытаний, связанных с <b>Angular</b>, <b>Nx</b>, <b>RxJS</b>, <b>Ngrx</b> и <b>Typescript</b>. Этот репозиторий содержит 53 испытаний, связанных с <b>Angular</b>, <b>Nx</b>, <b>RxJS</b>, <b>Ngrx</b> и <b>Typescript</b>.
Испытания основаны на реальных задачах или инструментах для того, чтобы прокачать вас. Испытания основаны на реальных задачах или инструментах для того, чтобы прокачать вас.
</Card> </Card>