[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"categories-en":3,"post:\u002Fpost\u002Fstop-risking-your-frontend-the-ultimate-angular-22-architecture":37},[4,11,17,24,30],{"id":5,"slug":6,"name":7,"colorHex":8,"iconName":9,"postCount":10},"0e2c1225-f78a-4c20-8c93-998ab9dc93b9","frontend","Frontend","#40484f",null,25,{"id":12,"slug":13,"name":14,"colorHex":15,"iconName":9,"postCount":16},"bc8df70e-b7fb-4d89-a80c-fd458d36d58c","code-development","Code & Development","#8b5cf6",23,{"id":18,"slug":19,"name":20,"colorHex":21,"iconName":22,"postCount":23},"550e8400-e29b-41d4-a716-446655440001","inteligencia-artificial","Artificial Intelligence","#6366f1","brain",14,{"id":25,"slug":26,"name":27,"colorHex":28,"iconName":9,"postCount":29},"ea63b69c-2eb4-4100-81f3-70ce52d33743","tech-news","Tech News","#e50606",4,{"id":31,"slug":32,"name":33,"colorHex":34,"iconName":35,"postCount":36},"550e8400-e29b-41d4-a716-446655440017","how-to-guides","How-To & Guides","#be123c","book-open",2,{"post":38,"related":2083,"translations":2154,"resolved":9},{"id":39,"slug":40,"title":41,"excerpt":42,"image":43,"featured":44,"groupId":45,"publishedAt":46,"readingTime":47,"views":36,"author":48,"category":50,"tags":51,"contentJson":61,"metaTitle":2080,"metaDescription":2081,"updatedAt":2082},"980f3f66-7eec-4089-84f5-cd6515a3e9d1","stop-risking-your-frontend-the-ultimate-angular-22-architecture","Stop risking your frontend: the ultimate Angular 22 architecture","Angular 22 is here. Discover how the latest architectural shifts and native reactivity primitives make it the ultimate choice for enterprise systems.","https:\u002F\u002Fmfgiomkkbihnlpfdxwrt.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fblog-assets\u002Fmedia\u002Ffeatured\u002F1783664697703-featured-bp1wut.webp",false,"9baf202d-f92f-4667-a3a3-8090369c1c0b","2026-07-10T06:25:52.559647+00:00",16,{"name":49,"avatar":9},"Genildo Souza",{"slug":13,"name":14,"color":15},[52,55,58],{"slug":53,"name":54},"angular","Angular",{"slug":56,"name":57},"nextjs","Next.js",{"slug":59,"name":60},"javascript","JavaScript",{"type":62,"content":63},"doc",[64,82,84,91,97,103,121,127,141,155,156,162,168,175,188,194,222,228,246,252,264,270,276,282,305,306,326,348,356,365,373,380,381,387,395,396,402,409,410,416,422,428,434,442,448,455,461,468,474,481,487,494,500,507,513,527,534,535,541,547,557,563,569,575,581,587,593,599,605,606,612,870,884,885,891,897,903,910,916,923,929,935,1025,1031,1037,1044,1050,1056,1063,1064,1070,1100,1106,1121,1149,1176,1198,1204,1211,1217,1529,1530,1536,1542,1619,1625,1671,1672,1678,1690,1696,1702,1710,1764,1772,1816,1817,1823,2070,2071],{"type":65,"attrs":66,"content":68},"blockquote",{"id":67},"quote_r7itatdo",[69],{"type":70,"attrs":71,"content":73},"paragraph",{"id":72},"p_dh8to6wv",[74,80],{"text":75,"type":76,"marks":77},"Technical guide · Enterprise framework · Angular 22 · June 2026","text",[78],{"type":79},"bold",{"text":81,"type":76}," Current stable: Angular 22.0 (released June 3, 2026)",{"type":83},"horizontalRule",{"type":85,"attrs":86,"content":88},"heading",{"id":87,"level":36},"h_3kon7i8m",[89],{"text":90,"type":76},"The Strategic Decision",{"type":70,"attrs":92,"content":94},{"id":93},"p_1qnythek",[95],{"text":96,"type":76},"Angular is not a developer choice. It is an organizational choice.",{"type":70,"attrs":98,"content":100},{"id":99},"p_pcnhn6ay",[101],{"text":102,"type":76},"When a team of 5 picks Angular, they are in practice deciding how a team of 50 will work three years from now. Few stack decisions carry that weight.",{"type":70,"attrs":104,"content":106},{"id":105},"p_7prgtbvm",[107,109,113,115,119],{"text":108,"type":76},"Angular is ",{"text":110,"type":76,"marks":111},"opinionated by design",[112],{"type":79},{"text":114,"type":76},". It prescribes how to structure modules (or standalone components), how to inject dependencies, how to handle routing, forms, testing, HTTP, and internationalization. For teams that value flexibility, this sounds like a constraint. For teams that value consistency, it sounds like ",{"text":116,"type":76,"marks":117},"freedom from having to decide all those things every time",[118],{"type":79},{"text":120,"type":76},".",{"type":70,"attrs":122,"content":124},{"id":123},"p_zj0zx680",[125],{"text":126,"type":76},"That is the real divide. Angular does not compete with React on learning speed or ecosystem size — and it shouldn't. It competes on something different: the ability of a 100K-line Angular codebase to be navigable by an engineer who has never seen it before, because the conventions are enforced by the framework, not by team discipline.",{"type":65,"attrs":128,"content":130},{"id":129},"quote_0bzyctro",[131],{"type":70,"attrs":132,"content":134},{"id":133},"p_cz3nvqzi",[135,139],{"text":136,"type":76,"marks":137},"The 2026 context:",[138],{"type":79},{"text":140,"type":76}," Angular 22 (June 2026) stabilized Signal Forms and Angular Aria, made zoneless the default for all new projects, and promoted the MCP server to stable. After years of criticism about learning curve and Zone.js, Angular underwent an architectural transformation that closed approximately 80% of the runtime performance gap versus vanilla JS in the krausest js-framework-benchmark. The question is no longer \"Is Angular still relevant?\" — it's \"Does my problem fit what Angular solves best?\"",{"type":65,"attrs":142,"content":144},{"id":143},"quote_qjeysshh",[145],{"type":70,"attrs":146,"content":148},{"id":147},"p_cfxdan3a",[149,153],{"text":150,"type":76,"marks":151},"\"Architecture is what remains when the feature is done.\"",[152],{"type":79},{"text":154,"type":76}," Angular is for teams that take that seriously.",{"type":83},{"type":85,"attrs":157,"content":159},{"id":158,"level":36},"h_eie67eme",[160],{"text":161,"type":76},"The Framework Pillars",{"type":70,"attrs":163,"content":165},{"id":164},"p_aevpmvtt",[166],{"text":167,"type":76},"Angular delivers a complete framework, not a library. Everything other stacks assemble from external pieces, Angular ships integrated and tested together.",{"type":85,"attrs":169,"content":172},{"id":170,"level":171},"h_dyj37qud",3,[173],{"text":174,"type":76},"Dependency Injection",{"type":70,"attrs":176,"content":178},{"id":177},"p_slsrjqnx",[179,181,186],{"text":180,"type":76},"Hierarchical DI built into the framework core. Services, repositories, guards, interceptors — all declared with ",{"text":182,"type":76,"marks":183},"@Injectable",[184],{"type":185},"code",{"text":187,"type":76}," and resolved automatically. Enables test substitution without manual mocks and genuine modularization of responsibilities.",{"type":85,"attrs":189,"content":191},{"id":190,"level":171},"h_9yc2rcju",[192],{"text":193,"type":76},"Signals (Stable since v20)",{"type":70,"attrs":195,"content":197},{"id":196},"p_8rolgfar",[198,202,204,208,210,214,216,220],{"text":199,"type":76,"marks":200},"signal()",[201],{"type":185},{"text":203,"type":76},", ",{"text":205,"type":76,"marks":206},"computed()",[207],{"type":185},{"text":209,"type":76},", and ",{"text":211,"type":76,"marks":212},"effect()",[213],{"type":185},{"text":215,"type":76}," are production-stable. Automatic dependency tracking without manual arrays. Signal Forms (experimental in v21, ",{"text":217,"type":76,"marks":218},"stable in v22",[219],{"type":79},{"text":221,"type":76},") replaces the RxJS\u002FFormControl pattern with a simpler, more performant API.",{"type":85,"attrs":223,"content":225},{"id":224,"level":171},"h_yzr5c99r",[226],{"text":227,"type":76},"Zoneless Change Detection (Default since v21)",{"type":70,"attrs":229,"content":231},{"id":230},"p_slg4n7e7",[232,234,238,240,244],{"text":233,"type":76},"New projects generated with ",{"text":235,"type":76,"marks":236},"ng new",[237],{"type":185},{"text":239,"type":76}," exclude Zone.js by default. The change reduces bundle size, cleans up stack traces, and improves interoperability. Existing projects migrate gradually via schematics using the ",{"text":241,"type":76,"marks":242},"onpush_zoneless_migration",[243],{"type":185},{"text":245,"type":76}," tool from the Angular MCP server.",{"type":85,"attrs":247,"content":249},{"id":248,"level":171},"h_13qrlxjn",[250],{"text":251,"type":76},"Standalone Components (Default since v17)",{"type":70,"attrs":253,"content":255},{"id":254},"p_avzbjyzq",[256,258,262],{"text":257,"type":76},"Components, pipes, and directives self-declare without ",{"text":259,"type":76,"marks":260},"NgModule",[261],{"type":185},{"text":263,"type":76},". Eliminates the boilerplate that was Angular's most common criticism for years. Enables per-component lazy loading, more efficient tree-shaking, and more explicit composition.",{"type":85,"attrs":265,"content":267},{"id":266,"level":171},"h_5q9dfbgw",[268],{"text":269,"type":76},"Routing",{"type":70,"attrs":271,"content":273},{"id":272},"p_qv7zw8v3",[274],{"text":275,"type":76},"Declarative routing with lazy loading, guards, resolvers, and route-level render mode (SSR, CSR, prerender per route — stable since v20). No library choice required: the official router works with SSR, animations, and the Angular CDK by design.",{"type":85,"attrs":277,"content":279},{"id":278,"level":171},"h_ojhfyoxo",[280],{"text":281,"type":76},"Forms",{"type":70,"attrs":283,"content":285},{"id":284},"p_iujccy8x",[286,288,292,294,297,299,303],{"text":287,"type":76},"Two form models included. Reactive Forms (RxJS-based) is the current standard for complexity. Signal Forms (",{"text":289,"type":76,"marks":290},"@angular\u002Fforms\u002Fsignals",[291],{"type":185},{"text":293,"type":76},") is ",{"text":217,"type":76,"marks":295},[296],{"type":79},{"text":298,"type":76}," — eliminates the ",{"text":300,"type":76,"marks":301},"valueChanges.pipe(…takeUntil(this.destroy$))",[302],{"type":185},{"text":304,"type":76}," pattern every Angular dev has written dozens of times.",{"type":83},{"type":85,"attrs":307,"content":309},{"id":308,"level":171},"h_nyvoi3qo",[310,312,316,317,321,322],{"text":311,"type":76},"Modern Template Syntax: ",{"text":313,"type":76,"marks":314},"@if",[315],{"type":185},{"text":203,"type":76},{"text":318,"type":76,"marks":319},"@for",[320],{"type":185},{"text":203,"type":76},{"text":323,"type":76,"marks":324},"@switch",[325],{"type":185},{"type":70,"attrs":327,"content":329},{"id":328},"p_2wwx6ei6",[330,332,336,337,341,342,346],{"text":331,"type":76},"Angular 17 replaced ",{"text":333,"type":76,"marks":334},"*ngIf",[335],{"type":185},{"text":203,"type":76},{"text":338,"type":76,"marks":339},"*ngFor",[340],{"type":185},{"text":209,"type":76},{"text":343,"type":76,"marks":344},"*ngSwitch",[345],{"type":185},{"text":347,"type":76}," with a native block syntax. The old directives were deprecated in v20 and will be removed in future versions.",{"type":70,"attrs":349,"content":351},{"id":350},"p_3vb6t58l",[352],{"text":353,"type":76,"marks":354},"Before — old directives (deprecated):",[355],{"type":79},{"type":357,"attrs":358,"content":362},"codeBlock",{"id":359,"language":360,"highlighted":361},"code_h6huokvz","html","\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">&#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#22863A;--shiki-dark:#85E89D\">div\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> *ngIf\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">\"user; else loading\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  &#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#22863A;--shiki-dark:#85E89D\">div\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> *ngFor\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">\"let item of items; trackBy: trackFn\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">    {{ item.name }}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  &#x3C;\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#22863A;--shiki-dark:#85E89D\">div\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">&#x3C;\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#22863A;--shiki-dark:#85E89D\">div\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">&#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#22863A;--shiki-dark:#85E89D\">ng-template\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> #loading\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  Loading...\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">&#x3C;\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#22863A;--shiki-dark:#85E89D\">ng-template\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>",[363],{"text":364,"type":76},"\u003Cdiv *ngIf=\"user; else loading\">\n  \u003Cdiv *ngFor=\"let item of items; trackBy: trackFn\">\n    {{ item.name }}\n  \u003C\u002Fdiv>\n\u003C\u002Fdiv>\n\u003Cng-template #loading>\n  Loading...\n\u003C\u002Fng-template>\n",{"type":70,"attrs":366,"content":368},{"id":367},"p_bja4ormk",[369],{"text":370,"type":76,"marks":371},"After — block syntax (v17+):",[372],{"type":79},{"type":357,"attrs":374,"content":377},{"id":375,"language":360,"highlighted":376},"code_z3kwy7i8","\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">@if (user) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  @for (item of items; track item.id) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">    &#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#22863A;--shiki-dark:#85E89D\">div\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">>{{ item.name }}&#x3C;\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#22863A;--shiki-dark:#85E89D\">div\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">} @else {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  &#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#22863A;--shiki-dark:#85E89D\">div\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">>Loading...&#x3C;\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#22863A;--shiki-dark:#85E89D\">div\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>",[378],{"text":379,"type":76},"@if (user) {\n  @for (item of items; track item.id) {\n    \u003Cdiv>{{ item.name }}\u003C\u002Fdiv>\n  }\n} @else {\n  \u003Cdiv>Loading...\u003C\u002Fdiv>\n}\n",{"type":83},{"type":85,"attrs":382,"content":384},{"id":383,"level":171},"h_cha1ht8h",[385],{"text":386,"type":76},"Signals: From Zone.js to Fine-Grained Reactivity",{"type":357,"attrs":388,"content":392},{"id":389,"language":390,"highlighted":391},"code_9qhe9bbb","typescript","\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F BEFORE: Zone.js + ChangeDetectorRef\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">@\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">Component\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">({ changeDetection: ChangeDetectionStrategy.OnPush })\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">export\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> class\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> CounterComponent\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">  counter\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 0\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  constructor\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">private\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\"> cdr\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">:\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> ChangeDetectorRef\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">) {}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">  increment\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">() {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">    this\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">.counter\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">++\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">    this\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">.cdr.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">detectChanges\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(); \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F manual trigger\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F AFTER: Signals (Angular 20+ stable)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">@\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">Component\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">({ standalone: \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">true\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> })\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">export\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> class\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> CounterComponent\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">  counter\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> signal\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">);                      \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F signal primitive\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">  double\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> computed\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(() \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> this\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">counter\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">() \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">*\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 2\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">); \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F derived, lazy\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">  increment\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">() {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">    this\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">.counter.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">update\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">v\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> v \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">+\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 1\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">);       \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F no manual trigger\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">    \u002F\u002F Angular detects automatically via reactive graph\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F Zoneless — app.config.ts (default in new Angular 22 projects)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">export\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> appConfig\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">:\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> ApplicationConfig\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  providers: [\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">    provideZonelessChangeDetection\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(),\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">    provideBrowserGlobalErrorListeners\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(),\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">    provideRouter\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(routes),\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  ]\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">};\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>",[393],{"text":394,"type":76},"\u002F\u002F BEFORE: Zone.js + ChangeDetectorRef\n@Component({ changeDetection: ChangeDetectionStrategy.OnPush })\nexport class CounterComponent {\n  counter = 0;\n  constructor(private cdr: ChangeDetectorRef) {}\n\n  increment() {\n    this.counter++;\n    this.cdr.detectChanges(); \u002F\u002F manual trigger\n  }\n}\n\n\u002F\u002F AFTER: Signals (Angular 20+ stable)\n@Component({ standalone: true })\nexport class CounterComponent {\n  counter = signal(0);                      \u002F\u002F signal primitive\n  double  = computed(() => this.counter() * 2); \u002F\u002F derived, lazy\n\n  increment() {\n    this.counter.update(v => v + 1);       \u002F\u002F no manual trigger\n    \u002F\u002F Angular detects automatically via reactive graph\n  }\n}\n\n\u002F\u002F Zoneless — app.config.ts (default in new Angular 22 projects)\nexport const appConfig: ApplicationConfig = {\n  providers: [\n    provideZonelessChangeDetection(),\n    provideBrowserGlobalErrorListeners(),\n    provideRouter(routes),\n  ]\n};\n",{"type":83},{"type":85,"attrs":397,"content":399},{"id":398,"level":171},"h_0s3keqba",[400],{"text":401,"type":76},"httpResource: Reactive HTTP with Signals",{"type":357,"attrs":403,"content":406},{"id":404,"language":390,"highlighted":405},"code_f6ezfzyr","\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">import\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> { httpResource } \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">from\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> '@angular\u002Fcommon\u002Fhttp'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">import\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> { signal, Component } \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">from\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> '@angular\u002Fcore'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">@\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">Component\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">({ standalone: \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">true\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> })\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">export\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> class\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> UserComponent\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">  userId\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> signal\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">1\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">  \u002F\u002F Automatically re-fetches when userId() changes\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">  user\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> httpResource\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">&#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">User\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">>(\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">    () \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> `\u002Fapi\u002Fusers\u002F${\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">this\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">userId\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">()\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">}`\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  );\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">  \u002F\u002F user.value()     → current value\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">  \u002F\u002F user.isLoading() → reactive boolean\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">  \u002F\u002F user.error()     → reactive error\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>",[407],{"text":408,"type":76},"import { httpResource } from '@angular\u002Fcommon\u002Fhttp';\nimport { signal, Component } from '@angular\u002Fcore';\n\n@Component({ standalone: true })\nexport class UserComponent {\n  userId = signal(1);\n\n  \u002F\u002F Automatically re-fetches when userId() changes\n  user = httpResource\u003CUser>(\n    () => `\u002Fapi\u002Fusers\u002F${this.userId()}`\n  );\n\n  \u002F\u002F user.value()     → current value\n  \u002F\u002F user.isLoading() → reactive boolean\n  \u002F\u002F user.error()     → reactive error\n}\n",{"type":83},{"type":85,"attrs":411,"content":413},{"id":412,"level":36},"h_whw7t61d",[414],{"text":415,"type":76},"Getting Started with Angular 22",{"type":70,"attrs":417,"content":419},{"id":418},"p_51mphvmp",[420],{"text":421,"type":76},"Angular 22 was released on June 3, 2026, and is the recommended version for new projects — stable Signal Forms, stable Angular Aria, zoneless by default, and stable MCP server.",{"type":85,"attrs":423,"content":425},{"id":424,"level":171},"h_q3yaw8e0",[426],{"text":427,"type":76},"Step 1 — Environment Requirements",{"type":70,"attrs":429,"content":431},{"id":430},"p_n4a2kwgt",[432],{"text":433,"type":76},"Angular 22 requires Node.js v22.22.0+ or v24.13.1+ and TypeScript 6. Verify before anything else — older versions block the CLI before it can even run.",{"type":357,"attrs":435,"content":439},{"id":436,"language":437,"highlighted":438},"code_i6au9khb","bash","\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\"># Check Node.js (needs v22.22.0+ or v24.x)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">node\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> --version\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">#\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> Install or update to Node LTS via nvm\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">nvm\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> install --lts &#x26;&#x26; nvm use --lts\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">#\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> Install the latest Angular CLI globally\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">npm\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> install -g @angular\u002Fcli\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">#\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> Confirm CLI version\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">ng\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> version\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">#\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> Angular CLI: 22.x.x  ✓\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>",[440],{"text":441,"type":76},"# Check Node.js (needs v22.22.0+ or v24.x)\nnode --version\n\n# Install or update to Node LTS via nvm\nnvm install --lts && nvm use --lts\n\n# Install the latest Angular CLI globally\nnpm install -g @angular\u002Fcli\n\n# Confirm CLI version\nng version\n# Angular CLI: 22.x.x  ✓\n",{"type":85,"attrs":443,"content":445},{"id":444,"level":171},"h_neslp4c3",[446],{"text":447,"type":76},"Step 2 — Create the Project",{"type":357,"attrs":449,"content":452},{"id":450,"language":437,"highlighted":451},"code_1qfl1pep","\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\"># Create a new project with recommended flags for 2026\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">ng\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> new my-app \\\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  --style=scss \\\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  --routing \\\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  --ssr\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">#\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> The CLI asks about SSR\u002FSSG — answer Y for SSR\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">#\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> Result: project with:\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">#\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">   ✓  Standalone components (no NgModule)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">#\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">   ✓  Zoneless change detection (no zone.js)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">#\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">   ✓  Vitest as test runner\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">#\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">   ✓  esbuild + Vite for builds\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">#\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">   ✓  @angular\u002Fssr configured\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">#\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">   ✓  TypeScript 6 strict mode\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">cd\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> my-app\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">ng\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> serve  # http:\u002F\u002Flocalhost:4200\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>",[453],{"text":454,"type":76},"# Create a new project with recommended flags for 2026\nng new my-app \\\n  --style=scss \\\n  --routing \\\n  --ssr\n\n# The CLI asks about SSR\u002FSSG — answer Y for SSR\n# Result: project with:\n#   ✓  Standalone components (no NgModule)\n#   ✓  Zoneless change detection (no zone.js)\n#   ✓  Vitest as test runner\n#   ✓  esbuild + Vite for builds\n#   ✓  @angular\u002Fssr configured\n#   ✓  TypeScript 6 strict mode\n\ncd my-app\nng serve  # http:\u002F\u002Flocalhost:4200\n",{"type":85,"attrs":456,"content":458},{"id":457,"level":171},"h_cjsfam7q",[459],{"text":460,"type":76},"Step 3 — Project Structure",{"type":357,"attrs":462,"content":465},{"id":463,"language":390,"highlighted":464},"code_1zijj91l","\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">my\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">-\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">app\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">\u002F\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">├── src\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">\u002F\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">│   ├── app\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">\u002F\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">│   │   ├── app.component.ts        # root \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">component\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (standalone)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">│   │   ├── app.config.ts           # bootstrap without AppModule\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">│   │   ├── app.routes.ts           # declarative routing\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">│   │   └── app.config.server.ts    # \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">SSR\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> config\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">│   ├── main.ts                     # \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">bootstrapApplication\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">()\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">│   └── main.server.ts              # \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">SSR\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> entry point\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">├── vitest.config.ts                # test \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">runner\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (no karma.conf)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">├── angular.json                    # workspace config\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">└── package.json                    # no zone.js \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">in\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> dependencies ✓\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>",[466],{"text":467,"type":76},"my-app\u002F\n├── src\u002F\n│   ├── app\u002F\n│   │   ├── app.component.ts        # root component (standalone)\n│   │   ├── app.config.ts           # bootstrap without AppModule\n│   │   ├── app.routes.ts           # declarative routing\n│   │   └── app.config.server.ts    # SSR config\n│   ├── main.ts                     # bootstrapApplication()\n│   └── main.server.ts              # SSR entry point\n├── vitest.config.ts                # test runner (no karma.conf)\n├── angular.json                    # workspace config\n└── package.json                    # no zone.js in dependencies ✓\n",{"type":85,"attrs":469,"content":471},{"id":470,"level":171},"h_ox8i4kol",[472],{"text":473,"type":76},"Step 4 — The Modern app.config.ts",{"type":357,"attrs":475,"content":478},{"id":476,"language":390,"highlighted":477},"code_mq6moxaa","\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F src\u002Fapp\u002Fapp.config.ts — generated by ng new in Angular 22\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">import\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> { ApplicationConfig, provideZonelessChangeDetection } \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">from\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> '@angular\u002Fcore'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">import\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> { provideRouter }                \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">from\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> '@angular\u002Frouter'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">import\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> { provideClientHydration }       \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">from\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> '@angular\u002Fplatform-browser'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">import\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> { provideHttpClient, withFetch } \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">from\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> '@angular\u002Fcommon\u002Fhttp'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">import\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> { routes }                        \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">from\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> '.\u002Fapp.routes'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">export\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> appConfig\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">:\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> ApplicationConfig\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  providers: [\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">    \u002F\u002F Zoneless: no Zone.js, changes detected by Signals\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">    provideZonelessChangeDetection\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(),\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">    \u002F\u002F Router with lazy loading by default\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">    provideRouter\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(routes),\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">    \u002F\u002F Incremental hydration for SSR — reduces TTI by 40-50%\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">    provideClientHydration\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(),\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">    \u002F\u002F HTTP with native Fetch API (not XMLHttpRequest)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">    provideHttpClient\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">withFetch\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">()),\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  ]\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">};\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>",[479],{"text":480,"type":76},"\u002F\u002F src\u002Fapp\u002Fapp.config.ts — generated by ng new in Angular 22\nimport { ApplicationConfig, provideZonelessChangeDetection } from '@angular\u002Fcore';\nimport { provideRouter }                from '@angular\u002Frouter';\nimport { provideClientHydration }       from '@angular\u002Fplatform-browser';\nimport { provideHttpClient, withFetch } from '@angular\u002Fcommon\u002Fhttp';\nimport { routes }                        from '.\u002Fapp.routes';\n\nexport const appConfig: ApplicationConfig = {\n  providers: [\n    \u002F\u002F Zoneless: no Zone.js, changes detected by Signals\n    provideZonelessChangeDetection(),\n\n    \u002F\u002F Router with lazy loading by default\n    provideRouter(routes),\n\n    \u002F\u002F Incremental hydration for SSR — reduces TTI by 40-50%\n    provideClientHydration(),\n\n    \u002F\u002F HTTP with native Fetch API (not XMLHttpRequest)\n    provideHttpClient(withFetch()),\n  ]\n};\n",{"type":85,"attrs":482,"content":484},{"id":483,"level":171},"h_7j69o696",[485],{"text":486,"type":76},"Step 5 — Your First Signal-First Component",{"type":357,"attrs":488,"content":491},{"id":489,"language":390,"highlighted":490},"code_cekl1ctr","\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F src\u002Fapp\u002Ffeatures\u002Fuser\u002Fuser.component.ts\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">import\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  Component, signal, computed, input\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">} \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">from\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> '@angular\u002Fcore'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">import\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> { httpResource } \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">from\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> '@angular\u002Fcommon\u002Fhttp'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">import\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> { DatePipe }     \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">from\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> '@angular\u002Fcommon'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">interface\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> User\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">  id\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">:\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> number\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">  name\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">:\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> string\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">  email\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">:\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> string\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">@\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">Component\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">({\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  selector: \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">'app-user'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  standalone: \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">true\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  imports: [DatePipe],\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  template: \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">`\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">    @if (user.isLoading()) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">      &#x3C;p>Loading...&#x3C;\u002Fp>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">    } @else if (user.error()) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">      &#x3C;p>Error: {{ user.error()?.message }}&#x3C;\u002Fp>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">    } @else {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">      &#x3C;article>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">        &#x3C;h2>{{ user.value()?.name }}&#x3C;\u002Fh2>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">        &#x3C;p>{{ user.value()?.email }}&#x3C;\u002Fp>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">        &#x3C;p>Score: {{ scoreFormatted() }}&#x3C;\u002Fp>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">        &#x3C;small>Loaded at {{ now | date:'HH:mm:ss' }}&#x3C;\u002Fsmall>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">      &#x3C;\u002Farticle>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">    }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">    &#x3C;button (click)=\"nextId()\">Next user&#x3C;\u002Fbutton>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">  `\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">})\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">export\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> class\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> UserComponent\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">  \u002F\u002F Signal input — works in zoneless without traditional @Input()\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">  userId\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> input.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">required\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">&#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">number\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">>();\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">  \u002F\u002F Reactive HTTP: re-fetches when userId() changes\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">  user\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> httpResource\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">&#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">User\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">>(\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">    () \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> `\u002Fapi\u002Fusers\u002F${\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">this\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">userId\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">()\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">}`\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  );\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">  \u002F\u002F Lazy derived — only recalculates when user.value() changes\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">  scoreFormatted\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> computed\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(() \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">    const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> u\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> this\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">.user.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">value\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">();\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">    return\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> u \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">?\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> `${\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">u\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">id\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> *\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 7\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">} pts`\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> :\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> '—'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  });\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">  now\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> new\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> Date\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">();\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">  nextId\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">() {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">    console.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">log\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">'current id:'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">this\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">userId\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">());\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F Generate via CLI:\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F ng generate component features\u002Fuser --standalone\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>",[492],{"text":493,"type":76},"\u002F\u002F src\u002Fapp\u002Ffeatures\u002Fuser\u002Fuser.component.ts\nimport {\n  Component, signal, computed, input\n} from '@angular\u002Fcore';\nimport { httpResource } from '@angular\u002Fcommon\u002Fhttp';\nimport { DatePipe }     from '@angular\u002Fcommon';\n\ninterface User {\n  id: number;\n  name: string;\n  email: string;\n}\n\n@Component({\n  selector: 'app-user',\n  standalone: true,\n  imports: [DatePipe],\n  template: `\n    @if (user.isLoading()) {\n      \u003Cp>Loading...\u003C\u002Fp>\n    } @else if (user.error()) {\n      \u003Cp>Error: {{ user.error()?.message }}\u003C\u002Fp>\n    } @else {\n      \u003Carticle>\n        \u003Ch2>{{ user.value()?.name }}\u003C\u002Fh2>\n        \u003Cp>{{ user.value()?.email }}\u003C\u002Fp>\n        \u003Cp>Score: {{ scoreFormatted() }}\u003C\u002Fp>\n        \u003Csmall>Loaded at {{ now | date:'HH:mm:ss' }}\u003C\u002Fsmall>\n      \u003C\u002Farticle>\n    }\n    \u003Cbutton (click)=\"nextId()\">Next user\u003C\u002Fbutton>\n  `,\n})\nexport class UserComponent {\n  \u002F\u002F Signal input — works in zoneless without traditional @Input()\n  userId = input.required\u003Cnumber>();\n\n  \u002F\u002F Reactive HTTP: re-fetches when userId() changes\n  user = httpResource\u003CUser>(\n    () => `\u002Fapi\u002Fusers\u002F${this.userId()}`\n  );\n\n  \u002F\u002F Lazy derived — only recalculates when user.value() changes\n  scoreFormatted = computed(() => {\n    const u = this.user.value();\n    return u ? `${u.id * 7} pts` : '—';\n  });\n\n  now = new Date();\n\n  nextId() {\n    console.log('current id:', this.userId());\n  }\n}\n\n\u002F\u002F Generate via CLI:\n\u002F\u002F ng generate component features\u002Fuser --standalone\n",{"type":85,"attrs":495,"content":497},{"id":496,"level":171},"h_6c8bmb56",[498],{"text":499,"type":76},"Step 6 — Essential CLI Commands",{"type":357,"attrs":501,"content":504},{"id":502,"language":437,"highlighted":503},"code_m6b21jr5","\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\"># Development\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">ng\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> serve                            # server with HMR and template hot reload\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">ng\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> serve --configuration=staging    # with specific environment\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">#\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> Code generation\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">ng\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> generate component features\u002Fdashboard --standalone\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">ng\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> generate service core\u002Fapi\u002Fuser\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">ng\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> generate guard core\u002Fauth\u002Fauth --implements CanActivate\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">ng\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> generate pipe shared\u002Fpipes\u002Ftruncate\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">ng\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> generate directive shared\u002Fdirectives\u002Fhighlight\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">#\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> Build\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">ng\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> build                            # production build with esbuild\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">ng\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> build --stats-json               # for bundle analysis\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">#\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> Tests (Vitest in Angular 22)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">ng\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> test                             # runs Vitest in watch mode\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">ng\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> test --coverage                  # coverage report\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">#\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> Upgrade and migration\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">ng\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> update @angular\u002Fcore @angular\u002Fcli   # upgrade with automatic schematics\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">ng\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> update                              # shows what can be updated\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">#\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> MCP Server for AI tooling (Angular 22 stable)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">ng\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> mcp                              # starts the Angular MCP server\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>",[505],{"text":506,"type":76},"# Development\nng serve                            # server with HMR and template hot reload\nng serve --configuration=staging    # with specific environment\n\n# Code generation\nng generate component features\u002Fdashboard --standalone\nng generate service core\u002Fapi\u002Fuser\nng generate guard core\u002Fauth\u002Fauth --implements CanActivate\nng generate pipe shared\u002Fpipes\u002Ftruncate\nng generate directive shared\u002Fdirectives\u002Fhighlight\n\n# Build\nng build                            # production build with esbuild\nng build --stats-json               # for bundle analysis\n\n# Tests (Vitest in Angular 22)\nng test                             # runs Vitest in watch mode\nng test --coverage                  # coverage report\n\n# Upgrade and migration\nng update @angular\u002Fcore @angular\u002Fcli   # upgrade with automatic schematics\nng update                              # shows what can be updated\n\n# MCP Server for AI tooling (Angular 22 stable)\nng mcp                              # starts the Angular MCP server\n",{"type":85,"attrs":508,"content":510},{"id":509,"level":171},"h_wide14e3",[511],{"text":512,"type":76},"Step 7 — Migrating from Previous Versions",{"type":65,"attrs":514,"content":516},{"id":515},"quote_ehnj9qly",[517],{"type":70,"attrs":518,"content":520},{"id":519},"p_qdl63u1h",[521,525],{"text":522,"type":76,"marks":523},"Important:",[524],{"type":79},{"text":526,"type":76}," Angular requires sequential upgrades — you cannot skip versions.",{"type":357,"attrs":528,"content":531},{"id":529,"language":437,"highlighted":530},"code_1o55hr55","\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\"># v19 → v20\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">ng\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> update @angular\u002Fcore@20 @angular\u002Fcli@20\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">#\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> v20 → v21 (zoneless becomes default for new projects)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">ng\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> update @angular\u002Fcore@21 @angular\u002Fcli@21\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">#\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> v21 → v22 (Signal Forms stable, Angular Aria stable, MCP stable)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">ng\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> update @angular\u002Fcore@22 @angular\u002Fcli@22\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">#\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> Check and run additional migrations\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">ng\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> update   # shows available migrations\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">#\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> Automatic migration to zoneless via MCP\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">ng\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> mcp  # activates onpush_zoneless_migration for the codebase\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>",[532],{"text":533,"type":76},"# v19 → v20\nng update @angular\u002Fcore@20 @angular\u002Fcli@20\n\n# v20 → v21 (zoneless becomes default for new projects)\nng update @angular\u002Fcore@21 @angular\u002Fcli@21\n\n# v21 → v22 (Signal Forms stable, Angular Aria stable, MCP stable)\nng update @angular\u002Fcore@22 @angular\u002Fcli@22\n\n# Check and run additional migrations\nng update   # shows available migrations\n\n# Automatic migration to zoneless via MCP\nng mcp  # activates onpush_zoneless_migration for the codebase\n",{"type":83},{"type":85,"attrs":536,"content":538},{"id":537,"level":36},"h_6pgx1wb6",[539],{"text":540,"type":76},"The Five Evaluation Criteria",{"type":85,"attrs":542,"content":544},{"id":543,"level":171},"h_icszh121",[545],{"text":546,"type":76},"01 — Scalability",{"type":70,"attrs":548,"content":550},{"id":549},"p_n4taq6r3",[551,555],{"text":552,"type":76,"marks":553},"Angular scales teams, not just applications.",[554],{"type":79},{"text":556,"type":76}," Hierarchical DI, strict TypeScript typing, and standalone components with clear API contracts make codebases grow predictably. Angular commands a 48.24% market share among specialized frontend frameworks, with over 51,737 companies worldwide. Google, Microsoft Office 365, Deutsche Bank, and Samsung use Angular for large-scale applications. The adoption of fine-grained Signals (v17) and the migration to zoneless change detection by default (v21) closed approximately 80% of the runtime performance gap versus vanilla JS.",{"type":85,"attrs":558,"content":560},{"id":559,"level":171},"h_q1zua26i",[561],{"text":562,"type":76},"02 — Learning Curve",{"type":70,"attrs":564,"content":566},{"id":565},"p_ul9ic55y",[567],{"text":568,"type":76},"The historical criticism remains partially true. TypeScript, DI, decorators, standalone components, routing, forms — many concepts arrive simultaneously. Angular developers command a premium of approximately $10K, averaging $130K\u002Fyear vs. approximately $120K\u002Fyear for React developers (Glassdoor, US averages). The direction in 2026 is simplification: standalone components eliminated NgModule, Signals eliminated most RxJS for state management, Signal Forms (stable in v22) eliminates verbose RxJS patterns.",{"type":85,"attrs":570,"content":572},{"id":571,"level":171},"h_ico5bf6x",[573],{"text":574,"type":76},"03 — Performance and Throughput",{"type":70,"attrs":576,"content":578},{"id":577},"p_xstxaei9",[579],{"text":580,"type":76},"Post-Signals Angular is substantially faster than the Zone.js era. The AOT compiler generates highly optimized JavaScript at build time. Incremental hydration (stable v20) reduces Time to Interactive by 40-50%, per the official roadmap. With Signals + zoneless, Angular knows exactly which DOM nodes need to update — no full tree traversal.",{"type":85,"attrs":582,"content":584},{"id":583,"level":171},"h_pp4od82j",[585],{"text":586,"type":76},"04 — Latency and SSR",{"type":70,"attrs":588,"content":590},{"id":589},"p_4ftirsfz",[591],{"text":592,"type":76},"Angular Universal delivers full SSR. Route-level render mode (stable v20) allows each route to be individually configured as SSR, prerender, or CSR. The base bundle size is approximately 2.7x larger than React's — irrelevant for internal enterprise apps, but a real consideration for mobile consumer apps.",{"type":85,"attrs":594,"content":596},{"id":595,"level":171},"h_bl1q19xd",[597],{"text":598,"type":76},"05 — Community Support",{"type":70,"attrs":600,"content":602},{"id":601},"p_2ip98iiy",[603],{"text":604,"type":76},"Google's backing is Angular's most underrated advantage — Gmail, Google Cloud Console, AdSense, Google Fonts all run on Angular. Regressions reach the team before they reach your app. One major release every 6 months, LTS versions with 18 months of support. 92% usage retention. Satisfaction: 44.7% 'admired' (State of JS 2025) vs React 52.1% and Vue 50.9%. Adoption growing at +5% per year, sustained by enterprise.",{"type":83},{"type":85,"attrs":607,"content":609},{"id":608,"level":36},"h_09lwv79p",[610],{"text":611,"type":76},"Version Timeline",{"type":613,"attrs":614,"content":616},"table",{"id":615},"tbl_0w305gb9",[617,649,691,722,753,794,829],{"type":618,"content":619},"tableRow",[620,631,640],{"type":621,"attrs":622,"content":624},"tableHeader",{"align":9,"colspan":623,"rowspan":623,"colwidth":9},1,[625],{"type":70,"attrs":626,"content":628},{"id":627},"p_fk9zivl9",[629],{"text":630,"type":76},"Version",{"type":621,"attrs":632,"content":633},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[634],{"type":70,"attrs":635,"content":637},{"id":636},"p_6y8t4d7c",[638],{"text":639,"type":76},"Date",{"type":621,"attrs":641,"content":642},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[643],{"type":70,"attrs":644,"content":646},{"id":645},"p_qc37slgr",[647],{"text":648,"type":76},"Key Milestone",{"type":618,"content":650},[651,663,672],{"type":652,"attrs":653,"content":654},"tableCell",{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[655],{"type":70,"attrs":656,"content":658},{"id":657},"p_cxovg5d6",[659],{"text":660,"type":76,"marks":661},"v17",[662],{"type":79},{"type":652,"attrs":664,"content":665},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[666],{"type":70,"attrs":667,"content":669},{"id":668},"p_0gevms77",[670],{"text":671,"type":76},"Nov 2023",{"type":652,"attrs":673,"content":674},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[675],{"type":70,"attrs":676,"content":678},{"id":677},"p_9w33b8y2",[679,681,685,687],{"text":680,"type":76},"Signals dev preview, ",{"text":682,"type":76,"marks":683},"@if\u002F@for",[684],{"type":185},{"text":686,"type":76}," block syntax, standalone default, Vite + esbuild, ",{"text":688,"type":76,"marks":689},"@defer",[690],{"type":185},{"type":618,"content":692},[693,704,713],{"type":652,"attrs":694,"content":695},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[696],{"type":70,"attrs":697,"content":699},{"id":698},"p_mr1y2mkx",[700],{"text":701,"type":76,"marks":702},"v18",[703],{"type":79},{"type":652,"attrs":705,"content":706},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[707],{"type":70,"attrs":708,"content":710},{"id":709},"p_vorjsls7",[711],{"text":712,"type":76},"May 2024",{"type":652,"attrs":714,"content":715},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[716],{"type":70,"attrs":717,"content":719},{"id":718},"p_9t2n0tzd",[720],{"text":721,"type":76},"Experimental zoneless, CDK\u002FMaterial zoneless support",{"type":618,"content":723},[724,735,744],{"type":652,"attrs":725,"content":726},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[727],{"type":70,"attrs":728,"content":730},{"id":729},"p_itlscjzx",[731],{"text":732,"type":76,"marks":733},"v19",[734],{"type":79},{"type":652,"attrs":736,"content":737},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[738],{"type":70,"attrs":739,"content":741},{"id":740},"p_eai6n0pl",[742],{"text":743,"type":76},"Nov 2024",{"type":652,"attrs":745,"content":746},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[747],{"type":70,"attrs":748,"content":750},{"id":749},"p_oeg6bv9h",[751],{"text":752,"type":76},"Incremental hydration (dev preview), route-level render mode (dev preview), template HMR",{"type":618,"content":754},[755,766,775],{"type":652,"attrs":756,"content":757},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[758],{"type":70,"attrs":759,"content":761},{"id":760},"p_u4n07kuj",[762],{"text":763,"type":76,"marks":764},"v20",[765],{"type":79},{"type":652,"attrs":767,"content":768},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[769],{"type":70,"attrs":770,"content":772},{"id":771},"p_3svhmio2",[773],{"text":774,"type":76},"May 2025",{"type":652,"attrs":776,"content":777},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[778],{"type":70,"attrs":779,"content":781},{"id":780},"p_ihd0h0wl",[782,786,788,792],{"text":783,"type":76,"marks":784},"Signals stable",[785],{"type":79},{"text":787,"type":76},", incremental hydration stable, route-level render mode stable, ",{"text":789,"type":76,"marks":790},"httpResource",[791],{"type":185},{"text":793,"type":76}," experimental",{"type":618,"content":795},[796,807,816],{"type":652,"attrs":797,"content":798},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[799],{"type":70,"attrs":800,"content":802},{"id":801},"p_akilmhbs",[803],{"text":804,"type":76,"marks":805},"v21",[806],{"type":79},{"type":652,"attrs":808,"content":809},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[810],{"type":70,"attrs":811,"content":813},{"id":812},"p_897mtn7g",[814],{"text":815,"type":76},"Nov 2025",{"type":652,"attrs":817,"content":818},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[819],{"type":70,"attrs":820,"content":822},{"id":821},"p_f603rq1s",[823,827],{"text":824,"type":76,"marks":825},"Zoneless by default",[826],{"type":79},{"text":828,"type":76},", Vitest replaces Karma, Signal Forms experimental, Angular Aria dev preview, MCP server",{"type":618,"content":830},[831,842,851],{"type":652,"attrs":832,"content":833},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[834],{"type":70,"attrs":835,"content":837},{"id":836},"p_yjnw4ur4",[838],{"text":839,"type":76,"marks":840},"v22",[841],{"type":79},{"type":652,"attrs":843,"content":844},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[845],{"type":70,"attrs":846,"content":848},{"id":847},"p_8290zvfk",[849],{"text":850,"type":76},"Jun 2026",{"type":652,"attrs":852,"content":853},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[854],{"type":70,"attrs":855,"content":857},{"id":856},"p_thjbeci6",[858,862,864,868],{"text":859,"type":76,"marks":860},"Signal Forms stable",[861],{"type":79},{"text":863,"type":76},", Angular Aria stable, ",{"text":865,"type":76,"marks":866},"provideWebMcpTools()",[867],{"type":185},{"text":869,"type":76},", MCP server stable",{"type":65,"attrs":871,"content":873},{"id":872},"quote_fapyve3o",[874],{"type":70,"attrs":875,"content":877},{"id":876},"p_a95zlefq",[878,882],{"text":879,"type":76,"marks":880},"⚠ End of Life:",[881],{"type":79},{"text":883,"type":76}," Angular 19 reached EOL in May 2026. Active CVEs (patches only for v19, v20, v21): CVE-2025-59052 (CVSS 7.1), CVE-2025-66035 (CVSS 7.7), CVE-2025-66412 (XSS in SVG\u002FMathML compiler).",{"type":83},{"type":85,"attrs":886,"content":888},{"id":887,"level":36},"h_ek11qhil",[889],{"text":890,"type":76},"Ecosystem",{"type":85,"attrs":892,"content":894},{"id":893,"level":171},"h_hbm6lo4l",[895],{"text":896,"type":76},"Angular Material + CDK",{"type":70,"attrs":898,"content":900},{"id":899},"p_rtxy10xq",[901],{"text":902,"type":76},"30+ accessible Material Design components. CDK provides behavior primitives: drag-and-drop, overlay, virtual scroll, accessibility, stepper.",{"type":357,"attrs":904,"content":907},{"id":905,"language":437,"highlighted":906},"code_pwnuhyf7","\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">npm\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> install @angular\u002Fmaterial @angular\u002Fcdk\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>",[908],{"text":909,"type":76},"npm install @angular\u002Fmaterial @angular\u002Fcdk\n",{"type":85,"attrs":911,"content":913},{"id":912,"level":171},"h_uhxr5381",[914],{"text":915,"type":76},"SSR",{"type":357,"attrs":917,"content":920},{"id":918,"language":437,"highlighted":919},"code_g0kwx6d9","\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">ng\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> add @angular\u002Fssr\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>",[921],{"text":922,"type":76},"ng add @angular\u002Fssr\n",{"type":70,"attrs":924,"content":926},{"id":925},"p_esp400op",[927],{"text":928,"type":76},"Integrated with the CLI. Supports Node.js, Deno, and Cloudflare Workers via adapters.",{"type":85,"attrs":930,"content":932},{"id":931,"level":171},"h_ep6vc3nn",[933],{"text":934,"type":76},"State Management",{"type":613,"attrs":936,"content":938},{"id":937},"tbl_tnlwzliu",[939,959,981,1003],{"type":618,"content":940},[941,950],{"type":621,"attrs":942,"content":943},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[944],{"type":70,"attrs":945,"content":947},{"id":946},"p_6ftdpz5h",[948],{"text":949,"type":76},"Option",{"type":621,"attrs":951,"content":952},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[953],{"type":70,"attrs":954,"content":956},{"id":955},"p_su4c79pe",[957],{"text":958,"type":76},"When to use",{"type":618,"content":960},[961,972],{"type":652,"attrs":962,"content":963},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[964],{"type":70,"attrs":965,"content":967},{"id":966},"p_b2cbdt7t",[968],{"text":969,"type":76,"marks":970},"Signals + computed",[971],{"type":79},{"type":652,"attrs":973,"content":974},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[975],{"type":70,"attrs":976,"content":978},{"id":977},"p_bjnofgs7",[979],{"text":980,"type":76},"Local state, derived values — covers most components in Angular 22",{"type":618,"content":982},[983,994],{"type":652,"attrs":984,"content":985},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[986],{"type":70,"attrs":987,"content":989},{"id":988},"p_fpqsmh4r",[990],{"text":991,"type":76,"marks":992},"NgRx",[993],{"type":79},{"type":652,"attrs":995,"content":996},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[997],{"type":70,"attrs":998,"content":1000},{"id":999},"p_1spkemrc",[1001],{"text":1002,"type":76},"Complex side effects, DevTools, time-travel debugging, large teams",{"type":618,"content":1004},[1005,1016],{"type":652,"attrs":1006,"content":1007},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[1008],{"type":70,"attrs":1009,"content":1011},{"id":1010},"p_guc8mg0r",[1012],{"text":1013,"type":76,"marks":1014},"Akita \u002F Elf",[1015],{"type":79},{"type":652,"attrs":1017,"content":1018},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[1019],{"type":70,"attrs":1020,"content":1022},{"id":1021},"p_6wgkggf1",[1023],{"text":1024,"type":76},"Lighter NgRx alternatives",{"type":85,"attrs":1026,"content":1028},{"id":1027,"level":171},"h_5114or9p",[1029],{"text":1030,"type":76},"Testing",{"type":70,"attrs":1032,"content":1034},{"id":1033},"p_n2l017yi",[1035],{"text":1036,"type":76},"Angular 22 replaced Karma with Vitest as the default test runner.",{"type":357,"attrs":1038,"content":1041},{"id":1039,"language":390,"highlighted":1040},"code_amdke7gj","\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">import\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> { TestBed } \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">from\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> '@angular\u002Fcore\u002Ftesting'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">import\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> { CounterComponent } \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">from\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> '.\u002Fcounter.component'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">describe\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">'CounterComponent'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, () \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">  beforeEach\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(() \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">    TestBed.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">configureTestingModule\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">({\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">      imports: [CounterComponent], \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F standalone: imported directly\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">    });\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  });\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">  it\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">'should increment the signal on click'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, () \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">    const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> fixture\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> TestBed.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">createComponent\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(CounterComponent);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">    const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> comp\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> fixture.componentInstance;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">    expect\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(comp.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">counter\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">()).\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">toBe\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">    comp.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">increment\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">();\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">    TestBed.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">tick\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">();  \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F replaces deprecated TestBed.flushEffects()\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">    expect\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(comp.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">counter\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">()).\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">toBe\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">1\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">    expect\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(comp.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">double\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">()).\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">toBe\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">2\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  });\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">});\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>",[1042],{"text":1043,"type":76},"import { TestBed } from '@angular\u002Fcore\u002Ftesting';\nimport { CounterComponent } from '.\u002Fcounter.component';\n\ndescribe('CounterComponent', () => {\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      imports: [CounterComponent], \u002F\u002F standalone: imported directly\n    });\n  });\n\n  it('should increment the signal on click', () => {\n    const fixture = TestBed.createComponent(CounterComponent);\n    const comp = fixture.componentInstance;\n\n    expect(comp.counter()).toBe(0);\n    comp.increment();\n    TestBed.tick();  \u002F\u002F replaces deprecated TestBed.flushEffects()\n    expect(comp.counter()).toBe(1);\n    expect(comp.double()).toBe(2);\n  });\n});\n",{"type":85,"attrs":1045,"content":1047},{"id":1046,"level":171},"h_r93brmps",[1048],{"text":1049,"type":76},"Microfrontends",{"type":70,"attrs":1051,"content":1053},{"id":1052},"p_zs0cvpd4",[1054],{"text":1055,"type":76},"Module Federation (Webpack 5) is the Angular enterprise standard for microfrontends. Nx is the most adopted monorepo toolchain for large-scale Angular.",{"type":357,"attrs":1057,"content":1060},{"id":1058,"language":390,"highlighted":1059},"code_770wvmut","\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F module-federation.config.ts (shell app)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">import\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> { ModuleFederationConfig } \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">from\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> '@nx\u002Fwebpack'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">export\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> config\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">:\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> ModuleFederationConfig\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  name: \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">'shell'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  remotes: [\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">'checkout'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">'catalog'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">'user'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">],\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">};\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F Each remote is an independent Angular standalone app\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F Lazy-loaded as a route in the shell\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>",[1061],{"text":1062,"type":76},"\u002F\u002F module-federation.config.ts (shell app)\nimport { ModuleFederationConfig } from '@nx\u002Fwebpack';\n\nexport const config: ModuleFederationConfig = {\n  name: 'shell',\n  remotes: ['checkout', 'catalog', 'user'],\n};\n\u002F\u002F Each remote is an independent Angular standalone app\n\u002F\u002F Lazy-loaded as a route in the shell\n",{"type":83},{"type":85,"attrs":1065,"content":1067},{"id":1066,"level":36},"h_l9f1ces7",[1068],{"text":1069,"type":76},"Angular and AI Agents",{"type":65,"attrs":1071,"content":1073},{"id":1072},"quote_qdoh19os",[1074],{"type":70,"attrs":1075,"content":1077},{"id":1076},"p_8czeuuj4",[1078,1082,1084,1088,1089,1093,1095,1099],{"text":1079,"type":76,"marks":1080},"SDK-agnostic note:",[1081],{"type":79},{"text":1083,"type":76}," LLM SDKs are TypeScript\u002FJavaScript — framework-agnostic. Vercel AI SDK (",{"text":1085,"type":76,"marks":1086},"streamText",[1087],{"type":185},{"text":203,"type":76},{"text":1090,"type":76,"marks":1091},"generateObject",[1092],{"type":185},{"text":1094,"type":76},"), Firebase Genkit, Anthropic SDK, and OpenAI SDK all work in Angular without modification. What changes is the UI layer: instead of React hooks, you use ",{"text":1096,"type":76,"marks":1097},"Signals + RxJS + DI",[1098],{"type":79},{"text":120,"type":76},{"type":85,"attrs":1101,"content":1103},{"id":1102,"level":171},"h_omrpbevt",[1104],{"text":1105,"type":76},"Four Core Strengths",{"type":70,"attrs":1107,"content":1109},{"id":1108},"p_l8awc0o3",[1110,1114,1116,1119],{"text":1111,"type":76,"marks":1112},"1. DI isolates the LLM client.",[1113],{"type":79},{"text":1115,"type":76}," The AI service lives in a ",{"text":182,"type":76,"marks":1117},[1118],{"type":185},{"text":1120,"type":76}," with a well-defined interface. Swap from Claude to Gemini, or from REST to WebSocket, without touching components. In tests, inject a mock — the UI never knows the difference.",{"type":70,"attrs":1122,"content":1124},{"id":1123},"p_7ju1zlg1",[1125,1129,1131,1135,1137,1141,1143,1147],{"text":1126,"type":76,"marks":1127},"2. Signals + RxJS for token streaming.",[1128],{"type":79},{"text":1130,"type":76}," Tokens arrive via SSE. RxJS — already embedded in Angular — is the natural mental model: ",{"text":1132,"type":76,"marks":1133},"Observable",[1134],{"type":185},{"text":1136,"type":76}," for the stream, ",{"text":1138,"type":76,"marks":1139},"pipe(scan())",[1140],{"type":185},{"text":1142,"type":76}," to accumulate tokens, ",{"text":1144,"type":76,"marks":1145},"takeUntilDestroyed()",[1146],{"type":185},{"text":1148,"type":76}," for automatic cleanup when the component is destroyed.",{"type":70,"attrs":1150,"content":1152},{"id":1151},"p_lys5jt33",[1153,1157,1159,1162,1164,1168,1170,1174],{"text":1154,"type":76,"marks":1155},"3. WebMCP — your UI as an agent-callable toolset.",[1156],{"type":79},{"text":1158,"type":76}," Angular 22 introduced ",{"text":865,"type":76,"marks":1160},[1161],{"type":185},{"text":1163,"type":76}," and ",{"text":1165,"type":76,"marks":1166},"declareWebMcpTool()",[1167],{"type":185},{"text":1169,"type":76},". Your app exposes capabilities that any agent with browser access can discover and call via ",{"text":1171,"type":76,"marks":1172},"navigator.modelContext",[1173],{"type":185},{"text":1175,"type":76},". Inversion of control: the agent calls the UI.",{"type":70,"attrs":1177,"content":1179},{"id":1178},"p_l7tizim6",[1180,1184,1186,1190,1192,1196],{"text":1181,"type":76,"marks":1182},"4. AG-UI Protocol.",[1183],{"type":79},{"text":1185,"type":76}," The AG-UI protocol standardizes communication between agents (LangGraph, Mastra, CrewAI) and frontends. The Angular implementation uses the ",{"text":1187,"type":76,"marks":1188},"Resource API",[1189],{"type":185},{"text":1191,"type":76}," — the same pattern as ",{"text":1193,"type":76,"marks":1194},"httpResource()",[1195],{"type":185},{"text":1197,"type":76}," — making agent state (chat history, widgets, tool calls) native reactive data.",{"type":85,"attrs":1199,"content":1201},{"id":1200,"level":171},"h_a9jqccu9",[1202],{"text":1203,"type":76},"Chat with Token Streaming",{"type":357,"attrs":1205,"content":1208},{"id":1206,"language":390,"highlighted":1207},"code_puubjya6","\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">@\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">Injectable\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">({ providedIn: \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">'root'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> })\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">export\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> class\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> ChatAiService\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">  messages\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">   =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> signal\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">&#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">Message\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">[]>([]);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">  streamText\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> signal\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">''\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">  loading\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">    =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> signal\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">false\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  private\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> createStream\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">payload\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">:\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> object\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">)\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">:\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> Observable\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">&#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">    return\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> new\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> Observable\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">observer\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">      const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> controller\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> new\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> AbortController\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">();\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">      fetch\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">'\u002Fapi\u002Fchat\u002Fstream'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">        method: \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">'POST'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">        headers: { \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">'Content-Type'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">'application\u002Fjson'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> },\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">        body: \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">JSON\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">stringify\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(payload),\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">        signal: controller.signal,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">      })\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">      .\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">then\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">async\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\"> res\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">        const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> reader\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> res.body\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">!\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">getReader\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">();\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">        const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> decoder\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> new\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> TextDecoder\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">();\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">        while\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">true\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">          const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> { \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">done\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">value\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> } \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> await\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> reader.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">read\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">();\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">          if\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (done) { observer.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">complete\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(); \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">break\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">; }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">          const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> chunk\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> decoder.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">decode\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(value, { stream: \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">true\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> });\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">          for\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> line\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> of\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> chunk.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">split\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">\\n\\n\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">)) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">            if\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">!\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">line.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">startsWith\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">'data: '\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">)) \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">continue\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">            const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> data\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> line.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">slice\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">6\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">            if\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (data \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">===\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> '[DONE]'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">) { observer.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">complete\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(); \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">return\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">; }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">            observer.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">next\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(data);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">          }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">        }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">      })\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">      .\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">catch\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">err\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> { \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">if\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (err.name \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">!==\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> 'AbortError'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">) observer.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">error\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(err); });\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">      return\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> () \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> controller.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">abort\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(); \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F cleanup on unsubscribe\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">    });\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  async\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> send\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">text\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">:\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> string\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">)\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">:\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> Promise\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">&#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">void\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">    this\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">.messages.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">update\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">m\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> [\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">...\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">m, { role: \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">'user'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, content: text }]);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">    this\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">.loading.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">set\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">true\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">    this\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">.streamText.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">set\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">''\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">    this\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">createStream\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">({ messages: \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">this\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">messages\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">() }).\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">subscribe\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">({\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">      next\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">:     \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">token\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> this\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">.streamText.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">update\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">s\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> s \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">+\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> token),\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">      error\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">:    ()    \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> this\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">.loading.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">set\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">false\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">),\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">      complete\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">: ()    \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">        this\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">.messages.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">update\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">m\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> [\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">          ...\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">m, { role: \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">'assistant'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, content: \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">this\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">streamText\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">() }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">        ]);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">        this\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">.streamText.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">set\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">''\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">        this\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">.loading.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">set\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">false\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">      },\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">    });\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>",[1209],{"text":1210,"type":76},"@Injectable({ providedIn: 'root' })\nexport class ChatAiService {\n  messages   = signal\u003CMessage[]>([]);\n  streamText = signal('');\n  loading    = signal(false);\n\n  private createStream(payload: object): Observable\u003Cstring> {\n    return new Observable(observer => {\n      const controller = new AbortController();\n      fetch('\u002Fapi\u002Fchat\u002Fstream', {\n        method: 'POST',\n        headers: { 'Content-Type': 'application\u002Fjson' },\n        body: JSON.stringify(payload),\n        signal: controller.signal,\n      })\n      .then(async res => {\n        const reader  = res.body!.getReader();\n        const decoder = new TextDecoder();\n        while (true) {\n          const { done, value } = await reader.read();\n          if (done) { observer.complete(); break; }\n          const chunk = decoder.decode(value, { stream: true });\n          for (const line of chunk.split('\\n\\n')) {\n            if (!line.startsWith('data: ')) continue;\n            const data = line.slice(6);\n            if (data === '[DONE]') { observer.complete(); return; }\n            observer.next(data);\n          }\n        }\n      })\n      .catch(err => { if (err.name !== 'AbortError') observer.error(err); });\n      return () => controller.abort(); \u002F\u002F cleanup on unsubscribe\n    });\n  }\n\n  async send(text: string): Promise\u003Cvoid> {\n    this.messages.update(m => [...m, { role: 'user', content: text }]);\n    this.loading.set(true);\n    this.streamText.set('');\n    this.createStream({ messages: this.messages() }).subscribe({\n      next:     token => this.streamText.update(s => s + token),\n      error:    ()    => this.loading.set(false),\n      complete: ()    => {\n        this.messages.update(m => [\n          ...m, { role: 'assistant', content: this.streamText() }\n        ]);\n        this.streamText.set('');\n        this.loading.set(false);\n      },\n    });\n  }\n}\n",{"type":85,"attrs":1212,"content":1214},{"id":1213,"level":171},"h_02pe57pb",[1215],{"text":1216,"type":76},"Angular vs Next.js for AI Agent Apps",{"type":613,"attrs":1218,"content":1220},{"id":1219},"tbl_587oqoeh",[1221,1250,1285,1325,1354,1390,1423,1452,1494],{"type":618,"content":1222},[1223,1232,1241],{"type":621,"attrs":1224,"content":1225},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[1226],{"type":70,"attrs":1227,"content":1229},{"id":1228},"p_wv5fhnzm",[1230],{"text":1231,"type":76},"Criterion",{"type":621,"attrs":1233,"content":1234},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[1235],{"type":70,"attrs":1236,"content":1238},{"id":1237},"p_2axm1nnl",[1239],{"text":1240,"type":76},"Angular 22",{"type":621,"attrs":1242,"content":1243},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[1244],{"type":70,"attrs":1245,"content":1247},{"id":1246},"p_2ehhhu6x",[1248],{"text":1249,"type":76},"Next.js 15 (React)",{"type":618,"content":1251},[1252,1261,1274],{"type":652,"attrs":1253,"content":1254},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[1255],{"type":70,"attrs":1256,"content":1258},{"id":1257},"p_u98f0pxm",[1259],{"text":1260,"type":76},"LLM SDKs",{"type":652,"attrs":1262,"content":1263},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[1264],{"type":70,"attrs":1265,"content":1267},{"id":1266},"p_bec1ubh5",[1268,1272],{"text":1269,"type":76,"marks":1270},"Equal",[1271],{"type":79},{"text":1273,"type":76}," — TypeScript, work in both",{"type":652,"attrs":1275,"content":1276},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[1277],{"type":70,"attrs":1278,"content":1280},{"id":1279},"p_rzmwhpcj",[1281,1284],{"text":1269,"type":76,"marks":1282},[1283],{"type":79},{"text":1273,"type":76},{"type":618,"content":1286},[1287,1296,1308],{"type":652,"attrs":1288,"content":1289},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[1290],{"type":70,"attrs":1291,"content":1293},{"id":1292},"p_06e26vdk",[1294],{"text":1295,"type":76},"Token streaming (SSE)",{"type":652,"attrs":1297,"content":1298},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[1299],{"type":70,"attrs":1300,"content":1302},{"id":1301},"p_p4sqh3su",[1303,1305],{"text":1304,"type":76},"RxJS + Signal, auto-cleanup via ",{"text":1144,"type":76,"marks":1306},[1307],{"type":185},{"type":652,"attrs":1309,"content":1310},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[1311],{"type":70,"attrs":1312,"content":1314},{"id":1313},"p_96cbtmrb",[1315,1319,1321],{"text":1316,"type":76,"marks":1317},"useChat",[1318],{"type":185},{"text":1320,"type":76}," (React hook) or manual ",{"text":1322,"type":76,"marks":1323},"ReadableStream",[1324],{"type":185},{"type":618,"content":1326},[1327,1336,1345],{"type":652,"attrs":1328,"content":1329},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[1330],{"type":70,"attrs":1331,"content":1333},{"id":1332},"p_68ztnl7e",[1334],{"text":1335,"type":76},"Multiple parallel agents",{"type":652,"attrs":1337,"content":1338},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[1339],{"type":70,"attrs":1340,"content":1342},{"id":1341},"p_9vac1mpo",[1343],{"text":1344,"type":76},"Signal per agent, DI isolation, zero interference",{"type":652,"attrs":1346,"content":1347},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[1348],{"type":70,"attrs":1349,"content":1351},{"id":1350},"p_qdswv3ol",[1352],{"text":1353,"type":76},"useState per agent, Context or Zustand",{"type":618,"content":1355},[1356,1365,1381],{"type":652,"attrs":1357,"content":1358},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[1359],{"type":70,"attrs":1360,"content":1362},{"id":1361},"p_uno4hsl0",[1363],{"text":1364,"type":76},"UI as agent-callable tool",{"type":652,"attrs":1366,"content":1367},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[1368],{"type":70,"attrs":1369,"content":1371},{"id":1370},"p_0dqjsb8j",[1372,1375,1377],{"text":865,"type":76,"marks":1373},[1374],{"type":185},{"text":1376,"type":76}," — ",{"text":1378,"type":76,"marks":1379},"native in Angular 22",[1380],{"type":79},{"type":652,"attrs":1382,"content":1383},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[1384],{"type":70,"attrs":1385,"content":1387},{"id":1386},"p_57i8xxho",[1388],{"text":1389,"type":76},"No native equivalent",{"type":618,"content":1391},[1392,1401,1414],{"type":652,"attrs":1393,"content":1394},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[1395],{"type":70,"attrs":1396,"content":1398},{"id":1397},"p_j33y9way",[1399],{"text":1400,"type":76},"AI tooling in IDE",{"type":652,"attrs":1402,"content":1403},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[1404],{"type":70,"attrs":1405,"content":1407},{"id":1406},"p_pa2xfbo7",[1408,1412],{"text":1409,"type":76,"marks":1410},"ng mcp",[1411],{"type":185},{"text":1413,"type":76}," stable — RAG + automatic migration",{"type":652,"attrs":1415,"content":1416},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[1417],{"type":70,"attrs":1418,"content":1420},{"id":1419},"p_g1rmpsc1",[1421],{"text":1422,"type":76},"No official MCP server",{"type":618,"content":1424},[1425,1434,1443],{"type":652,"attrs":1426,"content":1427},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[1428],{"type":70,"attrs":1429,"content":1431},{"id":1430},"p_d2eh9fyx",[1432],{"text":1433,"type":76},"Team scalability in AI apps",{"type":652,"attrs":1435,"content":1436},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[1437],{"type":70,"attrs":1438,"content":1440},{"id":1439},"p_jd5abanq",[1441],{"text":1442,"type":76},"DI + opinionated structure = predictable AI service location",{"type":652,"attrs":1444,"content":1445},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[1446],{"type":70,"attrs":1447,"content":1449},{"id":1448},"p_f2cal362",[1450],{"text":1451,"type":76},"Convention-dependent",{"type":618,"content":1453},[1454,1463,1475],{"type":652,"attrs":1455,"content":1456},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[1457],{"type":70,"attrs":1458,"content":1460},{"id":1459},"p_fjb1cnfz",[1461],{"text":1462,"type":76},"Auto stream cleanup on navigation",{"type":652,"attrs":1464,"content":1465},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[1466],{"type":70,"attrs":1467,"content":1469},{"id":1468},"p_et0a1y9e",[1470,1473],{"text":1144,"type":76,"marks":1471},[1472],{"type":185},{"text":1474,"type":76}," — zero config",{"type":652,"attrs":1476,"content":1477},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[1478],{"type":70,"attrs":1479,"content":1481},{"id":1480},"p_thcrs442",[1482,1486,1488,1492],{"text":1483,"type":76,"marks":1484},"AbortController",[1485],{"type":185},{"text":1487,"type":76}," + manual ",{"text":1489,"type":76,"marks":1490},"useEffect",[1491],{"type":185},{"text":1493,"type":76}," cleanup",{"type":618,"content":1495},[1496,1505,1520],{"type":652,"attrs":1497,"content":1498},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[1499],{"type":70,"attrs":1500,"content":1502},{"id":1501},"p_hd2iuku2",[1503],{"text":1504,"type":76},"Server Functions \u002F API Routes",{"type":652,"attrs":1506,"content":1507},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[1508],{"type":70,"attrs":1509,"content":1511},{"id":1510},"p_tyjm7pe3",[1512,1514,1518],{"text":1513,"type":76},"Via ",{"text":1515,"type":76,"marks":1516},"@angular\u002Fssr",[1517],{"type":185},{"text":1519,"type":76}," (evolving)",{"type":652,"attrs":1521,"content":1522},{"align":9,"colspan":623,"rowspan":623,"colwidth":9},[1523],{"type":70,"attrs":1524,"content":1526},{"id":1525},"p_y2d64s06",[1527],{"text":1528,"type":76},"Next.js Server Actions — more mature",{"type":83},{"type":85,"attrs":1531,"content":1533},{"id":1532,"level":36},"h_fd3pzwlg",[1534],{"text":1535,"type":76},"Use Cases",{"type":85,"attrs":1537,"content":1539},{"id":1538,"level":171},"h_ow009voi",[1540],{"text":1541,"type":76},"✅ Use Angular",{"type":1543,"attrs":1544,"content":1547},"bulletList",{"id":1545,"tight":1546},"ul_8zwnscwg",true,[1548,1563,1577,1591,1605],{"type":1549,"attrs":1550,"content":1552},"listItem",{"id":1551},"li_gs2nd660",[1553],{"type":70,"attrs":1554,"content":1556},{"id":1555},"p_5caqj1l7",[1557,1561],{"text":1558,"type":76,"marks":1559},"Enterprise SPA at scale",[1560],{"type":79},{"text":1562,"type":76}," — ERP, CRM, financial platforms, healthcare. 10+ devs, multi-year maintenance. Opinionated architecture ensures navigability by new engineers.",{"type":1549,"attrs":1564,"content":1566},{"id":1565},"li_dufmf7w5",[1567],{"type":70,"attrs":1568,"content":1570},{"id":1569},"p_1jjoyvng",[1571,1575],{"text":1572,"type":76,"marks":1573},"Real-time dashboards",[1574],{"type":79},{"text":1576,"type":76}," — IoT, financial monitoring, telemetry. Signals + zoneless: only the widget receiving new data updates.",{"type":1549,"attrs":1578,"content":1580},{"id":1579},"li_y9jt86pv",[1581],{"type":70,"attrs":1582,"content":1584},{"id":1583},"p_8kokxefr",[1585,1589],{"text":1586,"type":76,"marks":1587},"Complex forms",[1588],{"type":79},{"text":1590,"type":76}," — Insurance, credit, regulated onboarding. Reactive Forms + Signals for granular validation and DI-integrated business rules.",{"type":1549,"attrs":1592,"content":1594},{"id":1593},"li_w7n0qqjs",[1595],{"type":70,"attrs":1596,"content":1598},{"id":1597},"p_ru650ftq",[1599,1603],{"text":1600,"type":76,"marks":1601},"Multi-tenant enterprise SaaS",[1602],{"type":79},{"text":1604,"type":76}," — Lazy modules per tenant, permissions via guards, i18n per locale, per-client theming — all native Angular primitives.",{"type":1549,"attrs":1606,"content":1608},{"id":1607},"li_t19dxlrw",[1609],{"type":70,"attrs":1610,"content":1612},{"id":1611},"p_l6yuni1s",[1613,1617],{"text":1614,"type":76,"marks":1615},"AI agent dashboards",[1616],{"type":79},{"text":1618,"type":76}," — Multiple parallel agents, WebMCP tool exposure, DI-isolated AI services. Structure pays off as the AI layer grows.",{"type":85,"attrs":1620,"content":1622},{"id":1621,"level":171},"h_qicvrgiv",[1623],{"text":1624,"type":76},"⚠️ Evaluate carefully",{"type":1543,"attrs":1626,"content":1628},{"id":1627,"tight":1546},"ul_fjnkghgk",[1629,1643,1657],{"type":1549,"attrs":1630,"content":1632},{"id":1631},"li_4b8mjlkc",[1633],{"type":70,"attrs":1634,"content":1636},{"id":1635},"p_zoim55v7",[1637,1641],{"text":1638,"type":76,"marks":1639},"Consumer apps with critical SEO\u002Fmobile",[1640],{"type":79},{"text":1642,"type":76}," — Larger bundle, SSR tooling less mature than Next.js.",{"type":1549,"attrs":1644,"content":1646},{"id":1645},"li_2vae4mlw",[1647],{"type":70,"attrs":1648,"content":1650},{"id":1649},"p_gscl76r7",[1651,1655],{"text":1652,"type":76,"marks":1653},"MVPs and short-duration projects",[1654],{"type":79},{"text":1656,"type":76}," — Weeks of ramp-up before productivity. React or Vue ship faster.",{"type":1549,"attrs":1658,"content":1660},{"id":1659},"li_bw7hri2m",[1661],{"type":70,"attrs":1662,"content":1664},{"id":1663},"p_kpuyjnct",[1665,1669],{"text":1666,"type":76,"marks":1667},"Small teams without Angular experience",[1668],{"type":79},{"text":1670,"type":76}," — Longer hiring pipeline, higher cost per engineer.",{"type":83},{"type":85,"attrs":1673,"content":1675},{"id":1674,"level":36},"h_ihketkia",[1676],{"text":1677,"type":76},"Aligning to Business Objectives",{"type":70,"attrs":1679,"content":1681},{"id":1680},"p_66sriobn",[1682,1684,1688],{"text":1683,"type":76},"For the business, choosing Angular is not a technology bet. It is an ",{"text":1685,"type":76,"marks":1686},"organizational bet",[1687],{"type":79},{"text":1689,"type":76}," — that consistency compensates for onboarding cost, that the codebase will be maintainable by teams that don't yet exist, and that avoiding the \"which library should we use?\" debates saves more hours than setup time.",{"type":70,"attrs":1691,"content":1693},{"id":1692},"p_61b60762",[1694],{"text":1695,"type":76},"This bet has a specific profile: medium and long-term projects, growing teams, complex domains where code structure is as important as code functionality. With 18.2% adoption (Stack Overflow 2025), 51,000+ companies globally, and Google's backing, Angular's relevance is not in question.",{"type":70,"attrs":1697,"content":1699},{"id":1698},"p_ol6uy32v",[1700],{"text":1701,"type":76},"The bet doesn't make sense for MVPs, consumer apps with critical SEO requirements, or small teams where setup overhead outweighs scalability benefits.",{"type":70,"attrs":1703,"content":1705},{"id":1704},"p_stisu3g4",[1706],{"text":1707,"type":76,"marks":1708},"Choose Angular when:",[1709],{"type":79},{"type":1543,"attrs":1711,"content":1713},{"id":1712,"tight":1546},"ul_26weebn0",[1714,1724,1734,1744,1754],{"type":1549,"attrs":1715,"content":1717},{"id":1716},"li_0msw45w7",[1718],{"type":70,"attrs":1719,"content":1721},{"id":1720},"p_ixj0f2xt",[1722],{"text":1723,"type":76},"3+ year horizon, growing team",{"type":1549,"attrs":1725,"content":1727},{"id":1726},"li_4r7pytfe",[1728],{"type":70,"attrs":1729,"content":1731},{"id":1730},"p_o890ksbi",[1732],{"text":1733,"type":76},"Complex domain: financial, healthcare, government, enterprise B2B",{"type":1549,"attrs":1735,"content":1737},{"id":1736},"li_41se64we",[1738],{"type":70,"attrs":1739,"content":1741},{"id":1740},"p_mcqtnihm",[1742],{"text":1743,"type":76},"Codebase consistency over flexibility",{"type":1549,"attrs":1745,"content":1747},{"id":1746},"li_ekirkeyd",[1748],{"type":70,"attrs":1749,"content":1751},{"id":1750},"p_hd2cbddr",[1752],{"text":1753,"type":76},"TypeScript strict is an engineering requirement",{"type":1549,"attrs":1755,"content":1757},{"id":1756},"li_taaz9ywb",[1758],{"type":70,"attrs":1759,"content":1761},{"id":1760},"p_sxlap3v3",[1762],{"text":1763,"type":76},"DI isolation for AI services or any external clients matters architecturally",{"type":70,"attrs":1765,"content":1767},{"id":1766},"p_7rjsc690",[1768],{"text":1769,"type":76,"marks":1770},"Consider alternatives when:",[1771],{"type":79},{"type":1543,"attrs":1773,"content":1775},{"id":1774,"tight":1546},"ul_zhpoeylg",[1776,1786,1796,1806],{"type":1549,"attrs":1777,"content":1779},{"id":1778},"li_wk1vmibc",[1780],{"type":70,"attrs":1781,"content":1783},{"id":1782},"p_snce3atz",[1784],{"text":1785,"type":76},"MVP speed is primary → React",{"type":1549,"attrs":1787,"content":1789},{"id":1788},"li_nguzohrg",[1790],{"type":70,"attrs":1791,"content":1793},{"id":1792},"p_6qcahvqf",[1794],{"text":1795,"type":76},"SEO-critical consumer app → Next.js",{"type":1549,"attrs":1797,"content":1799},{"id":1798},"li_tef3u2ky",[1800],{"type":70,"attrs":1801,"content":1803},{"id":1802},"p_kxwueoyn",[1804],{"text":1805,"type":76},"Content site \u002F blog → Astro",{"type":1549,"attrs":1807,"content":1809},{"id":1808},"li_vwkfjzvd",[1810],{"type":70,"attrs":1811,"content":1813},{"id":1812},"p_1ucdgcng",[1814],{"text":1815,"type":76},"Team \u003C 5 without Angular experience → lower ramp-up cost matters more",{"type":83},{"type":85,"attrs":1818,"content":1820},{"id":1819,"level":36},"h_5zk3p0c4",[1821],{"text":1822,"type":76},"Sources",{"type":1543,"attrs":1824,"content":1826},{"id":1825,"tight":1546},"ul_1nei6qkj",[1827,1841,1855,1884,1908,1933,1957,1982,2006,2031,2045],{"type":1549,"attrs":1828,"content":1830},{"id":1829},"li_825fej2u",[1831],{"type":70,"attrs":1832,"content":1834},{"id":1833},"p_3b3cofpr",[1835,1839],{"text":1836,"type":76,"marks":1837},"Angular Blog (angular.dev\u002Fblog)",[1838],{"type":79},{"text":1840,"type":76}," — Announcing Angular v20 (Minko Gechev, May 2025).",{"type":1549,"attrs":1842,"content":1844},{"id":1843},"li_1pkq4i7d",[1845],{"type":70,"attrs":1846,"content":1848},{"id":1847},"p_ab3lgt79",[1849,1853],{"text":1850,"type":76,"marks":1851},"angular.dev\u002Froadmap",[1852],{"type":79},{"text":1854,"type":76}," (accessed June 2026) — Official feature roadmap and timeline.",{"type":1549,"attrs":1856,"content":1858},{"id":1857},"li_cmi6pkr0",[1859],{"type":70,"attrs":1860,"content":1862},{"id":1861},"p_rcif1kcg",[1863,1867,1878,1882],{"text":1864,"type":76,"marks":1865},"FrontendMinds (",[1866],{"type":79},{"text":1868,"type":76,"marks":1869},"frontendminds.com",[1870,1877],{"type":1871,"attrs":1872},"link",{"rel":1873,"href":1874,"class":1875,"title":9,"target":1876},"noopener noreferrer","http:\u002F\u002Ffrontendminds.com","editor-link","_blank",{"type":79},{"text":1879,"type":76,"marks":1880},", June 2026)",[1881],{"type":79},{"text":1883,"type":76}," — Angular 22 release details: Signal Forms stable, Angular Aria stable, MCP stable.",{"type":1549,"attrs":1885,"content":1887},{"id":1886},"li_awi9b6qt",[1888],{"type":70,"attrs":1889,"content":1891},{"id":1890},"p_r2aqrmfp",[1892,1896,1903,1906],{"text":1893,"type":76,"marks":1894},"Bacancy Technology (",[1895],{"type":79},{"text":1897,"type":76,"marks":1898},"bacancytechnology.com",[1899,1902],{"type":1871,"attrs":1900},{"rel":1873,"href":1901,"class":1875,"title":9,"target":1876},"http:\u002F\u002Fbacancytechnology.com",{"type":79},{"text":1879,"type":76,"marks":1904},[1905],{"type":79},{"text":1907,"type":76}," — Angular 22 new features and upgrade guide.",{"type":1549,"attrs":1909,"content":1911},{"id":1910},"li_wnqv4f3c",[1912],{"type":70,"attrs":1913,"content":1915},{"id":1914},"p_d8sr6nk9",[1916,1920,1927,1931],{"text":1917,"type":76,"marks":1918},"Cmarix (",[1919],{"type":79},{"text":1921,"type":76,"marks":1922},"cmarix.com",[1923,1926],{"type":1871,"attrs":1924},{"rel":1873,"href":1925,"class":1875,"title":9,"target":1876},"http:\u002F\u002Fcmarix.com",{"type":79},{"text":1928,"type":76,"marks":1929},", March 2026)",[1930],{"type":79},{"text":1932,"type":76}," — \"60+ Angular Statistics 2026\" — 51,737 companies, 4.65M downloads\u002Fweek, 18.2% Stack Overflow, 48.24% market share, 92% retention.",{"type":1549,"attrs":1934,"content":1936},{"id":1935},"li_0r47h6bs",[1937],{"type":70,"attrs":1938,"content":1940},{"id":1939},"p_mfn3fqc0",[1941,1945,1952,1955],{"text":1942,"type":76,"marks":1943},"mpiric Software (",[1944],{"type":79},{"text":1946,"type":76,"marks":1947},"mpiricsoftware.com",[1948,1951],{"type":1871,"attrs":1949},{"rel":1873,"href":1950,"class":1875,"title":9,"target":1876},"http:\u002F\u002Fmpiricsoftware.com",{"type":79},{"text":1879,"type":76,"marks":1953},[1954],{"type":79},{"text":1956,"type":76}," — \"React vs Angular vs Vue in 2026: Which for Enterprise?\"",{"type":1549,"attrs":1958,"content":1960},{"id":1959},"li_xmd93uso",[1961],{"type":70,"attrs":1962,"content":1964},{"id":1963},"p_lwojyo9k",[1965,1969,1976,1980],{"text":1966,"type":76,"marks":1967},"Scrimba (",[1968],{"type":79},{"text":1970,"type":76,"marks":1971},"scrimba.com",[1972,1975],{"type":1871,"attrs":1973},{"rel":1873,"href":1974,"class":1875,"title":9,"target":1876},"http:\u002F\u002Fscrimba.com",{"type":79},{"text":1977,"type":76,"marks":1978},", April 2026)",[1979],{"type":79},{"text":1981,"type":76}," — \"React vs Angular 2026\" — Stack Overflow 2025 data, Glassdoor salary data.",{"type":1549,"attrs":1983,"content":1985},{"id":1984},"li_l5i8jetk",[1986],{"type":70,"attrs":1987,"content":1989},{"id":1988},"p_057nupsz",[1990,1994,2001,2004],{"text":1991,"type":76,"marks":1992},"HeroDevs (",[1993],{"type":79},{"text":1995,"type":76,"marks":1996},"herodevs.com",[1997,2000],{"type":1871,"attrs":1998},{"rel":1873,"href":1999,"class":1875,"title":9,"target":1876},"http:\u002F\u002Fherodevs.com",{"type":79},{"text":1928,"type":76,"marks":2002},[2003],{"type":79},{"text":2005,"type":76}," — Angular CVEs: CVE-2025-59052, CVE-2025-66035, CVE-2025-66412. Angular 19 EOL May 2026.",{"type":1549,"attrs":2007,"content":2009},{"id":2008},"li_vewizpb9",[2010],{"type":70,"attrs":2011,"content":2013},{"id":2012},"p_n6y4rd38",[2014,2018,2025,2029],{"text":2015,"type":76,"marks":2016},"Angular Architects (",[2017],{"type":79},{"text":2019,"type":76,"marks":2020},"angulararchitects.io",[2021,2024],{"type":1871,"attrs":2022},{"rel":1873,"href":2023,"class":1875,"title":9,"target":1876},"http:\u002F\u002Fangulararchitects.io",{"type":79},{"text":2026,"type":76,"marks":2027},", May 2026)",[2028],{"type":79},{"text":2030,"type":76}," — \"Implementing AG-UI with Angular.\"",{"type":1549,"attrs":2032,"content":2034},{"id":2033},"li_febafuu5",[2035],{"type":70,"attrs":2036,"content":2038},{"id":2037},"p_yohwog8f",[2039,2043],{"text":2040,"type":76,"marks":2041},"Level Up Coding (May 2026)",[2042],{"type":79},{"text":2044,"type":76}," — \"Your Web App, Meet Your AI Agent — Angular WebMCP.\"",{"type":1549,"attrs":2046,"content":2048},{"id":2047},"li_vupx924s",[2049],{"type":70,"attrs":2050,"content":2052},{"id":2051},"p_utapg9mu",[2053,2057,2064,2068],{"text":2054,"type":76,"marks":2055},"Angular Blog (",[2056],{"type":79},{"text":2058,"type":76,"marks":2059},"blog.angular.dev",[2060,2063],{"type":1871,"attrs":2061},{"rel":1873,"href":2062,"class":1875,"title":9,"target":1876},"http:\u002F\u002Fblog.angular.dev",{"type":79},{"text":2065,"type":76,"marks":2066},", September 2025)",[2067],{"type":79},{"text":2069,"type":76}," — \"Beyond the Horizon: How Angular is Embracing AI\" — Angular MCP server, Angular Skills for coding agents.",{"type":83},{"type":70,"attrs":2072,"content":2074},{"id":2073},"p_b11yr97x",[2075],{"text":2076,"type":76,"marks":2077},"Version and data reflect June 2026. Angular 22 was released June 3, 2026. Check angular.dev\u002Froadmap for the current status of any feature. Salary figures are US averages from Glassdoor and may differ significantly by region.",[2078],{"type":2079},"italic","Angular 22 Architecture: The Enterprise Standard for 2026","Master Angular 22 architecture. Learn how zoneless defaults, Signal Forms, and reactive primitives help you build scalable, high-performance apps.","2026-08-24T14:53:53.315534+00:00",[2084,2107,2124,2138],{"id":2085,"slug":2086,"title":2087,"excerpt":2088,"image":2089,"featured":1546,"groupId":2090,"publishedAt":2091,"readingTime":2092,"views":2093,"author":2094,"category":2095,"tags":2096},"81f24e9a-fc6b-47d0-beb9-d00a6137ed99","framework-vs-sdk-who-calls-whom","Framework vs SDK: Who Calls Whom","Most developers memorize names, but few understand the mechanism. Here is the simple rule to tell a framework from an SDK and level up your debugging.","https:\u002F\u002Fmfgiomkkbihnlpfdxwrt.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fblog-assets\u002Fmedia\u002Ffeatured\u002F1787491947099-featured-ikba2e.jpg","0ccb21eb-6459-40ed-8110-227836e9bb74","2026-08-23T13:15:25.439194+00:00",10,0,{"name":49,"avatar":9},{"slug":13,"name":14,"color":15},[2097,2098,2101,2104],{"slug":59,"name":60},{"slug":2099,"name":2100},"python","Python",{"slug":2102,"name":2103},"runtime","Runtime",{"slug":2105,"name":2106},"sdk","Sdk",{"id":2108,"slug":2109,"title":2110,"excerpt":2111,"image":2112,"featured":44,"groupId":2113,"publishedAt":2114,"readingTime":2115,"views":2116,"author":2117,"category":2118,"tags":2119},"c2d6b1ca-29bf-401f-8ab9-a1f828504d0b","microfrontends-with-angular-and-nx-what-nobody-tells-you","Microfrontends with Angular and Nx: what nobody tells you","Every tutorial teaches how to set up microfrontends in minutes, but few reveal the architectural chaos that emerges after months of production deploys.","https:\u002F\u002Fmfgiomkkbihnlpfdxwrt.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fblog-assets\u002Fmedia\u002Ffeatured\u002F1785206853570-featured-zoyhgn.webp","3368e1b2-b6de-4e94-a3d4-294fae8ade13","2026-08-03T01:42:48.969355+00:00",15,5,{"name":49,"avatar":9},{"slug":13,"name":14,"color":15},[2120,2121,2122],{"slug":53,"name":54},{"slug":59,"name":60},{"slug":390,"name":2123},"TypeScript",{"id":2125,"slug":2126,"title":2127,"excerpt":2128,"image":2129,"featured":44,"groupId":2130,"publishedAt":2131,"readingTime":2132,"views":2092,"author":2133,"category":2134,"tags":2135},"36440333-311c-4081-92e6-030a04a38fed","astro-island-architecture-performance-and-where-the-framework-truly-fits","Astro: Island Architecture, Performance, and Where the Framework Truly Fits","Astro challenges the modern web status quo by prioritizing static HTML and isolating interactivity into independent, lightweight code islands.","https:\u002F\u002Fmfgiomkkbihnlpfdxwrt.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fblog-assets\u002Fmedia\u002Ffeatured\u002F1785721161920-featured-a5vzkb.webp","cb62459e-7ace-43d3-a545-661c5695e925","2026-08-03T01:00:45.280114+00:00",38,{"name":49,"avatar":9},{"slug":13,"name":14,"color":15},[2136,2137],{"slug":59,"name":60},{"slug":390,"name":2123},{"id":2139,"slug":2140,"title":2141,"excerpt":2142,"image":2143,"featured":44,"groupId":2144,"publishedAt":2145,"readingTime":2146,"views":2093,"author":2147,"category":2148,"tags":2149},"633b6488-2a90-4632-86a5-9cff7ed52f08","javascript-event-loop-the-heart-of-non-blocking-concurrency-revisited-in-2025","JavaScript Event Loop: The Heart of Non-Blocking Concurrency — Revisited in 2025","The Event Loop is not just a simple loop, but a sophisticated coordination mechanism between Call Stack, queues, and runtime. Essential for JS concurrency, it enables thousands of asynchronous operations without blocking the UI. This guide explores its structure, differences between Node.js and browsers, common bugs, advanced techniques, and 2025 trends like Structured Concurrency and scheduler.yield().","https:\u002F\u002Fmfgiomkkbihnlpfdxwrt.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fblog-assets\u002Fmedia\u002Ffeatured\u002F1772847201637-featured-oreiro.jpeg","df6ca967-8130-4b2d-bcac-3532a150131e","2026-07-26T18:54:25.359533+00:00",6,{"name":49,"avatar":9},{"slug":13,"name":14,"color":15},[2150,2151],{"slug":59,"name":60},{"slug":2152,"name":2153},"nodejs","Node.js",{"pt":2155,"en":40,"es":2156},"pare-de-arriscar-seu-frontend-a-arquitetura-definitiva-do-angular-22","deja-de-arriesgar-tu-frontend-la-arquitectura-definitiva-de-angular-22"]