<?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: Gary Großgarten</title>
    <description>The latest articles on DEV Community by Gary Großgarten (@garygrossgarten).</description>
    <link>https://dev.to/garygrossgarten</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%2F350286%2Fd078e67f-0a24-461d-aa2b-a10ea981e489.jpg</url>
      <title>DEV Community: Gary Großgarten</title>
      <link>https://dev.to/garygrossgarten</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/garygrossgarten"/>
    <language>en</language>
    <item>
      <title>Create Keyboard Shortcuts with RxJS</title>
      <dc:creator>Gary Großgarten</dc:creator>
      <pubDate>Mon, 08 Jun 2020 19:41:53 +0000</pubDate>
      <link>https://dev.to/notiz_dev/create-keyboard-shortcuts-with-rxjs-3dj5</link>
      <guid>https://dev.to/notiz_dev/create-keyboard-shortcuts-with-rxjs-3dj5</guid>
      <description>&lt;p&gt;I recently tried to add some keyboard shortcuts to my Angular app. 🤯 &lt;strong&gt;But don't worry&lt;/strong&gt; , the solution is quite simple. At least Brent Rambo approves.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/m2Q7FEc0bEr4I/source.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/m2Q7FEc0bEr4I/source.gif" alt="Brent Rambo - Shortcut master"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this &lt;a href="https://notiz.dev/tags/quick-tip"&gt;Quick Tip&lt;/a&gt;, I'll show you what I came up with, using &lt;a href="https://rxjs-dev.firebaseapp.com/"&gt;RxJS&lt;/a&gt;.This demonstration is done in an Angular Workspace scaffolded with the &lt;a href="https://cli.angular.io/"&gt;Angular CLI&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;shortcut&lt;/code&gt; function below can be used to effortlessly create &lt;code&gt;Observables&lt;/code&gt; for any keyboard shortcut. A keyboard shortcut is an array of keycodes (&lt;code&gt;event.code&lt;/code&gt;), each representing a key of your keyboard. Grab the &lt;a href="https://github.com/garygrossgarten/rxjs-shortcuts/blob/master/projects/shortcuts/src/lib/keycodes.ts"&gt;KeyCode Enum here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;See the comments in the code for explanation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const shortcut = (shortcut: KeyCode[]): Observable&amp;lt;KeyboardEvent[]&amp;gt; =&amp;gt; {
  // Observables for all keydown and keyup events
  const keyDown$ = fromEvent&amp;lt;KeyboardEvent&amp;gt;(document, 'keydown');
  const keyUp$ = fromEvent&amp;lt;KeyboardEvent&amp;gt;(document, 'keyup');

  // All KeyboardEvents - emitted only when KeyboardEvent changes (key or type)
  const keyEvents$ = merge(keyDown$, keyUp$).pipe(
    distinctUntilChanged((a, b) =&amp;gt; a.code === b.code &amp;amp;&amp;amp; a.type === b.type),
    share()
  );

  // Create KeyboardEvent Observable for specified KeyCode
  const createKeyPressStream = (charCode: KeyCode) =&amp;gt;
    keyEvents$.pipe(filter((event) =&amp;gt; event.code === charCode.valueOf()));

  // Create Event Stream for every KeyCode in shortcut
  const keyCodeEvents$ = shortcut.map((s) =&amp;gt; createKeyPressStream(s));

  // Emit when specified keys are pressed (keydown).
  // Emit only when all specified keys are pressed at the same time.
  // More on combineLatest below
  return combineLatest(keyCodeEvents$).pipe(
    filter&amp;lt;KeyboardEvent[]&amp;gt;((arr) =&amp;gt; arr.every((a) =&amp;gt; a.type === 'keydown'))
  );
};

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

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://rxjs-dev.firebaseapp.com/api/index/function/combineLatest"&gt;combineLatest&lt;/a&gt;&lt;/strong&gt;: Whenever any input &lt;code&gt;Observable&lt;/code&gt; emits, &lt;code&gt;combineLatest&lt;/code&gt; will compute and emit all the latest values of all inputs. However, &lt;code&gt;combineLatest&lt;/code&gt; will wait for all input &lt;code&gt;Observables&lt;/code&gt; to emit at least once, before it starts emitting results.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Usage is simple&lt;/strong&gt;. Just call the &lt;code&gt;shortcut&lt;/code&gt; function with your desired &lt;code&gt;KeyCode&lt;/code&gt; combination. Then subscribe to the result and handle the keyboard shortcut. More examples can be found in the &lt;a href="https://github.com/garygrossgarten/rxjs-shortcuts"&gt;repo&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const commaDot$ = shortcut([KeyCode.Comma, KeyCode.Period]);

const ctrlO$ = merge(
  shortcut([KeyCode.ControlLeft, KeyCode.KeyO]),
  shortcut([KeyCode.ControlRight, KeyCode.KeyO])
);

commaDot$.pipe(tap(() =&amp;gt; doSomething())).subscribe();

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Bonus
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;shortcut&lt;/code&gt; function emits whenever the specified keys are pressed simultaneously, no matter in which order they were pressed. If the sequence of the key presses is also important to you, you can use the pipeable operator below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export function sequence() {
  return (source: Observable&amp;lt;KeyboardEvent[]&amp;gt;) =&amp;gt; {
    return source.pipe(
      filter((arr) =&amp;gt; {
        const sorted = [...arr]
          .sort((a, b) =&amp;gt; (a.timeStamp &amp;lt; b.timeStamp ? -1 : 1))
          .map((a) =&amp;gt; a.code)
          .join();
        const seq = arr.map((a) =&amp;gt; a.code).join();
        return sorted === seq;
      })
    );
  };
}

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

&lt;/div&gt;



&lt;p&gt;Then use it like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const abc$ = shortcut([KeyCode.KeyA, KeyCode.KeyB, KeyCode.KeyC]).pipe(
  sequence()
);

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

&lt;/div&gt;



&lt;p&gt;Now the &lt;code&gt;abc$&lt;/code&gt; &lt;code&gt;Observable&lt;/code&gt; will only emit when the keys are pressed sequentially (a-&amp;gt;b-&amp;gt;c).&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;Beware that keyboard shortcuts could collide with global shortcuts specified by your OS or Browser (e.g. Spotlight on Mac for Cmd+Space). Also there are cases where &lt;code&gt;keyup&lt;/code&gt; events will be skipped when certain keys are pressed down. This is particularly the case with the cmd key (&lt;code&gt;KeyCode.MetaRight&lt;/code&gt; and &lt;code&gt;KeyCode.MetaLeft&lt;/code&gt;) on mac.&lt;/p&gt;




&lt;p&gt;If you have further questions on the article or just want to say hi, feel free to slide into my &lt;a href="https://twitter.com/garygrossgarten"&gt;twitter dms&lt;/a&gt;.🐦&lt;/p&gt;

</description>
      <category>rxjs</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Angular Elements: Create a Component Library for Angular and the Web</title>
      <dc:creator>Gary Großgarten</dc:creator>
      <pubDate>Wed, 25 Mar 2020 15:41:02 +0000</pubDate>
      <link>https://dev.to/notiz_dev/angular-elements-create-a-component-library-for-angular-and-the-web-1nef</link>
      <guid>https://dev.to/notiz_dev/angular-elements-create-a-component-library-for-angular-and-the-web-1nef</guid>
      <description>&lt;p&gt;Reuse your &lt;strong&gt;Angular components&lt;/strong&gt; almost everywhere - with &lt;a href="https://angular.io/guide/elements"&gt;Angular Elements&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this guide you'll learn how to&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scaffold a reusable component library.&lt;/li&gt;
&lt;li&gt;Export the library for &lt;strong&gt;Angular&lt;/strong&gt; and as &lt;strong&gt;&lt;a href="https://www.webcomponents.org/"&gt;Web Components&lt;/a&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Publish everything to &lt;strong&gt;npm&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's get started. ⬇&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the project
&lt;/h2&gt;

&lt;p&gt;This guide uses the &lt;a href="https://cli.angular.io/"&gt;Angular CLI 9.0.7&lt;/a&gt; to scaffold most of the project structure and configuration for your &lt;strong&gt;reusable UI Library&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;First, initialize a new Angular application with &lt;code&gt;ng new APP_NAME&lt;/code&gt;. Feel free to use routing and your favorite stylesheet format when prompted.&lt;/p&gt;

&lt;p&gt;Open the newly created project in your favorite IDE.&lt;/p&gt;

&lt;p&gt;Next, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng g library components

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

&lt;/div&gt;



&lt;p&gt;This step will generate a new &lt;strong&gt;library&lt;/strong&gt; under &lt;code&gt;./projects/components&lt;/code&gt; and add an example component. The library is ready to be shared and used in all of your Angular applications without further configuration. 💆&lt;/p&gt;

&lt;p&gt;Perform an initial build of the component library by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng build components

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

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Currently, &lt;strong&gt;Angular Elements&lt;/strong&gt; only supports projects of type &lt;code&gt;application&lt;/code&gt; to create Custom Elements. This means you need to generate an &lt;em&gt;additional&lt;/em&gt; application. The sole purpose of the application is to import your angular components and output them as Custom Elements.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To generate the elements application run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng g application elements

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

&lt;/div&gt;



&lt;p&gt;Additionally, run the &lt;code&gt;@angular/elements&lt;/code&gt; schematic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng add @angular/elements --project elements

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

&lt;/div&gt;



&lt;p&gt;This will create a new app in the subfolder &lt;code&gt;./projects/elements&lt;/code&gt; and install all the necessary dependencies and polyfills needed to set up Angular Elements.&lt;/p&gt;

&lt;p&gt;If you want to publish your components as Custom Elements cd into &lt;code&gt;./projects/elements&lt;/code&gt; and create a package.json using&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm init

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

&lt;/div&gt;



&lt;p&gt;Then, add the following to the newly created &lt;strong&gt;package.json&lt;/strong&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  ...
  "files": ["elements.js", "styles.css"],
  ...
}

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

&lt;/div&gt;



&lt;p&gt;Your project should now look something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kfX6qh6C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://notiz.dev/assets/img/blog/create-a-component-library-for-angular-and-the-web/optimized/structure.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kfX6qh6C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://notiz.dev/assets/img/blog/create-a-component-library-for-angular-and-the-web/optimized/structure.png" alt="folder structure and package.json content"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure Angular Elements
&lt;/h2&gt;

&lt;p&gt;In the elements application delete all files in &lt;code&gt;./projects/elements/src/app&lt;/code&gt; except &lt;code&gt;app.module.ts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You need to define your own bootstrapping method for the elements application.Do some changes to your elements &lt;code&gt;app.module.ts&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Remove the bootstrap array from &lt;code&gt;NgModule&lt;/code&gt; declaration.&lt;/li&gt;
&lt;li&gt;Import &lt;code&gt;ComponentsModule&lt;/code&gt; and &lt;code&gt;ComponentsComponent&lt;/code&gt; from the components library.&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;ngDoBootstrap&lt;/code&gt; hook.&lt;/li&gt;
&lt;li&gt;For every component create an element using the &lt;code&gt;createCustomElement&lt;/code&gt; function from &lt;code&gt;@angular/elements&lt;/code&gt;. Then define the element using web's native &lt;code&gt;customElemments.define&lt;/code&gt; function, specifying a selector.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { BrowserModule } from '@angular/platform-browser';
import { NgModule, Injector } from '@angular/core';
import { createCustomElement } from '@angular/elements';
import { ComponentsModule, ComponentsComponent } from 'components';

@NgModule({
  imports: [
    BrowserModule,
    ComponentsModule
  ],
  providers: []
})
export class AppModule {

  constructor(private injector: Injector){}

  ngDoBootstrap(){
    const element = createCustomElement(ComponentsComponent, { injector: this.injector })
    customElements.define("lib-components", element);
  }

 }

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

&lt;/div&gt;



&lt;p&gt;Remove &lt;code&gt;zone.js&lt;/code&gt; (optional):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Removing &lt;code&gt;zone.js&lt;/code&gt; is probably a good idea. Read more about it &lt;a href="https://www.angulararchitects.io/aktuelles/angular-elements-part-iii/"&gt;in this great article&lt;/a&gt;. Just keep in mind that you need to handle &lt;a href="https://angular.io/api/core/ChangeDetectorRef"&gt;change detection&lt;/a&gt; yourself.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';

if (environment.production) {
  enableProdMode();
}

platformBrowserDynamic()
  .bootstrapModule(AppModule, { ngZone: 'noop' })
  .catch(err =&amp;gt; console.error(err));

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Time to build ⚙
&lt;/h2&gt;

&lt;p&gt;In your root package.json add the following scripts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "scripts": {
    ...
    "build:elements": "ng build --prod --project elements --output-hashing none &amp;amp;&amp;amp; npm run pack:elements &amp;amp;&amp;amp; cp projects/elements/package.json dist/elements",
    "pack:elements": "cat ./dist/elements/{runtime,polyfills,main}-es5.js &amp;gt; dist/elements/elements.js &amp;amp;&amp;amp; ls -lah dist/elements/elements.js",
    "build:components": "ng build --prod --project components",
    ...
  },
  ...

}

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

&lt;/div&gt;



&lt;p&gt;To build the elements application run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run build:elements

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

&lt;/div&gt;



&lt;p&gt;The script exports your Angular components as Custom Elements during the build process. Also it will run the &lt;code&gt;pack:elements&lt;/code&gt; script and copy the previously created &lt;code&gt;package.json&lt;/code&gt; to &lt;code&gt;./dist/elements&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;pack:elements&lt;/code&gt; script is optional yet very useful because it will bundle the js build outputs into a single &lt;code&gt;elements.js&lt;/code&gt; file. This makes it easier to include your library in other applications.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Try it out
&lt;/h2&gt;

&lt;p&gt;Use your Angular components by including them in the root Angular application:&lt;/p&gt;

&lt;p&gt;In app.module.ts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { ComponentsModule } from 'components';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    ComponentsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

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

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;app.component.html&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;h1&amp;gt;angular component&amp;lt;/h1&amp;gt;
&amp;lt;lib-components&amp;gt;&amp;lt;/lib-components&amp;gt;

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

&lt;/div&gt;



&lt;p&gt;Run the root application with &lt;code&gt;ng s&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lWeQmqXL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://notiz.dev/assets/img/blog/create-a-component-library-for-angular-and-the-web/optimized/angular-component.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lWeQmqXL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://notiz.dev/assets/img/blog/create-a-component-library-for-angular-and-the-web/optimized/angular-component.png" alt="angular app running and displaying the component"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using your Custom Elements is simple. Create an index.html in the root of your project and add following code snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang="en"&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset="UTF-8"&amp;gt;
    &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&amp;gt;
    &amp;lt;title&amp;gt;Document&amp;lt;/title&amp;gt;
    &amp;lt;link rel="stylesheet" href="dist/elements/styles.css"&amp;gt;
    &amp;lt;script src="dist/elements/elements.js"&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;

    &amp;lt;h1&amp;gt;Web Component (Costum Elements)&amp;lt;/h1&amp;gt;
    &amp;lt;lib-components&amp;gt;&amp;lt;/lib-components&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;

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

&lt;/div&gt;



&lt;p&gt;To test, serve it on a http server and open the index.html. I'm using &lt;a href="https://www.npmjs.com/package/serve"&gt;serve&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;serve .

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--f_EJgwIf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://notiz.dev/assets/img/blog/create-a-component-library-for-angular-and-the-web/optimized/custom-element.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--f_EJgwIf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://notiz.dev/assets/img/blog/create-a-component-library-for-angular-and-the-web/optimized/custom-element.png" alt="web component"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Publish to npm
&lt;/h2&gt;

&lt;p&gt;The only thing left to do is to publish your components and Custom Elements to npm.This is fairly easy. Either run &lt;code&gt;npm publish dist/components&lt;/code&gt; or &lt;code&gt;npm publish dist/elements&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Reminder: Before releasing, you probably want to update &lt;code&gt;./projects/components/package.json&lt;/code&gt; and &lt;code&gt;./projects/elements/package.json&lt;/code&gt; to include your libraries' name and version. A way to name your libraries could be &lt;code&gt;ngx-&amp;lt;NAME&amp;gt;&lt;/code&gt; for angular and &lt;code&gt;wc-&amp;lt;NAME&amp;gt;&lt;/code&gt; for the Custom Elements.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;✨ Congratulations! You successfully created and published a custom Angular component library that can be used almost everywhere!&lt;/p&gt;

&lt;p&gt;If you have further questions on the topic, feedback on the article or just want to say hi you can hit me up on &lt;a href="https://twitter.com/garygrossgarten"&gt;twitter&lt;/a&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>design</category>
    </item>
    <item>
      <title>Build and publish your first GitHub Action</title>
      <dc:creator>Gary Großgarten</dc:creator>
      <pubDate>Wed, 18 Mar 2020 21:07:41 +0000</pubDate>
      <link>https://dev.to/notiz_dev/build-and-publish-your-first-github-action-4o02</link>
      <guid>https://dev.to/notiz_dev/build-and-publish-your-first-github-action-4o02</guid>
      <description>&lt;p&gt;If you are using GitHub you most likely already heard about &lt;a href="https://github.com/features/actions"&gt;GitHub Actions&lt;/a&gt;. With GitHub Actions you can fulfill all of your CI/CD dreams right where your code lives. You do this by defining &lt;strong&gt;jobs&lt;/strong&gt; that run a series of &lt;strong&gt;Actions&lt;/strong&gt; - The building blocks of your repository workflows. This enables you to stay productive even when managing multiple projects at once. 👨‍💻&lt;/p&gt;

&lt;p&gt;In this short guide you will learn how to create your first GitHub Action and publish it on the &lt;a href="https://github.com/marketplace"&gt;GitHub Marketplace&lt;/a&gt;! 💙&lt;/p&gt;

&lt;h2&gt;
  
  
  Quickstart
&lt;/h2&gt;

&lt;p&gt;To get started quickly, you can initialize your own Action repository by generating it from &lt;a href="https://github.com/notiz-dev/github-action-template"&gt;GitHub Action Template&lt;/a&gt;. For the sake of simplicity this repository is a minimized version of the official &lt;a href="https://github.com/actions/typescript-action"&gt;typescript action template&lt;/a&gt;. You are free to choose which starter you want to use. The steps to build and release your Action will essentially remain the same.&lt;/p&gt;

&lt;p&gt;Visit &lt;a href="https://github.com/notiz-dev/github-action-template"&gt;GitHub Action Template&lt;/a&gt; and click on &lt;strong&gt;&lt;a href="https://github.com/notiz-dev/github-action-template/generate"&gt;Use this template&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JSmeD-Qb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://notiz.dev/assets/img/blog/build-and-publish-your-first-github-action/optimized/template.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JSmeD-Qb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://notiz.dev/assets/img/blog/build-and-publish-your-first-github-action/optimized/template.png" alt="Use this template on GitHub"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fill out the form and click on &lt;strong&gt;Create repository from template&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--757-G4KY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://notiz.dev/assets/img/blog/build-and-publish-your-first-github-action/optimized/create_repository.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--757-G4KY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://notiz.dev/assets/img/blog/build-and-publish-your-first-github-action/optimized/create_repository.png" alt="Create Repository from template"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next clone your newly created repository and open it with your favorite IDE.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git clone git@github.com:&amp;lt;USERNAME/ORG&amp;gt;/&amp;lt;REPOSITORY&amp;gt;.git&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Install all dependencies by running &lt;code&gt;npm i&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Great! Everything is set up! 🚀 In the next section of this guide you'll get an overview of the most important files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Template Overview
&lt;/h2&gt;

&lt;p&gt;First, inspect &lt;code&gt;index.ts&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uMP5YhrR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://notiz.dev/assets/img/blog/build-and-publish-your-first-github-action/optimized/overview.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uMP5YhrR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://notiz.dev/assets/img/blog/build-and-publish-your-first-github-action/optimized/overview.png" alt="main project files"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The template Action is a simple script that receives an input string and outputs a hello world like greeting. (E.g. input &lt;code&gt;World&lt;/code&gt; ➡ output &lt;code&gt;Hello World&lt;/code&gt;). See how the &lt;code&gt;actions/core&lt;/code&gt; api is being used to receive the value of the &lt;code&gt;my_input&lt;/code&gt; input and to set the resulting string as an output. Also, &lt;code&gt;setFailed&lt;/code&gt; can be called to set the running workflow as failed and stop the execution. &lt;a href="https://www.npmjs.com/package/@actions/core"&gt;API Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most toolkit and CI/CD operations involve async operations so your &lt;code&gt;run&lt;/code&gt; function will most likely be async.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import * as core from '@actions/core';

async function run() {
  try {
    await asyncFunction();
  } catch (err) {
    core.setFailed(err.message);
  }
}

run();

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



&lt;p&gt;Second, see &lt;code&gt;action.yml&lt;/code&gt; in the root of your project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: 'GitHub Action Template'
description: 'simple typescript template for building GitHub Actions'
author: 'notiz.dev'
inputs:
  my_input:
    description: 'input description here'
    default: 'World'
runs:
  using: 'node12'
  main: 'dist/index.js'
branding:
  color: 'yellow'
  icon: 'bell'

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



&lt;p&gt;The &lt;code&gt;action.yml&lt;/code&gt; file defines some metadata that is mandatory to run and publish your Action on GitHub. Besides general information like name, description and author, you'll want to define all the necessary inputs for your Action. The entrypoint of the Action is set to run &lt;code&gt;dist/index.js&lt;/code&gt; using version 12 of node. This file will be created once you build and pack the project.&lt;/p&gt;

&lt;p&gt;To publish the Action, you additionally need to define a branding for how your Action appears on the GitHub Marketplace. For more information on the configuration of your Action see &lt;a href="https://help.github.com/en/actions/building-actions/metadata-syntax-for-github-actions"&gt;Metadata syntax for GitHub Actions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Lastly, you'll find a workflow file under &lt;code&gt;.github/workflows/test.yml&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: 'test'
on: # rebuild any PRs and main branch changes
  pull_request:
  push:
    branches:
      - master
      - 'releases/*'

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v1
    - name: run action
      id: run_action
      uses: ./
      with: 
        my_input: 'World'

    - name: log action output
      run: echo ${{steps.run_action.outputs.my_output}}     

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



&lt;p&gt;Essentially, this will start a workflow testing your Action on every push to &lt;code&gt;master/release&lt;/code&gt; or on PRs. The &lt;code&gt;test&lt;/code&gt; job will checkout and run your Action, defining &lt;code&gt;World&lt;/code&gt; as the input value for &lt;code&gt;my_input&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally, the &lt;code&gt;log action output&lt;/code&gt; step of your job will echo the output set by your GitHub Action. Note the id that is defined in the &lt;code&gt;run action&lt;/code&gt; step and later used to retrieve the output value.&lt;/p&gt;

&lt;p&gt;By creating your repository from the template earlier, the workflow already got invoked once:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mvi_F4hg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://notiz.dev/assets/img/blog/build-and-publish-your-first-github-action/optimized/workflow.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mvi_F4hg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://notiz.dev/assets/img/blog/build-and-publish-your-first-github-action/optimized/workflow.png" alt="invoked workflow"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jEK80nbp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://notiz.dev/assets/img/blog/build-and-publish-your-first-github-action/optimized/workflow_result.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jEK80nbp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://notiz.dev/assets/img/blog/build-and-publish-your-first-github-action/optimized/workflow_result.png" alt="workflow result"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see in the image above, the &lt;code&gt;log action output&lt;/code&gt; step successfully echoed &lt;code&gt;Hello World&lt;/code&gt; to the console.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implement the Action
&lt;/h2&gt;

&lt;p&gt;Next, the fun part! 🙋&lt;/p&gt;

&lt;p&gt;Implement your own Typescript code in &lt;code&gt;src/index.ts&lt;/code&gt;. Just remember to update the &lt;code&gt;action.yml&lt;/code&gt; and the test workflow &lt;code&gt;.github/workflows/test.yml&lt;/code&gt; before pushing your changes. You can obviously do everything you want here. Feel free to install other libraries via npm.&lt;/p&gt;

&lt;p&gt;To build changes to your Typescript code run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run build

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



&lt;p&gt;This will compile your Typescript to a lib folder.&lt;/p&gt;

&lt;p&gt;Next, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run pack

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



&lt;p&gt;This script will bundle your lib together with the required production node_modules. The bundled package can now be found in the &lt;code&gt;dist&lt;/code&gt; folder containing the &lt;code&gt;index.js&lt;/code&gt; that's been declared as the entrypoint in your &lt;code&gt;action.yml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;See &lt;a href="https://github.com/notiz-dev/github-action-json-property"&gt;JSON Property GitHub Action&lt;/a&gt; for another example.&lt;/p&gt;

&lt;h2&gt;
  
  
  Publish to GitHub Marketplace
&lt;/h2&gt;

&lt;p&gt;After you built and packed the Action you are ready to commit and push your changes to the GitHub Repository. You should definitely add a &lt;strong&gt;README&lt;/strong&gt; with instructions on how to use your Action.&lt;/p&gt;

&lt;p&gt;Check if your test workflow is working as expected. If you are happy with the results, you are ready to finally publish your Action to the Marketplace.&lt;/p&gt;

&lt;p&gt;Hit the &lt;strong&gt;release&lt;/strong&gt; tab of your repository to create a new version of your Action.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8I22ikP8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://notiz.dev/assets/img/blog/build-and-publish-your-first-github-action/optimized/create_release.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8I22ikP8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://notiz.dev/assets/img/blog/build-and-publish-your-first-github-action/optimized/create_release.png" alt="create release"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on &lt;strong&gt;Create a new release&lt;/strong&gt; and select &lt;strong&gt;Publish this Action to the GitHub Marketplace&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--043uHCNe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://notiz.dev/assets/img/blog/build-and-publish-your-first-github-action/optimized/publish.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--043uHCNe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://notiz.dev/assets/img/blog/build-and-publish-your-first-github-action/optimized/publish.png" alt="publish to marketplace"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check if all requirements are checked and proceed to file the release.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ntIseyfe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://notiz.dev/assets/img/blog/build-and-publish-your-first-github-action/optimized/release.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ntIseyfe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://notiz.dev/assets/img/blog/build-and-publish-your-first-github-action/optimized/release.png" alt="publish to marketplace"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Enter a &lt;strong&gt;tag&lt;/strong&gt; and &lt;strong&gt;release&lt;/strong&gt; title. Optionally specify a release description before clicking &lt;strong&gt;Publish release&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;To make it easy for users to always use the latest release of your Action you can tag the newly created version with a &lt;code&gt;release&lt;/code&gt; tag. Next time you release a version you can move the &lt;code&gt;release&lt;/code&gt; tag from the previous to the latest version.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Using your Action
&lt;/h2&gt;

&lt;p&gt;By now you should have a published version of your Action on the GitHub Marketplace.&lt;/p&gt;

&lt;p&gt;You should see the Marketplace banner on your repository page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vmxeEz5L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://notiz.dev/assets/img/blog/build-and-publish-your-first-github-action/optimized/marketplace_banner.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vmxeEz5L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://notiz.dev/assets/img/blog/build-and-publish-your-first-github-action/optimized/marketplace_banner.png" alt="marketplace banner"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Inspect the Action entry in GitHub Marketplace:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--29h-uf32--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://notiz.dev/assets/img/blog/build-and-publish-your-first-github-action/optimized/marketplace.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--29h-uf32--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://notiz.dev/assets/img/blog/build-and-publish-your-first-github-action/optimized/marketplace.png" alt="marketplace entry"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Use your Action by creating a &lt;strong&gt;workflow&lt;/strong&gt; file in a repository of your choice. In case you tagged the version with the &lt;code&gt;release&lt;/code&gt; tag, include your Action as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - name: run action
      id: run_action
      uses: &amp;lt;USERNAME/ORG&amp;gt;/&amp;lt;REPOSITORY&amp;gt;@release
      with: 
        my_input: 'World'

    - name: log action output
      run: echo ${{steps.run_action.outputs.my_output}} 

...    

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



&lt;p&gt;Please replace &lt;code&gt;&amp;lt;USERNAME/ORG&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;REPOSITORY&amp;gt;&lt;/code&gt; with your repository details.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Awesome, you made it to the end of this guide. 🎉&lt;/p&gt;

&lt;p&gt;As you could see, building and publishing your first GitHub Action is fairly straightforward. To not double the efforts of building certain Actions you should check the &lt;a href="https://github.com/marketplace"&gt;Marketplace&lt;/a&gt; and &lt;a href="https://github.com/sdras/awesome-actions"&gt;this awesome list&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you have further questions on the topic, feedback on the article or just want to say hi you can hit me up on &lt;a href="https://twitter.com/garygrossgarten"&gt;twitter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>githubactions</category>
      <category>typescript</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
