From 1999e2c611e195a11273c51447baffee3cd0760a Mon Sep 17 00:00:00 2001 From: thomas Date: Wed, 6 Dec 2023 21:31:19 +0400 Subject: [PATCH 1/8] feat: add pr stale and close --- .github/workflows/close-inactive-pr.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/close-inactive-pr.yml b/.github/workflows/close-inactive-pr.yml index e19063f..19a62db 100644 --- a/.github/workflows/close-inactive-pr.yml +++ b/.github/workflows/close-inactive-pr.yml @@ -13,10 +13,13 @@ jobs: - uses: actions/stale@v5 with: days-before-issue-stale: 20 - days-before-issue-close: 14 + days-before-issue-close: -1 stale-issue-label: 'stale' stale-issue-message: 'This issue is stale because it has been open for 20 days with no activity.' - close-issue-message: 'This issue was closed because it has been inactive for 14 days since being marked as stale.' - days-before-pr-stale: -1 - days-before-pr-close: -1 + days-before-pr-stale: 20 + days-before-pr-close: 7 + stale-pr-label: 'stale' + stale-pr-message: 'This pull request is stale because it has been open for 20 days with no activity.' + close-pr-message: 'This pull request was closed because it has been inactive for 7 days since being marked as stale.' + only-pr-labels: 'answer' repo-token: ${{ secrets.GITHUB_TOKEN }} From 3e1dc89d78f7b10b1b757493d2f51438cd6a9f46 Mon Sep 17 00:00:00 2001 From: thomas Date: Wed, 6 Dec 2023 21:37:20 +0400 Subject: [PATCH 2/8] feat: add prettier plugin for import and tailwind --- .prettierrc | 4 ++- package-lock.json | 91 +++++++++++++++++++++++++++++++++++++++++++++++ package.json | 2 ++ 3 files changed, 96 insertions(+), 1 deletion(-) diff --git a/.prettierrc b/.prettierrc index dea17d4..810823b 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,4 +1,6 @@ { "singleQuote": true, - "bracketSameLine": true + "bracketSameLine": true, + "htmlWhitespaceSensitivity": "ignore", + "plugins": ["prettier-plugin-organize-imports", "prettier-plugin-tailwindcss"] } diff --git a/package-lock.json b/package-lock.json index f0fbad7..8869862 100644 --- a/package-lock.json +++ b/package-lock.json @@ -92,6 +92,8 @@ "postcss-preset-env": "~7.5.0", "postcss-url": "~10.1.3", "prettier": "^3.1.0", + "prettier-plugin-organize-imports": "^3.2.4", + "prettier-plugin-tailwindcss": "^0.5.9", "testing-library-selector": "^0.3.1", "ts-jest": "29.1.0", "ts-node": "10.9.1", @@ -24405,6 +24407,95 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/prettier-plugin-organize-imports": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-3.2.4.tgz", + "integrity": "sha512-6m8WBhIp0dfwu0SkgfOxJqh+HpdyfqSSLfKKRZSFbDuEQXDDndb8fTpRWkUrX/uBenkex3MgnVk0J3b3Y5byog==", + "dev": true, + "peerDependencies": { + "@volar/vue-language-plugin-pug": "^1.0.4", + "@volar/vue-typescript": "^1.0.4", + "prettier": ">=2.0", + "typescript": ">=2.9" + }, + "peerDependenciesMeta": { + "@volar/vue-language-plugin-pug": { + "optional": true + }, + "@volar/vue-typescript": { + "optional": true + } + } + }, + "node_modules/prettier-plugin-tailwindcss": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.5.9.tgz", + "integrity": "sha512-9x3t1s2Cjbut2QiP+O0mDqV3gLXTe2CgRlQDgucopVkUdw26sQi53p/q4qvGxMLBDfk/dcTV57Aa/zYwz9l8Ew==", + "dev": true, + "engines": { + "node": ">=14.21.3" + }, + "peerDependencies": { + "@ianvs/prettier-plugin-sort-imports": "*", + "@prettier/plugin-pug": "*", + "@shopify/prettier-plugin-liquid": "*", + "@trivago/prettier-plugin-sort-imports": "*", + "prettier": "^3.0", + "prettier-plugin-astro": "*", + "prettier-plugin-css-order": "*", + "prettier-plugin-import-sort": "*", + "prettier-plugin-jsdoc": "*", + "prettier-plugin-marko": "*", + "prettier-plugin-organize-attributes": "*", + "prettier-plugin-organize-imports": "*", + "prettier-plugin-style-order": "*", + "prettier-plugin-svelte": "*" + }, + "peerDependenciesMeta": { + "@ianvs/prettier-plugin-sort-imports": { + "optional": true + }, + "@prettier/plugin-pug": { + "optional": true + }, + "@shopify/prettier-plugin-liquid": { + "optional": true + }, + "@trivago/prettier-plugin-sort-imports": { + "optional": true + }, + "prettier-plugin-astro": { + "optional": true + }, + "prettier-plugin-css-order": { + "optional": true + }, + "prettier-plugin-import-sort": { + "optional": true + }, + "prettier-plugin-jsdoc": { + "optional": true + }, + "prettier-plugin-marko": { + "optional": true + }, + "prettier-plugin-organize-attributes": { + "optional": true + }, + "prettier-plugin-organize-imports": { + "optional": true + }, + "prettier-plugin-style-order": { + "optional": true + }, + "prettier-plugin-svelte": { + "optional": true + }, + "prettier-plugin-twig-melody": { + "optional": true + } + } + }, "node_modules/pretty-bytes": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", diff --git a/package.json b/package.json index db971a7..2ac701c 100644 --- a/package.json +++ b/package.json @@ -95,6 +95,8 @@ "postcss-preset-env": "~7.5.0", "postcss-url": "~10.1.3", "prettier": "^3.1.0", + "prettier-plugin-organize-imports": "^3.2.4", + "prettier-plugin-tailwindcss": "^0.5.9", "testing-library-selector": "^0.3.1", "ts-jest": "29.1.0", "ts-node": "10.9.1", From 58215fe349b694a45f41bf9f8b9a57872204b6f0 Mon Sep 17 00:00:00 2001 From: thomas Date: Mon, 30 Oct 2023 21:28:40 +0100 Subject: [PATCH 3/8] feat(chritsmas): create challenge for christmas --- README.md | 2 +- .../christmas-web-worker/.eslintrc.json | 19 ++ .../christmas-web-worker/README.md | 13 + .../christmas-web-worker/project.json | 81 +++++++ .../src/app/app.component.ts | 32 +++ .../src/app/app.config.ts | 5 + .../src/app/prime-number.service.ts | 30 +++ .../unknown-person.component.css | 223 ++++++++++++++++++ .../unknown-person.component.ts | 35 +++ .../christmas-web-worker/src/assets/.gitkeep | 0 .../christmas-web-worker/src/favicon.ico | Bin 0 -> 15086 bytes .../christmas-web-worker/src/index.html | 13 + .../christmas-web-worker/src/main.ts | 7 + .../christmas-web-worker/src/styles.scss | 5 + .../christmas-web-worker/tailwind.config.js | 14 ++ .../christmas-web-worker/tsconfig.app.json | 10 + .../christmas-web-worker/tsconfig.editor.json | 7 + .../christmas-web-worker/tsconfig.json | 29 +++ challenge-number.json | 4 +- .../challenges/angular/39-injection-token.md | 1 - .../performance/40-christmas-web-worker.md | 20 ++ docs/src/content/docs/index.mdx | 6 +- 22 files changed, 549 insertions(+), 7 deletions(-) create mode 100644 apps/performance/christmas-web-worker/.eslintrc.json create mode 100644 apps/performance/christmas-web-worker/README.md create mode 100644 apps/performance/christmas-web-worker/project.json create mode 100644 apps/performance/christmas-web-worker/src/app/app.component.ts create mode 100644 apps/performance/christmas-web-worker/src/app/app.config.ts create mode 100644 apps/performance/christmas-web-worker/src/app/prime-number.service.ts create mode 100644 apps/performance/christmas-web-worker/src/app/unknown-person/unknown-person.component.css create mode 100644 apps/performance/christmas-web-worker/src/app/unknown-person/unknown-person.component.ts create mode 100644 apps/performance/christmas-web-worker/src/assets/.gitkeep create mode 100644 apps/performance/christmas-web-worker/src/favicon.ico create mode 100644 apps/performance/christmas-web-worker/src/index.html create mode 100644 apps/performance/christmas-web-worker/src/main.ts create mode 100644 apps/performance/christmas-web-worker/src/styles.scss create mode 100644 apps/performance/christmas-web-worker/tailwind.config.js create mode 100644 apps/performance/christmas-web-worker/tsconfig.app.json create mode 100644 apps/performance/christmas-web-worker/tsconfig.editor.json create mode 100644 apps/performance/christmas-web-worker/tsconfig.json create mode 100644 docs/src/content/docs/challenges/performance/40-christmas-web-worker.md diff --git a/README.md b/README.md index 2680b4a..4250a0a 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 39 challenges](https://angular-challenges.vercel.app/) +Check [all 40 challenges](https://angular-challenges.vercel.app/) ## Contributors ✨ diff --git a/apps/performance/christmas-web-worker/.eslintrc.json b/apps/performance/christmas-web-worker/.eslintrc.json new file mode 100644 index 0000000..d3cd799 --- /dev/null +++ b/apps/performance/christmas-web-worker/.eslintrc.json @@ -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": {} + } + ] +} diff --git a/apps/performance/christmas-web-worker/README.md b/apps/performance/christmas-web-worker/README.md new file mode 100644 index 0000000..6da9394 --- /dev/null +++ b/apps/performance/christmas-web-worker/README.md @@ -0,0 +1,13 @@ +# Web workers + +> Author: Thomas Laforge + +### Run Application + +```bash +npx nx serve performance-christmas-web-worker +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/performance/40-christmas-web-worker/). diff --git a/apps/performance/christmas-web-worker/project.json b/apps/performance/christmas-web-worker/project.json new file mode 100644 index 0000000..0f33ede --- /dev/null +++ b/apps/performance/christmas-web-worker/project.json @@ -0,0 +1,81 @@ +{ + "name": "performance-christmas-web-worker", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/performance/christmas-web-worker/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/performance/christmas-web-worker", + "index": "apps/performance/christmas-web-worker/src/index.html", + "main": "apps/performance/christmas-web-worker/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/performance/christmas-web-worker/tsconfig.app.json", + "assets": [ + "apps/performance/christmas-web-worker/src/favicon.ico", + "apps/performance/christmas-web-worker/src/assets" + ], + "styles": ["apps/performance/christmas-web-worker/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-christmas-web-worker:build:production" + }, + "development": { + "browserTarget": "performance-christmas-web-worker:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "browserTarget": "performance-christmas-web-worker:build" + } + }, + "lint": { + "executor": "@nx/eslint:lint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": [ + "apps/performance/christmas-web-worker/**/*.ts", + "apps/performance/christmas-web-worker/**/*.html" + ] + } + } + } +} diff --git a/apps/performance/christmas-web-worker/src/app/app.component.ts b/apps/performance/christmas-web-worker/src/app/app.component.ts new file mode 100644 index 0000000..a7e757f --- /dev/null +++ b/apps/performance/christmas-web-worker/src/app/app.component.ts @@ -0,0 +1,32 @@ +import { CommonModule } from '@angular/common'; +import { Component, inject } from '@angular/core'; +import { PrimeService } from './prime-number.service'; +import { UnknownPersonComponent } from './unknown-person/unknown-person.component'; + +@Component({ + standalone: true, + imports: [CommonModule, UnknownPersonComponent], + providers: [PrimeService], + selector: 'app-root', + template: ` + + +
Progress: {{ loadingPercentage() }}%
+ `, + host: { + class: `flex flex-col h-screen w-screen bg-[#1f75c0]`, + }, +}) +export class AppComponent { + primeService = inject(PrimeService); + + loadingPercentage = this.primeService.loadingPercentage; + + discover() { + this.primeService.calculatePrimeLength(); + } +} diff --git a/apps/performance/christmas-web-worker/src/app/app.config.ts b/apps/performance/christmas-web-worker/src/app/app.config.ts new file mode 100644 index 0000000..81a6edd --- /dev/null +++ b/apps/performance/christmas-web-worker/src/app/app.config.ts @@ -0,0 +1,5 @@ +import { ApplicationConfig } from '@angular/core'; + +export const appConfig: ApplicationConfig = { + providers: [], +}; diff --git a/apps/performance/christmas-web-worker/src/app/prime-number.service.ts b/apps/performance/christmas-web-worker/src/app/prime-number.service.ts new file mode 100644 index 0000000..9ef52fa --- /dev/null +++ b/apps/performance/christmas-web-worker/src/app/prime-number.service.ts @@ -0,0 +1,30 @@ +import { Injectable, computed, signal } from '@angular/core'; + +@Injectable() +export class PrimeService { + private finalResult = 664579; + private primesLength = signal(0); + + loadingPercentage = computed( + () => (this.primesLength() * 100) / this.finalResult + ); + + calculatePrimeLength() { + this.findPrimesUpToLimit(10000000); + } + + private findPrimesUpToLimit(limit: number) { + for (let num = 2; num <= limit; num++) { + let isPrime = true; + for (let i = 2; i <= Math.sqrt(num); i++) { + if (num % i === 0) { + isPrime = false; + break; + } + } + if (isPrime) { + this.primesLength.update((l) => l + 1); + } + } + } +} diff --git a/apps/performance/christmas-web-worker/src/app/unknown-person/unknown-person.component.css b/apps/performance/christmas-web-worker/src/app/unknown-person/unknown-person.component.css new file mode 100644 index 0000000..254caa2 --- /dev/null +++ b/apps/performance/christmas-web-worker/src/app/unknown-person/unknown-person.component.css @@ -0,0 +1,223 @@ +*, +*:before, +*:after { + padding: 0; + margin: 0; + box-sizing: border-box; +} +body { + background-color: #fff2c8; +} +.container { + width: 380px; + height: 500px; + position: absolute; + transform: translate(-50%, -50%); + top: 50%; + left: 50%; +} +.container *:before, +.container *:after { + position: absolute; + content: ''; +} +.santa { + height: 220px; + width: 200px; + background-color: #e84701; + border-radius: 80px; + position: absolute; + left: 115px; + top: 200px; +} +.santa:before, +.santa:after { + width: 40px; + margin: auto; + left: 0; + right: 0; + background-color: #fff2c8; +} +.santa:before { + height: 130px; +} +.santa:after { + height: 40px; + bottom: -15px; +} +.hand-l { + background-color: #e84701; + height: 90px; + width: 105px; + position: absolute; + right: -30px; + top: 20px; + border-radius: 0 80px 0 0; +} +.hand-l:before { + margin: auto; + width: 35px; + height: 15px; + background-color: #ffffff; + top: 85px; + left: 71px; +} +.hand-l:after { + height: 15px; + width: 30px; + background-color: #fad2af; + left: 74px; + top: 101px; + border-radius: 0 0 30px 30px; +} +.hand-r { + height: 150px; + width: 180px; + border: 30px solid transparent; + border-bottom: 40px solid #e84701; + position: absolute; + left: -100px; + bottom: 150px; + border-radius: 50%; + animation: wave 1.5s infinite; + transform-origin: right; +} +@keyframes wave { + 50% { + transform: rotate(15deg); + } +} +.hand-r:before { + width: 35px; + height: 15px; + background-color: #ffffff; + transform: rotate(-50deg); + top: 68px; + left: -22px; +} +.hand-r:after { + width: 30px; + height: 15px; + background-color: #fad2af; + transform: rotate(-50deg); + left: -31px; + top: 58px; + border-radius: 15px 15px 0 0; +} +.face { + position: absolute; + margin: auto; + height: 180px; + width: 180px; + background-color: #fad2af; + border: 25px solid #f2e6da; + border-radius: 50%; + left: 0; + right: 0; + bottom: 140px; +} +.beard { + position: absolute; + height: 90px; + width: 180px; + background-color: #ffffff; + border-radius: 0 0 90px 90px; + right: -25px; + bottom: -25px; +} +.beard:before { + width: 55px; + height: 25px; + background-color: #f2e6da; + border-radius: 20px 0; + left: 34px; +} +.beard:after { + height: 25px; + width: 55px; + background-color: #f2e6da; + border-radius: 0 20px; + right: 34px; +} +.eyes { + height: 12px; + width: 12px; + background-color: #0078ca; + border-radius: 50%; + position: absolute; + top: 40px; + left: 40px; + box-shadow: 38px 0 #0078ca, 19px 20px #f69697; +} +.eyes:before { + height: 12px; + width: 25px; + background-color: #ffffff; + border-radius: 10px 0; + left: -10px; + bottom: 20px; +} +.eyes:after { + height: 12px; + width: 25px; + background-color: #ffffff; + border-radius: 0 10px; + left: 32px; + bottom: 20px; +} +.hat { + position: absolute; + height: 60px; + width: 120px; + background-color: #e84701; + top: -98px; + left: 85px; + border-radius: 0 0 60px 60px; +} +.hat:before { + height: 40px; + width: 40px; + background-color: #ffffff; + left: 100px; + top: -15px; + border-radius: 50%; +} +.belt { + position: absolute; + width: 100%; + height: 30px; + background-color: #000000; + top: 100px; +} +.belt:before { + height: 100%; + width: 40px; + border: 7px solid #ffdc2e; + margin: auto; + left: 0; + right: 0; +} +.belt:after { + height: 5px; + width: 15px; + background-color: #ffdc2e; + left: 100px; + top: 12px; +} +.shoe { + height: 20px; + width: 20px; + background-color: #000000; + position: absolute; + top: 220px; + left: 60px; + border-radius: 20px 0 0 0; +} +.shoe:before { + height: 20px; + width: 20px; + background-color: #000000; + top: 0; + left: 60px; + border-radius: 0 20px 0 0; +} diff --git a/apps/performance/christmas-web-worker/src/app/unknown-person/unknown-person.component.ts b/apps/performance/christmas-web-worker/src/app/unknown-person/unknown-person.component.ts new file mode 100644 index 0000000..adbfa86 --- /dev/null +++ b/apps/performance/christmas-web-worker/src/app/unknown-person/unknown-person.component.ts @@ -0,0 +1,35 @@ +import { NgIf } from '@angular/common'; +import { Component, Input } from '@angular/core'; +@Component({ + selector: 'unknown-person', + standalone: true, + imports: [NgIf], + template: ` +
+
+ Who is here? +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `, + styleUrls: [`unknown-person.component.css`], +}) +export class UnknownPersonComponent { + @Input({ required: true }) step!: number; +} diff --git a/apps/performance/christmas-web-worker/src/assets/.gitkeep b/apps/performance/christmas-web-worker/src/assets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/apps/performance/christmas-web-worker/src/favicon.ico b/apps/performance/christmas-web-worker/src/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..317ebcb2336e0833a22dddf0ab287849f26fda57 GIT binary patch literal 15086 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 + + + + performance-christmas-web-worker + + + + + + + + diff --git a/apps/performance/christmas-web-worker/src/main.ts b/apps/performance/christmas-web-worker/src/main.ts new file mode 100644 index 0000000..514c89a --- /dev/null +++ b/apps/performance/christmas-web-worker/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/christmas-web-worker/src/styles.scss b/apps/performance/christmas-web-worker/src/styles.scss new file mode 100644 index 0000000..77e408a --- /dev/null +++ b/apps/performance/christmas-web-worker/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/christmas-web-worker/tailwind.config.js b/apps/performance/christmas-web-worker/tailwind.config.js new file mode 100644 index 0000000..38183db --- /dev/null +++ b/apps/performance/christmas-web-worker/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/christmas-web-worker/tsconfig.app.json b/apps/performance/christmas-web-worker/tsconfig.app.json new file mode 100644 index 0000000..5822042 --- /dev/null +++ b/apps/performance/christmas-web-worker/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/christmas-web-worker/tsconfig.editor.json b/apps/performance/christmas-web-worker/tsconfig.editor.json new file mode 100644 index 0000000..4ee6393 --- /dev/null +++ b/apps/performance/christmas-web-worker/tsconfig.editor.json @@ -0,0 +1,7 @@ +{ + "extends": "./tsconfig.json", + "include": ["src/**/*.ts"], + "compilerOptions": { + "types": [] + } +} diff --git a/apps/performance/christmas-web-worker/tsconfig.json b/apps/performance/christmas-web-worker/tsconfig.json new file mode 100644 index 0000000..51c7908 --- /dev/null +++ b/apps/performance/christmas-web-worker/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 6e455d3..cd65533 100644 --- a/challenge-number.json +++ b/challenge-number.json @@ -1,6 +1,6 @@ { - "total": 39, + "total": 40, "🟢": 14, - "🟠": 118, + "🟠": 119, "🔴": 207 } diff --git a/docs/src/content/docs/challenges/angular/39-injection-token.md b/docs/src/content/docs/challenges/angular/39-injection-token.md index 5dfdbd8..36aab19 100644 --- a/docs/src/content/docs/challenges/angular/39-injection-token.md +++ b/docs/src/content/docs/challenges/angular/39-injection-token.md @@ -6,7 +6,6 @@ challengeNumber: 39 command: angular-injection-token sidebar: order: 118 - badge: New --- ## Information diff --git a/docs/src/content/docs/challenges/performance/40-christmas-web-worker.md b/docs/src/content/docs/challenges/performance/40-christmas-web-worker.md new file mode 100644 index 0000000..91570e9 --- /dev/null +++ b/docs/src/content/docs/challenges/performance/40-christmas-web-worker.md @@ -0,0 +1,20 @@ +--- +title: 🟠 Web workers +description: Challenge 40 is about ... +author: Thomas Laforge +challengeNumber: 40 +command: performance-christmas-web-worker +sidebar: + order: 119 + badge: New +--- + +:::note +WIP: The following documentation need to be written. +::: + +## Information + +## Statement + +## Constraints diff --git a/docs/src/content/docs/index.mdx b/docs/src/content/docs/index.mdx index 3c7eabf..8cc1ae6 100644 --- a/docs/src/content/docs/index.mdx +++ b/docs/src/content/docs/index.mdx @@ -15,7 +15,7 @@ hero: icon: right-arrow variant: primary - text: Go to the latest Challenge - link: /challenges/angular/39-injection-token/ + link: /challenges/performance/40-christmas-web-worker/ icon: rocket - text: Give a star link: https://github.com/tomalaforge/angular-challenges @@ -27,8 +27,8 @@ import { Card, CardGrid } from '@astrojs/starlight/components'; import MyIcon from '../../components/MyIcon.astro'; - - This repository gathers 39 Challenges related to Angular, Nx, RxJS, Ngrx and Typescript. + + This repository gathers 40 Challenges related to Angular, Nx, RxJS, Ngrx and Typescript. These challenges resolve around real-life issues or specific features to elevate your skills. From bc6449cf571c5b2ac709e0b48b135037316726e6 Mon Sep 17 00:00:00 2001 From: thomas Date: Mon, 30 Oct 2023 22:13:53 +0100 Subject: [PATCH 4/8] feat: add text for happy christmas --- .../src/app/unknown-person/unknown-person.component.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/performance/christmas-web-worker/src/app/unknown-person/unknown-person.component.ts b/apps/performance/christmas-web-worker/src/app/unknown-person/unknown-person.component.ts index adbfa86..dbf9095 100644 --- a/apps/performance/christmas-web-worker/src/app/unknown-person/unknown-person.component.ts +++ b/apps/performance/christmas-web-worker/src/app/unknown-person/unknown-person.component.ts @@ -14,6 +14,7 @@ import { Component, Input } from '@angular/core'; Who is here? +
Happy Christmas !!!
From b521f45f4a37c552754fd5f4e92efbc60213aa0c Mon Sep 17 00:00:00 2001 From: thomas Date: Fri, 3 Nov 2023 20:40:29 +0100 Subject: [PATCH 5/8] feat: rename prime to random --- .../src/app/app.component.ts | 10 +++---- .../src/app/app.config.ts | 5 ---- .../src/app/heavy-calculation.service.ts | 30 +++++++++++++++++++ .../src/app/prime-number.service.ts | 30 ------------------- .../christmas-web-worker/src/main.ts | 5 +--- 5 files changed, 36 insertions(+), 44 deletions(-) delete mode 100644 apps/performance/christmas-web-worker/src/app/app.config.ts create mode 100644 apps/performance/christmas-web-worker/src/app/heavy-calculation.service.ts delete mode 100644 apps/performance/christmas-web-worker/src/app/prime-number.service.ts diff --git a/apps/performance/christmas-web-worker/src/app/app.component.ts b/apps/performance/christmas-web-worker/src/app/app.component.ts index a7e757f..ba55d27 100644 --- a/apps/performance/christmas-web-worker/src/app/app.component.ts +++ b/apps/performance/christmas-web-worker/src/app/app.component.ts @@ -1,12 +1,12 @@ import { CommonModule } from '@angular/common'; import { Component, inject } from '@angular/core'; -import { PrimeService } from './prime-number.service'; +import { HeavyCalculationService } from './heavy-calculation.service'; import { UnknownPersonComponent } from './unknown-person/unknown-person.component'; @Component({ standalone: true, imports: [CommonModule, UnknownPersonComponent], - providers: [PrimeService], + providers: [HeavyCalculationService], selector: 'app-root', template: ` @@ -22,11 +22,11 @@ import { UnknownPersonComponent } from './unknown-person/unknown-person.componen }, }) export class AppComponent { - primeService = inject(PrimeService); + private heavyCalculationService = inject(HeavyCalculationService); - loadingPercentage = this.primeService.loadingPercentage; + readonly loadingPercentage = this.heavyCalculationService.loadingPercentage; discover() { - this.primeService.calculatePrimeLength(); + this.heavyCalculationService.startLoading(); } } diff --git a/apps/performance/christmas-web-worker/src/app/app.config.ts b/apps/performance/christmas-web-worker/src/app/app.config.ts deleted file mode 100644 index 81a6edd..0000000 --- a/apps/performance/christmas-web-worker/src/app/app.config.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { ApplicationConfig } from '@angular/core'; - -export const appConfig: ApplicationConfig = { - providers: [], -}; diff --git a/apps/performance/christmas-web-worker/src/app/heavy-calculation.service.ts b/apps/performance/christmas-web-worker/src/app/heavy-calculation.service.ts new file mode 100644 index 0000000..84ce1e6 --- /dev/null +++ b/apps/performance/christmas-web-worker/src/app/heavy-calculation.service.ts @@ -0,0 +1,30 @@ +import { Injectable, computed, signal } from '@angular/core'; + +@Injectable() +export class HeavyCalculationService { + private finalLength = 664579; + private loadingLength = signal(0); + + loadingPercentage = computed( + () => (this.loadingLength() * 100) / this.finalLength + ); + + startLoading() { + this.randomHeavyCalculalationFunction(); + } + + private randomHeavyCalculalationFunction() { + for (let num = 2; num <= 10000000; num++) { + let randomFlag = true; + for (let i = 2; i <= Math.sqrt(num); i++) { + if (num % i === 0) { + randomFlag = false; + break; + } + } + if (randomFlag) { + this.loadingLength.update((l) => l + 1); + } + } + } +} diff --git a/apps/performance/christmas-web-worker/src/app/prime-number.service.ts b/apps/performance/christmas-web-worker/src/app/prime-number.service.ts deleted file mode 100644 index 9ef52fa..0000000 --- a/apps/performance/christmas-web-worker/src/app/prime-number.service.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Injectable, computed, signal } from '@angular/core'; - -@Injectable() -export class PrimeService { - private finalResult = 664579; - private primesLength = signal(0); - - loadingPercentage = computed( - () => (this.primesLength() * 100) / this.finalResult - ); - - calculatePrimeLength() { - this.findPrimesUpToLimit(10000000); - } - - private findPrimesUpToLimit(limit: number) { - for (let num = 2; num <= limit; num++) { - let isPrime = true; - for (let i = 2; i <= Math.sqrt(num); i++) { - if (num % i === 0) { - isPrime = false; - break; - } - } - if (isPrime) { - this.primesLength.update((l) => l + 1); - } - } - } -} diff --git a/apps/performance/christmas-web-worker/src/main.ts b/apps/performance/christmas-web-worker/src/main.ts index 514c89a..31c5da4 100644 --- a/apps/performance/christmas-web-worker/src/main.ts +++ b/apps/performance/christmas-web-worker/src/main.ts @@ -1,7 +1,4 @@ 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) -); +bootstrapApplication(AppComponent).catch((err) => console.error(err)); From 39702d3f385c396b87f2b50f0e3a8207ad820c6b Mon Sep 17 00:00:00 2001 From: thomas Date: Fri, 3 Nov 2023 22:05:32 +0100 Subject: [PATCH 6/8] feat: add documentation --- .../performance/40-christmas-web-worker.md | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/docs/src/content/docs/challenges/performance/40-christmas-web-worker.md b/docs/src/content/docs/challenges/performance/40-christmas-web-worker.md index 91570e9..0e6556c 100644 --- a/docs/src/content/docs/challenges/performance/40-christmas-web-worker.md +++ b/docs/src/content/docs/challenges/performance/40-christmas-web-worker.md @@ -1,6 +1,6 @@ --- title: 🟠 Web workers -description: Challenge 40 is about ... +description: Challenge 40 is about learning how to create and use a web worker author: Thomas Laforge challengeNumber: 40 command: performance-christmas-web-worker @@ -9,12 +9,24 @@ sidebar: badge: New --- -:::note -WIP: The following documentation need to be written. -::: - ## Information +This challenge has been created for Angular Advent Calendar 2023. + +This application is basic. We click on the **Discover** button to reveal the surprise hidden behind the black screen. However, the current application provides an awful user experience. When we click on the button, the page freezes, and after a while, it reveals the secret all at once without a smooth animation. + +> Note: To create the application freeze, the loader is based on a very heavy computation function. We could have used a basic timer, but that's not the point of this challenge. + +Since JavaScript is single-threaded, when we perform a heavy task, the browser cannot update the UI or respond to mouse clicks or any events. To free the main thread, the goal is to isolate the heavy computation into a different thread. To do so, we will need to use web workers. Web workers can run any scripts in the background, in isolation from the main thread, allowing the browser to still provide your user with a good experience. + +In Angular, this technology is often underused, however, it's straightforward to create one. There is a schematic that you can find here. + ## Statement -## Constraints +The goal of this challenge is to create a smooth animation by isolating the heavy computation function into a web worker. + +First, create a web worker using the schematics, then move the issuing function. Finally, the animation should be smooth and provide an awesome user experience. + +### Note + +Since we are inside an Nx workspace, simply replace the `ng` command with `nx` when running the schematic. From 5ab6f7e02c1528e32712efcf804db308b0e57147 Mon Sep 17 00:00:00 2001 From: thomas Date: Sun, 19 Nov 2023 22:36:38 +0400 Subject: [PATCH 7/8] feat: change target --- apps/performance/christmas-web-worker/project.json | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/apps/performance/christmas-web-worker/project.json b/apps/performance/christmas-web-worker/project.json index 0f33ede..a1eae3c 100644 --- a/apps/performance/christmas-web-worker/project.json +++ b/apps/performance/christmas-web-worker/project.json @@ -7,12 +7,12 @@ "tags": [], "targets": { "build": { - "executor": "@angular-devkit/build-angular:browser", + "executor": "@angular-devkit/build-angular:application", "outputs": ["{options.outputPath}"], "options": { "outputPath": "dist/apps/performance/christmas-web-worker", "index": "apps/performance/christmas-web-worker/src/index.html", - "main": "apps/performance/christmas-web-worker/src/main.ts", + "browser": "apps/performance/christmas-web-worker/src/main.ts", "polyfills": ["zone.js"], "tsConfig": "apps/performance/christmas-web-worker/tsconfig.app.json", "assets": [ @@ -39,9 +39,7 @@ "outputHashing": "all" }, "development": { - "buildOptimizer": false, "optimization": false, - "vendorChunk": true, "extractLicenses": false, "sourceMap": true, "namedChunks": true @@ -53,10 +51,10 @@ "executor": "@angular-devkit/build-angular:dev-server", "configurations": { "production": { - "browserTarget": "performance-christmas-web-worker:build:production" + "buildTarget": "performance-christmas-web-worker:build:production" }, "development": { - "browserTarget": "performance-christmas-web-worker:build:development" + "buildTarget": "performance-christmas-web-worker:build:development" } }, "defaultConfiguration": "development" From 671c7bf8c3891494204f0004b27f5fe8000c9f0d Mon Sep 17 00:00:00 2001 From: thomas Date: Thu, 30 Nov 2023 14:11:15 +0400 Subject: [PATCH 8/8] feat: new control flow --- .../app/unknown-person/unknown-person.component.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/apps/performance/christmas-web-worker/src/app/unknown-person/unknown-person.component.ts b/apps/performance/christmas-web-worker/src/app/unknown-person/unknown-person.component.ts index dbf9095..1682ddf 100644 --- a/apps/performance/christmas-web-worker/src/app/unknown-person/unknown-person.component.ts +++ b/apps/performance/christmas-web-worker/src/app/unknown-person/unknown-person.component.ts @@ -1,18 +1,17 @@ -import { NgIf } from '@angular/common'; import { Component, Input } from '@angular/core'; @Component({ selector: 'unknown-person', standalone: true, - imports: [NgIf], template: `
-
- Who is here? -
+ @if (step !== 100) { +
+ Who is here? +
+ }
Happy Christmas !!!