{"id":12266,"date":"2022-11-18T10:35:12","date_gmt":"2022-11-18T09:35:12","guid":{"rendered":"https:\/\/vived.io\/?p=12266"},"modified":"2022-11-18T10:35:15","modified_gmt":"2022-11-18T09:35:15","slug":"angular-15-ta-sama-logika-dwa-razy-mniej-kodu-frontend-weekly-vol-113","status":"publish","type":"post","link":"https:\/\/vived.io\/pl\/angular-15-ta-sama-logika-dwa-razy-mniej-kodu-frontend-weekly-vol-113\/","title":{"rendered":"Angular 15 &#8211; ta sama logika, dwa razy mniej kodu  | Frontend Weekly vol. 113"},"content":{"rendered":"\n<h2 id=\"1-angular-v15\" data-num=1>1. Angular v15&nbsp;<\/h2>\n\n\n\n<p>Kolejne wersje Angulara publikowane s\u0105 co 6 miesi\u0119cy z dok\u0142adno\u015bci\u0105 szwajcarskiego zegarka. Dzisiaj \u015bwiat\u0142o dzienne ujrza\u0142 Angular 15. Czy wywraca on do g\u00f3ry nogami status quo jak Svelte albo chocia\u017c prezentuje nowe innowacyjne koncepcje jak React Server Components? Niestety nie. Jest to jednak wydanie pe\u0142ne ma\u0142ych inkrementalnych zmian, adresuj\u0105cych realne bol\u0105czki deweloper\u00f3w. Je\u015bli mam by\u0107 szczery to dla mnie jest to najbardziej interesuj\u0105ce wydanie Angulara od co najmniej dw\u00f3ch lat.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"620\" height=\"465\" src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/download-48.jpeg\" alt=\"\" class=\"wp-image-12267\" srcset=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/download-48.jpeg 620w, https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/download-48-300x225.jpeg 300w\" sizes=\"auto, (max-width: 620px) 100vw, 620px\" \/><\/figure><\/div>\n\n\n<h3 class=\"wp-block-heading\">Angular Standalone Components<span style=\"font-size: revert; color: initial; font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, Oxygen-Sans, Ubuntu, Cantarell, &quot;Helvetica Neue&quot;, sans-serif;\">\/<\/span><\/h3>\n\n\n\n<p>Zanim przejdziemy do clue ca\u0142ej sprawy ma\u0142a dygresja dla wszystkich, kt\u00f3rzy na co dzie\u0144 nie maj\u0105 do czynienia z frameworkiem od Google. Angularowe modu\u0142y maj\u0105 niewiele wsp\u00f3lnego z modu\u0142ami znanym z JavaScriptu. Natywne modu\u0142y pozwalaj\u0105 podzieli\u0107 aplikacj\u0119 na wiele plik\u00f3w i zarz\u0105dza\u0107 API, jakie udost\u0119pniamy. Angularowe modu\u0142y maj\u0105 na celu zapewnia\u0107 konfiguracj\u0119 zale\u017cno\u015bci dla Dependency Injection. W Angularze ka\u017cdy komponent czy dyrektywa musi by\u0107 cz\u0119\u015bci\u0105 jakiego\u015b modu\u0142u, co czyni je najbardziej atomicznym elementem frameworku. Co ciekawe, modu\u0142y trafi\u0142y do Angulara dopiero w wersji 2.0.0-rc.5 i by\u0142y odpowiedzi\u0105 na problemy z publikowanie Angularowych bibliotek w npm. Z racji, \u017ce framework by\u0142 ju\u017c na etapie Release Candidate, to ca\u0142e rozwi\u0105zanie powsta\u0142o w przy\u015bpieszonym tempie, i jak to bywa z takimi rozwi\u0105zaniami zosta\u0142o z nami na d\u0142u\u017cej.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"666\" height=\"500\" src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/5qdvey.jpeg\" alt=\"\" class=\"wp-image-12269\" srcset=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/5qdvey.jpeg 666w, https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/5qdvey-300x225.jpeg 300w\" sizes=\"auto, (max-width: 666px) 100vw, 666px\" \/><\/figure><\/div>\n\n\n<p>Na przestrzeni lat dobre praktyki wok\u00f3\u0142 Angulara ewoluowa\u0142y i obecnie najcz\u0119\u015bciej uskuteczniamy jest schemat SCAM ( Single Component Angular Module). Pewnie nie by\u0142oby w tym nic z\u0142ego, gdyby nie ilo\u015b\u0107 boilerplateu jaka generowana jest przez tak\u0105 architektur\u0119.<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">@Component({\n  selector: &#039;vived-my-component&#039;,\n  template:`\n    &lt;div&gt;\n      &lt;h1&gt;Today is {{today | date}} &lt;\/h1&gt;&#039;\n      &lt;CustomComponent \/&gt;\n    &lt;\/div&gt;\n  `\n})\nexport class MyComponent {\n  readonly today = new Date();\n}\n\n@NgModule({\n  imports:      [ CommonModule, CustomComponentModule ],\n  declarations: [ MyComponent ],\n  exports:      [ MyComponent ],\n})\nexport class MyComponentModule { }<\/code><\/pre>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"686\" height=\"364\" src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/download-50.jpeg\" alt=\"\" class=\"wp-image-12271\" srcset=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/download-50.jpeg 686w, https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/download-50-300x159.jpeg 300w\" sizes=\"auto, (max-width: 686px) 100vw, 686px\" \/><\/figure><\/div>\n\n\n<p>Angular Standalone Components, czyli komponenty pozbawione modu\u0142\u00f3w,&nbsp; zosta\u0142y po raz pierwszy zaprezentowane w postaci RFC pod koniec 2021 roku. Spo\u0142eczno\u015b\u0107 w\u0142a\u015bciwie od razu pokocha\u0142a je bezwarunkowo. W po\u0142owie 2022 roku wraz z Angularem 14 otrzymali\u015bmy ich pierwsz\u0105 niestabiln\u0105 implementacj\u0119. W tym tygodniu wraz z Angularem 15 doczekali\u015bmy si\u0119 ich pierwszej stabilnej wersji.&nbsp;<\/p>\n\n\n\n<p>W du\u017cym uproszczeniu Standalone Components, to architektura SCAM zrobiona dobrze. Je\u015bli do komponentu do\u0142\u0105czymy odpowiednie metadane, to Angular automatycznie zacznie traktowa\u0107 dany komponent jako modu\u0142.<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">@Component({\n  selector: &#039;vived-my-component&#039;,\n  standalone: true.,\n  imports: [ CommonModule, CustomComponent ]\n  template: `\n    &lt;div&gt;\n      &lt;h1&gt;Today is {{today | date}} &lt;\/h1&gt;&#039;\n      &lt;CustomComponent \/&gt;\n    &lt;\/div&gt;\n    `\n})\nexport class MyComponent {\n  readonly today = new Date();\n}<\/code><\/pre>\n\n\n\n<p>Zesp\u00f3\u0142 Angulara nie poprzesta\u0142 na API do tworzenia Standalone Components, ale za cel postawi\u0142 sobie przygotowanie funkcyjnego API, kt\u00f3re pozwoli ca\u0142kowicie pozby\u0107 si\u0119 z modu\u0142\u00f3w z wi\u0119kszo\u015bci aplikacji. Angular 15 jest zwie\u0144czeniem tych stara\u0144, bo do funkcyjnego API do bootstapowania aplikacji do\u0142\u0105cza funkcyjny router oraz funkcyjny modu\u0142 http.<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">\/\/ This is how you bootstrap application with modules\n@NgModule({\n  declarations: [AppComponent],\n  imports: [\n    RouterModule.forRoot(\n      [\n        { path: &#039;\/home&#039;, component: HomeComponent },\n        { path: &#039;**&#039;, redirectTo: &#039;\/home&#039; },\n      ],\n      {\n        preloadingStrategy: PreloadAllModules,\n      }\n    ),\n  ],\n  providers: [\n    { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },\n  ],\n  bootstrap: [AppComponent],\n})\nexport class AppModule {}\n\nplatformBrowserDynamic().bootstrapModule(AppModule)<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">\/\/ This is how you bootstrap application without modules\nbootstrapApplication(AppComponent, {\n  providers: [\n    provideRouter([\n      { path: &#039;\/home&#039;, component: HomeComponent },\n      { path: &#039;**&#039;, redirectTo: &#039;\/home&#039; },\n    ], withPreloading(PreloadAllModules)),\n    provideHttpClient(withInterceptors([AuthInterceptor]))\n  ]\n});\n<\/code><\/pre>\n\n\n\n<p>Opr\u00f3cz oczywistych zalet w postaci czytelniejszego kodu oraz pozbycia si\u0119 skomplikowanych <code>NgModules<\/code>, zastosowanie funkcyjnego podej\u015bcia sprawi\u0142o, \u017ce wszystkie API s\u0105 teraz w pe\u0142ni tree-shakable. Jak chwali si\u0119 zesp\u00f3\u0142 Angulara, w przypadku API routera odchudza to paczk\u0119 o \u015brednio 11%!<\/p>\n\n\n\n<p>Na zako\u0144czenie warto podkre\u015bli\u0107, \u017ce Standalone Components nie s\u0105 pr\u00f3b\u0105 ca\u0142kowitego usuni\u0119cia Angularowych modu\u0142\u00f3w. Ich koncepcja jest g\u0142\u0119boko zakorzeniona w architekturze Angulara i w wielu przypadkach ich wykorzystanie wci\u0105\u017c b\u0119dzie niezb\u0119dne do osi\u0105gni\u0119cia po\u017c\u0105danego rezultatu. Modu\u0142y pozostaj\u0105 r\u00f3wnie\u017c kluczowym aspektem enkapsulacji wielu zewn\u0119trznych bibliotek.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"500\" height=\"500\" src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/5qdpk3-1.jpeg\" alt=\"\" class=\"wp-image-12273\" srcset=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/5qdpk3-1.jpeg 500w, https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/5qdpk3-1-300x300.jpeg 300w, https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/5qdpk3-1-150x150.jpeg 150w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><\/figure><\/div>\n\n\n<h3 class=\"wp-block-heading\">Functional Router Guards<\/h3>\n\n\n\n<p>W sporym uproszczeniu Routing w Angularze oparty jest o tablic\u0119 obiekt\u00f3w definiuj\u0105cych \u015bcie\u017ck\u0119, komponent do wyrenderowania oraz list\u0119 Guard\u00f3w. Te ostatnie pozwalaj\u0105 zawieraj\u0105 logik\u0119 warunkuj\u0105c\u0105 dost\u0119p do danej \u015bcie\u017cki oraz umo\u017cliwiaj\u0105 wykonanie odpowiedniego przekierowania.<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">@NgModule({\n  imports: [\n    RouterModule.forRoot(\n      [\n        { path: &#039;\/login&#039;, component: LoginComponent },\n        { path: &#039;\/home&#039;, component: HomeComponet, canActivate: [LoggedInGuard] },\n        { path: &#039;**&#039;, redirectTo: &#039;\/home&#039; },\n      ]\n    ),\n  ],\n  exports: [RouterModule],\n})\nexport class AppRoutingModule {}\n\n@Injectable({ providedIn: &#039;root&#039; })\nexport class LoggedInGuard implements CanActivate {\n  constructor(\n    private readonly authService: AuthService,\n    private readonly router: Router\n  ) {}\n\n  async canActivate(route: ActivatedRouteSnapshot): Promise&lt;boolean&gt; {\n    if (!await this.authService.isLoggedIn()) {\n      return true;\n    }\n    return this.router.navigate(\u2018\/home\u2019);\n  }\n}<\/code><\/pre>\n\n\n\n<p>Gdybym dla Angulara 15 mia\u0142 wymy\u015bli\u0107 chwytliwe has\u0142o reklamowe, to by\u0142oby to zdecydowanie \u201cMniej boilerplateu, wi\u0119cej frajdy\u201d. Kolejn\u0105 spor\u0105 nowo\u015bci\u0105 w Angularze 15 jest mo\u017cliwo\u015b\u0107 zast\u0105pienia skomplikowanych klasowych Gurad\u00f3w prost\u0105 funkcj\u0105 zwracaj\u0105c\u0105 warto\u015b\u0107 boolean. Zaryzykuj\u0119 stwierdzenie, \u017ce wykorzystuj\u0105c dodan\u0105 w Angularze 14 funkcj\u0119 <code>inject()<\/code> mo\u017cliwe jest ca\u0142kowite pozbycie si\u0119 z kodu klasowych Guard\u00f3w.<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">provideRouter([\n        { path: &#039;\/login&#039;, component: LoginComponent },\n        { path: &#039;\/home&#039;, component: HomeComponet, canActivate: [isLoggedIn()] },\n        { path: &#039;**&#039;, redirectTo: &#039;\/home&#039; },\n])\n\nfunction isLoggedIn() { \n    if (!await inject(AuthService).isLoggedIn()) {\n      return true;\n    }\n    return inject(Router).navigate(&#039;\/home&#039;);\n}<\/code><\/pre>\n\n\n\n<p>Niew\u0105tpliw\u0105 zalet\u0105 nowej architektury jest te\u017c prostota parametryzacji. Zamiast przekazywa\u0107 i czyta\u0107 dane z ActivatedRouteSnapshot, mo\u017cemy po prostu przekaza\u0107 je jako argumenty funkcji.<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">\/\/ This is how you parametarize Guards with class approach\n@NgModule({\n  imports: [\n    RouterModule.forRoot(\n      [\n        { path: &#039;\/login&#039;, component: LoginComponent },\n        { \n          path: &#039;\/home&#039;,\n          component: HomeComponet, \n          canActivate: [AuthStateGuard],\n          data: { states: [&#039;LOGGED_IN&#039;] } \n        },\n        { path: &#039;**&#039;, redirectTo: &#039;\/home&#039; },\n      ]\n    ),\n  ],\n  exports: [RouterModule],\n})\nexport class AppRoutingModule {}\n\n@Injectable({ providedIn: &#039;root&#039; })\nexport class AuthStateGuard implements CanActivate {\n  constructor(\n    private readonly authService: AuthService,\n    private readonly router: Router\n  ) {}\n\n  async canActivate(route: ActivatedRouteSnapshot): Promise&lt;boolean&gt; {\n    if (route.data.states.includes(&#039;LOGGED_IN&#039;) &amp;&amp; await this.authService.isLoggedIn()) {\n      return true;\n    }\n    return this.router.navigate(&#039;\/login&#039;);\n  }\n}<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">\/\/ This is how you parametarize Guards with functional approach\nprovideRouter([\n        { path: &#039;\/login&#039;, component: LoginComponent },\n        { \n          path: &#039;\/home&#039;, \n          component: HomeComponet, \n          canActivate: [authStatesGuard([&#039;LOGGED_IN&#039;])] \n        } ,\n        { path: &#039;**&#039;, redirectTo: &#039;\/home&#039; },\n])\n\nfunction authStatesGuard(states: string[]) { \n    if (states.includes(&#039;LOGGED_IN&#039;) &amp;&amp; await inject(AuthService).isLoggedIn()) {\n      return true;\n    }\n    return inject(Router).navigate(&#039;\/login&#039;);\n}<\/code><\/pre>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/716bku.gif\" alt=\"\" class=\"wp-image-12275\" width=\"464\" height=\"230\"\/><\/figure><\/div>\n\n\n<p>Na koniec warto wspomnie\u0107 jeszcze, \u017ce analogiczne funkcyjne API dosta\u0142y r\u00f3wnie\u017c interceptor HTTP&nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">provideHttpClient(\n      withInterceptors([\n       (req, next) =&gt; {\n          \/\/ We can use the inject() function inside this function\n          \/\/ For example: inject(AuthService)\n          return next(req);\n        },\n      ])\n)<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Directive Composition API<\/h3>\n\n\n\n<p>W odr\u00f3\u017cnieniu od Reacta czy Vue, kt\u00f3re oparte s\u0105 o funkcje, Angular zbudowany jest g\u0142\u00f3wnie wok\u00f3\u0142 klas. Z tego wzgl\u0119du w frameworku od Google nie mo\u017cna zastosowa\u0107 prostej kompozycji funkcji. Jej miejsce zajmuj\u0105 dyrektywy, czyli klasy pozwalaj\u0105ce rozszerzy\u0107 funkcjonalno\u015b\u0107 komponentu<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">@Directive({\n  selector: &#039;[appHighlight]&#039;\n})\nexport class HighlightDirective {\n    constructor(private el: ElementRef) {\n       this.el.nativeElement.style.backgroundColor = &#039;yellow&#039;;\n    }\n}\n\n@Component({\n  selector: &#039;vived-my-component&#039;,\n  standalone: true.,\n  imports: [ HighlightDirective ]\n  \/\/ \ud83d\udc47 This is how you enrich component behaviour with Directive\n  template: &#039;&lt;CustomComponent appHighlight \/&gt;&#039;;  \n})\nexport class MyComponent {}<\/code><\/pre>\n\n\n\n<p>Jedn\u0105 z najwi\u0119kszych bol\u0105czek dyrektyw do tej pory by\u0142 brak mo\u017cliwo\u015bci przypisania ich bezpo\u015brednio przy definiowaniu komponentu oraz problemy z ich rozszerzaniem.&nbsp; \u017beby lepiej zobrazowa\u0107 problem, wyobra\u017acie sobie, \u017ce implementujecie przycisk, kt\u00f3ry po najechaniu zapala si\u0119 na \u017c\u00f3\u0142to. W waszym kodzie istnieje ju\u017c dyrektywa, kt\u00f3ra umo\u017cliwia zapalenie dowolnego komponentu na \u017c\u00f3\u0142to. Angular nie umo\u017cliwia jednak przypisania dyrektywy do komponentu podczas jego definiowania. W efekcie skazani jeste\u015bcie albo na duplikacj\u0119 kodu, albo manualne dopinanie dyrektywy za ka\u017cdym razem, kiedy korzystacie z stworzonego komponentu.&nbsp;<\/p>\n\n\n\n<p>Angular 15 rozwi\u0105zuje ten problem, poprzez dodanie do dekoratora <code>@Component<\/code> w\u0142a\u015bciwo\u015bci <code>hostDirective<\/code>. Przekazujemy do niej list\u0119 dyrektyw, kt\u00f3re maj\u0105 zosta\u0107 zaaplikowane do naszego komponentu. Komponent bazowy automatycznie dziedziczy wszystkie w\u0142a\u015bciwo\u015bci przypisanych do niego dyrektyw.&nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">@Component({\n  selector: &#039;vived-my-component&#039;,\n  standalone: true,\n  imports: [ HighlightDirective ],\n  \/\/ \ud83d\udc47 This is how you assign directive to the component in Angular 15\n  hostDirectives: [AppHighlight],\n  template: &#039;&lt;button&gt;Hello World&lt;\/button&gt;&#039;;\n})\nexport class CustomComponent {\n  readonly today = new Date();\n}<\/code><\/pre>\n\n\n\n<p>Co interesuj\u0105ce, nowo dodana w\u0142a\u015bciwo\u015b\u0107 umo\u017cliwia r\u00f3wnie\u017c kompozycj\u0119 samych dyrektyw.&nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">@Directive({\n  selector: &#039;[appHighlightAndUnderline]&#039;,\n  hostDirectives: [AppHighlight, AppUnerline]\n})\nexport class HighlightAndUnderline { }<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Optimised Image Directive<\/h3>\n\n\n\n<p>Project Aurora to inicjatywa powo\u0142ana do \u017cycia przez zesp\u00f3\u0142 rozwijaj\u0105cy Google Chrome. Jego g\u0142\u00f3wnym zadaniem jest wsp\u00f3\u0142praca z tw\u00f3rcami popularnych bibliotek i framework\u00f3w, w celu tworzenia jak najlepszych do\u015bwiadcze\u0144 dla u\u017cytkownik\u00f3w internetu. Niespe\u0142na kilka tygodni temu informowali\u015bmy Was o <code>next\/image<\/code>, czyli komponencie do prezentowania obraz\u00f3w tak, aby optymalizowa\u0107 metryki Core Web Vitals. Komponent ten by\u0142 efektem wsp\u00f3\u0142pracy zespo\u0142u Project Aurora i Next.js. Do Angulara 15 trafi\u0142a analogiczna dyrektywa, kt\u00f3ra r\u00f3wnie\u017c jest efektem wsp\u00f3\u0142pracy z Project Aurora.&nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">@Component({\n  standalone: true,\n  \/\/ \ud83d\udc47 Notice how src is replaced with ngSrc\n  template: &#039;&lt;img [ngSrc]=\u201dsrc\u201d [alt]=\u201dalt\u201d\/&gt;&#039;\n  imports: [NgOptimizedImage],\n})\nclass MyStandaloneComponent {\n  @Input() src: string;\n  @Input() alt: string;\n}<\/code><\/pre>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"521\" height=\"496\" src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/download-52.jpeg\" alt=\"\" class=\"wp-image-12277\" srcset=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/download-52.jpeg 521w, https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/download-52-300x286.jpeg 300w\" sizes=\"auto, (max-width: 521px) 100vw, 521px\" \/><\/figure><\/div>\n\n\n<h3 class=\"wp-block-heading\">Usprawniony Stack Trace<\/h3>\n\n\n\n<p>Wyniki corocznej ankiety przeprowadzanej przez zesp\u00f3\u0142 Angulara wyra\u017anie pokaza\u0142y, \u017ce najwi\u0119kszym problemem w debugowaniu s\u0105 skomplikowane komunikaty b\u0142\u0119d\u00f3w. Aby zaadresowa\u0107 ten problem, we wsp\u00f3\u0142pracy z zespo\u0142em Chrome DevTools, stworzony zosta\u0142 mechanizm anotacji, kt\u00f3ry pozwala usun\u0105\u0107 z stack trace linie wskazuj\u0105ce na <code>node_modules<\/code>. Dzi\u0119ki temu \u0142atwiejsze powinno by\u0107 zrozumienie gdzie w aplikacji tak naprawd\u0119 wyst\u0105pi\u0142 b\u0142\u0105d.<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\">\/\/ Error from Angular 14\nERROR Error: Uncaught (in promise): Error\nError\n    at app.component.ts:18:11\n    at Generator.next (&lt;anonymous&gt;)\n    at asyncGeneratorStep (asyncToGenerator.js:3:1)\n    at _next (asyncToGenerator.js:25:1)\n    at _ZoneDelegate.invoke (zone.js:372:26)\n    at Object.onInvoke (core.mjs:26378:33)\n    at _ZoneDelegate.invoke (zone.js:371:52)\n    at Zone.run (zone.js:134:43)\n    at zone.js:1275:36\n    at _ZoneDelegate.invokeTask (zone.js:406:31)\n    at resolvePromise (zone.js:1211:31)\n    at zone.js:1118:17\n    at zone.js:1134:33<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\">\/\/ The same Error from Angular 15\nERROR Error: Uncaught (in promise): Error\nError\n    at app.component.ts:18:11\n    at fetch (async)  \n    at (anonymous) (app.component.ts:4)\n    at request (app.component.ts:4)\n    at (anonymous) (app.component.ts:17)\n    at submit (app.component.ts:15)\n    at AppComponent_click_3_listener (app.component.html:4)<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">\u0179r\u00f3d\u0142a:<\/h3>\n\n\n\n<p><a href=\"https:\/\/blog.angular.io\/angular-v15-is-now-available-df7be7f2f4c8\">https:\/\/blog.angular.io\/angular-v15-is-now-available-df7be7f2f4c8<\/a><\/p>\n\n\n\n<h2 id=\"2-typescript-4-9\" data-num=2>2. TypeScript 4.9<\/h2>\n\n\n\n<p>Ostatnie kilka wersji TypeScript to g\u0142\u00f3wnie nudne optymalizacje i obs\u0142uga kolejnych przypadk\u00f3w brzegowych. Wydany w tym tygodniu TypeScript 4.9 jest zupe\u0142nie inny, bo wprowadza a\u017c dwa nowe s\u0142owa kluczowe. Bez zb\u0119dnego przed\u0142u\u017cania przyjrzyjmy si\u0119 co nowego trafi\u0142o do j\u0119zyka od Microsoftu i dlaczego jest to jego najciekawsza wersja od dawna.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"360\" height=\"268\" src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/6v9rzo.gif\" alt=\"\" class=\"wp-image-12279\"\/><\/figure><\/div>\n\n\n<h3 class=\"wp-block-heading\">Satisfies operator<\/h3>\n\n\n\n<p>T\u0142umacz\u0105c dzia\u0142anie nowego operatora pos\u0142u\u017c\u0119 si\u0119 przyk\u0142adem z notatki od Microsoftu. Za\u0142\u00f3\u017cmy, \u017ce potrzebujemy otypowa\u0107 nast\u0119puj\u0105cy kod:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">\/\/ Each property can be a string or an RGB tuple.\nconst palette = {\n    red: [255, 0, 0],\n    green: &quot;#00ff00&quot;,\n    blue: [0, 0, 255]\n};\n\n\/\/ We want to be able to use array methods on &#039;red&#039;...\nconst redComponent = palette.red.at(0);\n\n\/\/ or string methods on &#039;green&#039;...\nconst greenNormalized = palette.green.toUpperCase();<\/code><\/pre>\n\n\n\n<p>W pierwszej chwili do g\u0142owy przyj\u015b\u0107 mo\u017ce zdefiniowanie typu Color oraz wykorzystanie typu Record. Niestety, w takim przypadku zmuszeni jeste\u015bmy wykonywa\u0107 niebezpieczn\u0105 operacj\u0119 rzutowania:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">type Color = &quot;red&quot; | &quot;green&quot; | &quot;blue&quot;;\ntype RGB = [red: number, green: number, blue: number];\n\ntype Palette = Record&lt;Color, string | RGB&gt;\n\nconst palette: Palette = {\n    red: [255, 0, 0],\n    green: &quot;#00ff00&quot;,\n    blue: [0, 0, 255]\n};\n\n\/\/ We want to be able to use array methods on &#039;red&#039;...\nconst redComponent = (palette.red as RGB).at(0);\n\n\/\/ or string methods on &#039;green&#039;...\nconst greenNormalized = (palette.green as string).toUpperCase();<\/code><\/pre>\n\n\n\n<p>Aby usun\u0105\u0107 rzutowanie, mo\u017cemy w definicji typu zawrze\u0107 spos\u00f3b w jaki b\u0119dzie on definiowany. W naszym przypadku nie jest to mo\u017ce najgorszy pomys\u0142, ale zobaczcie sami, ile dodatkowego kodu musimy wygenerowa\u0107, nie m\u00f3wi\u0105c ju\u017c o du\u017co mniejszej elastyczno\u015bci.<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">type StringColor =  &quot;green&quot;;\ntype RGBColor = &quot;red&quot; | &quot;blue&quot;;\ntype RGB = [red: number, green: number, blue: number];\n\ntype StringColorPalette = Record&lt;StringColor, string&gt;;\ntype RGBColorPalette = Record&lt;RGBColor, RGB&gt;;\ntype Palette = StringColorPalette &amp; RGBColorPalette;\n\nconst palette: Palette = {\n    red: [255, 0, 0],\n    green: &quot;#00ff00&quot;,\n    blue: [0, 0, 255]\n};\n\nconst redComponent = palette.red.at(0);\nconst greenNormalized = palette.green.toUpperCase();<\/code><\/pre>\n\n\n\n<p>Obej\u015bciem tego problemu ma by\u0107 nowy operator satisfies, kt\u00f3ry b\u0119dzie walidowa\u0142 typ w momencie przypisania, ale nie b\u0119dzie mia\u0142 wp\u0142ywu na typ ewaluowany przez TypeScript. Brzmi skomplikowanie, ale na prostym przyk\u0142adzie dobrze wida\u0107, o co chodzi:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">\ntype Color = &quot;red&quot; | &quot;green&quot; | &quot;blue&quot;;\ntype RGB = [red: number, green: number, blue: number];\n\ntype Palette = Record&lt;Color, string | RGB&gt;\n\nconst palette = {\n    red: [255, 0, 0],\n    green: &quot;#00ff00&quot;,\n    blue: [0, 0, 255]\n} satisfies Palette;\n\n\/\/ Both of these methods are still accessible!\nconst redComponent = palette.red.at(0);\nconst greenNormalized = palette.green.toUpperCase();\n\n\/\/ \u2014-----------------------------------\n\/\/ Example errors caught by satisfies\n\/\/  \u2014-----------------------------------\n\nconst spelloPalette = {\n    red: [255, 0, 0],\n    green: &quot;#00ff00&quot;,\n    bleu: [0, 0, 255] \/\/ Such typos are now caught\n} satisfies Palette;\n\n\/\/ Missing properties are now caught\nconst missingColorPalette = {\n    red: [255, 0, 0],\n    bleu: [0, 0, 255]\n} satisfies Palette;\n\nconst wrongColorTypePalette = {\n    red: [255, 0], \/\/ Such typos are now also caught\n    green: &quot;#00ff00&quot;,\n    bleu: [0, 0, 255]\n} satisfies Palette;<\/code><\/pre>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"541\" height=\"499\" src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/7169wt.jpeg\" alt=\"\" class=\"wp-image-12281\" srcset=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/7169wt.jpeg 541w, https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/7169wt-300x277.jpeg 300w\" sizes=\"auto, (max-width: 541px) 100vw, 541px\" \/><\/figure><\/div>\n\n\n<h3 class=\"wp-block-heading\">Auto-Accessors<\/h3>\n\n\n\n<p>TypeScript 4.9 wprowadza jeszcze jedno nowe s\u0142owo kluczowe `accessor`. Za jego pomoc\u0105 mo\u017cliwe b\u0119dzie zdefiniowanie pola w klasie, kt\u00f3re pod spodem b\u0119dzie prywatn\u0105 zmienn\u0105 zapakowan\u0105 w getter i setter. Po co to wszystko? Jak si\u0119 okazuje, jest to przygotowanie na dekoratory, kt\u00f3re obecnie znajduj\u0105 si\u0119 w 3 fazie procesu TC39.<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">class Person {\n  accessor name: string;\n\n  constructor(name: string) {\n    this.name = name;\n  }\n}\n\nclass Person {\n  #__name: string;\n\n  get name() {\n    return this.#__name;\n  }\n  set name(value: string) {\n    this.#__name = name;\n  }\n\n  constructor(name: string) {\n    this.name = name;\n  }\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Usprawnione por\u00f3wnania z NaN<\/h3>\n\n\n\n<p>Co do tego, \u017ce JavaScript to szalony j\u0119zyk, chyba wszyscy si\u0119 zgodzimy. W ko\u0144cu w jakim innym j\u0119zyku mog\u0142oby wydarzy\u0107 si\u0119 co\u015b takiego:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"575\" height=\"436\" src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/716a9u.jpeg\" alt=\"\" class=\"wp-image-12283\" srcset=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/716a9u.jpeg 575w, https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/716a9u-300x227.jpeg 300w\" sizes=\"auto, (max-width: 575px) 100vw, 575px\" \/><\/figure><\/div>\n\n\n<p>Dzisiaj nie b\u0119dziemy jednak rozmawia\u0107 o tym, a o por\u00f3wnaniach z <code>NaN<\/code> (Not a Number). W wi\u0119kszo\u015bci j\u0119zyk\u00f3w obs\u0142uguj\u0105cych zmienne zmiennoprzecinkowe, zak\u0142ada si\u0119, \u017ce nic nie mo\u017ce by\u0107 r\u00f3wne <code>NaN<\/code> &#8211; nawet inna instancja <code>NaN<\/code><\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">NaN == 0    \/\/ false\nNaN == Nan  \/\/ false\nNaN === Nan \/\/ false<\/code><\/pre>\n\n\n\n<p>Dosy\u0107 cz\u0119stym b\u0142\u0119dem, kt\u00f3ry \u0142atwo przeoczy\u0107 jest wi\u0119c bezpo\u015brednie por\u00f3wnywanie z `NaN`. TypeScript 4.9 b\u0119dzie nas skrupulatnie przed tym chroni\u0142 zwracaj\u0105c odpowiedni b\u0142\u0105d.<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">function validate(someValue: number) {\n  return someValue !== NaN;\n  \/\/     ~~~~~~~~~~~~~~~~~\n  \/\/ error: This condition will always return &#039;true&#039;.\n  \/\/        Did you mean &#039;!Number.isNaN(someValue)&#039;?\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Co przyniesie TypeScript 5.0?<\/h3>\n\n\n\n<p>Kolejna wersja TypeScript nad kt\u00f3r\u0105 rozpocz\u0119to ju\u017c prace b\u0119dzie oznaczona numerkiem 5.0. Nale\u017cy jednak pami\u0119ta\u0107, \u017ce TypeScript nie stosuje konwencji Semantic Versioning i nie koniecznie oznacza to, \u017ce wersja ta zawiera\u0107 b\u0119dzie breaking changes. Przegl\u0105daj\u0105c repozytorium projektu mo\u017cemy ju\u017c zobaczy\u0107 co szykuj\u0105 dla nas ludzie z Microsoft. W skr\u00f3cie, kompilator przepisany zosta\u0142 z archaicznych namespaces na modu\u0142y. Dzi\u0119ki temu kompilator uruchamia si\u0119 mi\u0119dzy 10-25% szybciej, a paczka zosta\u0142a odchudzona o prawie 50%.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u0179r\u00f3d\u0142a:<\/h3>\n\n\n\n<p><a href=\"https:\/\/devblogs.microsoft.com\/typescript\/announcing-typescript-4-9\/\">https:\/\/devblogs.microsoft.com\/typescript\/announcing-typescript-4-9\/<\/a><\/p>\n\n\n\n<h2 id=\"3-deno-1-28-z-wsparciem-dla-npm\" data-num=3>3. Deno 1.28 z wsparciem dla npm<\/h2>\n\n\n\n<p>Piek\u0142o oficjalnie zamarz\u0142o! Deno, czyli projekt, kt\u00f3ry mia\u0142 naprawi\u0107 wszystkie b\u0142\u0119dy Node.js, dosta\u0142 wsparcie dla npm. Po latach pr\u00f3b odci\u0119cia si\u0119 od najpopularniejszego repozytorium JavaScript tw\u00f3rcy zaakceptowali, \u017ce pomimo jego wielu wad, bez npm ci\u0119\u017cko \u017cy\u0107.&nbsp;<\/p>\n\n\n\n<p>Nie dajcie si\u0119 jednak zmyli\u0107 &#8211; npm w po\u0142\u0105czeniu z Deno b\u0119dzie dzia\u0142a\u0142 zupe\u0142nie inaczej ni\u017c w po\u0142\u0105czeniu z Node.js. Po pierwsze, Deno nie b\u0119dzie wymaga\u0107 uruchamiania `npm install`, ani \u017cadnej innej komendy npm. Po drugie, Deno nie b\u0119dzie tworzy\u0107 katalogu node_modules,a pobrane paczki przechowywane b\u0119d\u0105 globalnie. Po trzecie, importy z npm b\u0119d\u0105 oznaczone specjalnym prefixem `npm:`<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">import { chalk } from &quot;npm:chalk@5&quot;;<\/code><\/pre>\n\n\n\n<p>Dlaczego decyzja o dodaniu wsparcia dla npm zapad\u0142a w\u0142a\u015bnie teraz? Moim zdaniem, przede wszystkim dlatego, \u017ce jest to s\u0142uszna decyzja. Je\u015bli jednak lubicie filmy z \u017c\u00f3\u0142tymi napisami, to istnieje jeszcze jedna teoria.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"501\" height=\"500\" src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/download-49.jpeg\" alt=\"\" class=\"wp-image-12285\" srcset=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/download-49.jpeg 501w, https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/download-49-300x300.jpeg 300w, https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/download-49-150x150.jpeg 150w\" sizes=\"auto, (max-width: 501px) 100vw, 501px\" \/><\/figure><\/div>\n\n\n<p>Wok\u00f3\u0142 Deno zbudowany zosta\u0142a ca\u0142kiem poka\u017ana firma. Do tej pory zgromadzi\u0142a ona od szeregu inwestor\u00f3w ponad 25M$. Na samym rozwoju silnika uruchomieniowego JavaScript ci\u0119\u017cko zarabia\u0107, dlatego firma skupi\u0142a si\u0119 na rozbudowie infrastruktury chmurowej. Efektem ponad roku prac jest chmura Deno Deploy. Znalaz\u0142a ona ju\u017c pierwszych komercyjnych klient\u00f3w w postaci Supabase (otwarto\u017ar\u00f3d\u0142owa alternatywa dla Firebase) czy Netlify, kt\u00f3rzy swoje Edge Functions postanowili oprze\u0107 w\u0142a\u015bnie o Deno Deploy. Wraz z zewn\u0119trznymi inwestorami i klientami przychodz\u0105 oczekiwania wzrostu. Deno wok\u00f3\u0142 idei lepszego Node.js zbudowa\u0142 naprawd\u0119 du\u017co. Wydaje si\u0119 jednak, \u017ce bez sensownej integracji z npm dalszy rozw\u00f3j nie by\u0142 mo\u017cliwy.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"500\" height=\"590\" src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/frontend101-image10.jpeg\" alt=\"\" class=\"wp-image-12287\" srcset=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/frontend101-image10.jpeg 500w, https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/frontend101-image10-254x300.jpeg 254w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><\/figure><\/div>\n\n\n<p>Je\u015bli naprawd\u0119 lubicie filmy z \u017c\u00f3\u0142tym napisami, to istnieje jeszcze jedna teoria. Pod koniec wakacji na rynku pojawi\u0142 si\u0119 nowy gracz w postaci Bun.js. Jest to alternatywa typu drop-in dla Node.js, napisana w szybkim j\u0119zyku Zig i oparta o silnik JavaScriptCore. O ile Deno sw\u00f3j marketing skupia na rozwi\u0105zywaniu problem\u00f3w Node.js, to Bun stawia nacisk na wydajno\u015b\u0107.&nbsp;<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"439\" height=\"462\" src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/Screenshot-2022-08-04-at-15.06.18-1.png\" alt=\"\" class=\"wp-image-12289\" srcset=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/Screenshot-2022-08-04-at-15.06.18-1.png 439w, https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/Screenshot-2022-08-04-at-15.06.18-1-285x300.png 285w\" sizes=\"auto, (max-width: 439px) 100vw, 439px\" \/><\/figure><\/div>\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"904\" height=\"500\" src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/frontend101-image8.jpeg\" alt=\"\" class=\"wp-image-12291\" srcset=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/frontend101-image8.jpeg 904w, https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/frontend101-image8-300x166.jpeg 300w, https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/frontend101-image8-768x425.jpeg 768w\" sizes=\"auto, (max-width: 904px) 100vw, 904px\" \/><\/figure>\n\n\n\n<p>Pocz\u0105tkowo Bun wydawa\u0142 si\u0119 chwilow\u0105 ciekawostk\u0105. W ci\u0105gu kilkutygodni przerodzi\u0142 si\u0119 jednak w pe\u0142noprawny startup, kt\u00f3ry zgromadzi\u0142 7M$. Oven (bo tak zdecydowa\u0142a si\u0119 nazwa\u0107 firm\u0119) przyj\u0105\u0142 strategi\u0119 bli\u017aniaczo podobn\u0105 do Deno Company. Firma zamierza przygotowa\u0107 architektur\u0119 chmurow\u0105 opart\u0105 o Bun, kt\u00f3r\u0105 sprzedawa\u0107 b\u0119d\u0105 klientom.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"557\" height=\"500\" src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/frontend102-3.jpeg\" alt=\"\" class=\"wp-image-12293\" srcset=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/frontend102-3.jpeg 557w, https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/frontend102-3-300x269.jpeg 300w\" sizes=\"auto, (max-width: 557px) 100vw, 557px\" \/><\/figure><\/div>\n\n\n<p>Informacja o pracach nad dodaniem wsparcie dla npm w Deno zupe\u0142nie przypadkiem zbieg\u0142a si\u0119 w czasie z powstaniem firmy Oven, a fakt, \u017ce Bun.js wspiera npm na pewno nie mia\u0142 wp\u0142ywu na podj\u0119te decyzje<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u0179r\u00f3d\u0142a<\/h3>\n\n\n\n<p><a href=\"https:\/\/deno.com\/blog\/v1.28\">https:\/\/deno.com\/blog\/v1.28<\/a><\/p>\n\n\n\n<h2 id=\"bonus-opera-pierwsza-przegladarka-z-wbudowanym-tiktokiem\" data-num=4>Bonus: Opera pierwsz\u0105 przegl\u0105dark\u0105 z wbudowanym TikTok\u2019iem<\/h2>\n\n\n\n<p>Nie przes\u0142yszeli\u015bcie si\u0119 &#8211; Opera jest pierwsz\u0105 przegl\u0105dark\u0105, kt\u00f3ra zintegrowa\u0142a si\u0119 z TikTok\u2019iem. Sta\u0142 si\u0119 on cz\u0119\u015bci\u0105 paska integracji, w\u015br\u00f3d kt\u00f3rych znajdziemy na przyk\u0142ad Twittera cze Messengera. Jak twierdz\u0105 tw\u00f3rcy przegl\u0105darki &#8211; ludzie, kt\u00f3rzy zacz\u0119li korzysta\u0107 z natywnych integracji wbudowanych w przegl\u0105dark\u0119, nie wracaj\u0105 ju\u017c do ich webowych odpowiednik\u00f3w. To jak, instalujemy teraz Oper\u0119, \u017ceby bez skrupu\u0142\u00f3w ogl\u0105da\u0107 TikTok\u2019a w pracy?<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<div class=\"embed-responsive embed-responsive-16by9\"><iframe loading=\"lazy\" title=\"Opera becomes the first browser to add built-in TikTok into its browser sidebar\" width=\"500\" height=\"281\" src=\"https:\/\/www.youtube.com\/embed\/EeNsXkqP6TM?start=9&#038;feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe><\/div>\n<\/div><\/figure>\n","protected":false},"excerpt":{"rendered":"<p>Standalone Components to jedna z funckjonalno\u015bci na kt\u00f3r\u0105 spo\u0142eczno\u015b\u0107 Angulara czeka\u0142a od dawna. Angular 15 to jednak nie tylko Standalone Components, a ca\u0142a paczka z dawna wyczekiwanych funkcjonalno\u015bci.<\/p>\n","protected":false},"author":12,"featured_media":12302,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[273,1],"tags":[479,387,364],"class_list":["post-12266","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-frontend-pl","category-no-category","tag-angular-pl","tag-deno-pl","tag-typescript-pl"],"acf":{"feature_image_visible":false,"weekly_summary":true,"push_notification_image":"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/1-1.png","feature_image_blog":{"ID":12306,"id":12306,"title":"pexels-photo-214574","filename":"pexels-photo-214574.jpeg","filesize":285590,"url":"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/pexels-photo-214574.jpeg","link":"https:\/\/vived.io\/pl\/angular-15-ta-sama-logika-dwa-razy-mniej-kodu-frontend-weekly-vol-113\/pexels-photo-214574\/","alt":"","author":"12","description":"","caption":"","name":"pexels-photo-214574","status":"inherit","uploaded_to":12266,"date":"2022-11-18 08:41:34","modified":"2022-11-18 08:41:34","menu_order":0,"mime_type":"image\/jpeg","type":"image","subtype":"jpeg","icon":"https:\/\/vived.io\/wp-includes\/images\/media\/default.png","width":2250,"height":1500,"sizes":{"thumbnail":"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/pexels-photo-214574-150x150.jpeg","thumbnail-width":150,"thumbnail-height":150,"medium":"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/pexels-photo-214574-300x200.jpeg","medium-width":300,"medium-height":200,"medium_large":"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/pexels-photo-214574-768x512.jpeg","medium_large-width":768,"medium_large-height":512,"large":"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/pexels-photo-214574-1024x683.jpeg","large-width":1024,"large-height":683,"1536x1536":"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/pexels-photo-214574-1536x1024.jpeg","1536x1536-width":1536,"1536x1536-height":1024,"2048x2048":"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/pexels-photo-214574-2048x1365.jpeg","2048x2048-width":2048,"2048x2048-height":1365,"gform-image-choice-sm":"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/pexels-photo-214574.jpeg","gform-image-choice-sm-width":300,"gform-image-choice-sm-height":200,"gform-image-choice-md":"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/pexels-photo-214574.jpeg","gform-image-choice-md-width":400,"gform-image-choice-md-height":267,"gform-image-choice-lg":"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/pexels-photo-214574.jpeg","gform-image-choice-lg-width":600,"gform-image-choice-lg-height":400}},"estimated_reading_time":"14"},"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.0 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Angular 15 - ta sama logika, dwa razy mniej kodu | Frontend Weekly vol. 113 - Vived<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/vived.io\/pl\/angular-15-ta-sama-logika-dwa-razy-mniej-kodu-frontend-weekly-vol-113\/\" \/>\n<meta property=\"og:locale\" content=\"pl_PL\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Angular 15 - ta sama logika, dwa razy mniej kodu | Frontend Weekly vol. 113 - Vived\" \/>\n<meta property=\"og:description\" content=\"Standalone Components to jedna z funckjonalno\u015bci na kt\u00f3r\u0105 spo\u0142eczno\u015b\u0107 Angulara czeka\u0142a od dawna. Angular 15 to jednak nie tylko Standalone Components, a ca\u0142a paczka z dawna wyczekiwanych funkcjonalno\u015bci.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/vived.io\/pl\/angular-15-ta-sama-logika-dwa-razy-mniej-kodu-frontend-weekly-vol-113\/\" \/>\n<meta property=\"og:site_name\" content=\"Vived\" \/>\n<meta property=\"article:published_time\" content=\"2022-11-18T09:35:12+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2022-11-18T09:35:15+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/1.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"628\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Tomasz Borowicz\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/vived.io\/pl\/angular-15-ta-sama-logika-dwa-razy-mniej-kodu-frontend-weekly-vol-113\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/vived.io\/pl\/angular-15-ta-sama-logika-dwa-razy-mniej-kodu-frontend-weekly-vol-113\/\"},\"author\":{\"name\":\"Tomasz Borowicz\",\"@id\":\"https:\/\/vived.io\/pl\/#\/schema\/person\/9d2a72fe7d0dfbb4092675afbab742bb\"},\"headline\":\"Angular 15 &#8211; ta sama logika, dwa razy mniej kodu | Frontend Weekly vol. 113\",\"datePublished\":\"2022-11-18T09:35:12+00:00\",\"dateModified\":\"2022-11-18T09:35:15+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/vived.io\/pl\/angular-15-ta-sama-logika-dwa-razy-mniej-kodu-frontend-weekly-vol-113\/\"},\"wordCount\":2059,\"publisher\":{\"@id\":\"https:\/\/vived.io\/pl\/#organization\"},\"image\":{\"@id\":\"https:\/\/vived.io\/pl\/angular-15-ta-sama-logika-dwa-razy-mniej-kodu-frontend-weekly-vol-113\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/1.png\",\"keywords\":[\"Angular\",\"deno\",\"typescript\"],\"articleSection\":[\"Frontend\",\"No category\"],\"inLanguage\":\"pl-PL\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/vived.io\/pl\/angular-15-ta-sama-logika-dwa-razy-mniej-kodu-frontend-weekly-vol-113\/\",\"url\":\"https:\/\/vived.io\/pl\/angular-15-ta-sama-logika-dwa-razy-mniej-kodu-frontend-weekly-vol-113\/\",\"name\":\"Angular 15 - ta sama logika, dwa razy mniej kodu | Frontend Weekly vol. 113 - Vived\",\"isPartOf\":{\"@id\":\"https:\/\/vived.io\/pl\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/vived.io\/pl\/angular-15-ta-sama-logika-dwa-razy-mniej-kodu-frontend-weekly-vol-113\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/vived.io\/pl\/angular-15-ta-sama-logika-dwa-razy-mniej-kodu-frontend-weekly-vol-113\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/1.png\",\"datePublished\":\"2022-11-18T09:35:12+00:00\",\"dateModified\":\"2022-11-18T09:35:15+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/vived.io\/pl\/angular-15-ta-sama-logika-dwa-razy-mniej-kodu-frontend-weekly-vol-113\/#breadcrumb\"},\"inLanguage\":\"pl-PL\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/vived.io\/pl\/angular-15-ta-sama-logika-dwa-razy-mniej-kodu-frontend-weekly-vol-113\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"pl-PL\",\"@id\":\"https:\/\/vived.io\/pl\/angular-15-ta-sama-logika-dwa-razy-mniej-kodu-frontend-weekly-vol-113\/#primaryimage\",\"url\":\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/1.png\",\"contentUrl\":\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/1.png\",\"width\":1200,\"height\":628},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/vived.io\/pl\/angular-15-ta-sama-logika-dwa-razy-mniej-kodu-frontend-weekly-vol-113\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Strona g\u0142\u00f3wna\",\"item\":\"https:\/\/vived.io\/pl\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Angular 15 &#8211; ta sama logika, dwa razy mniej kodu | Frontend Weekly vol. 113\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/vived.io\/pl\/#website\",\"url\":\"https:\/\/vived.io\/pl\/\",\"name\":\"Vived\",\"description\":\"platform empowering IT people and technology companies to synergic growth\",\"publisher\":{\"@id\":\"https:\/\/vived.io\/pl\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/vived.io\/pl\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"pl-PL\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/vived.io\/pl\/#organization\",\"name\":\"Vived\",\"url\":\"https:\/\/vived.io\/pl\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pl-PL\",\"@id\":\"https:\/\/vived.io\/pl\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/vived.io\/wp-content\/uploads\/2020\/03\/logo_vived_color.png\",\"contentUrl\":\"https:\/\/vived.io\/wp-content\/uploads\/2020\/03\/logo_vived_color.png\",\"width\":136,\"height\":45,\"caption\":\"Vived\"},\"image\":{\"@id\":\"https:\/\/vived.io\/pl\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/vived.io\/pl\/#\/schema\/person\/9d2a72fe7d0dfbb4092675afbab742bb\",\"name\":\"Tomasz Borowicz\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pl-PL\",\"@id\":\"https:\/\/vived.io\/pl\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/804536d2672538508d43f60ad2108e5aaea76c192653eaf95d4c3934b7d1dbb6?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/804536d2672538508d43f60ad2108e5aaea76c192653eaf95d4c3934b7d1dbb6?s=96&d=mm&r=g\",\"caption\":\"Tomasz Borowicz\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Angular 15 - ta sama logika, dwa razy mniej kodu | Frontend Weekly vol. 113 - Vived","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/vived.io\/pl\/angular-15-ta-sama-logika-dwa-razy-mniej-kodu-frontend-weekly-vol-113\/","og_locale":"pl_PL","og_type":"article","og_title":"Angular 15 - ta sama logika, dwa razy mniej kodu | Frontend Weekly vol. 113 - Vived","og_description":"Standalone Components to jedna z funckjonalno\u015bci na kt\u00f3r\u0105 spo\u0142eczno\u015b\u0107 Angulara czeka\u0142a od dawna. Angular 15 to jednak nie tylko Standalone Components, a ca\u0142a paczka z dawna wyczekiwanych funkcjonalno\u015bci.","og_url":"https:\/\/vived.io\/pl\/angular-15-ta-sama-logika-dwa-razy-mniej-kodu-frontend-weekly-vol-113\/","og_site_name":"Vived","article_published_time":"2022-11-18T09:35:12+00:00","article_modified_time":"2022-11-18T09:35:15+00:00","og_image":[{"width":1200,"height":628,"url":"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/1.png","type":"image\/png"}],"author":"Tomasz Borowicz","twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/vived.io\/pl\/angular-15-ta-sama-logika-dwa-razy-mniej-kodu-frontend-weekly-vol-113\/#article","isPartOf":{"@id":"https:\/\/vived.io\/pl\/angular-15-ta-sama-logika-dwa-razy-mniej-kodu-frontend-weekly-vol-113\/"},"author":{"name":"Tomasz Borowicz","@id":"https:\/\/vived.io\/pl\/#\/schema\/person\/9d2a72fe7d0dfbb4092675afbab742bb"},"headline":"Angular 15 &#8211; ta sama logika, dwa razy mniej kodu | Frontend Weekly vol. 113","datePublished":"2022-11-18T09:35:12+00:00","dateModified":"2022-11-18T09:35:15+00:00","mainEntityOfPage":{"@id":"https:\/\/vived.io\/pl\/angular-15-ta-sama-logika-dwa-razy-mniej-kodu-frontend-weekly-vol-113\/"},"wordCount":2059,"publisher":{"@id":"https:\/\/vived.io\/pl\/#organization"},"image":{"@id":"https:\/\/vived.io\/pl\/angular-15-ta-sama-logika-dwa-razy-mniej-kodu-frontend-weekly-vol-113\/#primaryimage"},"thumbnailUrl":"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/1.png","keywords":["Angular","deno","typescript"],"articleSection":["Frontend","No category"],"inLanguage":"pl-PL"},{"@type":"WebPage","@id":"https:\/\/vived.io\/pl\/angular-15-ta-sama-logika-dwa-razy-mniej-kodu-frontend-weekly-vol-113\/","url":"https:\/\/vived.io\/pl\/angular-15-ta-sama-logika-dwa-razy-mniej-kodu-frontend-weekly-vol-113\/","name":"Angular 15 - ta sama logika, dwa razy mniej kodu | Frontend Weekly vol. 113 - Vived","isPartOf":{"@id":"https:\/\/vived.io\/pl\/#website"},"primaryImageOfPage":{"@id":"https:\/\/vived.io\/pl\/angular-15-ta-sama-logika-dwa-razy-mniej-kodu-frontend-weekly-vol-113\/#primaryimage"},"image":{"@id":"https:\/\/vived.io\/pl\/angular-15-ta-sama-logika-dwa-razy-mniej-kodu-frontend-weekly-vol-113\/#primaryimage"},"thumbnailUrl":"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/1.png","datePublished":"2022-11-18T09:35:12+00:00","dateModified":"2022-11-18T09:35:15+00:00","breadcrumb":{"@id":"https:\/\/vived.io\/pl\/angular-15-ta-sama-logika-dwa-razy-mniej-kodu-frontend-weekly-vol-113\/#breadcrumb"},"inLanguage":"pl-PL","potentialAction":[{"@type":"ReadAction","target":["https:\/\/vived.io\/pl\/angular-15-ta-sama-logika-dwa-razy-mniej-kodu-frontend-weekly-vol-113\/"]}]},{"@type":"ImageObject","inLanguage":"pl-PL","@id":"https:\/\/vived.io\/pl\/angular-15-ta-sama-logika-dwa-razy-mniej-kodu-frontend-weekly-vol-113\/#primaryimage","url":"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/1.png","contentUrl":"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/1.png","width":1200,"height":628},{"@type":"BreadcrumbList","@id":"https:\/\/vived.io\/pl\/angular-15-ta-sama-logika-dwa-razy-mniej-kodu-frontend-weekly-vol-113\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Strona g\u0142\u00f3wna","item":"https:\/\/vived.io\/pl\/"},{"@type":"ListItem","position":2,"name":"Angular 15 &#8211; ta sama logika, dwa razy mniej kodu | Frontend Weekly vol. 113"}]},{"@type":"WebSite","@id":"https:\/\/vived.io\/pl\/#website","url":"https:\/\/vived.io\/pl\/","name":"Vived","description":"platform empowering IT people and technology companies to synergic growth","publisher":{"@id":"https:\/\/vived.io\/pl\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/vived.io\/pl\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"pl-PL"},{"@type":"Organization","@id":"https:\/\/vived.io\/pl\/#organization","name":"Vived","url":"https:\/\/vived.io\/pl\/","logo":{"@type":"ImageObject","inLanguage":"pl-PL","@id":"https:\/\/vived.io\/pl\/#\/schema\/logo\/image\/","url":"https:\/\/vived.io\/wp-content\/uploads\/2020\/03\/logo_vived_color.png","contentUrl":"https:\/\/vived.io\/wp-content\/uploads\/2020\/03\/logo_vived_color.png","width":136,"height":45,"caption":"Vived"},"image":{"@id":"https:\/\/vived.io\/pl\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/vived.io\/pl\/#\/schema\/person\/9d2a72fe7d0dfbb4092675afbab742bb","name":"Tomasz Borowicz","image":{"@type":"ImageObject","inLanguage":"pl-PL","@id":"https:\/\/vived.io\/pl\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/804536d2672538508d43f60ad2108e5aaea76c192653eaf95d4c3934b7d1dbb6?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/804536d2672538508d43f60ad2108e5aaea76c192653eaf95d4c3934b7d1dbb6?s=96&d=mm&r=g","caption":"Tomasz Borowicz"}}]}},"blocks_vived":[{"blockName":"core\/heading","attrs":[],"innerBlocks":[],"innerHTML":"\n<h2>1. Angular v15&nbsp;<\/h2>\n","innerContent":["\n<h2>1. Angular v15&nbsp;<\/h2>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Kolejne wersje Angulara publikowane s\u0105 co 6 miesi\u0119cy z dok\u0142adno\u015bci\u0105 szwajcarskiego zegarka. Dzisiaj \u015bwiat\u0142o dzienne ujrza\u0142 Angular 15. Czy wywraca on do g\u00f3ry nogami status quo jak Svelte albo chocia\u017c prezentuje nowe innowacyjne koncepcje jak React Server Components? Niestety nie. Jest to jednak wydanie pe\u0142ne ma\u0142ych inkrementalnych zmian, adresuj\u0105cych realne bol\u0105czki deweloper\u00f3w. Je\u015bli mam by\u0107 szczery to dla mnie jest to najbardziej interesuj\u0105ce wydanie Angulara od co najmniej dw\u00f3ch lat.<\/p>\n","innerContent":["\n<p>Kolejne wersje Angulara publikowane s\u0105 co 6 miesi\u0119cy z dok\u0142adno\u015bci\u0105 szwajcarskiego zegarka. Dzisiaj \u015bwiat\u0142o dzienne ujrza\u0142 Angular 15. Czy wywraca on do g\u00f3ry nogami status quo jak Svelte albo chocia\u017c prezentuje nowe innowacyjne koncepcje jak React Server Components? Niestety nie. Jest to jednak wydanie pe\u0142ne ma\u0142ych inkrementalnych zmian, adresuj\u0105cych realne bol\u0105czki deweloper\u00f3w. Je\u015bli mam by\u0107 szczery to dla mnie jest to najbardziej interesuj\u0105ce wydanie Angulara od co najmniej dw\u00f3ch lat.<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/image","attrs":{"align":"center","id":12267,"sizeSlug":"full","linkDestination":"none"},"innerBlocks":[],"innerHTML":"\n<figure class=\"wp-block-image aligncenter size-full\"><img src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/download-48.jpeg\" alt=\"\" class=\"wp-image-12267\"\/><\/figure>\n","innerContent":["\n<figure class=\"wp-block-image aligncenter size-full\"><img src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/download-48.jpeg\" alt=\"\" class=\"wp-image-12267\"\/><\/figure>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/heading","attrs":{"level":3},"innerBlocks":[],"innerHTML":"\n<h3>Angular Standalone Components<span style=\"font-size: revert; color: initial; font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, Oxygen-Sans, Ubuntu, Cantarell, &quot;Helvetica Neue&quot;, sans-serif;\">\/<\/span><\/h3>\n","innerContent":["\n<h3>Angular Standalone Components<span style=\"font-size: revert; color: initial; font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, Oxygen-Sans, Ubuntu, Cantarell, &quot;Helvetica Neue&quot;, sans-serif;\">\/<\/span><\/h3>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Zanim przejdziemy do clue ca\u0142ej sprawy ma\u0142a dygresja dla wszystkich, kt\u00f3rzy na co dzie\u0144 nie maj\u0105 do czynienia z frameworkiem od Google. Angularowe modu\u0142y maj\u0105 niewiele wsp\u00f3lnego z modu\u0142ami znanym z JavaScriptu. Natywne modu\u0142y pozwalaj\u0105 podzieli\u0107 aplikacj\u0119 na wiele plik\u00f3w i zarz\u0105dza\u0107 API, jakie udost\u0119pniamy. Angularowe modu\u0142y maj\u0105 na celu zapewnia\u0107 konfiguracj\u0119 zale\u017cno\u015bci dla Dependency Injection. W Angularze ka\u017cdy komponent czy dyrektywa musi by\u0107 cz\u0119\u015bci\u0105 jakiego\u015b modu\u0142u, co czyni je najbardziej atomicznym elementem frameworku. Co ciekawe, modu\u0142y trafi\u0142y do Angulara dopiero w wersji 2.0.0-rc.5 i by\u0142y odpowiedzi\u0105 na problemy z publikowanie Angularowych bibliotek w npm. Z racji, \u017ce framework by\u0142 ju\u017c na etapie Release Candidate, to ca\u0142e rozwi\u0105zanie powsta\u0142o w przy\u015bpieszonym tempie, i jak to bywa z takimi rozwi\u0105zaniami zosta\u0142o z nami na d\u0142u\u017cej.<\/p>\n","innerContent":["\n<p>Zanim przejdziemy do clue ca\u0142ej sprawy ma\u0142a dygresja dla wszystkich, kt\u00f3rzy na co dzie\u0144 nie maj\u0105 do czynienia z frameworkiem od Google. Angularowe modu\u0142y maj\u0105 niewiele wsp\u00f3lnego z modu\u0142ami znanym z JavaScriptu. Natywne modu\u0142y pozwalaj\u0105 podzieli\u0107 aplikacj\u0119 na wiele plik\u00f3w i zarz\u0105dza\u0107 API, jakie udost\u0119pniamy. Angularowe modu\u0142y maj\u0105 na celu zapewnia\u0107 konfiguracj\u0119 zale\u017cno\u015bci dla Dependency Injection. W Angularze ka\u017cdy komponent czy dyrektywa musi by\u0107 cz\u0119\u015bci\u0105 jakiego\u015b modu\u0142u, co czyni je najbardziej atomicznym elementem frameworku. Co ciekawe, modu\u0142y trafi\u0142y do Angulara dopiero w wersji 2.0.0-rc.5 i by\u0142y odpowiedzi\u0105 na problemy z publikowanie Angularowych bibliotek w npm. Z racji, \u017ce framework by\u0142 ju\u017c na etapie Release Candidate, to ca\u0142e rozwi\u0105zanie powsta\u0142o w przy\u015bpieszonym tempie, i jak to bywa z takimi rozwi\u0105zaniami zosta\u0142o z nami na d\u0142u\u017cej.<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/image","attrs":{"align":"center","id":12269,"sizeSlug":"full","linkDestination":"none"},"innerBlocks":[],"innerHTML":"\n<figure class=\"wp-block-image aligncenter size-full\"><img src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/5qdvey.jpeg\" alt=\"\" class=\"wp-image-12269\"\/><\/figure>\n","innerContent":["\n<figure class=\"wp-block-image aligncenter size-full\"><img src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/5qdvey.jpeg\" alt=\"\" class=\"wp-image-12269\"\/><\/figure>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Na przestrzeni lat dobre praktyki wok\u00f3\u0142 Angulara ewoluowa\u0142y i obecnie najcz\u0119\u015bciej uskuteczniamy jest schemat SCAM ( Single Component Angular Module). Pewnie nie by\u0142oby w tym nic z\u0142ego, gdyby nie ilo\u015b\u0107 boilerplateu jaka generowana jest przez tak\u0105 architektur\u0119.<\/p>\n","innerContent":["\n<p>Na przestrzeni lat dobre praktyki wok\u00f3\u0142 Angulara ewoluowa\u0142y i obecnie najcz\u0119\u015bciej uskuteczniamy jest schemat SCAM ( Single Component Angular Module). Pewnie nie by\u0142oby w tym nic z\u0142ego, gdyby nie ilo\u015b\u0107 boilerplateu jaka generowana jest przez tak\u0105 architektur\u0119.<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"prismatic\/blocks","attrs":{"language":"typescript"},"innerBlocks":[],"innerHTML":"\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">@Component({\n  selector: 'vived-my-component',\n  template:`\n    &lt;div>\n      &lt;h1>Today is {{today | date}} &lt;\/h1>'\n      &lt;CustomComponent \/>\n    &lt;\/div>\n  `\n})\nexport class MyComponent {\n  readonly today = new Date();\n}\n\n@NgModule({\n  imports:      [ CommonModule, CustomComponentModule ],\n  declarations: [ MyComponent ],\n  exports:      [ MyComponent ],\n})\nexport class MyComponentModule { }<\/code><\/pre>\n","innerContent":["\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">@Component({\n  selector: 'vived-my-component',\n  template:`\n    &lt;div>\n      &lt;h1>Today is {{today | date}} &lt;\/h1>'\n      &lt;CustomComponent \/>\n    &lt;\/div>\n  `\n})\nexport class MyComponent {\n  readonly today = new Date();\n}\n\n@NgModule({\n  imports:      [ CommonModule, CustomComponentModule ],\n  declarations: [ MyComponent ],\n  exports:      [ MyComponent ],\n})\nexport class MyComponentModule { }<\/code><\/pre>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/image","attrs":{"align":"center","id":12271,"sizeSlug":"full","linkDestination":"none"},"innerBlocks":[],"innerHTML":"\n<figure class=\"wp-block-image aligncenter size-full\"><img src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/download-50.jpeg\" alt=\"\" class=\"wp-image-12271\"\/><\/figure>\n","innerContent":["\n<figure class=\"wp-block-image aligncenter size-full\"><img src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/download-50.jpeg\" alt=\"\" class=\"wp-image-12271\"\/><\/figure>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Angular Standalone Components, czyli komponenty pozbawione modu\u0142\u00f3w,&nbsp; zosta\u0142y po raz pierwszy zaprezentowane w postaci RFC pod koniec 2021 roku. Spo\u0142eczno\u015b\u0107 w\u0142a\u015bciwie od razu pokocha\u0142a je bezwarunkowo. W po\u0142owie 2022 roku wraz z Angularem 14 otrzymali\u015bmy ich pierwsz\u0105 niestabiln\u0105 implementacj\u0119. W tym tygodniu wraz z Angularem 15 doczekali\u015bmy si\u0119 ich pierwszej stabilnej wersji.&nbsp;<\/p>\n","innerContent":["\n<p>Angular Standalone Components, czyli komponenty pozbawione modu\u0142\u00f3w,&nbsp; zosta\u0142y po raz pierwszy zaprezentowane w postaci RFC pod koniec 2021 roku. Spo\u0142eczno\u015b\u0107 w\u0142a\u015bciwie od razu pokocha\u0142a je bezwarunkowo. W po\u0142owie 2022 roku wraz z Angularem 14 otrzymali\u015bmy ich pierwsz\u0105 niestabiln\u0105 implementacj\u0119. W tym tygodniu wraz z Angularem 15 doczekali\u015bmy si\u0119 ich pierwszej stabilnej wersji.&nbsp;<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>W du\u017cym uproszczeniu Standalone Components, to architektura SCAM zrobiona dobrze. Je\u015bli do komponentu do\u0142\u0105czymy odpowiednie metadane, to Angular automatycznie zacznie traktowa\u0107 dany komponent jako modu\u0142.<\/p>\n","innerContent":["\n<p>W du\u017cym uproszczeniu Standalone Components, to architektura SCAM zrobiona dobrze. Je\u015bli do komponentu do\u0142\u0105czymy odpowiednie metadane, to Angular automatycznie zacznie traktowa\u0107 dany komponent jako modu\u0142.<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"prismatic\/blocks","attrs":{"language":"typescript"},"innerBlocks":[],"innerHTML":"\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">@Component({\n  selector: 'vived-my-component',\n  standalone: true.,\n  imports: [ CommonModule, CustomComponent ]\n  template: `\n    &lt;div>\n      &lt;h1>Today is {{today | date}} &lt;\/h1>'\n      &lt;CustomComponent \/>\n    &lt;\/div>\n    `\n})\nexport class MyComponent {\n  readonly today = new Date();\n}<\/code><\/pre>\n","innerContent":["\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">@Component({\n  selector: 'vived-my-component',\n  standalone: true.,\n  imports: [ CommonModule, CustomComponent ]\n  template: `\n    &lt;div>\n      &lt;h1>Today is {{today | date}} &lt;\/h1>'\n      &lt;CustomComponent \/>\n    &lt;\/div>\n    `\n})\nexport class MyComponent {\n  readonly today = new Date();\n}<\/code><\/pre>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Zesp\u00f3\u0142 Angulara nie poprzesta\u0142 na API do tworzenia Standalone Components, ale za cel postawi\u0142 sobie przygotowanie funkcyjnego API, kt\u00f3re pozwoli ca\u0142kowicie pozby\u0107 si\u0119 z modu\u0142\u00f3w z wi\u0119kszo\u015bci aplikacji. Angular 15 jest zwie\u0144czeniem tych stara\u0144, bo do funkcyjnego API do bootstapowania aplikacji do\u0142\u0105cza funkcyjny router oraz funkcyjny modu\u0142 http.<\/p>\n","innerContent":["\n<p>Zesp\u00f3\u0142 Angulara nie poprzesta\u0142 na API do tworzenia Standalone Components, ale za cel postawi\u0142 sobie przygotowanie funkcyjnego API, kt\u00f3re pozwoli ca\u0142kowicie pozby\u0107 si\u0119 z modu\u0142\u00f3w z wi\u0119kszo\u015bci aplikacji. Angular 15 jest zwie\u0144czeniem tych stara\u0144, bo do funkcyjnego API do bootstapowania aplikacji do\u0142\u0105cza funkcyjny router oraz funkcyjny modu\u0142 http.<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"prismatic\/blocks","attrs":{"language":"typescript"},"innerBlocks":[],"innerHTML":"\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">\/\/ This is how you bootstrap application with modules\n@NgModule({\n  declarations: [AppComponent],\n  imports: [\n    RouterModule.forRoot(\n      [\n        { path: '\/home', component: HomeComponent },\n        { path: '**', redirectTo: '\/home' },\n      ],\n      {\n        preloadingStrategy: PreloadAllModules,\n      }\n    ),\n  ],\n  providers: [\n    { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },\n  ],\n  bootstrap: [AppComponent],\n})\nexport class AppModule {}\n\nplatformBrowserDynamic().bootstrapModule(AppModule)<\/code><\/pre>\n","innerContent":["\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">\/\/ This is how you bootstrap application with modules\n@NgModule({\n  declarations: [AppComponent],\n  imports: [\n    RouterModule.forRoot(\n      [\n        { path: '\/home', component: HomeComponent },\n        { path: '**', redirectTo: '\/home' },\n      ],\n      {\n        preloadingStrategy: PreloadAllModules,\n      }\n    ),\n  ],\n  providers: [\n    { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },\n  ],\n  bootstrap: [AppComponent],\n})\nexport class AppModule {}\n\nplatformBrowserDynamic().bootstrapModule(AppModule)<\/code><\/pre>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"prismatic\/blocks","attrs":{"language":"typescript"},"innerBlocks":[],"innerHTML":"\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">\/\/ This is how you bootstrap application without modules\nbootstrapApplication(AppComponent, {\n  providers: [\n    provideRouter([\n      { path: '\/home', component: HomeComponent },\n      { path: '**', redirectTo: '\/home' },\n    ], withPreloading(PreloadAllModules)),\n    provideHttpClient(withInterceptors([AuthInterceptor]))\n  ]\n});\n<\/code><\/pre>\n","innerContent":["\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">\/\/ This is how you bootstrap application without modules\nbootstrapApplication(AppComponent, {\n  providers: [\n    provideRouter([\n      { path: '\/home', component: HomeComponent },\n      { path: '**', redirectTo: '\/home' },\n    ], withPreloading(PreloadAllModules)),\n    provideHttpClient(withInterceptors([AuthInterceptor]))\n  ]\n});\n<\/code><\/pre>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Opr\u00f3cz oczywistych zalet w postaci czytelniejszego kodu oraz pozbycia si\u0119 skomplikowanych <code>NgModules<\/code>, zastosowanie funkcyjnego podej\u015bcia sprawi\u0142o, \u017ce wszystkie API s\u0105 teraz w pe\u0142ni tree-shakable. Jak chwali si\u0119 zesp\u00f3\u0142 Angulara, w przypadku API routera odchudza to paczk\u0119 o \u015brednio 11%!<\/p>\n","innerContent":["\n<p>Opr\u00f3cz oczywistych zalet w postaci czytelniejszego kodu oraz pozbycia si\u0119 skomplikowanych <code>NgModules<\/code>, zastosowanie funkcyjnego podej\u015bcia sprawi\u0142o, \u017ce wszystkie API s\u0105 teraz w pe\u0142ni tree-shakable. Jak chwali si\u0119 zesp\u00f3\u0142 Angulara, w przypadku API routera odchudza to paczk\u0119 o \u015brednio 11%!<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Na zako\u0144czenie warto podkre\u015bli\u0107, \u017ce Standalone Components nie s\u0105 pr\u00f3b\u0105 ca\u0142kowitego usuni\u0119cia Angularowych modu\u0142\u00f3w. Ich koncepcja jest g\u0142\u0119boko zakorzeniona w architekturze Angulara i w wielu przypadkach ich wykorzystanie wci\u0105\u017c b\u0119dzie niezb\u0119dne do osi\u0105gni\u0119cia po\u017c\u0105danego rezultatu. Modu\u0142y pozostaj\u0105 r\u00f3wnie\u017c kluczowym aspektem enkapsulacji wielu zewn\u0119trznych bibliotek.<\/p>\n","innerContent":["\n<p>Na zako\u0144czenie warto podkre\u015bli\u0107, \u017ce Standalone Components nie s\u0105 pr\u00f3b\u0105 ca\u0142kowitego usuni\u0119cia Angularowych modu\u0142\u00f3w. Ich koncepcja jest g\u0142\u0119boko zakorzeniona w architekturze Angulara i w wielu przypadkach ich wykorzystanie wci\u0105\u017c b\u0119dzie niezb\u0119dne do osi\u0105gni\u0119cia po\u017c\u0105danego rezultatu. Modu\u0142y pozostaj\u0105 r\u00f3wnie\u017c kluczowym aspektem enkapsulacji wielu zewn\u0119trznych bibliotek.<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/image","attrs":{"align":"center","id":12273,"sizeSlug":"full","linkDestination":"none"},"innerBlocks":[],"innerHTML":"\n<figure class=\"wp-block-image aligncenter size-full\"><img src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/5qdpk3-1.jpeg\" alt=\"\" class=\"wp-image-12273\"\/><\/figure>\n","innerContent":["\n<figure class=\"wp-block-image aligncenter size-full\"><img src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/5qdpk3-1.jpeg\" alt=\"\" class=\"wp-image-12273\"\/><\/figure>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/heading","attrs":{"level":3},"innerBlocks":[],"innerHTML":"\n<h3>Functional Router Guards<\/h3>\n","innerContent":["\n<h3>Functional Router Guards<\/h3>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>W sporym uproszczeniu Routing w Angularze oparty jest o tablic\u0119 obiekt\u00f3w definiuj\u0105cych \u015bcie\u017ck\u0119, komponent do wyrenderowania oraz list\u0119 Guard\u00f3w. Te ostatnie pozwalaj\u0105 zawieraj\u0105 logik\u0119 warunkuj\u0105c\u0105 dost\u0119p do danej \u015bcie\u017cki oraz umo\u017cliwiaj\u0105 wykonanie odpowiedniego przekierowania.<\/p>\n","innerContent":["\n<p>W sporym uproszczeniu Routing w Angularze oparty jest o tablic\u0119 obiekt\u00f3w definiuj\u0105cych \u015bcie\u017ck\u0119, komponent do wyrenderowania oraz list\u0119 Guard\u00f3w. Te ostatnie pozwalaj\u0105 zawieraj\u0105 logik\u0119 warunkuj\u0105c\u0105 dost\u0119p do danej \u015bcie\u017cki oraz umo\u017cliwiaj\u0105 wykonanie odpowiedniego przekierowania.<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"prismatic\/blocks","attrs":{"language":"typescript"},"innerBlocks":[],"innerHTML":"\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">@NgModule({\n  imports: [\n    RouterModule.forRoot(\n      [\n        { path: '\/login', component: LoginComponent },\n        { path: '\/home', component: HomeComponet, canActivate: [LoggedInGuard] },\n        { path: '**', redirectTo: '\/home' },\n      ]\n    ),\n  ],\n  exports: [RouterModule],\n})\nexport class AppRoutingModule {}\n\n@Injectable({ providedIn: 'root' })\nexport class LoggedInGuard implements CanActivate {\n  constructor(\n    private readonly authService: AuthService,\n    private readonly router: Router\n  ) {}\n\n  async canActivate(route: ActivatedRouteSnapshot): Promise&lt;boolean> {\n    if (!await this.authService.isLoggedIn()) {\n      return true;\n    }\n    return this.router.navigate(\u2018\/home\u2019);\n  }\n}<\/code><\/pre>\n","innerContent":["\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">@NgModule({\n  imports: [\n    RouterModule.forRoot(\n      [\n        { path: '\/login', component: LoginComponent },\n        { path: '\/home', component: HomeComponet, canActivate: [LoggedInGuard] },\n        { path: '**', redirectTo: '\/home' },\n      ]\n    ),\n  ],\n  exports: [RouterModule],\n})\nexport class AppRoutingModule {}\n\n@Injectable({ providedIn: 'root' })\nexport class LoggedInGuard implements CanActivate {\n  constructor(\n    private readonly authService: AuthService,\n    private readonly router: Router\n  ) {}\n\n  async canActivate(route: ActivatedRouteSnapshot): Promise&lt;boolean> {\n    if (!await this.authService.isLoggedIn()) {\n      return true;\n    }\n    return this.router.navigate(\u2018\/home\u2019);\n  }\n}<\/code><\/pre>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Gdybym dla Angulara 15 mia\u0142 wymy\u015bli\u0107 chwytliwe has\u0142o reklamowe, to by\u0142oby to zdecydowanie \u201cMniej boilerplateu, wi\u0119cej frajdy\u201d. Kolejn\u0105 spor\u0105 nowo\u015bci\u0105 w Angularze 15 jest mo\u017cliwo\u015b\u0107 zast\u0105pienia skomplikowanych klasowych Gurad\u00f3w prost\u0105 funkcj\u0105 zwracaj\u0105c\u0105 warto\u015b\u0107 boolean. Zaryzykuj\u0119 stwierdzenie, \u017ce wykorzystuj\u0105c dodan\u0105 w Angularze 14 funkcj\u0119 <code>inject()<\/code> mo\u017cliwe jest ca\u0142kowite pozbycie si\u0119 z kodu klasowych Guard\u00f3w.<\/p>\n","innerContent":["\n<p>Gdybym dla Angulara 15 mia\u0142 wymy\u015bli\u0107 chwytliwe has\u0142o reklamowe, to by\u0142oby to zdecydowanie \u201cMniej boilerplateu, wi\u0119cej frajdy\u201d. Kolejn\u0105 spor\u0105 nowo\u015bci\u0105 w Angularze 15 jest mo\u017cliwo\u015b\u0107 zast\u0105pienia skomplikowanych klasowych Gurad\u00f3w prost\u0105 funkcj\u0105 zwracaj\u0105c\u0105 warto\u015b\u0107 boolean. Zaryzykuj\u0119 stwierdzenie, \u017ce wykorzystuj\u0105c dodan\u0105 w Angularze 14 funkcj\u0119 <code>inject()<\/code> mo\u017cliwe jest ca\u0142kowite pozbycie si\u0119 z kodu klasowych Guard\u00f3w.<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"prismatic\/blocks","attrs":{"language":"typescript"},"innerBlocks":[],"innerHTML":"\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">provideRouter([\n        { path: '\/login', component: LoginComponent },\n        { path: '\/home', component: HomeComponet, canActivate: [isLoggedIn()] },\n        { path: '**', redirectTo: '\/home' },\n])\n\nfunction isLoggedIn() { \n    if (!await inject(AuthService).isLoggedIn()) {\n      return true;\n    }\n    return inject(Router).navigate('\/home');\n}<\/code><\/pre>\n","innerContent":["\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">provideRouter([\n        { path: '\/login', component: LoginComponent },\n        { path: '\/home', component: HomeComponet, canActivate: [isLoggedIn()] },\n        { path: '**', redirectTo: '\/home' },\n])\n\nfunction isLoggedIn() { \n    if (!await inject(AuthService).isLoggedIn()) {\n      return true;\n    }\n    return inject(Router).navigate('\/home');\n}<\/code><\/pre>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Niew\u0105tpliw\u0105 zalet\u0105 nowej architektury jest te\u017c prostota parametryzacji. Zamiast przekazywa\u0107 i czyta\u0107 dane z ActivatedRouteSnapshot, mo\u017cemy po prostu przekaza\u0107 je jako argumenty funkcji.<\/p>\n","innerContent":["\n<p>Niew\u0105tpliw\u0105 zalet\u0105 nowej architektury jest te\u017c prostota parametryzacji. Zamiast przekazywa\u0107 i czyta\u0107 dane z ActivatedRouteSnapshot, mo\u017cemy po prostu przekaza\u0107 je jako argumenty funkcji.<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"prismatic\/blocks","attrs":{"language":"typescript"},"innerBlocks":[],"innerHTML":"\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">\/\/ This is how you parametarize Guards with class approach\n@NgModule({\n  imports: [\n    RouterModule.forRoot(\n      [\n        { path: '\/login', component: LoginComponent },\n        { \n          path: '\/home',\n          component: HomeComponet, \n          canActivate: [AuthStateGuard],\n          data: { states: ['LOGGED_IN'] } \n        },\n        { path: '**', redirectTo: '\/home' },\n      ]\n    ),\n  ],\n  exports: [RouterModule],\n})\nexport class AppRoutingModule {}\n\n@Injectable({ providedIn: 'root' })\nexport class AuthStateGuard implements CanActivate {\n  constructor(\n    private readonly authService: AuthService,\n    private readonly router: Router\n  ) {}\n\n  async canActivate(route: ActivatedRouteSnapshot): Promise&lt;boolean> {\n    if (route.data.states.includes('LOGGED_IN') &amp;&amp; await this.authService.isLoggedIn()) {\n      return true;\n    }\n    return this.router.navigate('\/login');\n  }\n}<\/code><\/pre>\n","innerContent":["\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">\/\/ This is how you parametarize Guards with class approach\n@NgModule({\n  imports: [\n    RouterModule.forRoot(\n      [\n        { path: '\/login', component: LoginComponent },\n        { \n          path: '\/home',\n          component: HomeComponet, \n          canActivate: [AuthStateGuard],\n          data: { states: ['LOGGED_IN'] } \n        },\n        { path: '**', redirectTo: '\/home' },\n      ]\n    ),\n  ],\n  exports: [RouterModule],\n})\nexport class AppRoutingModule {}\n\n@Injectable({ providedIn: 'root' })\nexport class AuthStateGuard implements CanActivate {\n  constructor(\n    private readonly authService: AuthService,\n    private readonly router: Router\n  ) {}\n\n  async canActivate(route: ActivatedRouteSnapshot): Promise&lt;boolean> {\n    if (route.data.states.includes('LOGGED_IN') &amp;&amp; await this.authService.isLoggedIn()) {\n      return true;\n    }\n    return this.router.navigate('\/login');\n  }\n}<\/code><\/pre>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"prismatic\/blocks","attrs":{"language":"typescript"},"innerBlocks":[],"innerHTML":"\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">\/\/ This is how you parametarize Guards with functional approach\nprovideRouter([\n        { path: '\/login', component: LoginComponent },\n        { \n          path: '\/home', \n          component: HomeComponet, \n          canActivate: [authStatesGuard(['LOGGED_IN'])] \n        } ,\n        { path: '**', redirectTo: '\/home' },\n])\n\nfunction authStatesGuard(states: string[]) { \n    if (states.includes('LOGGED_IN') &amp;&amp; await inject(AuthService).isLoggedIn()) {\n      return true;\n    }\n    return inject(Router).navigate('\/login');\n}<\/code><\/pre>\n","innerContent":["\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">\/\/ This is how you parametarize Guards with functional approach\nprovideRouter([\n        { path: '\/login', component: LoginComponent },\n        { \n          path: '\/home', \n          component: HomeComponet, \n          canActivate: [authStatesGuard(['LOGGED_IN'])] \n        } ,\n        { path: '**', redirectTo: '\/home' },\n])\n\nfunction authStatesGuard(states: string[]) { \n    if (states.includes('LOGGED_IN') &amp;&amp; await inject(AuthService).isLoggedIn()) {\n      return true;\n    }\n    return inject(Router).navigate('\/login');\n}<\/code><\/pre>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/image","attrs":{"align":"center","id":12275,"width":464,"height":230,"sizeSlug":"full","linkDestination":"none"},"innerBlocks":[],"innerHTML":"\n<figure class=\"wp-block-image aligncenter size-full is-resized\"><img src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/716bku.gif\" alt=\"\" class=\"wp-image-12275\" width=\"464\" height=\"230\"\/><\/figure>\n","innerContent":["\n<figure class=\"wp-block-image aligncenter size-full is-resized\"><img src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/716bku.gif\" alt=\"\" class=\"wp-image-12275\" width=\"464\" height=\"230\"\/><\/figure>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Na koniec warto wspomnie\u0107 jeszcze, \u017ce analogiczne funkcyjne API dosta\u0142y r\u00f3wnie\u017c interceptor HTTP&nbsp;<\/p>\n","innerContent":["\n<p>Na koniec warto wspomnie\u0107 jeszcze, \u017ce analogiczne funkcyjne API dosta\u0142y r\u00f3wnie\u017c interceptor HTTP&nbsp;<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"prismatic\/blocks","attrs":{"language":"typescript"},"innerBlocks":[],"innerHTML":"\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">provideHttpClient(\n      withInterceptors([\n       (req, next) => {\n          \/\/ We can use the inject() function inside this function\n          \/\/ For example: inject(AuthService)\n          return next(req);\n        },\n      ])\n)<\/code><\/pre>\n","innerContent":["\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">provideHttpClient(\n      withInterceptors([\n       (req, next) => {\n          \/\/ We can use the inject() function inside this function\n          \/\/ For example: inject(AuthService)\n          return next(req);\n        },\n      ])\n)<\/code><\/pre>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/heading","attrs":{"level":3},"innerBlocks":[],"innerHTML":"\n<h3>Directive Composition API<\/h3>\n","innerContent":["\n<h3>Directive Composition API<\/h3>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>W odr\u00f3\u017cnieniu od Reacta czy Vue, kt\u00f3re oparte s\u0105 o funkcje, Angular zbudowany jest g\u0142\u00f3wnie wok\u00f3\u0142 klas. Z tego wzgl\u0119du w frameworku od Google nie mo\u017cna zastosowa\u0107 prostej kompozycji funkcji. Jej miejsce zajmuj\u0105 dyrektywy, czyli klasy pozwalaj\u0105ce rozszerzy\u0107 funkcjonalno\u015b\u0107 komponentu<\/p>\n","innerContent":["\n<p>W odr\u00f3\u017cnieniu od Reacta czy Vue, kt\u00f3re oparte s\u0105 o funkcje, Angular zbudowany jest g\u0142\u00f3wnie wok\u00f3\u0142 klas. Z tego wzgl\u0119du w frameworku od Google nie mo\u017cna zastosowa\u0107 prostej kompozycji funkcji. Jej miejsce zajmuj\u0105 dyrektywy, czyli klasy pozwalaj\u0105ce rozszerzy\u0107 funkcjonalno\u015b\u0107 komponentu<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"prismatic\/blocks","attrs":{"language":"typescript"},"innerBlocks":[],"innerHTML":"\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">@Directive({\n  selector: '[appHighlight]'\n})\nexport class HighlightDirective {\n    constructor(private el: ElementRef) {\n       this.el.nativeElement.style.backgroundColor = 'yellow';\n    }\n}\n\n@Component({\n  selector: 'vived-my-component',\n  standalone: true.,\n  imports: [ HighlightDirective ]\n  \/\/ \ud83d\udc47 This is how you enrich component behaviour with Directive\n  template: '&lt;CustomComponent appHighlight \/>';  \n})\nexport class MyComponent {}<\/code><\/pre>\n","innerContent":["\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">@Directive({\n  selector: '[appHighlight]'\n})\nexport class HighlightDirective {\n    constructor(private el: ElementRef) {\n       this.el.nativeElement.style.backgroundColor = 'yellow';\n    }\n}\n\n@Component({\n  selector: 'vived-my-component',\n  standalone: true.,\n  imports: [ HighlightDirective ]\n  \/\/ \ud83d\udc47 This is how you enrich component behaviour with Directive\n  template: '&lt;CustomComponent appHighlight \/>';  \n})\nexport class MyComponent {}<\/code><\/pre>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Jedn\u0105 z najwi\u0119kszych bol\u0105czek dyrektyw do tej pory by\u0142 brak mo\u017cliwo\u015bci przypisania ich bezpo\u015brednio przy definiowaniu komponentu oraz problemy z ich rozszerzaniem.&nbsp; \u017beby lepiej zobrazowa\u0107 problem, wyobra\u017acie sobie, \u017ce implementujecie przycisk, kt\u00f3ry po najechaniu zapala si\u0119 na \u017c\u00f3\u0142to. W waszym kodzie istnieje ju\u017c dyrektywa, kt\u00f3ra umo\u017cliwia zapalenie dowolnego komponentu na \u017c\u00f3\u0142to. Angular nie umo\u017cliwia jednak przypisania dyrektywy do komponentu podczas jego definiowania. W efekcie skazani jeste\u015bcie albo na duplikacj\u0119 kodu, albo manualne dopinanie dyrektywy za ka\u017cdym razem, kiedy korzystacie z stworzonego komponentu.&nbsp;<\/p>\n","innerContent":["\n<p>Jedn\u0105 z najwi\u0119kszych bol\u0105czek dyrektyw do tej pory by\u0142 brak mo\u017cliwo\u015bci przypisania ich bezpo\u015brednio przy definiowaniu komponentu oraz problemy z ich rozszerzaniem.&nbsp; \u017beby lepiej zobrazowa\u0107 problem, wyobra\u017acie sobie, \u017ce implementujecie przycisk, kt\u00f3ry po najechaniu zapala si\u0119 na \u017c\u00f3\u0142to. W waszym kodzie istnieje ju\u017c dyrektywa, kt\u00f3ra umo\u017cliwia zapalenie dowolnego komponentu na \u017c\u00f3\u0142to. Angular nie umo\u017cliwia jednak przypisania dyrektywy do komponentu podczas jego definiowania. W efekcie skazani jeste\u015bcie albo na duplikacj\u0119 kodu, albo manualne dopinanie dyrektywy za ka\u017cdym razem, kiedy korzystacie z stworzonego komponentu.&nbsp;<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Angular 15 rozwi\u0105zuje ten problem, poprzez dodanie do dekoratora <code>@Component<\/code> w\u0142a\u015bciwo\u015bci <code>hostDirective<\/code>. Przekazujemy do niej list\u0119 dyrektyw, kt\u00f3re maj\u0105 zosta\u0107 zaaplikowane do naszego komponentu. Komponent bazowy automatycznie dziedziczy wszystkie w\u0142a\u015bciwo\u015bci przypisanych do niego dyrektyw.&nbsp;<\/p>\n","innerContent":["\n<p>Angular 15 rozwi\u0105zuje ten problem, poprzez dodanie do dekoratora <code>@Component<\/code> w\u0142a\u015bciwo\u015bci <code>hostDirective<\/code>. Przekazujemy do niej list\u0119 dyrektyw, kt\u00f3re maj\u0105 zosta\u0107 zaaplikowane do naszego komponentu. Komponent bazowy automatycznie dziedziczy wszystkie w\u0142a\u015bciwo\u015bci przypisanych do niego dyrektyw.&nbsp;<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"prismatic\/blocks","attrs":{"language":"typescript"},"innerBlocks":[],"innerHTML":"\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">@Component({\n  selector: 'vived-my-component',\n  standalone: true,\n  imports: [ HighlightDirective ],\n  \/\/ \ud83d\udc47 This is how you assign directive to the component in Angular 15\n  hostDirectives: [AppHighlight],\n  template: '&lt;button>Hello World&lt;\/button>';\n})\nexport class CustomComponent {\n  readonly today = new Date();\n}<\/code><\/pre>\n","innerContent":["\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">@Component({\n  selector: 'vived-my-component',\n  standalone: true,\n  imports: [ HighlightDirective ],\n  \/\/ \ud83d\udc47 This is how you assign directive to the component in Angular 15\n  hostDirectives: [AppHighlight],\n  template: '&lt;button>Hello World&lt;\/button>';\n})\nexport class CustomComponent {\n  readonly today = new Date();\n}<\/code><\/pre>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Co interesuj\u0105ce, nowo dodana w\u0142a\u015bciwo\u015b\u0107 umo\u017cliwia r\u00f3wnie\u017c kompozycj\u0119 samych dyrektyw.&nbsp;<\/p>\n","innerContent":["\n<p>Co interesuj\u0105ce, nowo dodana w\u0142a\u015bciwo\u015b\u0107 umo\u017cliwia r\u00f3wnie\u017c kompozycj\u0119 samych dyrektyw.&nbsp;<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"prismatic\/blocks","attrs":{"language":"typescript"},"innerBlocks":[],"innerHTML":"\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">@Directive({\n  selector: '[appHighlightAndUnderline]',\n  hostDirectives: [AppHighlight, AppUnerline]\n})\nexport class HighlightAndUnderline { }<\/code><\/pre>\n","innerContent":["\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">@Directive({\n  selector: '[appHighlightAndUnderline]',\n  hostDirectives: [AppHighlight, AppUnerline]\n})\nexport class HighlightAndUnderline { }<\/code><\/pre>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/heading","attrs":{"level":3},"innerBlocks":[],"innerHTML":"\n<h3>Optimised Image Directive<\/h3>\n","innerContent":["\n<h3>Optimised Image Directive<\/h3>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Project Aurora to inicjatywa powo\u0142ana do \u017cycia przez zesp\u00f3\u0142 rozwijaj\u0105cy Google Chrome. Jego g\u0142\u00f3wnym zadaniem jest wsp\u00f3\u0142praca z tw\u00f3rcami popularnych bibliotek i framework\u00f3w, w celu tworzenia jak najlepszych do\u015bwiadcze\u0144 dla u\u017cytkownik\u00f3w internetu. Niespe\u0142na kilka tygodni temu informowali\u015bmy Was o <code>next\/image<\/code>, czyli komponencie do prezentowania obraz\u00f3w tak, aby optymalizowa\u0107 metryki Core Web Vitals. Komponent ten by\u0142 efektem wsp\u00f3\u0142pracy zespo\u0142u Project Aurora i Next.js. Do Angulara 15 trafi\u0142a analogiczna dyrektywa, kt\u00f3ra r\u00f3wnie\u017c jest efektem wsp\u00f3\u0142pracy z Project Aurora.&nbsp;<\/p>\n","innerContent":["\n<p>Project Aurora to inicjatywa powo\u0142ana do \u017cycia przez zesp\u00f3\u0142 rozwijaj\u0105cy Google Chrome. Jego g\u0142\u00f3wnym zadaniem jest wsp\u00f3\u0142praca z tw\u00f3rcami popularnych bibliotek i framework\u00f3w, w celu tworzenia jak najlepszych do\u015bwiadcze\u0144 dla u\u017cytkownik\u00f3w internetu. Niespe\u0142na kilka tygodni temu informowali\u015bmy Was o <code>next\/image<\/code>, czyli komponencie do prezentowania obraz\u00f3w tak, aby optymalizowa\u0107 metryki Core Web Vitals. Komponent ten by\u0142 efektem wsp\u00f3\u0142pracy zespo\u0142u Project Aurora i Next.js. Do Angulara 15 trafi\u0142a analogiczna dyrektywa, kt\u00f3ra r\u00f3wnie\u017c jest efektem wsp\u00f3\u0142pracy z Project Aurora.&nbsp;<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"prismatic\/blocks","attrs":{"language":"typescript"},"innerBlocks":[],"innerHTML":"\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">@Component({\n  standalone: true,\n  \/\/ \ud83d\udc47 Notice how src is replaced with ngSrc\n  template: '&lt;img [ngSrc]=\u201dsrc\u201d [alt]=\u201dalt\u201d\/>'\n  imports: [NgOptimizedImage],\n})\nclass MyStandaloneComponent {\n  @Input() src: string;\n  @Input() alt: string;\n}<\/code><\/pre>\n","innerContent":["\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">@Component({\n  standalone: true,\n  \/\/ \ud83d\udc47 Notice how src is replaced with ngSrc\n  template: '&lt;img [ngSrc]=\u201dsrc\u201d [alt]=\u201dalt\u201d\/>'\n  imports: [NgOptimizedImage],\n})\nclass MyStandaloneComponent {\n  @Input() src: string;\n  @Input() alt: string;\n}<\/code><\/pre>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/image","attrs":{"align":"center","id":12277,"sizeSlug":"full","linkDestination":"none"},"innerBlocks":[],"innerHTML":"\n<figure class=\"wp-block-image aligncenter size-full\"><img src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/download-52.jpeg\" alt=\"\" class=\"wp-image-12277\"\/><\/figure>\n","innerContent":["\n<figure class=\"wp-block-image aligncenter size-full\"><img src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/download-52.jpeg\" alt=\"\" class=\"wp-image-12277\"\/><\/figure>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/heading","attrs":{"level":3},"innerBlocks":[],"innerHTML":"\n<h3>Usprawniony Stack Trace<\/h3>\n","innerContent":["\n<h3>Usprawniony Stack Trace<\/h3>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Wyniki corocznej ankiety przeprowadzanej przez zesp\u00f3\u0142 Angulara wyra\u017anie pokaza\u0142y, \u017ce najwi\u0119kszym problemem w debugowaniu s\u0105 skomplikowane komunikaty b\u0142\u0119d\u00f3w. Aby zaadresowa\u0107 ten problem, we wsp\u00f3\u0142pracy z zespo\u0142em Chrome DevTools, stworzony zosta\u0142 mechanizm anotacji, kt\u00f3ry pozwala usun\u0105\u0107 z stack trace linie wskazuj\u0105ce na <code>node_modules<\/code>. Dzi\u0119ki temu \u0142atwiejsze powinno by\u0107 zrozumienie gdzie w aplikacji tak naprawd\u0119 wyst\u0105pi\u0142 b\u0142\u0105d.<\/p>\n","innerContent":["\n<p>Wyniki corocznej ankiety przeprowadzanej przez zesp\u00f3\u0142 Angulara wyra\u017anie pokaza\u0142y, \u017ce najwi\u0119kszym problemem w debugowaniu s\u0105 skomplikowane komunikaty b\u0142\u0119d\u00f3w. Aby zaadresowa\u0107 ten problem, we wsp\u00f3\u0142pracy z zespo\u0142em Chrome DevTools, stworzony zosta\u0142 mechanizm anotacji, kt\u00f3ry pozwala usun\u0105\u0107 z stack trace linie wskazuj\u0105ce na <code>node_modules<\/code>. Dzi\u0119ki temu \u0142atwiejsze powinno by\u0107 zrozumienie gdzie w aplikacji tak naprawd\u0119 wyst\u0105pi\u0142 b\u0142\u0105d.<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"prismatic\/blocks","attrs":{"language":"bash"},"innerBlocks":[],"innerHTML":"\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\">\/\/ Error from Angular 14\nERROR Error: Uncaught (in promise): Error\nError\n    at app.component.ts:18:11\n    at Generator.next (&lt;anonymous>)\n    at asyncGeneratorStep (asyncToGenerator.js:3:1)\n    at _next (asyncToGenerator.js:25:1)\n    at _ZoneDelegate.invoke (zone.js:372:26)\n    at Object.onInvoke (core.mjs:26378:33)\n    at _ZoneDelegate.invoke (zone.js:371:52)\n    at Zone.run (zone.js:134:43)\n    at zone.js:1275:36\n    at _ZoneDelegate.invokeTask (zone.js:406:31)\n    at resolvePromise (zone.js:1211:31)\n    at zone.js:1118:17\n    at zone.js:1134:33<\/code><\/pre>\n","innerContent":["\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\">\/\/ Error from Angular 14\nERROR Error: Uncaught (in promise): Error\nError\n    at app.component.ts:18:11\n    at Generator.next (&lt;anonymous>)\n    at asyncGeneratorStep (asyncToGenerator.js:3:1)\n    at _next (asyncToGenerator.js:25:1)\n    at _ZoneDelegate.invoke (zone.js:372:26)\n    at Object.onInvoke (core.mjs:26378:33)\n    at _ZoneDelegate.invoke (zone.js:371:52)\n    at Zone.run (zone.js:134:43)\n    at zone.js:1275:36\n    at _ZoneDelegate.invokeTask (zone.js:406:31)\n    at resolvePromise (zone.js:1211:31)\n    at zone.js:1118:17\n    at zone.js:1134:33<\/code><\/pre>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"prismatic\/blocks","attrs":{"language":"bash"},"innerBlocks":[],"innerHTML":"\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\">\/\/ The same Error from Angular 15\nERROR Error: Uncaught (in promise): Error\nError\n    at app.component.ts:18:11\n    at fetch (async)  \n    at (anonymous) (app.component.ts:4)\n    at request (app.component.ts:4)\n    at (anonymous) (app.component.ts:17)\n    at submit (app.component.ts:15)\n    at AppComponent_click_3_listener (app.component.html:4)<\/code><\/pre>\n","innerContent":["\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\">\/\/ The same Error from Angular 15\nERROR Error: Uncaught (in promise): Error\nError\n    at app.component.ts:18:11\n    at fetch (async)  \n    at (anonymous) (app.component.ts:4)\n    at request (app.component.ts:4)\n    at (anonymous) (app.component.ts:17)\n    at submit (app.component.ts:15)\n    at AppComponent_click_3_listener (app.component.html:4)<\/code><\/pre>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/heading","attrs":{"level":3},"innerBlocks":[],"innerHTML":"\n<h3>\u0179r\u00f3d\u0142a:<\/h3>\n","innerContent":["\n<h3>\u0179r\u00f3d\u0142a:<\/h3>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p><a href=\"https:\/\/blog.angular.io\/angular-v15-is-now-available-df7be7f2f4c8\">https:\/\/blog.angular.io\/angular-v15-is-now-available-df7be7f2f4c8<\/a><\/p>\n","innerContent":["\n<p><a href=\"https:\/\/blog.angular.io\/angular-v15-is-now-available-df7be7f2f4c8\">https:\/\/blog.angular.io\/angular-v15-is-now-available-df7be7f2f4c8<\/a><\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/heading","attrs":[],"innerBlocks":[],"innerHTML":"\n<h2>2. TypeScript 4.9<\/h2>\n","innerContent":["\n<h2>2. TypeScript 4.9<\/h2>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Ostatnie kilka wersji TypeScript to g\u0142\u00f3wnie nudne optymalizacje i obs\u0142uga kolejnych przypadk\u00f3w brzegowych. Wydany w tym tygodniu TypeScript 4.9 jest zupe\u0142nie inny, bo wprowadza a\u017c dwa nowe s\u0142owa kluczowe. Bez zb\u0119dnego przed\u0142u\u017cania przyjrzyjmy si\u0119 co nowego trafi\u0142o do j\u0119zyka od Microsoftu i dlaczego jest to jego najciekawsza wersja od dawna.<\/p>\n","innerContent":["\n<p>Ostatnie kilka wersji TypeScript to g\u0142\u00f3wnie nudne optymalizacje i obs\u0142uga kolejnych przypadk\u00f3w brzegowych. Wydany w tym tygodniu TypeScript 4.9 jest zupe\u0142nie inny, bo wprowadza a\u017c dwa nowe s\u0142owa kluczowe. Bez zb\u0119dnego przed\u0142u\u017cania przyjrzyjmy si\u0119 co nowego trafi\u0142o do j\u0119zyka od Microsoftu i dlaczego jest to jego najciekawsza wersja od dawna.<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/image","attrs":{"align":"center","id":12279,"sizeSlug":"full","linkDestination":"none"},"innerBlocks":[],"innerHTML":"\n<figure class=\"wp-block-image aligncenter size-full\"><img src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/6v9rzo.gif\" alt=\"\" class=\"wp-image-12279\"\/><\/figure>\n","innerContent":["\n<figure class=\"wp-block-image aligncenter size-full\"><img src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/6v9rzo.gif\" alt=\"\" class=\"wp-image-12279\"\/><\/figure>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/heading","attrs":{"level":3},"innerBlocks":[],"innerHTML":"\n<h3>Satisfies operator<\/h3>\n","innerContent":["\n<h3>Satisfies operator<\/h3>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>T\u0142umacz\u0105c dzia\u0142anie nowego operatora pos\u0142u\u017c\u0119 si\u0119 przyk\u0142adem z notatki od Microsoftu. Za\u0142\u00f3\u017cmy, \u017ce potrzebujemy otypowa\u0107 nast\u0119puj\u0105cy kod:<\/p>\n","innerContent":["\n<p>T\u0142umacz\u0105c dzia\u0142anie nowego operatora pos\u0142u\u017c\u0119 si\u0119 przyk\u0142adem z notatki od Microsoftu. Za\u0142\u00f3\u017cmy, \u017ce potrzebujemy otypowa\u0107 nast\u0119puj\u0105cy kod:<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"prismatic\/blocks","attrs":{"language":"typescript"},"innerBlocks":[],"innerHTML":"\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">\/\/ Each property can be a string or an RGB tuple.\nconst palette = {\n    red: [255, 0, 0],\n    green: \"#00ff00\",\n    blue: [0, 0, 255]\n};\n\n\/\/ We want to be able to use array methods on 'red'...\nconst redComponent = palette.red.at(0);\n\n\/\/ or string methods on 'green'...\nconst greenNormalized = palette.green.toUpperCase();<\/code><\/pre>\n","innerContent":["\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">\/\/ Each property can be a string or an RGB tuple.\nconst palette = {\n    red: [255, 0, 0],\n    green: \"#00ff00\",\n    blue: [0, 0, 255]\n};\n\n\/\/ We want to be able to use array methods on 'red'...\nconst redComponent = palette.red.at(0);\n\n\/\/ or string methods on 'green'...\nconst greenNormalized = palette.green.toUpperCase();<\/code><\/pre>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>W pierwszej chwili do g\u0142owy przyj\u015b\u0107 mo\u017ce zdefiniowanie typu Color oraz wykorzystanie typu Record. Niestety, w takim przypadku zmuszeni jeste\u015bmy wykonywa\u0107 niebezpieczn\u0105 operacj\u0119 rzutowania:<\/p>\n","innerContent":["\n<p>W pierwszej chwili do g\u0142owy przyj\u015b\u0107 mo\u017ce zdefiniowanie typu Color oraz wykorzystanie typu Record. Niestety, w takim przypadku zmuszeni jeste\u015bmy wykonywa\u0107 niebezpieczn\u0105 operacj\u0119 rzutowania:<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"prismatic\/blocks","attrs":{"language":"typescript"},"innerBlocks":[],"innerHTML":"\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">type Color = \"red\" | \"green\" | \"blue\";\ntype RGB = [red: number, green: number, blue: number];\n\ntype Palette = Record&lt;Color, string | RGB>\n\nconst palette: Palette = {\n    red: [255, 0, 0],\n    green: \"#00ff00\",\n    blue: [0, 0, 255]\n};\n\n\/\/ We want to be able to use array methods on 'red'...\nconst redComponent = (palette.red as RGB).at(0);\n\n\/\/ or string methods on 'green'...\nconst greenNormalized = (palette.green as string).toUpperCase();<\/code><\/pre>\n","innerContent":["\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">type Color = \"red\" | \"green\" | \"blue\";\ntype RGB = [red: number, green: number, blue: number];\n\ntype Palette = Record&lt;Color, string | RGB>\n\nconst palette: Palette = {\n    red: [255, 0, 0],\n    green: \"#00ff00\",\n    blue: [0, 0, 255]\n};\n\n\/\/ We want to be able to use array methods on 'red'...\nconst redComponent = (palette.red as RGB).at(0);\n\n\/\/ or string methods on 'green'...\nconst greenNormalized = (palette.green as string).toUpperCase();<\/code><\/pre>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Aby usun\u0105\u0107 rzutowanie, mo\u017cemy w definicji typu zawrze\u0107 spos\u00f3b w jaki b\u0119dzie on definiowany. W naszym przypadku nie jest to mo\u017ce najgorszy pomys\u0142, ale zobaczcie sami, ile dodatkowego kodu musimy wygenerowa\u0107, nie m\u00f3wi\u0105c ju\u017c o du\u017co mniejszej elastyczno\u015bci.<\/p>\n","innerContent":["\n<p>Aby usun\u0105\u0107 rzutowanie, mo\u017cemy w definicji typu zawrze\u0107 spos\u00f3b w jaki b\u0119dzie on definiowany. W naszym przypadku nie jest to mo\u017ce najgorszy pomys\u0142, ale zobaczcie sami, ile dodatkowego kodu musimy wygenerowa\u0107, nie m\u00f3wi\u0105c ju\u017c o du\u017co mniejszej elastyczno\u015bci.<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"prismatic\/blocks","attrs":{"language":"typescript"},"innerBlocks":[],"innerHTML":"\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">type StringColor =  \"green\";\ntype RGBColor = \"red\" | \"blue\";\ntype RGB = [red: number, green: number, blue: number];\n\ntype StringColorPalette = Record&lt;StringColor, string>;\ntype RGBColorPalette = Record&lt;RGBColor, RGB>;\ntype Palette = StringColorPalette &amp; RGBColorPalette;\n\nconst palette: Palette = {\n    red: [255, 0, 0],\n    green: \"#00ff00\",\n    blue: [0, 0, 255]\n};\n\nconst redComponent = palette.red.at(0);\nconst greenNormalized = palette.green.toUpperCase();<\/code><\/pre>\n","innerContent":["\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">type StringColor =  \"green\";\ntype RGBColor = \"red\" | \"blue\";\ntype RGB = [red: number, green: number, blue: number];\n\ntype StringColorPalette = Record&lt;StringColor, string>;\ntype RGBColorPalette = Record&lt;RGBColor, RGB>;\ntype Palette = StringColorPalette &amp; RGBColorPalette;\n\nconst palette: Palette = {\n    red: [255, 0, 0],\n    green: \"#00ff00\",\n    blue: [0, 0, 255]\n};\n\nconst redComponent = palette.red.at(0);\nconst greenNormalized = palette.green.toUpperCase();<\/code><\/pre>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Obej\u015bciem tego problemu ma by\u0107 nowy operator satisfies, kt\u00f3ry b\u0119dzie walidowa\u0142 typ w momencie przypisania, ale nie b\u0119dzie mia\u0142 wp\u0142ywu na typ ewaluowany przez TypeScript. Brzmi skomplikowanie, ale na prostym przyk\u0142adzie dobrze wida\u0107, o co chodzi:<\/p>\n","innerContent":["\n<p>Obej\u015bciem tego problemu ma by\u0107 nowy operator satisfies, kt\u00f3ry b\u0119dzie walidowa\u0142 typ w momencie przypisania, ale nie b\u0119dzie mia\u0142 wp\u0142ywu na typ ewaluowany przez TypeScript. Brzmi skomplikowanie, ale na prostym przyk\u0142adzie dobrze wida\u0107, o co chodzi:<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"prismatic\/blocks","attrs":{"language":"typescript"},"innerBlocks":[],"innerHTML":"\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">\ntype Color = \"red\" | \"green\" | \"blue\";\ntype RGB = [red: number, green: number, blue: number];\n\ntype Palette = Record&lt;Color, string | RGB>\n\nconst palette = {\n    red: [255, 0, 0],\n    green: \"#00ff00\",\n    blue: [0, 0, 255]\n} satisfies Palette;\n\n\/\/ Both of these methods are still accessible!\nconst redComponent = palette.red.at(0);\nconst greenNormalized = palette.green.toUpperCase();\n\n\/\/ \u2014-----------------------------------\n\/\/ Example errors caught by satisfies\n\/\/  \u2014-----------------------------------\n\nconst spelloPalette = {\n    red: [255, 0, 0],\n    green: \"#00ff00\",\n    bleu: [0, 0, 255] \/\/ Such typos are now caught\n} satisfies Palette;\n\n\/\/ Missing properties are now caught\nconst missingColorPalette = {\n    red: [255, 0, 0],\n    bleu: [0, 0, 255]\n} satisfies Palette;\n\nconst wrongColorTypePalette = {\n    red: [255, 0], \/\/ Such typos are now also caught\n    green: \"#00ff00\",\n    bleu: [0, 0, 255]\n} satisfies Palette;<\/code><\/pre>\n","innerContent":["\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">\ntype Color = \"red\" | \"green\" | \"blue\";\ntype RGB = [red: number, green: number, blue: number];\n\ntype Palette = Record&lt;Color, string | RGB>\n\nconst palette = {\n    red: [255, 0, 0],\n    green: \"#00ff00\",\n    blue: [0, 0, 255]\n} satisfies Palette;\n\n\/\/ Both of these methods are still accessible!\nconst redComponent = palette.red.at(0);\nconst greenNormalized = palette.green.toUpperCase();\n\n\/\/ \u2014-----------------------------------\n\/\/ Example errors caught by satisfies\n\/\/  \u2014-----------------------------------\n\nconst spelloPalette = {\n    red: [255, 0, 0],\n    green: \"#00ff00\",\n    bleu: [0, 0, 255] \/\/ Such typos are now caught\n} satisfies Palette;\n\n\/\/ Missing properties are now caught\nconst missingColorPalette = {\n    red: [255, 0, 0],\n    bleu: [0, 0, 255]\n} satisfies Palette;\n\nconst wrongColorTypePalette = {\n    red: [255, 0], \/\/ Such typos are now also caught\n    green: \"#00ff00\",\n    bleu: [0, 0, 255]\n} satisfies Palette;<\/code><\/pre>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/image","attrs":{"align":"center","id":12281,"sizeSlug":"full","linkDestination":"none"},"innerBlocks":[],"innerHTML":"\n<figure class=\"wp-block-image aligncenter size-full\"><img src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/7169wt.jpeg\" alt=\"\" class=\"wp-image-12281\"\/><\/figure>\n","innerContent":["\n<figure class=\"wp-block-image aligncenter size-full\"><img src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/7169wt.jpeg\" alt=\"\" class=\"wp-image-12281\"\/><\/figure>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/heading","attrs":{"level":3},"innerBlocks":[],"innerHTML":"\n<h3>Auto-Accessors<\/h3>\n","innerContent":["\n<h3>Auto-Accessors<\/h3>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>TypeScript 4.9 wprowadza jeszcze jedno nowe s\u0142owo kluczowe `accessor`. Za jego pomoc\u0105 mo\u017cliwe b\u0119dzie zdefiniowanie pola w klasie, kt\u00f3re pod spodem b\u0119dzie prywatn\u0105 zmienn\u0105 zapakowan\u0105 w getter i setter. Po co to wszystko? Jak si\u0119 okazuje, jest to przygotowanie na dekoratory, kt\u00f3re obecnie znajduj\u0105 si\u0119 w 3 fazie procesu TC39.<\/p>\n","innerContent":["\n<p>TypeScript 4.9 wprowadza jeszcze jedno nowe s\u0142owo kluczowe `accessor`. Za jego pomoc\u0105 mo\u017cliwe b\u0119dzie zdefiniowanie pola w klasie, kt\u00f3re pod spodem b\u0119dzie prywatn\u0105 zmienn\u0105 zapakowan\u0105 w getter i setter. Po co to wszystko? Jak si\u0119 okazuje, jest to przygotowanie na dekoratory, kt\u00f3re obecnie znajduj\u0105 si\u0119 w 3 fazie procesu TC39.<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"prismatic\/blocks","attrs":{"language":"typescript"},"innerBlocks":[],"innerHTML":"\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">class Person {\n  accessor name: string;\n\n  constructor(name: string) {\n    this.name = name;\n  }\n}\n\nclass Person {\n  #__name: string;\n\n  get name() {\n    return this.#__name;\n  }\n  set name(value: string) {\n    this.#__name = name;\n  }\n\n  constructor(name: string) {\n    this.name = name;\n  }\n}<\/code><\/pre>\n","innerContent":["\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">class Person {\n  accessor name: string;\n\n  constructor(name: string) {\n    this.name = name;\n  }\n}\n\nclass Person {\n  #__name: string;\n\n  get name() {\n    return this.#__name;\n  }\n  set name(value: string) {\n    this.#__name = name;\n  }\n\n  constructor(name: string) {\n    this.name = name;\n  }\n}<\/code><\/pre>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/heading","attrs":{"level":3},"innerBlocks":[],"innerHTML":"\n<h3>Usprawnione por\u00f3wnania z NaN<\/h3>\n","innerContent":["\n<h3>Usprawnione por\u00f3wnania z NaN<\/h3>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Co do tego, \u017ce JavaScript to szalony j\u0119zyk, chyba wszyscy si\u0119 zgodzimy. W ko\u0144cu w jakim innym j\u0119zyku mog\u0142oby wydarzy\u0107 si\u0119 co\u015b takiego:<\/p>\n","innerContent":["\n<p>Co do tego, \u017ce JavaScript to szalony j\u0119zyk, chyba wszyscy si\u0119 zgodzimy. W ko\u0144cu w jakim innym j\u0119zyku mog\u0142oby wydarzy\u0107 si\u0119 co\u015b takiego:<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/image","attrs":{"align":"center","id":12283,"sizeSlug":"full","linkDestination":"none"},"innerBlocks":[],"innerHTML":"\n<figure class=\"wp-block-image aligncenter size-full\"><img src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/716a9u.jpeg\" alt=\"\" class=\"wp-image-12283\"\/><\/figure>\n","innerContent":["\n<figure class=\"wp-block-image aligncenter size-full\"><img src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/716a9u.jpeg\" alt=\"\" class=\"wp-image-12283\"\/><\/figure>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Dzisiaj nie b\u0119dziemy jednak rozmawia\u0107 o tym, a o por\u00f3wnaniach z <code>NaN<\/code> (Not a Number). W wi\u0119kszo\u015bci j\u0119zyk\u00f3w obs\u0142uguj\u0105cych zmienne zmiennoprzecinkowe, zak\u0142ada si\u0119, \u017ce nic nie mo\u017ce by\u0107 r\u00f3wne <code>NaN<\/code> - nawet inna instancja <code>NaN<\/code><\/p>\n","innerContent":["\n<p>Dzisiaj nie b\u0119dziemy jednak rozmawia\u0107 o tym, a o por\u00f3wnaniach z <code>NaN<\/code> (Not a Number). W wi\u0119kszo\u015bci j\u0119zyk\u00f3w obs\u0142uguj\u0105cych zmienne zmiennoprzecinkowe, zak\u0142ada si\u0119, \u017ce nic nie mo\u017ce by\u0107 r\u00f3wne <code>NaN<\/code> - nawet inna instancja <code>NaN<\/code><\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"prismatic\/blocks","attrs":{"language":"typescript"},"innerBlocks":[],"innerHTML":"\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">NaN == 0    \/\/ false\nNaN == Nan  \/\/ false\nNaN === Nan \/\/ false<\/code><\/pre>\n","innerContent":["\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">NaN == 0    \/\/ false\nNaN == Nan  \/\/ false\nNaN === Nan \/\/ false<\/code><\/pre>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Dosy\u0107 cz\u0119stym b\u0142\u0119dem, kt\u00f3ry \u0142atwo przeoczy\u0107 jest wi\u0119c bezpo\u015brednie por\u00f3wnywanie z `NaN`. TypeScript 4.9 b\u0119dzie nas skrupulatnie przed tym chroni\u0142 zwracaj\u0105c odpowiedni b\u0142\u0105d.<\/p>\n","innerContent":["\n<p>Dosy\u0107 cz\u0119stym b\u0142\u0119dem, kt\u00f3ry \u0142atwo przeoczy\u0107 jest wi\u0119c bezpo\u015brednie por\u00f3wnywanie z `NaN`. TypeScript 4.9 b\u0119dzie nas skrupulatnie przed tym chroni\u0142 zwracaj\u0105c odpowiedni b\u0142\u0105d.<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"prismatic\/blocks","attrs":{"language":"typescript"},"innerBlocks":[],"innerHTML":"\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">function validate(someValue: number) {\n  return someValue !== NaN;\n  \/\/     ~~~~~~~~~~~~~~~~~\n  \/\/ error: This condition will always return 'true'.\n  \/\/        Did you mean '!Number.isNaN(someValue)'?\n}<\/code><\/pre>\n","innerContent":["\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">function validate(someValue: number) {\n  return someValue !== NaN;\n  \/\/     ~~~~~~~~~~~~~~~~~\n  \/\/ error: This condition will always return 'true'.\n  \/\/        Did you mean '!Number.isNaN(someValue)'?\n}<\/code><\/pre>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/heading","attrs":{"level":3},"innerBlocks":[],"innerHTML":"\n<h3>Co przyniesie TypeScript 5.0?<\/h3>\n","innerContent":["\n<h3>Co przyniesie TypeScript 5.0?<\/h3>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Kolejna wersja TypeScript nad kt\u00f3r\u0105 rozpocz\u0119to ju\u017c prace b\u0119dzie oznaczona numerkiem 5.0. Nale\u017cy jednak pami\u0119ta\u0107, \u017ce TypeScript nie stosuje konwencji Semantic Versioning i nie koniecznie oznacza to, \u017ce wersja ta zawiera\u0107 b\u0119dzie breaking changes. Przegl\u0105daj\u0105c repozytorium projektu mo\u017cemy ju\u017c zobaczy\u0107 co szykuj\u0105 dla nas ludzie z Microsoft. W skr\u00f3cie, kompilator przepisany zosta\u0142 z archaicznych namespaces na modu\u0142y. Dzi\u0119ki temu kompilator uruchamia si\u0119 mi\u0119dzy 10-25% szybciej, a paczka zosta\u0142a odchudzona o prawie 50%.<\/p>\n","innerContent":["\n<p>Kolejna wersja TypeScript nad kt\u00f3r\u0105 rozpocz\u0119to ju\u017c prace b\u0119dzie oznaczona numerkiem 5.0. Nale\u017cy jednak pami\u0119ta\u0107, \u017ce TypeScript nie stosuje konwencji Semantic Versioning i nie koniecznie oznacza to, \u017ce wersja ta zawiera\u0107 b\u0119dzie breaking changes. Przegl\u0105daj\u0105c repozytorium projektu mo\u017cemy ju\u017c zobaczy\u0107 co szykuj\u0105 dla nas ludzie z Microsoft. W skr\u00f3cie, kompilator przepisany zosta\u0142 z archaicznych namespaces na modu\u0142y. Dzi\u0119ki temu kompilator uruchamia si\u0119 mi\u0119dzy 10-25% szybciej, a paczka zosta\u0142a odchudzona o prawie 50%.<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/heading","attrs":{"level":3},"innerBlocks":[],"innerHTML":"\n<h3>\u0179r\u00f3d\u0142a:<\/h3>\n","innerContent":["\n<h3>\u0179r\u00f3d\u0142a:<\/h3>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p><a href=\"https:\/\/devblogs.microsoft.com\/typescript\/announcing-typescript-4-9\/\">https:\/\/devblogs.microsoft.com\/typescript\/announcing-typescript-4-9\/<\/a><\/p>\n","innerContent":["\n<p><a href=\"https:\/\/devblogs.microsoft.com\/typescript\/announcing-typescript-4-9\/\">https:\/\/devblogs.microsoft.com\/typescript\/announcing-typescript-4-9\/<\/a><\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/heading","attrs":[],"innerBlocks":[],"innerHTML":"\n<h2>3. Deno 1.28 z wsparciem dla npm<\/h2>\n","innerContent":["\n<h2>3. Deno 1.28 z wsparciem dla npm<\/h2>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Piek\u0142o oficjalnie zamarz\u0142o! Deno, czyli projekt, kt\u00f3ry mia\u0142 naprawi\u0107 wszystkie b\u0142\u0119dy Node.js, dosta\u0142 wsparcie dla npm. Po latach pr\u00f3b odci\u0119cia si\u0119 od najpopularniejszego repozytorium JavaScript tw\u00f3rcy zaakceptowali, \u017ce pomimo jego wielu wad, bez npm ci\u0119\u017cko \u017cy\u0107.&nbsp;<\/p>\n","innerContent":["\n<p>Piek\u0142o oficjalnie zamarz\u0142o! Deno, czyli projekt, kt\u00f3ry mia\u0142 naprawi\u0107 wszystkie b\u0142\u0119dy Node.js, dosta\u0142 wsparcie dla npm. Po latach pr\u00f3b odci\u0119cia si\u0119 od najpopularniejszego repozytorium JavaScript tw\u00f3rcy zaakceptowali, \u017ce pomimo jego wielu wad, bez npm ci\u0119\u017cko \u017cy\u0107.&nbsp;<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Nie dajcie si\u0119 jednak zmyli\u0107 - npm w po\u0142\u0105czeniu z Deno b\u0119dzie dzia\u0142a\u0142 zupe\u0142nie inaczej ni\u017c w po\u0142\u0105czeniu z Node.js. Po pierwsze, Deno nie b\u0119dzie wymaga\u0107 uruchamiania `npm install`, ani \u017cadnej innej komendy npm. Po drugie, Deno nie b\u0119dzie tworzy\u0107 katalogu node_modules,a pobrane paczki przechowywane b\u0119d\u0105 globalnie. Po trzecie, importy z npm b\u0119d\u0105 oznaczone specjalnym prefixem `npm:`<\/p>\n","innerContent":["\n<p>Nie dajcie si\u0119 jednak zmyli\u0107 - npm w po\u0142\u0105czeniu z Deno b\u0119dzie dzia\u0142a\u0142 zupe\u0142nie inaczej ni\u017c w po\u0142\u0105czeniu z Node.js. Po pierwsze, Deno nie b\u0119dzie wymaga\u0107 uruchamiania `npm install`, ani \u017cadnej innej komendy npm. Po drugie, Deno nie b\u0119dzie tworzy\u0107 katalogu node_modules,a pobrane paczki przechowywane b\u0119d\u0105 globalnie. Po trzecie, importy z npm b\u0119d\u0105 oznaczone specjalnym prefixem `npm:`<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"prismatic\/blocks","attrs":{"language":"typescript"},"innerBlocks":[],"innerHTML":"\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">import { chalk } from \"npm:chalk@5\";<\/code><\/pre>\n","innerContent":["\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">import { chalk } from \"npm:chalk@5\";<\/code><\/pre>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Dlaczego decyzja o dodaniu wsparcia dla npm zapad\u0142a w\u0142a\u015bnie teraz? Moim zdaniem, przede wszystkim dlatego, \u017ce jest to s\u0142uszna decyzja. Je\u015bli jednak lubicie filmy z \u017c\u00f3\u0142tymi napisami, to istnieje jeszcze jedna teoria.<\/p>\n","innerContent":["\n<p>Dlaczego decyzja o dodaniu wsparcia dla npm zapad\u0142a w\u0142a\u015bnie teraz? Moim zdaniem, przede wszystkim dlatego, \u017ce jest to s\u0142uszna decyzja. Je\u015bli jednak lubicie filmy z \u017c\u00f3\u0142tymi napisami, to istnieje jeszcze jedna teoria.<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/image","attrs":{"align":"center","id":12285,"sizeSlug":"full","linkDestination":"none"},"innerBlocks":[],"innerHTML":"\n<figure class=\"wp-block-image aligncenter size-full\"><img src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/download-49.jpeg\" alt=\"\" class=\"wp-image-12285\"\/><\/figure>\n","innerContent":["\n<figure class=\"wp-block-image aligncenter size-full\"><img src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/download-49.jpeg\" alt=\"\" class=\"wp-image-12285\"\/><\/figure>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Wok\u00f3\u0142 Deno zbudowany zosta\u0142a ca\u0142kiem poka\u017ana firma. Do tej pory zgromadzi\u0142a ona od szeregu inwestor\u00f3w ponad 25M$. Na samym rozwoju silnika uruchomieniowego JavaScript ci\u0119\u017cko zarabia\u0107, dlatego firma skupi\u0142a si\u0119 na rozbudowie infrastruktury chmurowej. Efektem ponad roku prac jest chmura Deno Deploy. Znalaz\u0142a ona ju\u017c pierwszych komercyjnych klient\u00f3w w postaci Supabase (otwarto\u017ar\u00f3d\u0142owa alternatywa dla Firebase) czy Netlify, kt\u00f3rzy swoje Edge Functions postanowili oprze\u0107 w\u0142a\u015bnie o Deno Deploy. Wraz z zewn\u0119trznymi inwestorami i klientami przychodz\u0105 oczekiwania wzrostu. Deno wok\u00f3\u0142 idei lepszego Node.js zbudowa\u0142 naprawd\u0119 du\u017co. Wydaje si\u0119 jednak, \u017ce bez sensownej integracji z npm dalszy rozw\u00f3j nie by\u0142 mo\u017cliwy.<\/p>\n","innerContent":["\n<p>Wok\u00f3\u0142 Deno zbudowany zosta\u0142a ca\u0142kiem poka\u017ana firma. Do tej pory zgromadzi\u0142a ona od szeregu inwestor\u00f3w ponad 25M$. Na samym rozwoju silnika uruchomieniowego JavaScript ci\u0119\u017cko zarabia\u0107, dlatego firma skupi\u0142a si\u0119 na rozbudowie infrastruktury chmurowej. Efektem ponad roku prac jest chmura Deno Deploy. Znalaz\u0142a ona ju\u017c pierwszych komercyjnych klient\u00f3w w postaci Supabase (otwarto\u017ar\u00f3d\u0142owa alternatywa dla Firebase) czy Netlify, kt\u00f3rzy swoje Edge Functions postanowili oprze\u0107 w\u0142a\u015bnie o Deno Deploy. Wraz z zewn\u0119trznymi inwestorami i klientami przychodz\u0105 oczekiwania wzrostu. Deno wok\u00f3\u0142 idei lepszego Node.js zbudowa\u0142 naprawd\u0119 du\u017co. Wydaje si\u0119 jednak, \u017ce bez sensownej integracji z npm dalszy rozw\u00f3j nie by\u0142 mo\u017cliwy.<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/image","attrs":{"align":"center","id":12287,"sizeSlug":"full","linkDestination":"none"},"innerBlocks":[],"innerHTML":"\n<figure class=\"wp-block-image aligncenter size-full\"><img src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/frontend101-image10.jpeg\" alt=\"\" class=\"wp-image-12287\"\/><\/figure>\n","innerContent":["\n<figure class=\"wp-block-image aligncenter size-full\"><img src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/frontend101-image10.jpeg\" alt=\"\" class=\"wp-image-12287\"\/><\/figure>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Je\u015bli naprawd\u0119 lubicie filmy z \u017c\u00f3\u0142tym napisami, to istnieje jeszcze jedna teoria. Pod koniec wakacji na rynku pojawi\u0142 si\u0119 nowy gracz w postaci Bun.js. Jest to alternatywa typu drop-in dla Node.js, napisana w szybkim j\u0119zyku Zig i oparta o silnik JavaScriptCore. O ile Deno sw\u00f3j marketing skupia na rozwi\u0105zywaniu problem\u00f3w Node.js, to Bun stawia nacisk na wydajno\u015b\u0107.&nbsp;<\/p>\n","innerContent":["\n<p>Je\u015bli naprawd\u0119 lubicie filmy z \u017c\u00f3\u0142tym napisami, to istnieje jeszcze jedna teoria. Pod koniec wakacji na rynku pojawi\u0142 si\u0119 nowy gracz w postaci Bun.js. Jest to alternatywa typu drop-in dla Node.js, napisana w szybkim j\u0119zyku Zig i oparta o silnik JavaScriptCore. O ile Deno sw\u00f3j marketing skupia na rozwi\u0105zywaniu problem\u00f3w Node.js, to Bun stawia nacisk na wydajno\u015b\u0107.&nbsp;<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/image","attrs":{"align":"center","id":12289,"sizeSlug":"full","linkDestination":"none"},"innerBlocks":[],"innerHTML":"\n<figure class=\"wp-block-image aligncenter size-full\"><img src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/Screenshot-2022-08-04-at-15.06.18-1.png\" alt=\"\" class=\"wp-image-12289\"\/><\/figure>\n","innerContent":["\n<figure class=\"wp-block-image aligncenter size-full\"><img src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/Screenshot-2022-08-04-at-15.06.18-1.png\" alt=\"\" class=\"wp-image-12289\"\/><\/figure>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/image","attrs":{"id":12291,"sizeSlug":"full","linkDestination":"none"},"innerBlocks":[],"innerHTML":"\n<figure class=\"wp-block-image size-full\"><img src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/frontend101-image8.jpeg\" alt=\"\" class=\"wp-image-12291\"\/><\/figure>\n","innerContent":["\n<figure class=\"wp-block-image size-full\"><img src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/frontend101-image8.jpeg\" alt=\"\" class=\"wp-image-12291\"\/><\/figure>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Pocz\u0105tkowo Bun wydawa\u0142 si\u0119 chwilow\u0105 ciekawostk\u0105. W ci\u0105gu kilkutygodni przerodzi\u0142 si\u0119 jednak w pe\u0142noprawny startup, kt\u00f3ry zgromadzi\u0142 7M$. Oven (bo tak zdecydowa\u0142a si\u0119 nazwa\u0107 firm\u0119) przyj\u0105\u0142 strategi\u0119 bli\u017aniaczo podobn\u0105 do Deno Company. Firma zamierza przygotowa\u0107 architektur\u0119 chmurow\u0105 opart\u0105 o Bun, kt\u00f3r\u0105 sprzedawa\u0107 b\u0119d\u0105 klientom.<\/p>\n","innerContent":["\n<p>Pocz\u0105tkowo Bun wydawa\u0142 si\u0119 chwilow\u0105 ciekawostk\u0105. W ci\u0105gu kilkutygodni przerodzi\u0142 si\u0119 jednak w pe\u0142noprawny startup, kt\u00f3ry zgromadzi\u0142 7M$. Oven (bo tak zdecydowa\u0142a si\u0119 nazwa\u0107 firm\u0119) przyj\u0105\u0142 strategi\u0119 bli\u017aniaczo podobn\u0105 do Deno Company. Firma zamierza przygotowa\u0107 architektur\u0119 chmurow\u0105 opart\u0105 o Bun, kt\u00f3r\u0105 sprzedawa\u0107 b\u0119d\u0105 klientom.<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/image","attrs":{"align":"center","id":12293,"sizeSlug":"full","linkDestination":"none"},"innerBlocks":[],"innerHTML":"\n<figure class=\"wp-block-image aligncenter size-full\"><img src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/frontend102-3.jpeg\" alt=\"\" class=\"wp-image-12293\"\/><\/figure>\n","innerContent":["\n<figure class=\"wp-block-image aligncenter size-full\"><img src=\"https:\/\/vived.io\/wp-content\/uploads\/2022\/11\/frontend102-3.jpeg\" alt=\"\" class=\"wp-image-12293\"\/><\/figure>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Informacja o pracach nad dodaniem wsparcie dla npm w Deno zupe\u0142nie przypadkiem zbieg\u0142a si\u0119 w czasie z powstaniem firmy Oven, a fakt, \u017ce Bun.js wspiera npm na pewno nie mia\u0142 wp\u0142ywu na podj\u0119te decyzje<\/p>\n","innerContent":["\n<p>Informacja o pracach nad dodaniem wsparcie dla npm w Deno zupe\u0142nie przypadkiem zbieg\u0142a si\u0119 w czasie z powstaniem firmy Oven, a fakt, \u017ce Bun.js wspiera npm na pewno nie mia\u0142 wp\u0142ywu na podj\u0119te decyzje<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/heading","attrs":{"level":3},"innerBlocks":[],"innerHTML":"\n<h3>\u0179r\u00f3d\u0142a<\/h3>\n","innerContent":["\n<h3>\u0179r\u00f3d\u0142a<\/h3>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p><a href=\"https:\/\/deno.com\/blog\/v1.28\">https:\/\/deno.com\/blog\/v1.28<\/a><\/p>\n","innerContent":["\n<p><a href=\"https:\/\/deno.com\/blog\/v1.28\">https:\/\/deno.com\/blog\/v1.28<\/a><\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/heading","attrs":[],"innerBlocks":[],"innerHTML":"\n<h2>Bonus: Opera pierwsz\u0105 przegl\u0105dark\u0105 z wbudowanym TikTok\u2019iem<\/h2>\n","innerContent":["\n<h2>Bonus: Opera pierwsz\u0105 przegl\u0105dark\u0105 z wbudowanym TikTok\u2019iem<\/h2>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Nie przes\u0142yszeli\u015bcie si\u0119 - Opera jest pierwsz\u0105 przegl\u0105dark\u0105, kt\u00f3ra zintegrowa\u0142a si\u0119 z TikTok\u2019iem. Sta\u0142 si\u0119 on cz\u0119\u015bci\u0105 paska integracji, w\u015br\u00f3d kt\u00f3rych znajdziemy na przyk\u0142ad Twittera cze Messengera. Jak twierdz\u0105 tw\u00f3rcy przegl\u0105darki - ludzie, kt\u00f3rzy zacz\u0119li korzysta\u0107 z natywnych integracji wbudowanych w przegl\u0105dark\u0119, nie wracaj\u0105 ju\u017c do ich webowych odpowiednik\u00f3w. To jak, instalujemy teraz Oper\u0119, \u017ceby bez skrupu\u0142\u00f3w ogl\u0105da\u0107 TikTok\u2019a w pracy?<\/p>\n","innerContent":["\n<p>Nie przes\u0142yszeli\u015bcie si\u0119 - Opera jest pierwsz\u0105 przegl\u0105dark\u0105, kt\u00f3ra zintegrowa\u0142a si\u0119 z TikTok\u2019iem. Sta\u0142 si\u0119 on cz\u0119\u015bci\u0105 paska integracji, w\u015br\u00f3d kt\u00f3rych znajdziemy na przyk\u0142ad Twittera cze Messengera. Jak twierdz\u0105 tw\u00f3rcy przegl\u0105darki - ludzie, kt\u00f3rzy zacz\u0119li korzysta\u0107 z natywnych integracji wbudowanych w przegl\u0105dark\u0119, nie wracaj\u0105 ju\u017c do ich webowych odpowiednik\u00f3w. To jak, instalujemy teraz Oper\u0119, \u017ceby bez skrupu\u0142\u00f3w ogl\u0105da\u0107 TikTok\u2019a w pracy?<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/embed","attrs":{"url":"https:\/\/www.youtube.com\/watch?v=EeNsXkqP6TM&t=9s","type":"video","providerNameSlug":"youtube","responsive":true,"className":"wp-embed-aspect-16-9 wp-has-aspect-ratio"},"innerBlocks":[],"innerHTML":"\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\nhttps:\/\/www.youtube.com\/watch?v=EeNsXkqP6TM&amp;t=9s\n<\/div><\/figure>\n","innerContent":["\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\nhttps:\/\/www.youtube.com\/watch?v=EeNsXkqP6TM&amp;t=9s\n<\/div><\/figure>\n"]}],"_links":{"self":[{"href":"https:\/\/vived.io\/pl\/wp-json\/wp\/v2\/posts\/12266","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vived.io\/pl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vived.io\/pl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vived.io\/pl\/wp-json\/wp\/v2\/users\/12"}],"replies":[{"embeddable":true,"href":"https:\/\/vived.io\/pl\/wp-json\/wp\/v2\/comments?post=12266"}],"version-history":[{"count":11,"href":"https:\/\/vived.io\/pl\/wp-json\/wp\/v2\/posts\/12266\/revisions"}],"predecessor-version":[{"id":12318,"href":"https:\/\/vived.io\/pl\/wp-json\/wp\/v2\/posts\/12266\/revisions\/12318"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/vived.io\/pl\/wp-json\/wp\/v2\/media\/12302"}],"wp:attachment":[{"href":"https:\/\/vived.io\/pl\/wp-json\/wp\/v2\/media?parent=12266"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vived.io\/pl\/wp-json\/wp\/v2\/categories?post=12266"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vived.io\/pl\/wp-json\/wp\/v2\/tags?post=12266"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}