<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Johannes Hoppe</title>
    <description>The latest articles on DEV Community by Johannes Hoppe (@johanneshoppe).</description>
    <link>https://dev.to/johanneshoppe</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F341823%2F24106618-a3c6-4fec-9ba3-91e819b9bef7.jpg</url>
      <title>DEV Community: Johannes Hoppe</title>
      <link>https://dev.to/johanneshoppe</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/johanneshoppe"/>
    <language>en</language>
    <item>
      <title>TypeScript Hero is dead (is yet another VS Code extension gone forever?)</title>
      <dc:creator>Johannes Hoppe</dc:creator>
      <pubDate>Mon, 16 Mar 2026 10:17:37 +0000</pubDate>
      <link>https://dev.to/johanneshoppe/typescript-hero-is-dead-is-yet-another-vs-code-extension-gone-forever-1gpg</link>
      <guid>https://dev.to/johanneshoppe/typescript-hero-is-dead-is-yet-another-vs-code-extension-gone-forever-1gpg</guid>
      <description>&lt;p&gt;I use TypeScript Hero every single day. Multiple times per hour, actually. One keyboard shortcut (&lt;code&gt;Ctrl+Alt+O&lt;/code&gt;) and my messy imports transform into a well organized, alphabetically sorted list. Unused imports? Gone. Proper grouping? Done. Consistent formatting? Check. Then one day, VSCode hit me with a warning I couldn't ignore: &lt;strong&gt;"This extension is deprecated as it is no longer being maintained."&lt;/strong&gt; My heart sank. Not another one!&lt;/p&gt;

&lt;p&gt;So, is TypeScript Hero dead? &lt;strong&gt;Yes!&lt;/strong&gt;&lt;br&gt;
But there's a new hero in town! 🦸‍♂️&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqeo9c2gdlezrloiutckh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqeo9c2gdlezrloiutckh.png" alt="Mini TypeScript Hero" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Mini TypeScript Hero – Small hero. Big cleanup!
&lt;/h1&gt;


&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Here's what TypeScript Hero does for me (and hopefully for you too):&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before&lt;/strong&gt; (the chaos):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;UserDetail&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./components/user-detail&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;UnusedService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./services/unused&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@angular/router&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;switchMap&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rxjs/operators&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;OnInit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;BookList&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./components/book-list&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After&lt;/strong&gt; pressing &lt;code&gt;Ctrl+Alt+O&lt;/code&gt; (or &lt;code&gt;Cmd+Alt+O&lt;/code&gt; on macOS):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Router&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;switchMap&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rxjs/operators&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;BookList&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./components/book-list&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;UserDetail&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./components/user-detail&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the Angular libraries are grouped together and automatically merged into one import. Then the local imports follow, separated by a blank line. Unused imports are removed. Everything is sorted with consistent quotes and semicolons. And if you want, you could even go further and separate the RxJS operators into their own group. Beautiful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This really helps keep the code clean.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdrklkp5043bo00gm2c09.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdrklkp5043bo00gm2c09.gif" alt="Demo" width="800" height="514"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Mission
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://me.cbue.ch/" rel="noopener noreferrer"&gt;Christoph Bühler&lt;/a&gt;, the original author of TypeScript Hero, no longer had time to maintain the extension. He's moved on from TypeScript work, which is totally fair. We all have our seasons with different technologies.&lt;/p&gt;

&lt;p&gt;But I needed this feature. Every. Single. Day.&lt;br&gt;
So I reached out to Christoph with a simple question: Could I pick up TypeScript Hero and release it as a new extension?&lt;br&gt;
His response was incredibly kind and supportive. He gave me his blessing, shared what code he still had, and even said he'd be excited to see the work continue.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My mission was simple&lt;/strong&gt;: Preserve this feature for myself. And hopefully, other people will like it too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cool New Features
&lt;/h2&gt;

&lt;p&gt;While modernizing, I added some features that the original never had:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🗂️ Organize entire folders or your whole workspace at once!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Right-click any folder in the Explorer → "Organize imports in folder". Or run "Organize imports in workspace" from the Command Palette. Perfect for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cleaning up after major refactorings&lt;/li&gt;
&lt;li&gt;Onboarding legacy projects to your team's import style&lt;/li&gt;
&lt;li&gt;Enforcing consistent imports across hundreds of files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The extension intelligently skips &lt;code&gt;node_modules&lt;/code&gt;, &lt;code&gt;dist&lt;/code&gt;, &lt;code&gt;build&lt;/code&gt;, and other artifacts. You can also configure custom exclude patterns for auto-generated files your team shouldn't touch.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzfd8kh0mozdquq1vm8jr.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzfd8kh0mozdquq1vm8jr.gif" alt="Folder organization demo" width="720" height="469"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⚠️ Conflict detection&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Using Prettier or ESLint plugins that also sort imports? Run "Check for configuration conflicts" to detect if multiple tools are fighting over your imports. This would have saved me a lot of fiddling in the past.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wait, Doesn't VS Code Already Have This?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Yes, but no.&lt;/strong&gt; VS Code has a built-in "Organize Imports" feature that removes unused imports, sorts alphabetically, and merges duplicate imports. Since TypeScript 4.7+, it preserves blank lines you manually add between import groups. The fundamental difference is &lt;strong&gt;how groups are created&lt;/strong&gt;: you manually type blank lines (VS Code preserves them), versus automatic grouping (Mini TypeScript Hero creates them).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;VS Code's approach:&lt;/strong&gt; You type blank lines between imports to create groups. VS Code sees these blank lines and treats them as group separators, sorting within each group while preserving the blank lines. If you want external (node_modules) imports separated from internal (local files) imports, you manually add a blank line between them and maintain it yourself every time you add new imports.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mini TypeScript Hero's approach:&lt;/strong&gt; The extension automatically separates external (node_modules) from internal (local files) imports with blank lines between them. This will cover most use cases without any configuration. Want more? Optionally add specific patterns like &lt;code&gt;["/^@angular/", "/rxjs/", "Workspace"]&lt;/code&gt; to group framework or library imports separately. No manual maintenance required.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What VS Code cannot do:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;❌ &lt;strong&gt;Automatically create groups based on patterns&lt;/strong&gt; — Without manual blank lines, VS Code sorts everything alphabetically as one flat list&lt;br&gt;
❌ &lt;strong&gt;Remove &lt;code&gt;/index&lt;/code&gt; from paths&lt;/strong&gt; — Keeps &lt;code&gt;./lib/index&lt;/code&gt; as-is instead of cleaning to &lt;code&gt;./lib&lt;/code&gt;&lt;br&gt;
❌ &lt;strong&gt;Sort by first specifier&lt;/strong&gt; — Only sorts by module path, not by the first imported name&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In practice:&lt;/strong&gt; When you add a new import, VS Code requires you to manually maintain blank line separators between import groups. With Mini TypeScript Hero, you press &lt;code&gt;Ctrl+Alt+O&lt;/code&gt; and it automatically places imports in the correct groups with proper spacing. Configure once, organize forever.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Changed Under the Hood
&lt;/h2&gt;

&lt;p&gt;The original TypeScript Hero used Christoph's own &lt;code&gt;typescript-parser&lt;/code&gt; library (&lt;a href="https://github.com/buehler/node-typescript-parser" rel="noopener noreferrer"&gt;node-typescript-parser&lt;/a&gt; on GitHub), a great piece of software that did its job well. But like the extension itself, it hasn't been maintained in years. Updating it to work with modern TypeScript versions would become increasingly challenging.&lt;/p&gt;

&lt;p&gt;For a tool I rely on daily, that was a ticking time bomb.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The old engine:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Custom-built &lt;code&gt;typescript-parser&lt;/code&gt; (Christoph's library, great but unmaintained)&lt;/li&gt;
&lt;li&gt;InversifyJS for dependency injection&lt;/li&gt;
&lt;li&gt;A lot of hand-written infrastructure code from 2018&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The new engine:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/dsherret/ts-morph" rel="noopener noreferrer"&gt;&lt;code&gt;ts-morph&lt;/code&gt;&lt;/a&gt; for parsing (actively maintained, battle-tested)&lt;/li&gt;
&lt;li&gt;TypeScript with strict mode&lt;/li&gt;
&lt;li&gt;Leaner codebase — delegate the heavy lifting to a proven library instead of rolling our own parser&lt;/li&gt;
&lt;li&gt;No deprecated dependencies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Other improvements:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Smart blank line handling&lt;/strong&gt;: Choose how many blank lines you want after imports (1, 2, or preserve existing). The old behavior where blank lines would sometimes "move" unpredictably is now configurable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configurable import merging&lt;/strong&gt;: Combine multiple imports from the same module into one clean statement. Migrated users keep their original behavior; new users get modern best practices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modern TypeScript support&lt;/strong&gt;: Full support for &lt;code&gt;import type&lt;/code&gt; syntax and import attributes (&lt;code&gt;with { type: 'json' }&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal was simple: &lt;strong&gt;Future-proof&lt;/strong&gt;. Make sure this tool keeps working for years to come, without depending on abandoned libraries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Migration
&lt;/h2&gt;

&lt;p&gt;If you're already using TypeScript Hero, switching is straightforward:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install Mini TypeScript Hero from the marketplace&lt;/li&gt;
&lt;li&gt;Open VSCode&lt;/li&gt;
&lt;li&gt;Your settings automatically migrate (one-time, on first startup)&lt;/li&gt;
&lt;li&gt;Done.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All your custom configurations transfer automatically — quote style, semicolons, import grouping rules, blank line handling, everything. The extension preserves your output format by automatically enabling &lt;code&gt;legacyMode: true&lt;/code&gt; for migrated users, which matches the old TypeScript Hero behavior as closely as possible, including replicating certain quirks to ensure consistent output. You can switch to the new defaults anytime you want cleaner, more consistent behavior. You can even keep both extensions installed if you want, but I highly recommend deactivating the old hero because both will fight for the same shortcut. Speaking of which: the keyboard shortcut works exactly the same, &lt;code&gt;Ctrl+Alt+O&lt;/code&gt; (or &lt;code&gt;Cmd+Alt+O&lt;/code&gt; on macOS).&lt;/p&gt;

&lt;h2&gt;
  
  
  A Quick Thank You
&lt;/h2&gt;

&lt;p&gt;Thanks to Christoph Bühler for creating TypeScript Hero in the first place. The original code, the design decisions, the thoughtful features: all of that came from Christoph.&lt;/p&gt;

&lt;p&gt;I'm committed to keeping this tool maintained and working for the community. This extension is &lt;strong&gt;MIT licensed and free for everyone&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install Mini TypeScript Hero Now
&lt;/h2&gt;

&lt;p&gt;Ready to organize your imports with a single keystroke?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Install from VSCode Marketplace:&lt;/strong&gt;&lt;br&gt;
Search for "Mini TypeScript Hero" or visit:&lt;br&gt;
👉 &lt;a href="https://marketplace.visualstudio.com/items?itemName=angular-schule.mini-typescript-hero" rel="noopener noreferrer"&gt;marketplace.visualstudio.com/items?itemName=angular-schule.mini-typescript-hero&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Keyboard shortcut:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;Ctrl+Alt+O&lt;/code&gt; (Windows/Linux) | &lt;code&gt;Cmd+Alt+O&lt;/code&gt; (macOS)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Works with:&lt;/strong&gt;&lt;br&gt;
TypeScript, JavaScript, TSX, JSX&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Found a bug or have a feature request?&lt;/strong&gt;&lt;br&gt;
👉 &lt;a href="https://github.com/angular-schule/mini-typescript-hero" rel="noopener noreferrer"&gt;github.com/angular-schule/mini-typescript-hero&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's Next? (Your call to action!)
&lt;/h2&gt;

&lt;p&gt;Here's a genuine question: &lt;strong&gt;Does nicely formatted code still matter in the age of AI?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With AI generating more and more code, the temptation is to just let it write whatever and move on. But I still believe that clean, well-organized imports make a real difference. For readability, for code reviews, for the next person who opens your file.&lt;/p&gt;

&lt;p&gt;So if you still care about this stuff, tell me. I'm considering a standalone CLI tool for CI pipelines, or an MCP server that formats all that AI-generated slop before it lands in your codebase. But only if someone actually wants it.&lt;/p&gt;

&lt;p&gt;Please reach out! 🙏 &lt;a href="https://github.com/angular-schule/mini-typescript-hero" rel="noopener noreferrer"&gt;Give it a star on GitHub&lt;/a&gt;, &lt;a href="https://github.com/angular-schule/mini-typescript-hero/issues" rel="noopener noreferrer"&gt;give me feedback via an issue&lt;/a&gt; or just drop me a nice message.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; TypeScript Hero isn't really dead. I picked it up and modernized it as Mini TypeScript Hero. VS Code has basic organize imports, but Mini TypeScript Hero gives you custom grouping patterns, formatting control, and import organization that can match your team's style guide.&lt;/p&gt;

&lt;p&gt;Happy coding! ✨&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>javascript</category>
      <category>vscode</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Everything GitHub: Continuous Integration, Deployment and Hosting for your Angular App</title>
      <dc:creator>Johannes Hoppe</dc:creator>
      <pubDate>Tue, 25 Feb 2020 22:17:33 +0000</pubDate>
      <link>https://dev.to/angular/everything-github-continuous-integration-deployment-and-hosting-for-your-angular-app-25j3</link>
      <guid>https://dev.to/angular/everything-github-continuous-integration-deployment-and-hosting-for-your-angular-app-25j3</guid>
      <description>&lt;p&gt;&lt;strong&gt;In this article we want to use several tools from the GitHub universe to launch a website with Angular. We will establish a professional pipeline, including version management, continuous deployment and web hosting. Best of all, for public repositories, this will not cost you a single cent!&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;Table of contents:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1. All parts explained&lt;/li&gt;
&lt;li&gt;2. A simple Angular app&lt;/li&gt;
&lt;li&gt;3. Hosting the source code on GitHub&lt;/li&gt;
&lt;li&gt;4. A first deployment to GitHub Pages&lt;/li&gt;
&lt;li&gt;5. Automating the Deployment with GitHub Actions&lt;/li&gt;
&lt;li&gt;6. Extra: Custom Domains&lt;/li&gt;
&lt;li&gt;Summary&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;All starts are hard, so we will try to explain all steps in detail, so that you can eventually come up with a fully deployed Angular app. During our journey we will get comfortable with &lt;code&gt;angular-cli-ghpages&lt;/code&gt; and GitHub Actions, and see how they work together. We will create and setup tokens and GitHub Action YAML files, to deploy our Angular app directly to GitHub Pages, a free webhosting service from GitHub.&lt;/p&gt;
&lt;h2&gt;
  
  
  1. All parts explained
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1.1. Git and GitHub Version Control
&lt;/h3&gt;

&lt;p&gt;Version Control allows you to keep track of your work and helps you to easily recognize the changes you have made, whether it is program code, text, images or other data. This is also absolutely necessary if you want to work together in a team efficiently. &lt;a href="https://git-scm.com/" rel="noopener noreferrer"&gt;Git&lt;/a&gt; is a free software for distributed version management and is currently the most popular solution. The leading platform around Git is GitHub, which belongs to Microsoft since the end of 2018.&lt;/p&gt;
&lt;h3&gt;
  
  
  1.2. GitHub Actions
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;GitHub Actions&lt;/a&gt; is a solution for CI/CD pipelines (continuous integration and continuous delivery). With actions we can test, build and release our code while staying in the GitHub ecosystem. GitHub has just recently launched this product to the market and is now directly competing with Travis CI, CircleCI or AppVeyor. Similar to other state-of-the-art CI/CD tools, the individual steps are all saved to a file in YAML format.&lt;/p&gt;
&lt;h3&gt;
  
  
  1.3. GitHub Pages
&lt;/h3&gt;

&lt;p&gt;You can use &lt;a href="https://pages.github.com/" rel="noopener noreferrer"&gt;GitHub Pages&lt;/a&gt; to host a website directly from a GitHub repository. This website can either contain completely static content (i.e. pure HTML files and assets, but no scripts running on the server) or you can use Jekyll to convert Markdown files to static content. Since we work with Angular, we do not need Jekyll as a static site generator . A good companion for Angular is the static site generator &lt;a href="https://github.com/scullyio/scully" rel="noopener noreferrer"&gt;Scully&lt;/a&gt;, which we will definitely cover in an upcoming article. &lt;/p&gt;
&lt;h3&gt;
  
  
  1.4. angular-cli-ghpages
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/angular-schule/angular-cli-ghpages" rel="noopener noreferrer"&gt;angular-cli-ghpages&lt;/a&gt; is a project made by Johannes Hoppe, one of the two authors of this article. His Angular Book uses a new GitHub repository in every chapter (so there are quite a lot of repos 😅). So he developed a solution that makes it as easy as possible to bring an Angular App to GitHub Pages. The project exists since 2016 and if it was started today, it would certainly have a nicer name. According to GitHub, 7100 projects already deploy their apps with angular-cli-ghpages.&lt;/p&gt;
&lt;h3&gt;
  
  
  1.5. GitHub plans
&lt;/h3&gt;

&lt;p&gt;The following information is based on the details from &lt;a href="https://github.com/pricing" rel="noopener noreferrer"&gt;the pricing page&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;free plan&lt;/strong&gt; gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;unlimited public repositories&lt;/li&gt;
&lt;li&gt;unlimited private repositories&lt;/li&gt;
&lt;li&gt;only 3 collaborators for private repositories&lt;/li&gt;
&lt;li&gt;2000 total GitHub action minutes/month&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;strong&gt;pro plan&lt;/strong&gt; gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;everything that is included in the free plan&lt;/li&gt;
&lt;li&gt;unlimited collaborators&lt;/li&gt;
&lt;li&gt;3000 total action minutes/month &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Back in 2016, GitHub migrated from a pricing based on the number of repositories to a new schema that considers the number of users. &lt;strong&gt;Legacy plans&lt;/strong&gt; do not have access to GitHub Actions.&lt;/p&gt;

&lt;p&gt;This article will distinguish several times between private and public repos. The reason behind this is due to the following point, which we must take into account:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub Pages&lt;/strong&gt; is available... &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;in public repositories with GitHub Free.&lt;/li&gt;
&lt;li&gt;in public and &lt;strong&gt;private&lt;/strong&gt; repositories with GitHub Pro and all the other paid plans.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Plan&lt;/th&gt;
&lt;th&gt;Private repos&lt;/th&gt;
&lt;th&gt;Actions&lt;/th&gt;
&lt;th&gt;Pages for public repos&lt;/th&gt;
&lt;th&gt;Pages for private repos&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;✅️&lt;/td&gt;
&lt;td&gt;✅️&lt;/td&gt;
&lt;td&gt;✅️&lt;/td&gt;
&lt;td&gt;❌️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pro and Higher&lt;/td&gt;
&lt;td&gt;✅️&lt;/td&gt;
&lt;td&gt;✅️&lt;/td&gt;
&lt;td&gt;✅️&lt;/td&gt;
&lt;td&gt;✅️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Legacy paid plans&lt;/td&gt;
&lt;td&gt;✅️&lt;/td&gt;
&lt;td&gt;❌️&lt;/td&gt;
&lt;td&gt;✅️&lt;/td&gt;
&lt;td&gt;?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Please register an account on github.com, if you haven't already done so.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;For this article, it is sufficient to use the free plan!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By the way, this sounds a bit like advertising.&lt;br&gt;
But we're not affiliated with GitHub in any way.&lt;br&gt;
We're just passionate GitHub users and recommend their service based on our experience.&lt;/p&gt;
&lt;h2&gt;
  
  
  2. A simple Angular app
&lt;/h2&gt;

&lt;p&gt;We assume that the majority of our readers have already worked with Angular. However, in order for this article to be as complete as possible, we will very shortly set up a simple website based on Angular.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;If you have not already done so, please install &lt;a href="https://nodejs.org" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt;, &lt;a href="https://www.google.com/chrome/" rel="noopener noreferrer"&gt;Google Chrome&lt;/a&gt; and optionally &lt;a href="https://code.visualstudio.com" rel="noopener noreferrer"&gt;Visual Studio Code&lt;/a&gt;. Later on we also need &lt;a href="https://git-scm.com/" rel="noopener noreferrer"&gt;Git&lt;/a&gt; for the deployment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install the latest version of the Angular CLI  globally and create a new Angular project.&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @angular/cli
ng new everything-github-demo &lt;span class="nt"&gt;--defaults&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Now we want to make some small changes to the source code.&lt;br&gt;
With the command &lt;code&gt;code .&lt;/code&gt; we open the current directory in the &lt;em&gt;Visual Studio Code&lt;/em&gt; editor. Of course you can also open the folder through the menus of VS Code.&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;everything-github-demo
code &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;We change the content of the &lt;code&gt;AppModule&lt;/code&gt; and &lt;code&gt;AppComponent&lt;/code&gt; a bit and call a HTTP API. By this, we want to prove that the Google search engine can correctly crawl our website – even with data loaded from remote.&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/app/app.module.ts (excerpt)&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;HttpClientModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/common/http&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;NgModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;declarations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;AppComponent&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;BrowserModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;HttpClientModule&lt;/span&gt; &lt;span class="c1"&gt;// NEW: import HttpClientModule!&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;bootstrap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;AppComponent&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;For example, we could load a book from our backend at &lt;a href="https://api.angular.schule" rel="noopener noreferrer"&gt;https://api.angular.schule&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/app/app.component.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;HttpClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/common/http&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;templateUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app.component.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;styleUrls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app.component.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;book&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.angular.schule/book/9783864906466&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;book&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;This is the matching template:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- src/app/app.component.html --&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Everything GitHub Demo&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;h4&amp;gt;&lt;/span&gt;deployed with ❤️ and angular-cli-ghpages&lt;span class="nt"&gt;&amp;lt;/h4&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
  This is some dynamically loaded content that we hope to find in the Google index later on:
&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;hr&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;{{ book.title }}&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;[src]=&lt;/span&gt;&lt;span class="s"&gt;"book.firstThumbnailUrl"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"100"&lt;/span&gt; &lt;span class="na"&gt;align=&lt;/span&gt;&lt;span class="s"&gt;"left"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  {{ book.description }}
&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;This example loads data from a remote API. Our hope is that later we will be able to find both the regular text as well as the loaded book in the index of our preferred search engine. We have also added &lt;a href="https://getbootstrap.com" rel="noopener noreferrer"&gt;Bootstrap CSS&lt;/a&gt; to make the result look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhw1rl2ncxh7935n9l6fe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhw1rl2ncxh7935n9l6fe.png" alt="Screenshot of the Demo page" width="800" height="636"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;h2&gt;
  
  
  3. Hosting the source code on GitHub
&lt;/h2&gt;

&lt;p&gt;Now we take care of version management.&lt;br&gt;
This is very easy because the Angular CLI has already created a local Git repository for us. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;First things first: Let's save the latest changes.&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"chore: demo content"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Let's crete a GitHub repository. In the upper-right corner of any GitHub page, use the ➕ drop-down menu, and select &lt;strong&gt;New repository&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F884e05r2ziwmvcebifi4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F884e05r2ziwmvcebifi4.png" alt="Screenshot" width="192" height="201"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Choose a short, memorable name for your repository. In our example, we will call it &lt;code&gt;everything-github-demo&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;For now, choose to make the repository &lt;strong&gt;public&lt;/strong&gt;. Please note, the source code of public repositories is visible to the public.  Since we want to use the free GitHub plan, we have to keep it public or we would lose access to the free hosting service of GitHub Pages.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Since we already have source code, you should &lt;strong&gt;not&lt;/strong&gt; initialize the repository with a README.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjfo9de4txubdm1bomh4i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjfo9de4txubdm1bomh4i.png" alt="Screenshot" width="800" height="368"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;After you have pressed "Create Repository" a confirmation page will appear. You can now connect to GitHub using SSH or HTTPS. Both ways will work, but &lt;a href="https://help.github.com/en/github/using-git/which-remote-url-should-i-use" rel="noopener noreferrer"&gt;GitHub recommends HTTPS&lt;/a&gt;. If you are completely lost in authenticating against GitHub, try cloning another repository with &lt;a href="https://desktop.github.com/" rel="noopener noreferrer"&gt;GitHub Desktop&lt;/a&gt; first. For the remaining article we assume that the communication has been successfully established.&lt;/p&gt;

&lt;p&gt;To add GitHub as a new remote for our local repository, use the &lt;code&gt;git remote add&lt;/code&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;git remote add origin https://github.com/&amp;lt;username&amp;gt;/&amp;lt;repositoryname&amp;gt;.git
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Replace &lt;code&gt;&amp;lt;username&amp;gt;&lt;/code&gt; (or organisation name) and &lt;code&gt;&amp;lt;repositoryname&amp;gt;&lt;/code&gt; with your username from GitHub and the name of your new repository. &lt;small&gt;(In our example, it's &lt;code&gt;git remote add origin https://github.com/angular-schule/everything-github-demo.git&lt;/code&gt;)&lt;/small&gt;&lt;/p&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Finally, we can transfer the whole repository to GitHub:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin master
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;/ol&gt;

&lt;h2&gt;
  
  
  4. A first deployment to GitHub Pages
&lt;/h2&gt;

&lt;p&gt;We are now ready to host our first app on GitHub Pages. For this, the project must be compiled first and the compiled assets should be pushed to a new branch. That functionality is provided by &lt;code&gt;angular-cli-ghpages&lt;/code&gt;. GitHub will activate the hosting automatically, if this branch has the name &lt;code&gt;gh-pages&lt;/code&gt; – which is the default setting for &lt;code&gt;angular-cli-ghpages&lt;/code&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;The following command adds &lt;code&gt;angular-cli-ghpages&lt;/code&gt; to your project.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng add angular-cli-ghpages
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now we can deploy our project to GitHub pages with all default settings. The project will be automatically built in production mode:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng deploy
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The deployment will create a temporary git repository and will commit/push all files from &lt;code&gt;dist/everything-github-demo&lt;/code&gt; to a branch with the name &lt;code&gt;gh-pages&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;However, in this example we haven't provided a target repository. In this case the deployment assumes that the current working directory is already a Git repository, and that we want to push changes to the same repository with the name &lt;code&gt;origin&lt;/code&gt;. We have prepared this before with the command &lt;code&gt;git remote add&lt;/code&gt;, so there is nothing to do here for us.  &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The app should be available at &lt;code&gt;https://&amp;lt;username&amp;gt;.github.io/&amp;lt;repositoryname&amp;gt;/&lt;/code&gt; soon. If it is not immediately available, you should first wait a moment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If we now check the results (in our case at &lt;a href="https://angular-schule.github.io/everything-github-demo/" rel="noopener noreferrer"&gt;https://angular-schule.github.io/everything-github-demo/&lt;/a&gt;) we will see a blank page! 😲 But no problem, we open the Console panel of the Chrome DevTools by pressing &lt;code&gt;Control+Shift+I&lt;/code&gt; (Windows, Linux) or &lt;code&gt;Command+Option+I&lt;/code&gt; (Mac). We immediately see some red 404 errors for all files:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Failed to load resource: the server responded with a status of 404 ()&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The reason for this: The application is configured as if it is running in the root path of the domain. However, this is not the case here! Our application is located in the &lt;code&gt;/&amp;lt;repositoryname&amp;gt;/&lt;/code&gt; path, so all links are broken. Of course, this is adjustable – let's try the deployment a second time with the &lt;code&gt;--base-href&lt;/code&gt; option:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng deploy &lt;span class="nt"&gt;--base-href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/&amp;lt;repositoryname&amp;gt;/

&lt;span class="c"&gt;# so in our case it must be&lt;/span&gt;
ng deploy &lt;span class="nt"&gt;--base-href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/everything-github-demo/
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;&lt;strong&gt;Hint:&lt;/strong&gt; Please make sure to really add the trailing slash. It won't work without!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now you should see our app running on GitHub Pages! You can make sure that everything went well by going into the &lt;strong&gt;Settings&lt;/strong&gt; of the repo. Scroll down there to the &lt;em&gt;GitHub Pages&lt;/em&gt; section. The following should appear here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1jfapyx8g9hjzfo3zdhy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1jfapyx8g9hjzfo3zdhy.png" alt="Screenshot" width="800" height="719"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hint:&lt;/strong&gt; You can also see the setting for a custom domain here. Please do not try to set a value. This will work at first, but the setting is not permanent, because &lt;code&gt;angular-cli-ghpages&lt;/code&gt; will overwrite it again.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now add, commit and push the changes:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"build: add angular-cli-gh-pages"&lt;/span&gt;
git push origin master
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  5. Automating the Deployment with GitHub Actions
&lt;/h2&gt;

&lt;p&gt;We don't want to stop here and trigger the deployment manually all the time. An ideally workflow would be to make changes to the app and the deployment will then be handled automatically for us. For this we want to use GitHub Actions which is now available for all repositories. So there is no need to register anymore, we can start right now! 🚀&lt;/p&gt;

&lt;p&gt;As with all CI/CD systems, we have to think about how to grant the necessary write permissions to our repo.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.1 About all tokens
&lt;/h3&gt;

&lt;p&gt;The easiest way to grant access to the repository is to implement this with tokens. Tokens can be used instead of a password for Git over HTTPS (&lt;em&gt;this is what we want to do&lt;/em&gt;), or can be used to authenticate to the GitHub API (&lt;em&gt;angular-cli-ghpages right now does not use the GitHub API at all&lt;/em&gt;).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;⚠️ Warning:&lt;/strong&gt; Treat tokens like passwords and keep them secret. Always use tokens as environment variables instead of hardcoding them into your code!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At GitHub there are several types of tokens, which we have to distinguish carefully. The following two are relevant for us:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;GH_TOKEN&lt;/code&gt; / Personal access token:&lt;/strong&gt; As the name suggests, personal access tokens grant rights that a particular user has. In order to prevent the release of too many rights, the range of features can be limited with so-called "scopes". Furthermore, scopes can not grant any additional permission beyond those the user already has. Read more about the &lt;a href="https://developer.github.com/apps/building-oauth-apps/understanding-scopes-for-oauth-apps/#available-scopes" rel="noopener noreferrer"&gt;available scopes here&lt;/a&gt;. We will need the &lt;code&gt;repo&lt;/code&gt; access scope, which grants &lt;strong&gt;access to all&lt;/strong&gt; private and public repositories. The use of such a token is dangerous, because it's always possible that potentially someone with bad intentions could gain access to the token. In this case, the evil person would gain more rights than we should actually release  – because for the deployment we only need write access to one repo and not all of them. In many projects this token is stored in an environment variable called &lt;code&gt;GH_TOKEN&lt;/code&gt; or sometimess &lt;code&gt;PERSONAL_TOKEN&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;GITHUB_TOKEN&lt;/code&gt; / Installation access token:&lt;/strong&gt; GitHub provides this kind of token to authenticate on behalf of GitHub Actions.   When you enable GitHub Actions, GitHub automatically installs a GitHub App on your repository,   and makes this "installation access token" available as a secret.    This is great because there is no need to set up anything extra.   Furthermore, the token's permissions are &lt;strong&gt;limited to the repository&lt;/strong&gt; that contains the workflow.   The installation access token expires after 60 minutes.   GitHub fetches a token for each job, before the job begins.   This is pretty awesome, because there are very limited possibilities of what a malicious person could take advantage of. For more information, see "&lt;a href="https://help.github.com/en/actions/automating-your-workflow-with-github-actions/authenticating-with-the-github_token" rel="noopener noreferrer"&gt;Authenticating with the GITHUB_TOKEN&lt;/a&gt;".&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Git via SSH:&lt;/strong&gt; As already mentioned, GitHub recommends &lt;a href="https://help.github.com/en/github/using-git/which-remote-url-should-i-use" rel="noopener noreferrer"&gt;HTTPS&lt;/a&gt;. Of course, we could ignore this advice and save a private key as a secret and use this to authenticate via SSH. However, this key would still be bound to one user and would grant write access to all repositories of the user, too. We do not recommend this option at all, because it's really not very common to maintain public keys on GitHub like one does this with tokens that were at least designed for the purpose of rights management... &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In a perfect world the &lt;code&gt;GITHUB_TOKEN&lt;/code&gt; would do all the work for us. However, for &lt;strong&gt;public&lt;/strong&gt; repositories it doesn't have authorization to create any successive events, such as GitHub Pages builds. This means, we can actually push to our &lt;code&gt;gh-pages&lt;/code&gt; branch using the &lt;code&gt;GITHUB_TOKEN&lt;/code&gt; and all the changes would be visible in version control. But this would NOT trigger a GitHub Pages build so that the website would not change at all (&lt;a href="https://github.com/angular-schule/angular-cli-ghpages/issues/73#issuecomment-527405699" rel="noopener noreferrer"&gt;see issue #73&lt;/a&gt; and &lt;a href="https://github.community/t5/GitHub-Actions/Github-action-not-triggering-gh-pages-upon-push/m-p/27454/highlight/true#M302" rel="noopener noreferrer"&gt;this comment&lt;/a&gt;). To further confuse the situation, however, for &lt;strong&gt;private repositories&lt;/strong&gt; the token works as desired...&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
This table gives you an overview:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Token&lt;/th&gt;
&lt;th&gt;Private repos&lt;/th&gt;
&lt;th&gt;Public repos&lt;/th&gt;
&lt;th&gt;Protocol&lt;/th&gt;
&lt;th&gt;Setup&lt;/th&gt;
&lt;th&gt;Security&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GITHUB_TOKEN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;✅️&lt;/td&gt;
&lt;td&gt;❌️&lt;/td&gt;
&lt;td&gt;HTTPS&lt;/td&gt;
&lt;td&gt;Unnecessary&lt;/td&gt;
&lt;td&gt;🤩&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GH_TOKEN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;✅️&lt;/td&gt;
&lt;td&gt;✅️&lt;/td&gt;
&lt;td&gt;HTTPS&lt;/td&gt;
&lt;td&gt;Necessary&lt;/td&gt;
&lt;td&gt;😐&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(Private SSH Key)&lt;/td&gt;
&lt;td&gt;✅️&lt;/td&gt;
&lt;td&gt;✅️&lt;/td&gt;
&lt;td&gt;SSH&lt;/td&gt;
&lt;td&gt;Necessary&lt;/td&gt;
&lt;td&gt;😓&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you are using a private repository, the decision should be clear. &lt;br&gt;
For free / public repositories you can use the personal access token and ideally consider the following tip.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Extra tip:&lt;/strong&gt; If you want to use &lt;strong&gt;public repos&lt;/strong&gt; and therefore use personal access tokens (known as &lt;code&gt;GH_TOKEN&lt;/code&gt; or &lt;code&gt;PERSONAL_TOKEN&lt;/code&gt;), we recommend to create an additional user account that is only dedicated to be used for deployments.&lt;/p&gt;

&lt;p&gt;Then this account should only get access to the repositories where there is something to deploy.&lt;br&gt;
This increases security again and we have a sufficiently good solution for public repositories.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  5.2 Automate a public repo (via &lt;code&gt;GH_TOKEN&lt;/code&gt;)
&lt;/h3&gt;
&lt;h4&gt;
  
  
  5.2.1 Setup a Personal Access Token
&lt;/h4&gt;

&lt;p&gt;If we are using a public repository (as described in the previous instructions), then we want to use a personal access token. The procedure is as following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create a &lt;a href="https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line" rel="noopener noreferrer"&gt;Personal Access Token &lt;strong&gt;with repo access&lt;/strong&gt;&lt;/a&gt; and make sure to copy your new token to the clipboard. You won’t be able to see it again later! If you want to remember the token later, save it in a secure place only (e.g. a password manager). Please make sure that the token has the following permissions:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fu6q8tjy0wbc4czzmk5q9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fu6q8tjy0wbc4czzmk5q9.png" alt="repo access" width="800" height="360"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Open your Angular app's GitHub repo.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go to &lt;strong&gt;Settings&lt;/strong&gt; &amp;gt; &lt;strong&gt;Secrets&lt;/strong&gt; and click on &lt;strong&gt;Add a new secret&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fh6erk7ltapqjm6bd8r6n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fh6erk7ltapqjm6bd8r6n.png" alt="add new secret" width="759" height="529"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Secrets are encrypted environment variables and only exposed to selected GitHub Actions. GitHub automatically redacts secrets printed to the log, but you should avoid printing secrets to the log intentionally.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a secret with name &lt;code&gt;GH_TOKEN&lt;/code&gt; and paste your token (which you copied in step 1) into the &lt;em&gt;value&lt;/em&gt; field. If you prefer, you can also choose the name &lt;code&gt;PERSONAL_TOKEN&lt;/code&gt; for all further steps. Finish this chapter by clicking the green &lt;strong&gt;Add secret&lt;/strong&gt; button. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffberb63oi331w8q62x4u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffberb63oi331w8q62x4u.png" alt="secret name and value" width="759" height="529"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is perfectly fine not to store the token anywhere else. You can always create new tokens and just throw the old ones away.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;
  
  
  5.2.2 Setup the GitHub Action Workflow
&lt;/h4&gt;

&lt;p&gt;Now we have everything ready to create an automated workflow that will do the work for us in the future. GitHub Actions usage is free for public repositories, as mentioned before.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Again in our repo, we go to &lt;strong&gt;Actions&lt;/strong&gt; and click on &lt;strong&gt;Set up workflow yourself&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3lxen61de8n1wsrus9wz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3lxen61de8n1wsrus9wz.png" alt="setup workflow" width="800" height="265"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;An editor will open. Keep the file name (e.g. &lt;code&gt;main.yml&lt;/code&gt;) as it is and simply replace the entire content with the following example:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to GitHub Pages via angular-cli-ghpages&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build-and-deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Use Node.js 10.x&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v1&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10.x&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Prepare and deploy&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;GH_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GH_TOKEN }}&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;npm install&lt;/span&gt;
        &lt;span class="s"&gt;npm run lint&lt;/span&gt;
        &lt;span class="s"&gt;###&lt;/span&gt;
        &lt;span class="s"&gt;# Configure Angular first!&lt;/span&gt;
        &lt;span class="s"&gt;####&lt;/span&gt;
        &lt;span class="s"&gt;# npm test -- --watch=false --progress=false --browsers=ChromeHeadlessCI&lt;/span&gt;
        &lt;span class="s"&gt;# npm run webdriver-update-ci&lt;/span&gt;
        &lt;span class="s"&gt;# npm run e2e -- --protractor-config=e2e/protractor-ci.conf.js --webdriver-update=false&lt;/span&gt;
        &lt;span class="s"&gt;####&lt;/span&gt;
        &lt;span class="s"&gt;npm run ng -- deploy --base-href=/everything-github-demo/ --name="Displayed Username" --email=your.mail@example.org&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Fortunately, the step &lt;code&gt;actions/checkout@v2&lt;/code&gt; checks-out a nice Git repository, where the remote &lt;code&gt;origin&lt;/code&gt; is already adjusted. However, username and email are not set. Therefore, we have to include these two values via parameters. Make sure to replace &lt;strong&gt;"Displayed Username"&lt;/strong&gt; (e.g. "I am a bot") and &lt;strong&gt;&lt;a href="mailto:your.mail@example.org"&gt;&lt;/a&gt;&lt;a href="mailto:your.mail@example.org"&gt;your.mail@example.org&lt;/a&gt;&lt;/strong&gt; with meaningful values in the above example. At this place you do not have to specify any real name and mail. However, you don't want to overdo it, because the provided values will be shown in the Git history later.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;If you want GitHub Actions to perform unit tests and end-to-end tests, you will need to make some small additional configurations in your Angular app. The necessary changes are described in the &lt;a href="https://angular.io/guide/testing#set-up-continuous-integration" rel="noopener noreferrer"&gt;Angular CLI Documentation&lt;/a&gt;. To be precise:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You need to &lt;a href="https://github.com/angular/angular-cli/wiki/stories-continuous-integration#update-test-configuration" rel="noopener noreferrer"&gt;update the test configurations for Karma and Protractor&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;You have to setup a specific &lt;a href="https://github.com/angular/angular-cli/wiki/stories-continuous-integration#chromedriver" rel="noopener noreferrer"&gt;chrome driver version&lt;/a&gt;.
Otherwise, the e2e tests will fail with an error message like this:
&lt;code&gt;... E/launcher - session not created: This version of ChromeDriver only supports Chrome version 79&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After those changes have been done, you can un-comment sections for the tests in above example.&lt;/p&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;We can also control when our workflows are triggered: It can be helpful to not have our workflow run on every push to every branch in the repo. For example, this workflow only runs on push events to &lt;code&gt;master&lt;/code&gt; and &lt;code&gt;release&lt;/code&gt; branches. Here we see the very common convention of grouping branches with a slash (e.g. &lt;code&gt;relase/42&lt;/code&gt;). Many Git clients will display those groups like folders.&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;release/*&lt;/span&gt;  &lt;span class="c1"&gt;# branches matching refs/heads/release/*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;As another example, we can setup a cronjob to run the script every day of the week from Monday – Friday at 02:00 AM:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;cron&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0 2 * * 1-5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;For more information see &lt;a href="https://help.github.com/articles/events-that-trigger-workflows" rel="noopener noreferrer"&gt;Events that trigger workflows&lt;/a&gt; and &lt;a href="https://help.github.com/articles/workflow-syntax-for-github-actions#on" rel="noopener noreferrer"&gt;Workflow syntax for GitHub Actions&lt;/a&gt;.&lt;/p&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Click on &lt;strong&gt;Start commit&lt;/strong&gt;, add message and description if you like and click on &lt;strong&gt;Commit new file&lt;/strong&gt;. This will add the config file to the repo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqmj4yz9hmjoujcuzew16.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqmj4yz9hmjoujcuzew16.png" alt="start commit" width="466" height="436"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Done!&lt;/strong&gt; 🚀.  &lt;/p&gt;&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;This action will run by itself the first time and each time when you push your changes to GitHub.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.3 Automate a private repo (via &lt;code&gt;GITHUB_TOKEN&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;The following example is additional, because we have promised for this article that you do not have to pay a cent. As already said, the usage of a private repos with GitHub Actions and GitHub Pages is only possible from the pro plan and higher. However, the big advantage is that we do not have to spend any time and effort to set up a token. The &lt;code&gt;GITHUB_TOKEN&lt;/code&gt; is already there and we do not need to bother with it at all.&lt;/p&gt;

&lt;p&gt;Behind the scenes, GitHub reuses an existing feature known as GitHub apps. In contrast to programs that authenticate with a "personal access token", apps do not run on behalf of a specific user – which is great. To make this happen, GitHub automatically installs a GitHub App on the repository and creates a corresponding "installation access token" with the name &lt;code&gt;GITHUB_TOKEN&lt;/code&gt; available as a secret.  GitHub fetches a new token for each job before the job begins. Awesome!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;ℹ️ Note&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As already mentioned above, the &lt;code&gt;GITHUB_TOKEN&lt;/code&gt; (installation access token) will only trigger a release of a new website if the action runs in a &lt;strong&gt;private repository&lt;/strong&gt;. In a public repo, a commit is generated, but the site does not change. See this &lt;a href="https://github.community/t5/GitHub-Actions/Github-action-not-triggering-gh-pages-upon-push/m-p/26869" rel="noopener noreferrer"&gt;GitHub Community post&lt;/a&gt; for more info. If your repo is public, you must still use the &lt;code&gt;GH_TOKEN&lt;/code&gt; (personal access token).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you have not already done so, please read the text on general workflow usage. The workflow looks very similar, but now we must use the other token. Here is a shorter example, without the tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to GitHub Pages via angular-cli-ghpages&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build-and-deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Use Node.js 10.x&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v1&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10.x&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Prepare and deploy&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;npm install&lt;/span&gt;
        &lt;span class="s"&gt;npm run ng -- deploy --base-href=/everything-github-demo/ --name="&amp;lt;Your Git Username&amp;gt;" --email=your.mail@example.org&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Et voila!&lt;/strong&gt; 🚀&lt;/p&gt;

&lt;p&gt;This is all it takes to deploy the latest version of the Angular App to GitHub Pages with each push.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Extra: Custom Domains
&lt;/h2&gt;

&lt;p&gt;Finally, we would like to shortly describe how you can use your own domain. GitHub Pages supports custom domains by placing a specific &lt;code&gt;CNAME&lt;/code&gt; file in the root directory of the &lt;code&gt;gh-pages&lt;/code&gt; branch – and &lt;code&gt;angular-cli-ghpages&lt;/code&gt; will create that file for you automatically. GitHub also provides &lt;a href="https://help.github.com/en/github/working-with-github-pages/about-custom-domains-and-github-pages" rel="noopener noreferrer"&gt;detailed instructions for this&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  6.1 Configuring a subdomain
&lt;/h3&gt;

&lt;p&gt;Setting up a subdomain isn't very hard. And if you already own a domain, you do not need to make any new investments. In our example the app should be accessible through the domain &lt;code&gt;everything-github-demo.angular.schule&lt;/code&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;First we have to change the DNS for the domain by setting up a so-called &lt;code&gt;CNAME&lt;/code&gt; record. That &lt;code&gt;CNAME&lt;/code&gt; record must point to a domain that looks like this: &lt;code&gt;&amp;lt;username&amp;gt;.github.io&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;&amp;lt;username&amp;gt;&lt;/code&gt; (or organisation name) is in our case &lt;code&gt;angular-schule&lt;/code&gt;. As an example, the following screenshot shows the required setting for the DNS provider &lt;a href="https://cloudflare.com" rel="noopener noreferrer"&gt;cloudflare.com&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fm8yvz1pno0zjkvkfbxot.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fm8yvz1pno0zjkvkfbxot.png" alt="Screenshot Cloudflare" width="800" height="151"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now we have to adjust the &lt;code&gt;ng deploy&lt;/code&gt; command a little bit! By using our own domain, we no longer have to use a subdirectory. Instead we now specify the parameter &lt;code&gt;--cname&lt;/code&gt; and place the application at the root directory!&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# OLD&lt;/span&gt;
ng deploy &lt;span class="nt"&gt;--base-href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/&amp;lt;repositoryname&amp;gt;/

&lt;span class="c"&gt;# NEW&lt;/span&gt;
ng deploy &lt;span class="nt"&gt;--cname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;everything-github-demo.angular.schule
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;At the next deployment the website will be known under the new address.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It is important that you have an SSL certificate, because otherwise Chrome will tell your visitors that your website is not secure:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fq43x0yjowcbislkbndr0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fq43x0yjowcbislkbndr0.png" alt="Screenshot Not Secure" width="704" height="654"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pretty ugly, isn't it?&lt;/strong&gt;   The good news: nowadays you don't have to spend money for a SSL certificate anymore! GitHub provides you with a free SSL certificate. To make this possible, they are partnering with letsencrypt.org. You can make the necessary changes in the repository settings. Go to &lt;strong&gt;Settings&lt;/strong&gt; &amp;gt; GitHub Pages and select &lt;strong&gt;Enforce HTTPS&lt;/strong&gt;, to enable HTTPS encryption for your site:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frvi8axbyttww54qwfuoi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frvi8axbyttww54qwfuoi.png" alt="Screenshot HTTPS GitHub" width="800" height="614"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It can take up to 24 hours before this option is available. As soon as the change is applied, you can now surf the website via HTTPS:   &lt;a href="https://everything-github-demo.angular.schule" rel="noopener noreferrer"&gt;&lt;strong&gt;https&lt;/strong&gt;://everything-github-demo.angular.schule&lt;/a&gt; – please feel free to try it out!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hint:&lt;/strong&gt; You should not change the custom domain through GitHub's web interface. The next time you deploy the app, this setting will be overwritten. Always use the &lt;code&gt;--cname&lt;/code&gt; parameter for this.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  6.2 Configuring an apex domain
&lt;/h3&gt;

&lt;p&gt;Setting up an apex domain, such as &lt;code&gt;everything-github-demo.com&lt;/code&gt; &lt;em&gt;(this domain does not exist, feel free to be the first 😉)&lt;/em&gt;, is very similar to the procedure for a subdomain. We need to use the same &lt;code&gt;--cname&lt;/code&gt; parameter as described before, but we have to make some different settings in the DNS.&lt;/p&gt;

&lt;p&gt;First, navigate to your DNS provider and create either an &lt;code&gt;ALIAS&lt;/code&gt;  an &lt;code&gt;A&lt;/code&gt; record.&lt;/p&gt;

&lt;p&gt;If your provider already uses the new standard, you should consider using an &lt;code&gt;ALIAS&lt;/code&gt; record. The &lt;code&gt;ALIAS&lt;/code&gt; record type (also known as &lt;code&gt;ANAME&lt;/code&gt; or &lt;code&gt;flattened CNAME&lt;/code&gt;) provides a way to specify a hostname in the DNS records which is then resolved at request time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To create an &lt;code&gt;ALIAS&lt;/code&gt; record,&lt;/strong&gt; point your apex domain to a domain that looks like this: &lt;code&gt;&amp;lt;username&amp;gt;.github.io&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;&amp;lt;username&amp;gt;&lt;/code&gt; (or organisation name) is in our case &lt;code&gt;angular-schule&lt;/code&gt;. As an example, the following screenshot shows the required setting for the DNS provider &lt;a href="https://cloudflare.com" rel="noopener noreferrer"&gt;cloudflare.com&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fugfb7oupw0nve24x6fwa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fugfb7oupw0nve24x6fwa.png" alt="Screenshot CNAME flatteing 1" width="800" height="154"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We should also set a &lt;code&gt;CNAME&lt;/code&gt; entry for &lt;code&gt;www&lt;/code&gt;, as many people always type in this subdomain. The final settings should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fohhlac9ir82szr3mcz68.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fohhlac9ir82szr3mcz68.png" alt="Screenshot CNAME flatteing 2" width="800" height="162"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To create an &lt;code&gt;A&lt;/code&gt; record&lt;/strong&gt;, point your apex domain to the following IP addresses from GitHub:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;185.199.108.153
185.199.109.153
185.199.110.153
185.199.111.153
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These IP addresses have been the same for years, but you should still compare them against &lt;a href="https://help.github.com/en/github/working-with-github-pages/managing-a-custom-domain-for-your-github-pages-site#configuring-an-apex-domain" rel="noopener noreferrer"&gt;the list in the GitHub documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;We hope you had fun with this tutorial and that your &lt;strong&gt;Angular App&lt;/strong&gt; now builds automatically via &lt;strong&gt;GitHub Actions&lt;/strong&gt; – and runs successfully on &lt;strong&gt;GitHub Pages&lt;/strong&gt;. If you have any questions, please contact us via Twitter. We are also very happy to receive your suggestion for improvement as a PR.&lt;/p&gt;

&lt;p&gt;You can check out the complete demo code here:&lt;br&gt;&lt;br&gt;
&lt;strong&gt;☞ &lt;a href="https://github.com/angular-schule/everything-github-demo/" rel="noopener noreferrer"&gt;https://github.com/angular-schule/everything-github-demo/&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;



&lt;h3&gt;
  
  
  Thank you by Dharmen Shah
&lt;/h3&gt;

&lt;p&gt;Special thanks go to &lt;strong&gt;&lt;a href="https://twitter.com/johanneshoppe" rel="noopener noreferrer"&gt;Johannes Hoppe&lt;/a&gt;&lt;/strong&gt; for giving me an opportunity to write this article.&lt;/p&gt;

&lt;h3&gt;
  
  
  Thank you by Johannes Hoppe
&lt;/h3&gt;

&lt;p&gt;Thanks to &lt;strong&gt;&lt;a href="https://twitter.com/shhdharmen" rel="noopener noreferrer"&gt;Dharmen Shah&lt;/a&gt;&lt;/strong&gt; for contributing to &lt;code&gt;angular-cli-ghpages&lt;/code&gt; and for starting this article. I would also like to thank &lt;strong&gt;&lt;a href="https://edricchan03.github.io/" rel="noopener noreferrer"&gt;Edric Chan&lt;/a&gt;&lt;/strong&gt;, who has been very involved in both &lt;code&gt;angular-cli-ghpages&lt;/code&gt; and in providing help for this article. 👍&lt;/p&gt;

&lt;p&gt;Only with the help from Dharmen and Edric it was possible for me to finally achieve full support for GitHub Actions in &lt;a href="https://github.com/angular-schule/angular-cli-ghpages/releases/tag/v0.6.2" rel="noopener noreferrer"&gt;v0.6.2 of angular-cli-ghpages&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Thank you by both
&lt;/h3&gt;

&lt;p&gt;We would like to thank &lt;a href="https://twitter.com/fmalcher01/" rel="noopener noreferrer"&gt;Ferdinand Malcher&lt;/a&gt; for reviewing the article and providing critical feedback, and &lt;a href="https://twitter.com/d_koppenhagen/" rel="noopener noreferrer"&gt;Danny Koppenhagen&lt;/a&gt; for kindly proofreading this article.&lt;/p&gt;




&lt;p&gt;This article was written by two people.&lt;/p&gt;

&lt;h3&gt;
  
  
  About Johannes Hoppe
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://twitter.com/johanneshoppe" rel="noopener noreferrer"&gt;Johannes&lt;/a&gt; is one of the two founders of the Angular.Schule and the main developer of angular-cli-ghpages. Recently he has been recognized as a Google Developer Expert (GDE).&lt;/p&gt;

&lt;h3&gt;
  
  
  About Dharmen Shah
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://twitter.com/shhdharmen" rel="noopener noreferrer"&gt;Dharmen&lt;/a&gt; is a full stack JavaScript developer from Ahmedabad, India with core skills in JavaScript and CSS. He enjoys working with both Angular and React. Dharmen contributes to some open source projects and has also contributed to the documentation of angular-cli-ghpages. By the way, he is a foodie and loves listening to music, especially Hindi Pop music.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>github</category>
      <category>git</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
