<?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>Forem: beeman 🐝</title>
    <description>The latest articles on Forem by beeman 🐝 (@beeman).</description>
    <link>https://forem.com/beeman</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%2F182109%2F3c3ccee1-b179-4961-b07e-134da4caab48.jpeg</url>
      <title>Forem: beeman 🐝</title>
      <link>https://forem.com/beeman</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/beeman"/>
    <language>en</language>
    <item>
      <title>Deploy a NestJS API to Heroku from a Nx Workspace</title>
      <dc:creator>beeman 🐝</dc:creator>
      <pubDate>Fri, 21 Aug 2020 03:48:50 +0000</pubDate>
      <link>https://forem.com/beeman/deploy-a-nestjs-api-to-heroku-from-a-nx-workspace-o85</link>
      <guid>https://forem.com/beeman/deploy-a-nestjs-api-to-heroku-from-a-nx-workspace-o85</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this tutorial, we deploy the API to Heroku. First, the &lt;em&gt;run-scripts&lt;/em&gt; &lt;code&gt;build&lt;/code&gt; and &lt;code&gt;start&lt;/code&gt; in &lt;code&gt;package.json&lt;/code&gt; are configured and tested. After that, we use the Heroku CLI to create a new app under our account, and deploy the API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;For this tutorial, you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An account on Heroku, &lt;a href="https://signup.heroku.com/"&gt;sign up here&lt;/a&gt; if you don't have one.

&lt;ul&gt;
&lt;li&gt;A free account is sufficient, and you don't need a credit card to get one!&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;The Heroku CLI, visit &lt;a href="https://devcenter.heroku.com/articles/heroku-cli"&gt;this page&lt;/a&gt; and follow the installation instructions.

&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;heroku -v&lt;/code&gt; to verify it's installed.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. Configure and test the production build.
&lt;/h2&gt;

&lt;p&gt;In this step, we run the build command locally to make sure everything works as expected.&lt;/p&gt;

&lt;h3&gt;
  
  
  1.1 Update the run-scripts in package.json
&lt;/h3&gt;

&lt;p&gt;Open &lt;code&gt;package.json&lt;/code&gt; and find the &lt;em&gt;scripts&lt;/em&gt; object. Replace the values of the &lt;code&gt;start&lt;/code&gt; and &lt;code&gt;build&lt;/code&gt; scripts with the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node dist/apps/api/main.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"nx build api --prod"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  1.2 Build and run the API locally
&lt;/h3&gt;

&lt;p&gt;With these scripts in place, run the following command to build the API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn build
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The output will be similar to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn run v1.22.4
$ nx build api --prod

&amp;gt; nx run api:build:production
Starting type checking service...
Using 14 workers with 2048MB memory limit
Hash: c521fa45a781fce8412b
Built at: 08/20/2020 10:02:15 PM
Entrypoint main = main.js main.js.map
chunk    {0} main.js, main.js.map (main) 4.15 KiB [entry] [rendered]
✨  Done in 9.95s.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Once the API has been built, run the following command to start the API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;💡 Make sure to stop your development server before starting the API, because you can only have one process listening on the same port. If you forget that, the API will fail, and print message like this:&lt;/p&gt;

&lt;p&gt;Error: listen EADDRINUSE: address already in use :::3000&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  1.3 Commit your changes
&lt;/h3&gt;

&lt;p&gt;The Heroku deployments work by pushing a branch to the created application. That means that in order for the last changes to take effect, we need to commit the changes before we move on.&lt;/p&gt;

&lt;p&gt;Run the following command to commit the changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git commit -am "Update run-scripts"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Deploy to Heroku.
&lt;/h2&gt;

&lt;p&gt;In order to deploy the API to Heroku, we first create an application on Heroku. After that, we can use &lt;code&gt;git push&lt;/code&gt; to actually deploy the API.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.1 Create the application on Heroku
&lt;/h3&gt;

&lt;p&gt;Run the following command to create the application on Heroku:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;heroku create beehive-graphql
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;💡 The application name on Heroku has to be unique. If you use an existing name, Heroku will tell you:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Creating ⬢ beehive-graphql... !
 ▸    Name beehive-graphql is already taken
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  2.2 Deploy the application to Heroku
&lt;/h3&gt;

&lt;p&gt;Run the following command to trigger the deployment on Heroku:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;git push heroku master
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This will push the latest commit to Heroku, and start the build process. You can follow the output in your terminal.&lt;/p&gt;

&lt;p&gt;Once you get the following text, the application has been successfully deployed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;remote: https://beehive-graphql.herokuapp.com/ deployed to Heroku
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  2.3 Test the GraphQL API on Heroku
&lt;/h3&gt;

&lt;p&gt;You can now visit the GraphQL endpoint on your newly deployed API:&lt;/p&gt;

&lt;p&gt;Visit &lt;a href="https://beehive-graphql.herokuapp.com/graphql"&gt;https://beehive-graphql.herokuapp.com/graphql&lt;/a&gt; to check it out!&lt;/p&gt;

&lt;p&gt;However, what you see now not the playground you saw in the previous tutorial 😲.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET query missing.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The reason is that the API on Heroku runs in &lt;em&gt;production&lt;/em&gt; mode, and this disabled playground the playground by default.&lt;/p&gt;

&lt;p&gt;Luckily, we can use a &lt;code&gt;curl&lt;/code&gt; command to verify the API is working&lt;/p&gt;

&lt;p&gt;Run the following command to execute the &lt;code&gt;uptime&lt;/code&gt; query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-XPOST&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s1"&gt;' { "query": "query { uptime }"  }'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     https://beehive-graphql.herokuapp.com/graphql
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  2.4 Enable the Playground on production servers (optional)
&lt;/h3&gt;

&lt;p&gt;Sometimes it can be useful to deploy a GraphQL server with the playground enabled in &lt;em&gt;production&lt;/em&gt; mode.&lt;/p&gt;

&lt;p&gt;In order to do so, open &lt;code&gt;libs/core/src/lib/core.module.ts&lt;/code&gt; and change the configuration of the &lt;code&gt;GraphQLModule&lt;/code&gt;, and set the &lt;code&gt;playground&lt;/code&gt; option to &lt;code&gt;true&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;GraphQLModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forRoot&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;autoSchemaFile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;playground&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;/div&gt;



&lt;p&gt;In order to deploy this, commit the changes and run the deployment again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;git commit &lt;span class="nt"&gt;-am&lt;/span&gt; &lt;span class="s2"&gt;"Enable playground in Production mode"&lt;/span&gt;
git push heroku master
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When you now visit &lt;a href="https://beehive-graphql.herokuapp.com/graphql"&gt;https://beehive-graphql.herokuapp.com/graphql&lt;/a&gt;, you should be greeted with the playground again! 🎉&lt;/p&gt;

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

&lt;p&gt;In this tutorial, we configured the &lt;code&gt;start&lt;/code&gt; and &lt;code&gt;build&lt;/code&gt; &lt;em&gt;run-scripts&lt;/em&gt; in &lt;code&gt;package.json&lt;/code&gt; and made sure they worked as expected. We committed those changes in order for them to be pushed to Heroku.&lt;/p&gt;

&lt;p&gt;After that, we created a new application on Heroku and used the &lt;code&gt;git push&lt;/code&gt; command to deploy the API.&lt;/p&gt;

&lt;p&gt;Because Heroku runs the apps in &lt;em&gt;production&lt;/em&gt; by default, we did not get the GraphQL Playground when visiting the &lt;code&gt;/graphql&lt;/code&gt; endpoint on the API. Luckily, this is easy to fix by enabling the &lt;code&gt;playground&lt;/code&gt; option in the &lt;code&gt;GrapQLModule&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thanks!
&lt;/h2&gt;

&lt;p&gt;And with that, this series comes to an end, I hope it was useful. If you want to see more content like this, make sure to follow me on &lt;a href="https://twitter.com/beeman_nl/"&gt;Twitter&lt;/a&gt;. If you have any questions, send me a tweet or leave a comment on DEV! Cheers! 🐝&lt;/p&gt;

</description>
      <category>api</category>
      <category>nest</category>
      <category>nx</category>
      <category>node</category>
    </item>
    <item>
      <title>Add GraphQL to a NestJS API in a Nx Workspace</title>
      <dc:creator>beeman 🐝</dc:creator>
      <pubDate>Thu, 20 Aug 2020 03:51:07 +0000</pubDate>
      <link>https://forem.com/beeman/add-graphql-to-a-nestjs-api-in-a-nx-workspace-2p8n</link>
      <guid>https://forem.com/beeman/add-graphql-to-a-nestjs-api-in-a-nx-workspace-2p8n</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this tutorial, we add GraphQL functionality to the API using the &lt;a href="https://docs.nestjs.com/graphql/quick-start" rel="noopener noreferrer"&gt;@nestjs/graphql&lt;/a&gt; package.&lt;/p&gt;

&lt;p&gt;GraphQL is a specification for a strongly-typed query language for API's, and is well-supported by NestJS. If you're not familiar with GraphQL you can read &lt;a href="https://graphql.org/learn/" rel="noopener noreferrer"&gt;this introduction&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Install and configure the @nestjs/graphql package.
&lt;/h2&gt;

&lt;p&gt;In order to use GraphQL, we need to install the dependencies and configure the &lt;code&gt;GraphQLModule&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  1.1 Install the dependencies
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add @nestjs/graphql graphql-tools graphql apollo-server-express
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We install the &lt;code&gt;apollo-server-express&lt;/code&gt; dependency because NestJS uses &lt;a href="https://expressjs.com/" rel="noopener noreferrer"&gt;express&lt;/a&gt; by default. Next to Express there is also support for &lt;a href="https://www.fastify.io/" rel="noopener noreferrer"&gt;Fastify&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  1.2 Import the Module
&lt;/h3&gt;

&lt;p&gt;Open &lt;code&gt;libs/core/src/lib/core.module.ts&lt;/code&gt; and add the following lint on the top:&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;GraphQLModule&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;@nestjs/graphql&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;Next, add the &lt;code&gt;GraphQLModule&lt;/code&gt; to the &lt;code&gt;imports&lt;/code&gt; array in the &lt;code&gt;Module&lt;/code&gt; decorator:&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="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Module&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="c1"&gt;// The ConfigModule lives here&lt;/span&gt;
    &lt;span class="nx"&gt;GraphQLModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forRoot&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;autoSchemaFile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="c1"&gt;// The controllers, providers, exports arrays live here.&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;CoreModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To initialize the &lt;code&gt;GraphQLModule&lt;/code&gt;, we invoke the &lt;code&gt;forRoot()&lt;/code&gt; method and pass it an object with the property &lt;code&gt;autoSchemaFile&lt;/code&gt; set to &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Setting &lt;code&gt;autoSchemaFile&lt;/code&gt; set to &lt;code&gt;true&lt;/code&gt; enables the &lt;a href="https://docs.nestjs.com/graphql/quick-start#code-first" rel="noopener noreferrer"&gt;&lt;em&gt;code-first&lt;/em&gt;&lt;/a&gt; approach, which means that we can define our GraphQL schema by writing TypeScript classes with decorators, and NestJS will generate the actual GraphQL schema file based on that.&lt;/p&gt;

&lt;h3&gt;
  
  
  2 Add a Resolver
&lt;/h3&gt;

&lt;p&gt;When you restart the dev server, you will get an error:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GraphQLError: Query root type must be provided.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This is because a GraphQL server must have at least one &lt;em&gt;Query&lt;/em&gt; defined, and currently we have none. Time to add one and make the server run again!&lt;/p&gt;

&lt;h3&gt;
  
  
  2.1 Implement the CoreResolver
&lt;/h3&gt;

&lt;p&gt;Create the file &lt;code&gt;libs/core/src/lib/core.resolver.ts&lt;/code&gt; and add the following snippet:&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;Float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Resolver&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;@nestjs/graphql&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;Resolver&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;CoreResolver&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;uptime&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uptime&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;/div&gt;



&lt;p&gt;This class, that is decorated with the &lt;em&gt;@Resolver()&lt;/em&gt; decorator, that has two functions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It defines which GraphQL &lt;em&gt;queries&lt;/em&gt; exists, and what &lt;em&gt;type&lt;/em&gt; these queries returns.&lt;/li&gt;
&lt;li&gt;It defines which code to execute when this query is invoked.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The queries can be defined by adding the &lt;code&gt;@Query&lt;/code&gt; decorator to a method. The decorator will, by default, use the name of the method that is decorated, so our first query is called &lt;code&gt;uptime&lt;/code&gt;. Inside the decorator is an anonymous function that returns the &lt;em&gt;type&lt;/em&gt;, in our case this is a &lt;em&gt;Float&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Inside the method body we simply return &lt;code&gt;process.uptime()&lt;/code&gt;, which returns the &lt;em&gt;uptime&lt;/em&gt; of the server.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Make sure to import the &lt;code&gt;Query&lt;/code&gt; decorator from the &lt;code&gt;@nestjs/graphql&lt;/code&gt; package. The &lt;code&gt;@nestjs/common&lt;/code&gt; package also exports a &lt;code&gt;Query&lt;/code&gt; decorator, but that one is uses for REST API's.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  2.2 Provide the CoreResolver in the CoreModule
&lt;/h3&gt;

&lt;p&gt;Open &lt;code&gt;libs/core/src/lib/core.module.ts&lt;/code&gt; and add the following lint on the top:&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;CoreResolver&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;./core.resolver&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;Next, add the &lt;code&gt;CoreResolver&lt;/code&gt; to the &lt;code&gt;providers&lt;/code&gt; array in the &lt;code&gt;Module&lt;/code&gt; decorator:&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="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// The imports and controllers live here&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;CoreResolver&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="c1"&gt;// The exports live here&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;CoreModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this in place, the server should start again!&lt;/p&gt;

&lt;p&gt;Visit &lt;a href="http://localhost:3000/graphql" rel="noopener noreferrer"&gt;http://localhost:3000/graphql&lt;/a&gt; to load the GraphQL Playground.&lt;/p&gt;

&lt;p&gt;To test it, add the following query in the left-hand panel and click the Play button. The output should be similar to what you see in the screenshot.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;uptime&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

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

&lt;p&gt;In this tutorial, we added support for GraphQL to our API.&lt;/p&gt;

&lt;p&gt;After installing the dependencies, we configured the &lt;code&gt;GraphQLModule&lt;/code&gt; in the &lt;code&gt;CoreModule&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Because a GraphQL server always needs at least one query, we implemented a &lt;em&gt;resolver&lt;/em&gt; called &lt;code&gt;CoreResolver&lt;/code&gt; and exposed a simple query called &lt;code&gt;uptime&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To verify that this all worked, we launched the playground and tested the query.&lt;/p&gt;

&lt;p&gt;In the next tutorial, the last one of this series, we will expose our server to Heroku! Stay tuned!&lt;/p&gt;

&lt;h2&gt;
  
  
  Thanks!
&lt;/h2&gt;

&lt;p&gt;Thanks for reading my article, I hope it was useful. Feel free to reach out and follow me on &lt;a href="https://twitter.com/beeman_nl/" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; or leave a comment on DEV! 🐝&lt;/p&gt;

</description>
      <category>api</category>
      <category>nest</category>
      <category>graphql</category>
      <category>node</category>
    </item>
    <item>
      <title>Add a NestJS API to a Nx Workspace</title>
      <dc:creator>beeman 🐝</dc:creator>
      <pubDate>Fri, 07 Aug 2020 05:03:17 +0000</pubDate>
      <link>https://forem.com/beeman/add-a-nestjs-api-to-a-nx-workspace-24f</link>
      <guid>https://forem.com/beeman/add-a-nestjs-api-to-a-nx-workspace-24f</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this tutorial, we add two &lt;em&gt;projects&lt;/em&gt; to the workspace, an &lt;em&gt;application&lt;/em&gt; called &lt;em&gt;api&lt;/em&gt;, and a library called &lt;em&gt;core&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In this app, the &lt;em&gt;Core&lt;/em&gt; library is responsible for providing the application-wide configuration using the &lt;a href="https://github.com/nestjs/config"&gt;@nestjs/config&lt;/a&gt; package. To validate the configuration we configure NestJS Config to use &lt;a href="https://npm.im/joi"&gt;Joi&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Add the Nx Nest plugin.
&lt;/h2&gt;

&lt;p&gt;Nx has a plugin system that provides functionality for various frameworks. There are official ones and community plugins. One of the official ones is the Nest plugin.&lt;/p&gt;

&lt;p&gt;Run the following command to install the plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add &lt;span class="nt"&gt;-D&lt;/span&gt; @nrwl/nest
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This plugin provides functionality to create Nest applications and libraries. Let's start with the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Create the API.
&lt;/h2&gt;

&lt;p&gt;In this step we create an &lt;em&gt;application&lt;/em&gt; called &lt;em&gt;api&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.1 Generate the &lt;em&gt;api&lt;/em&gt; application
&lt;/h3&gt;

&lt;p&gt;Run the following command to create the application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;nx generate @nrwl/nest:app api
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This generates a new application in &lt;code&gt;apps/api&lt;/code&gt;, and adds it as a &lt;em&gt;project&lt;/em&gt; to &lt;code&gt;workspace.json&lt;/code&gt; and &lt;code&gt;nx.json&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.2 Start the dev server
&lt;/h3&gt;

&lt;p&gt;Run the following command to start the application&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;nx serve api
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This starts the development server and the prints the message 'Listening at &lt;a href="http://localhost:3333/api"&gt;http://localhost:3333/api&lt;/a&gt;'.&lt;/p&gt;

&lt;p&gt;When you open that URL in the browser, you are greeted with the following message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Welcome to api!"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Create the &lt;em&gt;core&lt;/em&gt; library
&lt;/h2&gt;

&lt;p&gt;One of the great things of building an app using Nx Workspace, is that you can separate the functionality of the app into libraries.&lt;/p&gt;

&lt;p&gt;This has numerous benefits: it creates a separation of concerns, it allows members of a team to work on parts of the app in isolation with less risk of conflicts, and allows for re-using the libraries in other projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.1 Generate the library
&lt;/h3&gt;

&lt;p&gt;Run the following command to create the library:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;nx generate @nrwl/nest:lib core
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This generates a new library in &lt;code&gt;libs/core&lt;/code&gt;, adds it as a &lt;em&gt;project&lt;/em&gt; to &lt;code&gt;workspace.json&lt;/code&gt; and &lt;code&gt;nx.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Additionally, it adds an entry to the &lt;em&gt;paths&lt;/em&gt; object in &lt;code&gt;tsconfig.base.json&lt;/code&gt;, mapping the name &lt;code&gt;@beehive/core&lt;/code&gt; to path &lt;code&gt;libs/core/src/index.ts&lt;/code&gt;. This allows for using the library by importing it from the package name &lt;code&gt;@beehive/core&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.2 Use the library
&lt;/h3&gt;

&lt;p&gt;Open &lt;code&gt;apps/api/src/app/app.module.ts&lt;/code&gt; and add the following line on top, next to the other imports:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;CoreModule&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;@beehive/core&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;Next, add the &lt;code&gt;CoreModule&lt;/code&gt; to the &lt;code&gt;imports&lt;/code&gt; array in the &lt;code&gt;@Module&lt;/code&gt; decorator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Module&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;CoreModule&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;controllers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;AppController&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;AppService&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="nx"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Make sure to stop and start the dev server, so it will pick up the changes made in &lt;code&gt;tsconfig.base.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When the server restarts, you should see that it loads the &lt;code&gt;CoreModule&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[InstanceLoader] CoreModule dependencies initialized
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 If you don't restart the dev server, it will not pick up the changes made in &lt;code&gt;tsconfig.base.json&lt;/code&gt; and you will get an error like this:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ERROR in ./apps/api/src/app/app.module.ts
Module not found: Error: Can't resolve '@beehive/core'
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Time to add some functionality to the &lt;em&gt;core&lt;/em&gt; library.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Add the configuration.
&lt;/h2&gt;

&lt;h3&gt;
  
  
  4.1 Install the dependencies
&lt;/h3&gt;

&lt;p&gt;Run the following command to install the dependencies and devDependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add @nestjs/config joi
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  4.2 Create the configuration file
&lt;/h3&gt;

&lt;p&gt;Create the directory &lt;code&gt;libs/core/src/lib/config&lt;/code&gt;, this is where the configuration is stored.&lt;/p&gt;

&lt;p&gt;Next, create the file &lt;code&gt;libs/core/src/lib/config/configuration.ts&lt;/code&gt;, and add the following snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;configuration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODE_ENV&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;3000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&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;/div&gt;



&lt;p&gt;This file exports a method that returns an object with the configuration for the API.&lt;/p&gt;

&lt;p&gt;The configuration object reads the values from the &lt;em&gt;environment variables&lt;/em&gt;. Because environment variables are always represented as a string, the &lt;code&gt;port&lt;/code&gt; property converts the value to an integer using &lt;code&gt;parseInt&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Because the &lt;code&gt;process.env.PORT&lt;/code&gt; variable can be undefined, the default string '3000' is provided. Leaving this out will make TypeScript's strict mode unhappy.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.3 Create the validation file
&lt;/h3&gt;

&lt;p&gt;Create the file &lt;code&gt;libs/core/src/lib/config/validation.ts&lt;/code&gt; and add the following snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Joi&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;joi&lt;/span&gt;&lt;span class="dl"&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;const&lt;/span&gt; &lt;span class="nx"&gt;validationSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Joi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;NODE_ENV&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Joi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;valid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;development&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;required&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Joi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&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;/div&gt;



&lt;p&gt;The validation file exports a schema that uses Joi for validating the &lt;em&gt;environment variables&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;PORT&lt;/code&gt; environment variable validates that the type is a number, and sets the default value.&lt;/p&gt;

&lt;p&gt;For the &lt;code&gt;NODE_ENV&lt;/code&gt; environment variable, the valid options are either &lt;code&gt;development&lt;/code&gt;, &lt;code&gt;production&lt;/code&gt; or &lt;code&gt;test&lt;/code&gt;. We don't provide a default which means we should always apply one explicitly.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.4 Tying it all together
&lt;/h3&gt;

&lt;p&gt;Open &lt;code&gt;libs/core/src/lib/core.module.ts&lt;/code&gt; and add the following imports at the top:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;ConfigModule&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;@nestjs/config&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;configuration&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;./config/configuration&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;validationSchema&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;./config/validation&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;After that, add a new array called &lt;code&gt;imports&lt;/code&gt; to the &lt;code&gt;@Module&lt;/code&gt; decorator, and add the &lt;code&gt;ConfigModule&lt;/code&gt; like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Module&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;ConfigModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forRoot&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;isGlobal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;load&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="nx"&gt;validationSchema&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;span class="na"&gt;controllers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="na"&gt;exports&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;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;CoreModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When you have the server still running, the following error will appear:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Error: Config validation error: "NODE_ENV" is required
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is because we did not provide a default value for the &lt;code&gt;NODE_ENV&lt;/code&gt; &lt;em&gt;environment variable&lt;/em&gt;, which is required.&lt;/p&gt;

&lt;h2&gt;
  
  
  4.5 Add a .env file for development.
&lt;/h2&gt;

&lt;p&gt;The Nest Config module uses dotenv under the hood. This means we can configure the environment using a &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Create a new file called &lt;code&gt;.env&lt;/code&gt; in your project root, and add the following snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NODE_ENV=development
PORT=3000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Restart the dev server to make it read the &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;

&lt;h2&gt;
  
  
  4.6 Update the .gitignore
&lt;/h2&gt;

&lt;p&gt;Best practice is to not commit the &lt;code&gt;.env&lt;/code&gt; file into git, as it might store sensitive information like API keys or database connections strings.&lt;/p&gt;

&lt;p&gt;Open &lt;code&gt;.gitignore&lt;/code&gt; from your project root and add the following line:&lt;br&gt;
&lt;/p&gt;

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



&lt;blockquote&gt;
&lt;p&gt;💡 Because we don't include the &lt;em&gt;.env&lt;/em&gt; file in the repository, it's considered a 'best practice' to provide a default &lt;em&gt;.env.example&lt;/em&gt; file that can be used as a reference.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  5. Use the configuration object.
&lt;/h2&gt;

&lt;p&gt;Last thing to do is use the configuration in our api.&lt;/p&gt;

&lt;p&gt;Open &lt;code&gt;apps/api/src/main.ts&lt;/code&gt; and add the following imports at the top:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;ConfigService&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;@nestjs/config&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;Next, in the body of the &lt;code&gt;bootstrap&lt;/code&gt; function, add the following to the start of the method, right below the definition of &lt;code&gt;const app&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;NestFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AppModule&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ConfigService&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Lastly, we update the method of the &lt;code&gt;listen&lt;/code&gt; method, and create a new line that invokes &lt;code&gt;Logger.log&lt;/code&gt;, below the existin gone:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Listening at http://localhost:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;port&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;globalPrefix&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Running in &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;environment&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; mode`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When you start the dev server again, the following lines should appear in the output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;Listening at http://localhost:3000/api
Running &lt;span class="k"&gt;in &lt;/span&gt;development mode
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Awesome, the system works!&lt;/p&gt;

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

&lt;p&gt;In this tutorial we created a Nest application called &lt;em&gt;api&lt;/em&gt;, and a module called &lt;em&gt;core&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The module is responsible for the application configuration and provides validation to make sure the required properties are defined and have the expected value.&lt;/p&gt;

&lt;p&gt;We created a &lt;code&gt;.env&lt;/code&gt; so we can easily apply environment vars during development, and added this file to &lt;code&gt;.gitignore&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Lastly, we updated the &lt;code&gt;main.ts&lt;/code&gt; file to make it use the &lt;code&gt;ConfigService&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In the next tutorial, we will add a GraphQL endpoint to our API, stay tuned!&lt;/p&gt;

&lt;h2&gt;
  
  
  Thanks!
&lt;/h2&gt;

&lt;p&gt;Thanks for reading my article, I hope it was useful. Feel free to reach out and follow me on &lt;a href="https://twitter.com/beeman_nl/"&gt;Twitter&lt;/a&gt; or leave a comment on DEV! 🐝&lt;/p&gt;

</description>
      <category>api</category>
      <category>nest</category>
      <category>nx</category>
      <category>node</category>
    </item>
    <item>
      <title>Set up and configure a new Nx Workspace</title>
      <dc:creator>beeman 🐝</dc:creator>
      <pubDate>Thu, 06 Aug 2020 04:50:17 +0000</pubDate>
      <link>https://forem.com/beeman/set-up-and-configure-a-new-nx-workspace-1oh6</link>
      <guid>https://forem.com/beeman/set-up-and-configure-a-new-nx-workspace-1oh6</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this tutorial, you learn how to set up and configure a Nx Workspace. Read &lt;a href="https://dev.to/beeman/introduction-to-building-api-s-with-nestjs-and-nrwl-nx-1l2b"&gt;the introduction&lt;/a&gt; to learn more about Nx Workspace.&lt;/p&gt;

&lt;p&gt;We use the &lt;code&gt;create-nx-workspace&lt;/code&gt; package to scaffold a new project. After that, we adjust the &lt;a href="https://prettier.io/"&gt;prettier&lt;/a&gt; settings to our liking, and add &lt;a href="https://github.com/okonet/lint-staged"&gt;lint-staged&lt;/a&gt; and &lt;a href="https://github.com/typicode/husky"&gt;husky&lt;/a&gt; to make sure our code gets properly formatted on commit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;For this tutorial, you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node.js, visit the &lt;a href="https://nodejs.org"&gt;homepage&lt;/a&gt; for installation instructions.

&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;node -v&lt;/code&gt; to verify you have version 12 or higher.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Yarn (the classic version), visit the &lt;a href="https://classic.yarnpkg.com/lang/en/"&gt;homepage&lt;/a&gt; for installation instructions.

&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;yarn -v&lt;/code&gt; to verify you have version 1.22.0 or higher (in the 1.x range).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. Set up new project.
&lt;/h2&gt;

&lt;p&gt;In this step we create a new project using the &lt;a href="https://www.npmjs.com/package/create-nx-workspace"&gt;create-nx-workspace&lt;/a&gt; package on npm. The name of the project in this tutorial is &lt;strong&gt;beehive&lt;/strong&gt; which will also be the &lt;em&gt;npm scope&lt;/em&gt; of the packages that are created.&lt;/p&gt;

&lt;h3&gt;
  
  
  1.1 Create Workspace
&lt;/h3&gt;

&lt;p&gt;Run the following command in your terminal to create a new workspace with the name &lt;strong&gt;beehive&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn create nx-workspace beehive
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The installer asks a few questions, we provide the following options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create an &lt;strong&gt;empty&lt;/strong&gt; workspace, we will add a custom structure.&lt;/li&gt;
&lt;li&gt;Select the &lt;strong&gt;Nx&lt;/strong&gt; CLI.&lt;/li&gt;
&lt;li&gt;Answer &lt;strong&gt;Yes&lt;/strong&gt; to enable &lt;a href="https://nx.app/"&gt;Nx Cloud&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This generates a new workspace in the &lt;strong&gt;beehive&lt;/strong&gt; directory.&lt;/p&gt;

&lt;p&gt;Run the following command to enter the &lt;em&gt;project root&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;beehive
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;💡 All the following commands in this series will be executed from this directory, unless explicitly stated otherwise.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  1.2 Create and add GitHub repo
&lt;/h3&gt;

&lt;p&gt;Navigate to &lt;a href="https://github.com/new"&gt;github.com/new&lt;/a&gt;, add a repository name like &lt;strong&gt;tutorial-nestjs-apis-with-nx&lt;/strong&gt;, select either &lt;strong&gt;private&lt;/strong&gt; or &lt;strong&gt;public&lt;/strong&gt; and click &lt;strong&gt;Create Repository&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We are importing an existing repository, so be sure to not select any of the options below the line &lt;em&gt;Skip this step if you’re importing an existing repository&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;After that we land on the page of the new repository. Look for the commands in the second block on the page that says, &lt;em&gt;...or push an existing repository from the command line&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Execute the commands and in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;git remote add origin git@github.com:beeman/tutorial-nestjs-apis-with-nx.git
git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin master
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After this is done, switch back to the browser and refresh the page to verify the empty workspace is push to GitHub.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Configure Prettier
&lt;/h2&gt;

&lt;p&gt;When creating a new Nx Workspace, it comes with support for Prettier out of the box. Let's adjust the default settings so that the formatting is done in line with our other projects.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡This step is not essential, but it's very likely that you have some preference on how Prettier is formatting your code. Check &lt;a href="https://prettier.io/docs/en/options.html"&gt;this page&lt;/a&gt; to see what options are available.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  2.1 Update the Prettier configuration
&lt;/h3&gt;

&lt;p&gt;Open the project in your editor, then open the file &lt;code&gt;.prettierrc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Update the content with the settings you prefer or use my default options:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"singleQuote"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"printWidth"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"semi"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"trailingComma"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"all"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"arrowParens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"always"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  2.2 Re-format your code with the new settings
&lt;/h3&gt;

&lt;p&gt;Once we have that in place, it's time to format the project with these settings.&lt;/p&gt;

&lt;p&gt;In your terminal, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;nx format:write &lt;span class="nt"&gt;--all&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;💡 As the output suggest, because of performance it is not recommended running this command with the &lt;em&gt;--all&lt;/em&gt; flag in larger projects. However, our project is empty and with the auto-formatting in place our project should always be properly formatted.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  3. Set up automatic formatting on commit
&lt;/h2&gt;

&lt;p&gt;To make sure the formatting gets applied consistently for each contributor of the project, it makes sense to have auto-format the code on each commit. With this in place we can be sure formatting is not dependent on whatever extensions the contributors might have installed in their editors.&lt;/p&gt;

&lt;p&gt;To achieve this, we use the tools &lt;a href="http://npm.im/husky"&gt;husky&lt;/a&gt; and &lt;a href="http://npm.im/lint-staged"&gt;lint-staged&lt;/a&gt;. The first one, &lt;strong&gt;husky&lt;/strong&gt;, is a tool that allows you to define hooks on various git commands, we will be using the &lt;code&gt;pre-commit&lt;/code&gt; hook. The second one, &lt;strong&gt;lint-staged&lt;/strong&gt;, is a tool that runs commands like linters (or formatters in our case) on the files that are &lt;em&gt;staged&lt;/em&gt; by git.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.1 Add the dependencies
&lt;/h3&gt;

&lt;p&gt;Run the following command to install these packages as dev-dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add -D husky lint-staged
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  3.2 Configure husky
&lt;/h3&gt;

&lt;p&gt;Open &lt;code&gt;package.json&lt;/code&gt; and add a new the following object on the &lt;em&gt;top-level&lt;/em&gt; (for example, right below the &lt;em&gt;devDependencies&lt;/em&gt; object):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"husky"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"pre-commit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"lint-staged"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This configures &lt;strong&gt;husky&lt;/strong&gt; to run the command &lt;strong&gt;lint-staged&lt;/strong&gt; before each commit.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.3 Configure lint-staged
&lt;/h3&gt;

&lt;p&gt;Open &lt;code&gt;package.json&lt;/code&gt; and right below your &lt;strong&gt;husky&lt;/strong&gt; configuration, add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"lint-staged"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"*.{js,json,css,scss,md,ts,html,graphql}"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"yarn format --uncommitted"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;With this in place, when &lt;strong&gt;lint-staged&lt;/strong&gt; runs, it will look for any of the extensions defined in the configuration, and execute the command &lt;code&gt;yarn format --uncommitted&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Commit changes and push
&lt;/h2&gt;

&lt;p&gt;With all this in place, the basic project is ready.&lt;/p&gt;

&lt;p&gt;Run the following command to add the files commit and push:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&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;"configure prettier, husky and lint-staged"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When you run the commands above, you should see &lt;strong&gt;husky&lt;/strong&gt; kicking in, which executes &lt;strong&gt;lint-staged&lt;/strong&gt; which in turn formats your code.&lt;/p&gt;

&lt;p&gt;Run the following command to push to GitHub&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;git push
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



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

&lt;p&gt;In this tutorial, we created a new Nx Workspace and set it up with some tools to help us keep the project neat and clean.&lt;/p&gt;

&lt;p&gt;We configured Prettier to our liking. After that, we installed &lt;strong&gt;husky&lt;/strong&gt; and &lt;strong&gt;lint-staged&lt;/strong&gt; and configured them in our &lt;code&gt;package.json&lt;/code&gt;. After adding the files and committing them, we verified that we say these tools do their job.&lt;/p&gt;

&lt;p&gt;In the next tutorial, we will add the Nest API to our project, stay tuned!&lt;/p&gt;

&lt;h2&gt;
  
  
  Thanks!
&lt;/h2&gt;

&lt;p&gt;Thanks for reading my article, I hope it was useful. Feel free to reach out and follow me on &lt;a href="https://twitter.com/beeman_nl/"&gt;Twitter&lt;/a&gt; or leave a comment on DEV! 🐝&lt;/p&gt;

</description>
      <category>api</category>
      <category>nest</category>
      <category>nx</category>
      <category>node</category>
    </item>
    <item>
      <title>Introduction to Building API's with NestJS and Nrwl Nx</title>
      <dc:creator>beeman 🐝</dc:creator>
      <pubDate>Wed, 05 Aug 2020 14:34:12 +0000</pubDate>
      <link>https://forem.com/beeman/introduction-to-building-api-s-with-nestjs-and-nrwl-nx-1l2b</link>
      <guid>https://forem.com/beeman/introduction-to-building-api-s-with-nestjs-and-nrwl-nx-1l2b</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this tutorial, you learn how to build API's with NestJS and Nx Workspace. The goal is to give you a nice starting point that's easy to extend. Additionally, it will serve as a reference for later posts and series that I intend to write.&lt;/p&gt;

&lt;p&gt;This post serves as an introduction to the technology stack and goes over the tutorials in the series.&lt;/p&gt;

&lt;h2&gt;
  
  
  NestJS
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gBqBW81R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/b2f1x6outcd3fzswwbrb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gBqBW81R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/b2f1x6outcd3fzswwbrb.png" alt="NestJS logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nestjs.com/"&gt;NestJS&lt;/a&gt; is a framework for building API's using Node.js and TypeScript. NestJS provides an opinionated API on top of Express (or optionally Fastify) and makes heavy use of TypeScript classes and decorators, enabling a declarative way to quickly add new functionality without writing a lot of code.&lt;/p&gt;

&lt;p&gt;NestJS has great &lt;a href="https://docs.nestjs.com/"&gt;documentation&lt;/a&gt; and is actively maintained. There are a lot of useful libraries provided by the project itself, and there is a growing community that provides even more functionality. Besides that, NestJS is easy to extend if the functionality you need does not exist.&lt;/p&gt;

&lt;h3&gt;
  
  
  NestJS concepts
&lt;/h3&gt;

&lt;p&gt;Here are a few NestJS concepts you should be aware of when going through this series.&lt;/p&gt;

&lt;h4&gt;
  
  
  Modules
&lt;/h4&gt;

&lt;p&gt;The architecture from NestJS is inspired by Angular. It uses &lt;em&gt;modules&lt;/em&gt; to encapsulate functionality in standalone, reusable blocks that can be imported by other modules. Modules tie the other components together, and make sure &lt;em&gt;dependency injection&lt;/em&gt; works.&lt;/p&gt;

&lt;h4&gt;
  
  
  Controllers
&lt;/h4&gt;

&lt;p&gt;The &lt;em&gt;Controllers&lt;/em&gt; are used to build a RESTful API. They allow building any HTTP api that you can dream of, and does so in a clean and declarative matter by adding methods to TypeScript classes, and decorate them. These &lt;em&gt;Controllers&lt;/em&gt; define the external REST API, most of the heavy lifting is done through &lt;em&gt;Providers&lt;/em&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Providers
&lt;/h4&gt;

&lt;p&gt;The &lt;em&gt;Providers&lt;/em&gt; are injected into the &lt;em&gt;Controllers&lt;/em&gt;, &lt;em&gt;Resolvers&lt;/em&gt; or other &lt;em&gt;Providers&lt;/em&gt;, and handle their requests. Things like accessing a database or calling into third-party API's or libraries are all done in &lt;em&gt;Providers&lt;/em&gt;. This keeps the &lt;em&gt;Controllers&lt;/em&gt; clean and focussed, and makes it easy to share the functionality with other parts of the application.&lt;/p&gt;

&lt;h4&gt;
  
  
  Resolvers
&lt;/h4&gt;

&lt;p&gt;The &lt;em&gt;Resolvers&lt;/em&gt; are used to build a GraphQL API. They allow building a GraphQL API using a code-first approach. That means that you don't need use GraphQL's Schema Definition Language (SDL) to define the API, but rather TypeScript code. Like the controllers, the &lt;em&gt;Resolvers&lt;/em&gt; define the external API, and use &lt;em&gt;Providers&lt;/em&gt; to do the heavy lifting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nx
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2ba5iJCp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/jmsyzyk6pdkjf7bflwu2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2ba5iJCp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/jmsyzyk6pdkjf7bflwu2.png" alt="Nx Logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nx.dev"&gt;Nx&lt;/a&gt; combines a mono-repository structure with CLI tools to develop and manage one or more applications and libraries, all within the same repository. Nx encourages code collaboration, unified testing, and optimizes builds and testing performances.&lt;/p&gt;

&lt;p&gt;Nx is an amazing tool for building medium or large sized applications. Using a mono-repo allows you to easily share code between various parts of the project, without having to worry about the these parts being out of sync. Nx is smart in the sense that it knows which parts of the app relate to each other. Read more about the &lt;em&gt;Dependency Graph&lt;/em&gt; below.&lt;/p&gt;

&lt;h3&gt;
  
  
  Nx concepts
&lt;/h3&gt;

&lt;p&gt;Here are a few Nx concepts you should be aware of when going through this series.&lt;/p&gt;

&lt;h4&gt;
  
  
  Workspace
&lt;/h4&gt;

&lt;p&gt;The &lt;em&gt;workspace&lt;/em&gt; is defined on the root of the repository, and consists of one or more projects, which can be either an &lt;em&gt;application&lt;/em&gt; or a &lt;em&gt;library&lt;/em&gt;. The workspace uses either the Nx CLI or Angular CLI to serve, test, build and lint the projects. The workspace is defined in the files &lt;code&gt;nx.json&lt;/code&gt; and &lt;code&gt;workspace.json&lt;/code&gt; (or &lt;code&gt;angular.json&lt;/code&gt; if using the Angular CLI).&lt;/p&gt;

&lt;h4&gt;
  
  
  Applications
&lt;/h4&gt;

&lt;p&gt;In Nx, the &lt;em&gt;applications&lt;/em&gt; (or apps), are the projects that contain a runnable application. Applications should be light-weight, and expose the functionality defined in the &lt;em&gt;libraries&lt;/em&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Libraries
&lt;/h4&gt;

&lt;p&gt;The &lt;em&gt;libraries&lt;/em&gt; (or libs), are the projects that implement the functionality for the apps. The libraries define an external API that can be consumed by the apps and other libs.&lt;/p&gt;

&lt;h4&gt;
  
  
  Plugins
&lt;/h4&gt;

&lt;p&gt;The actual functionality of the Nx workspace is defined by the plugins that are installed. Nx comes with quite a few official plugins that add support for, for example, Angular, Node, Next, React and Web Components. Additionally, there is a growing list of community plugins.&lt;/p&gt;

&lt;h4&gt;
  
  
  Dependency Graph
&lt;/h4&gt;

&lt;p&gt;The &lt;em&gt;Dependency Graph&lt;/em&gt;, or &lt;em&gt;dep graph&lt;/em&gt;, is an automatically generated schema that shows how different parts of the monorepo depend on each other. Nx uses this information to intelligently execute commands on parts of the workspace. For example, it will only re-build projects that are actually changed, or when one of the dependencies are change.&lt;/p&gt;

&lt;h2&gt;
  
  
  The project structure
&lt;/h2&gt;

&lt;p&gt;In this series though, we use a simple structure. We build an app called &lt;code&gt;api&lt;/code&gt; that consumes the libraries &lt;code&gt;core&lt;/code&gt; and &lt;code&gt;course&lt;/code&gt;, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apps/api
libs/core
libs/course
libs/&amp;lt;library&amp;gt; (any other functionality goes here).
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Tutorial in this series
&lt;/h2&gt;

&lt;p&gt;This series consists of four tutorials that, when finished, result in a project that is solid basis that's easy to extend.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://dev.to/beeman/set-up-and-configure-a-new-nx-workspace-1oh6"&gt;Set up and configure a new Nx Workspace&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;To start the project, we create an empty Nx Workspace and take a look around to see what it consists of. We install and configure some tools to automatically format the code on each commit. Having this in place makes sure all future code has a similar style.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://dev.to/beeman/add-a-nestjs-api-to-a-nx-workspace-24f"&gt;Add a NestJS API to a Nx Workspace&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;After creating the project, we use the official NestJS plugin for Nx to create an application called &lt;em&gt;api&lt;/em&gt; with a library called &lt;em&gt;core&lt;/em&gt;. The &lt;em&gt;core&lt;/em&gt; library is responsible for exporting the runtime configuration, and is consumed by the &lt;em&gt;api&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://dev.to/beeman/add-graphql-to-a-nestjs-api-in-a-nx-workspace-2p8n"&gt;Add GraphQL to a NestJS API in a Nx Workspace&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;When these parts are in place, we move on to adding actual functionality to the &lt;em&gt;api&lt;/em&gt;. After installing the needed dependencies and configure the GraphQL Module for NestJS, we implement a GraphQL &lt;em&gt;resolver&lt;/em&gt; and add a simple query that returns the servers' uptime.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://dev.to/beeman/deploy-a-nestjs-api-to-heroku-from-a-nx-workspace-o85"&gt;Deploy a NestJS API to Heroku from a Nx Workspace&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Once this is all done, the API is ready to ship! After building the project locally and making sure it all works as expected, we add the configuration to deploy it to Heroku.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thanks!
&lt;/h2&gt;

&lt;p&gt;First of all, thanks to the reviewers of this series 🙏:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/bhaidar"&gt;Bilal Haidar&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/TheSpiciestDev"&gt;James Allen&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/rhutchison"&gt;Ryan Hutchison&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/ThomasBurleson"&gt;Thomas Burleson&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The cover photo for this series is an edited version of &lt;a href="https://unsplash.com/photos/onnJOfF-okU"&gt;this photo&lt;/a&gt; by &lt;a href="https://unsplash.com/@churchoftodd"&gt;Todd Kent&lt;/a&gt; on unsplash.&lt;/p&gt;

&lt;p&gt;Thank YOU for reading my article, I hope it was useful. Feel free to reach out and follow me on &lt;a href="https://twitter.com/beeman_nl/"&gt;Twitter&lt;/a&gt; or leave a comment on DEV! 🐝&lt;/p&gt;

</description>
      <category>api</category>
      <category>nest</category>
      <category>nx</category>
      <category>node</category>
    </item>
    <item>
      <title>Using oclif to create a CLI for the DEV API</title>
      <dc:creator>beeman 🐝</dc:creator>
      <pubDate>Thu, 09 Jul 2020 02:42:53 +0000</pubDate>
      <link>https://forem.com/beeman/using-oclif-to-create-a-cli-for-the-dev-api-2iej</link>
      <guid>https://forem.com/beeman/using-oclif-to-create-a-cli-for-the-dev-api-2iej</guid>
      <description>&lt;p&gt;In this tutorial, you learn how to use &lt;a href="https://oclif.io"&gt;oclif&lt;/a&gt; to create a CLI that lists the articles in your DEV account.&lt;/p&gt;

&lt;p&gt;The goal is to show how to create a CLI that interacts with an authenticated API. We will only add one single command, (&lt;em&gt;list&lt;/em&gt;), however extending the CLI should be pretty straightforward.&lt;/p&gt;

&lt;p&gt;This tutorial documents the first steps I took when I built &lt;a href="http://npm.im/dev-to-sync"&gt;dev-to-sync&lt;/a&gt;, take a look at &lt;a href="https://github.com/beeman/dev-to-sync"&gt;that repo&lt;/a&gt; to see how I added some more commands.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Node.js and NPM, visit the &lt;a href="https://nodejs.org"&gt;homepage&lt;/a&gt; for installation instructions.

&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;node -v&lt;/code&gt; to verify you have version 12 or higher.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;npm -v&lt;/code&gt; to verify you have version 6 or higher.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;A DEV API key

&lt;ul&gt;
&lt;li&gt;Generate one here &lt;a href="https://dev.to/settings/account"&gt;https://dev.to/settings/account&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Install the oclif cli
&lt;/h2&gt;



&lt;div class="highlight"&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; oclif
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Setup a new project
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;oclif multi dev-to-sync
&lt;span class="nb"&gt;cd &lt;/span&gt;dev-to-sync 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Initialize git repo
&lt;/h3&gt;

&lt;p&gt;Even though it's not essential for the working of the CLI, you probably want to initialize a git repo and do an initial commit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;git init
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Initial commit"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Link local project
&lt;/h3&gt;

&lt;p&gt;In order to make our new CLI available for running it locally while we're developing it, it needs to be linked:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;link&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Run it
&lt;/h3&gt;

&lt;p&gt;Now that that's done, we can give it a run to see if it all works.&lt;/p&gt;

&lt;p&gt;If all went well, running the command &lt;code&gt;dev-to-sync&lt;/code&gt; should output something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;dev-to-sync
Sync your DEV account with a &lt;span class="nb"&gt;local &lt;/span&gt;folder

VERSION
  dev-to-sync/0.0.0 darwin-x64 node-v12.18.1

USAGE
  &lt;span class="nv"&gt;$ &lt;/span&gt;dev-to-sync &lt;span class="o"&gt;[&lt;/span&gt;COMMAND]

COMMANDS
  hello  describe the &lt;span class="nb"&gt;command &lt;/span&gt;here
  &lt;span class="nb"&gt;help   &lt;/span&gt;display &lt;span class="nb"&gt;help &lt;/span&gt;&lt;span class="k"&gt;for &lt;/span&gt;dev-to-sync
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This shows us there is a &lt;em&gt;hello&lt;/em&gt; command, which we can execute like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;dev-to-sync hello
hello world from ./src/commands/hello.ts
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Creating alias
&lt;/h3&gt;

&lt;p&gt;In this step we give our CLI a shortcut &lt;code&gt;dts&lt;/code&gt; so we can invoke it with less keystrokes.&lt;/p&gt;

&lt;p&gt;Open &lt;code&gt;package.json&lt;/code&gt; and add a key &lt;code&gt;dts&lt;/code&gt; with value &lt;code&gt;./bin/run&lt;/code&gt; to the &lt;code&gt;bin&lt;/code&gt; object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"bin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dev-to-sync"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./bin/run"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./bin/run"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After this you need to run &lt;code&gt;npm link&lt;/code&gt; again to make sure your operating system is aware of the new command.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a wrapper for the DEV api
&lt;/h2&gt;

&lt;p&gt;To access the DEV api we create a wrapper class called &lt;code&gt;DevtoClient&lt;/code&gt;. We initialize the class with the API key and use that to set up the header, adding the &lt;code&gt;api-key&lt;/code&gt; property to each request.&lt;/p&gt;

&lt;p&gt;We implement a &lt;code&gt;get&lt;/code&gt; method to execute authenticated requests to the DEV api and a &lt;code&gt;getArticles&lt;/code&gt; method that retreives the articles.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install the dependencies
&lt;/h3&gt;

&lt;p&gt;Install &lt;code&gt;node-fetch&lt;/code&gt; and it's types:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;node-fetch
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-D&lt;/span&gt; @types/node-fetch
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Create the client
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;src/lib/devto-client.ts&lt;/code&gt; and add the following snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fetch&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;node-fetch&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;DevtoClient&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;baseUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://dev.to/api&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;headers&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="s2"&gt;api-key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;content-type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&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;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;api-key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&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;apiKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;content-type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&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="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&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;baseUrl&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&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;headers&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&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;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;getArticles&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/articles/me/all&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error retrieving articles&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;return&lt;/span&gt; &lt;span class="nx"&gt;result&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;/div&gt;



&lt;p&gt;Create &lt;code&gt;src/lib/utils.ts&lt;/code&gt; and add the following snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;DevtoClient&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;./devto-client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DEV_TO_TOKEN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Environment variable DEV_TO_TOKEN not found`&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;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;DevtoClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DEV_TO_TOKEN&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We now can import the &lt;code&gt;client&lt;/code&gt; at any of the commands and use it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing the list command
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Create the command
&lt;/h3&gt;

&lt;p&gt;Run the following command to create a new command to the CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;oclif command list
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Implement the command
&lt;/h3&gt;

&lt;p&gt;Open &lt;code&gt;src/commands/list.ts&lt;/code&gt; and replace the content with the following snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;Command&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;@oclif/command&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;client&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;../lib/utils&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;List&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Command&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;List articles in a DEV account&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;articles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getArticles&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;article&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;articles&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Test the command
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;dts list
Tutorial: Styling Angular CLI Apps with Bootstrap
Automate your DEV Posts using GitHub Actions
Using yarn with Angular CLI
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Where to go from here?
&lt;/h2&gt;

&lt;p&gt;This should be a steady basis to quickly build more functionality. You can, for example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;oclif command&lt;/code&gt; to add more commands, check the &lt;a href="http://dev.to/api"&gt;DEV api documentation&lt;/a&gt; for the available API methods.&lt;/li&gt;
&lt;li&gt;Add colors to the output using &lt;a href="http://npm.im/chalk"&gt;chalk&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Make the CLI interactive using &lt;a href="http://npm.im/inquirer"&gt;inquirer&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Use &lt;a href="https://oclif.io/docs/plugins"&gt;oclif plugins&lt;/a&gt; if you want to add additional functionality to your CLI like autoupdate, autocomplete or update warnings.&lt;/li&gt;
&lt;li&gt;Download &lt;a href="https://github.com/beeman/dev-to-sync"&gt;beeman/dev-to-sync&lt;/a&gt; for a more complete implementation.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;In this tutorial, we created a CLI from scratch by using oclif. After setting up the project, we implemented an API client that communicates with the DEV api, and a small method that wraps the API client and takes the API key from the environment. The last step was implementing the list command to retrieve the articles from the list, and show them in the console.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thanks!
&lt;/h2&gt;

&lt;p&gt;Thanks for reading my article. Feel free to reach out if you have any questions! Follow me on &lt;a href="https://twitter.com/beeman_nl/"&gt;Twitter&lt;/a&gt; or leave a comment on DEV! 🐝&lt;/p&gt;

</description>
      <category>api</category>
      <category>cli</category>
      <category>devto</category>
      <category>oclif</category>
    </item>
    <item>
      <title>Tutorial: Styling Angular CLI Apps with Bootstrap</title>
      <dc:creator>beeman 🐝</dc:creator>
      <pubDate>Tue, 07 Jul 2020 17:20:22 +0000</pubDate>
      <link>https://forem.com/beeman/tutorial-styling-angular-cli-apps-with-bootstrap-foa</link>
      <guid>https://forem.com/beeman/tutorial-styling-angular-cli-apps-with-bootstrap-foa</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FkDpKNBw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/uisbw2k5xdupr3lrtipy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FkDpKNBw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/uisbw2k5xdupr3lrtipy.gif" alt="Example of the pages of the final app"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this tutorial, you learn how to use Bootstrap to style Angular CLI Apps.&lt;/p&gt;

&lt;p&gt;The goal is to build an application layout with a header and footer, a home page, about page, and a login page with form.&lt;/p&gt;

&lt;p&gt;Check the &lt;a href="https://tutorial-styling-angular-cli-apps-with-bootstrap.netlify.app/"&gt;live demo here&lt;/a&gt; or the &lt;a href="https://github.com/beeman/tutorial-styling-angular-cli-apps-with-bootstrap"&gt;GitHub repo&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;Make sure you have the following tools installed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node.js and NPM, visit the &lt;a href="https://nodejs.org"&gt;homepage&lt;/a&gt; for installation instructions.

&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;node -v&lt;/code&gt; to verify you have version 12 or higher.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;npm -v&lt;/code&gt; to verify you have version 6 or higher.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Angular CLI (&lt;code&gt;npm install -g @angular/cli@latest&lt;/code&gt; to install)

&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;ng --version&lt;/code&gt; to verify you have version 10 or higher.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you prefer using &lt;code&gt;yarn&lt;/code&gt;, first &lt;a href="https://beeman.dev/posts/using-yarn-with-angular-cli-1n73/"&gt;configure Angular CLI's default package manager&lt;/a&gt;. This makes sure the generated application has a &lt;code&gt;yarn.lock&lt;/code&gt; file instead of a &lt;code&gt;package-lock.json&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Create a new application
&lt;/h2&gt;

&lt;p&gt;Open a terminal and run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng new sandbox --routing --style scss --strict
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;ng new&lt;/code&gt; command generates a basic Angular application in a directory called &lt;code&gt;sandbox&lt;/code&gt; and installs the dependencies.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;--routing&lt;/code&gt; flag instructs Angular CLI to generate a routing module.&lt;br&gt;
The &lt;code&gt;--style scss&lt;/code&gt; parameter sets SCSS as the style preprocessor.&lt;br&gt;
The &lt;code&gt;--strict&lt;/code&gt; flag configures the application to run in &lt;a href="https://angular.io/guide/strict-mode"&gt;strict mode&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;At the end of the setup, the Angular CLI also initializes a git repository and does an initial commit.&lt;/p&gt;
&lt;h2&gt;
  
  
  2. Start the application in development mode
&lt;/h2&gt;

&lt;p&gt;After the installation is finished, run the following command to navigate to the &lt;em&gt;project directory&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;sandbox
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In the project directory you can start the development server using &lt;code&gt;ng serve&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng serve
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;** Angular Live Development Server is listening on localhost:4200, open your browser on &lt;a href="http://localhost:4200/"&gt;http://localhost:4200/&lt;/a&gt; **&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Navigate to the link displayed by the Dev server and verify that it works. The app is now ready to get some style(s)! 😎&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Install Bootstrap
&lt;/h2&gt;

&lt;p&gt;Run the following command in your project directory to install Bootstrap:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install bootstrap
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When the installation is finished we now can tell Angular CLI to use these styles.&lt;/p&gt;

&lt;p&gt;Open &lt;code&gt;src/styles.scss&lt;/code&gt; and add the following lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s1"&gt;'~bootstrap/scss/bootstrap'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Set the full page height so we can stick the footer to the bottom&lt;/span&gt;
&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&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;/div&gt;



&lt;p&gt;Next, open &lt;code&gt;src/app/app.component.html&lt;/code&gt; and delete all the content, replace it with the following snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-center text-primary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Hello Bootstrap!&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When you go back to your browser, you should see &lt;code&gt;Hello Bootstrap&lt;/code&gt; in big blue letters! 🎉&lt;/p&gt;

&lt;p&gt;Let's move on to make our app look a little better!&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Configure the application layout
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eRTbqQ2G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/890nao89aq581a8xiles.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eRTbqQ2G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/890nao89aq581a8xiles.png" alt="The basic application layout"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this step we create a &lt;code&gt;UiModule&lt;/code&gt; and add three components to it: &lt;code&gt;LayoutComponent&lt;/code&gt;, &lt;code&gt;HeaderComponent&lt;/code&gt; and &lt;code&gt;FooterComponent&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 It's a good idea to keep the UI separate from the rest of the app. This 'separation of concerns' also allows you to easily re-use the UI in other projects.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  4.1 Create the &lt;code&gt;UiModule&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Run the following command to generate the &lt;code&gt;UiModule&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng generate module ui --module app
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;--module&lt;/code&gt; parameter imports the &lt;code&gt;UiModule&lt;/code&gt; in our main &lt;code&gt;AppModule&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;Next, generate the 3 components inside of this new module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng generate component ui/layout
ng generate component ui/header
ng generate component ui/footer
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;💡 The &lt;code&gt;ng generate&lt;/code&gt; command supports shortcuts: use &lt;code&gt;ng g c&lt;/code&gt; to generate a component, &lt;code&gt;ng g m&lt;/code&gt; to generate a module, etc.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  4.2 Implement the LayoutComponent
&lt;/h3&gt;

&lt;p&gt;Open &lt;code&gt;src/app/ui/layout/layout.component.html&lt;/code&gt; replace the content with the following snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- This flex container takes the full height --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"d-flex flex-column h-100"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;app-header&amp;gt;&amp;lt;/app-header&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- The main area does not shrink, 'pushing down' the footer --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;main&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex-shrink-0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- This will render the routes --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;router-outlet&amp;gt;&amp;lt;/router-outlet&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- This keeps the footer down if the main content does not fill up the space --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;footer&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"mt-auto"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;app-footer&amp;gt;&amp;lt;/app-footer&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/footer&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We use this &lt;code&gt;LayoutComponent&lt;/code&gt; in the router, and render the &lt;em&gt;children&lt;/em&gt; in the location of &lt;code&gt;router-outlet&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Before moving on, make sure to import &lt;code&gt;RouterModule&lt;/code&gt; in &lt;code&gt;UiModule&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Open &lt;code&gt;src/app/ui/ui.module.ts&lt;/code&gt; and add the following code next to the other imports:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;RouterModule&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Add &lt;code&gt;RouterModule&lt;/code&gt; to the &lt;code&gt;imports&lt;/code&gt; array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&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;LayoutComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;HeaderComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FooterComponent&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;CommonModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;RouterModule&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;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;💡 If you forget to import the &lt;code&gt;RouterModule&lt;/code&gt;, the server will tell you:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ERROR in src/app/ui/layout/layout.component.html:3:3 - error NG8001: 'router-outlet' is not a known element:
  1.  If 'router-outlet' is an Angular component, then verify that it is part of this module.
  2.  If 'router-outlet' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.&amp;lt;/pre&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  4.3 Use the LayoutComponent
&lt;/h3&gt;

&lt;p&gt;Open &lt;code&gt;src/app/app-routing.module.ts&lt;/code&gt; and replace the line &lt;code&gt;const routes: Routes = []&lt;/code&gt; with the following snippet:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Routes&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="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LayoutComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="c1"&gt;// Here we will add our application pages&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;/div&gt;



&lt;p&gt;Make sure to import &lt;code&gt;LayoutComponent&lt;/code&gt; in &lt;code&gt;src/app/app-routing.module.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;LayoutComponent&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;./ui/layout/layout.component&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;Open &lt;code&gt;src/app/app.component.html&lt;/code&gt; and replace the content with the following snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;router-outlet&amp;gt;&amp;lt;/router-outlet&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Save all the files and check your browser, you should see the default &lt;code&gt;HeaderComponent&lt;/code&gt; and &lt;code&gt;FooterComponent&lt;/code&gt; being rendered. Time to spice them up!&lt;/p&gt;

&lt;h3&gt;
  
  
  4.4 Implement the Header
&lt;/h3&gt;

&lt;p&gt;Open &lt;code&gt;src/app/ui/header/header.component.html&lt;/code&gt; and replace the content with the following snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- You can change the values `dark` here with any of the following: --&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- dark, light, primary, secondary, success, info, danger, warning --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;nav&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"navbar navbar-dark bg-dark"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- This is the application title with a link to the root --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"navbar-brand"&lt;/span&gt; &lt;span class="na"&gt;routerLinkActive=&lt;/span&gt;&lt;span class="s"&gt;"active"&lt;/span&gt; &lt;span class="na"&gt;routerLink=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Angular &lt;span class="err"&gt;&amp;amp;&lt;/span&gt; Bootstrap&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- This is a spacer so the links move to the end --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"mr-auto"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- This main navigation links are defined here --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"navbar-expand"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"navbar-nav"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="c"&gt;&amp;lt;!-- Each link has the routerLink property set to a different route --&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"nav-item nav-link"&lt;/span&gt; &lt;span class="na"&gt;routerLinkActive=&lt;/span&gt;&lt;span class="s"&gt;"active"&lt;/span&gt; &lt;span class="na"&gt;routerLink=&lt;/span&gt;&lt;span class="s"&gt;"/home"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Home&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"nav-item nav-link"&lt;/span&gt; &lt;span class="na"&gt;routerLinkActive=&lt;/span&gt;&lt;span class="s"&gt;"active"&lt;/span&gt; &lt;span class="na"&gt;routerLink=&lt;/span&gt;&lt;span class="s"&gt;"/about"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;About&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"nav-item nav-link"&lt;/span&gt; &lt;span class="na"&gt;routerLinkActive=&lt;/span&gt;&lt;span class="s"&gt;"active"&lt;/span&gt; &lt;span class="na"&gt;routerLink=&lt;/span&gt;&lt;span class="s"&gt;"/login"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Login&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Refer to the &lt;a href="https://getbootstrap.com/docs/4.5/components/navbar/"&gt;bootstrap documentation of the navbar&lt;/a&gt; for more details on the syntax of the navbar and how to make it responsive.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.5 Implement the Footer
&lt;/h3&gt;

&lt;p&gt;Open &lt;code&gt;src/app/ui/footer/footer.component.html&lt;/code&gt; and replace the content with this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"py-3 bg-dark text-center text-muted"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;small&amp;gt;&lt;/span&gt;Copyright &lt;span class="ni"&gt;&amp;amp;copy;&lt;/span&gt; 2020&lt;span class="nt"&gt;&amp;lt;/small&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  5. Add application Pages
&lt;/h2&gt;

&lt;p&gt;With the application layout in place, it's time to add a few pages.&lt;/p&gt;

&lt;p&gt;The command we use creates a &lt;em&gt;module&lt;/em&gt; with a &lt;em&gt;component&lt;/em&gt; and &lt;a href="https://angular.io/guide/lazy-loading-ngmodules"&gt;lazy-loads&lt;/a&gt; it in the &lt;code&gt;AppModule&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Lazy loading is the recommended way of routing in an Angular app as it makes sure the users don't download any code they won't run.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  5.1 Create a Home page
&lt;/h3&gt;

&lt;p&gt;Run the following command to generate the &lt;code&gt;HomeModule&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng g module pages/home --route home --module app
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Open &lt;code&gt;src/app/pages/home/home.component.html&lt;/code&gt; and replace the content with this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container py-5"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"jumbotron"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-secondary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Home&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Go to your application in the browser and click the &lt;em&gt;Home&lt;/em&gt; link in the header.&lt;/p&gt;

&lt;p&gt;You will be taken to the route &lt;code&gt;/home&lt;/code&gt; with the text 'Home'. However, the layout with the header and footer is gone!&lt;/p&gt;

&lt;p&gt;To fix this, open &lt;code&gt;src/app/app-routing.module.ts&lt;/code&gt; and move the newly created route inside the &lt;code&gt;children&lt;/code&gt; array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Routes&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="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LayoutComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="c1"&gt;// Here we will add our application pages&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;loadChildren&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./pages/home/home.module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HomeModule&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;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After saving this file, the page should render properly.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.2 Create an About page
&lt;/h3&gt;

&lt;p&gt;Run the following command to generate the &lt;code&gt;AboutModule&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng g module pages/about --route about --module app
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Open &lt;code&gt;src/app/pages/about/about.component.html&lt;/code&gt; and replace the content with this snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container py-5"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"jumbotron"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-secondary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;About&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Open &lt;code&gt;src/app/app-routing.module.ts&lt;/code&gt; and move the about route inside the &lt;code&gt;children&lt;/code&gt;, so it sits next to the route to the &lt;code&gt;HomeModule&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.3 Create a Login page
&lt;/h3&gt;

&lt;p&gt;The login page is a bit more complex because it has a form and uses the router to redirect.&lt;/p&gt;

&lt;p&gt;Run the following command to generate the &lt;code&gt;LoginModule&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng g module pages/login --route login --module app
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Open &lt;code&gt;src/app/pages/login/login.component.ts&lt;/code&gt; and add the following code next to the other imports:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;FormControl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FormGroup&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/forms&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Change the content of the &lt;code&gt;LoginComponent&lt;/code&gt; class to this snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;LoginComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// The form group defines the fields used in the form&lt;/span&gt;
  &lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;FormGroup&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;FormControl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;FormControl&lt;/span&gt;&lt;span class="p"&gt;(&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="c1"&gt;// Inject the router so we can navigate after a successful login&lt;/span&gt;
  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;router&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="p"&gt;{}&lt;/span&gt;

  &lt;span class="nx"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Use the form value to do authentication&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&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;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Navigate after successful login&lt;/span&gt;
    &lt;span class="k"&gt;return&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;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Open &lt;code&gt;src/app/pages/login/login.component.html&lt;/code&gt; and replace the content with this snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- This flex container takes the full height and vertically centers the content --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"d-flex flex-column h-100 justify-content-center"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"row"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="c"&gt;&amp;lt;!-- This is a single column that is responsive --&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"col-12 col-md-6 offset-md-3"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card-header"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Login&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card-body"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="c"&gt;&amp;lt;!-- The formGroup 'form' is defined in the component class --&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;[formGroup]=&lt;/span&gt;&lt;span class="s"&gt;"form"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-group"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Email address&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
                &lt;span class="c"&gt;&amp;lt;!-- The formControlName defines the name of the field in the formGroup --&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;formControlName=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-control"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-group"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Password&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt; &lt;span class="na"&gt;formControlName=&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-control"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card-footer"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"d-flex justify-content-between"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;routerLink=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"ml-2 btn btn-outline-secondary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                Home
              &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
              &lt;span class="c"&gt;&amp;lt;!-- The button has a click handler, it will be disabled if the form is not valid --&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;(click)=&lt;/span&gt;&lt;span class="s"&gt;"submit()"&lt;/span&gt; &lt;span class="na"&gt;[disabled]=&lt;/span&gt;&lt;span class="s"&gt;"!form.valid"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn btn-outline-success"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                Log in
              &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;💡 The template of the &lt;code&gt;LoginComponent&lt;/code&gt; is quite large. When adding more authentication pages, consider creating a separate &lt;code&gt;AuthLayoutComponent&lt;/code&gt; and use that like &lt;code&gt;LayoutComponent&lt;/code&gt;, then add &lt;code&gt;LoginComponent&lt;/code&gt;, &lt;code&gt;RegisterComponent&lt;/code&gt;, etc as the children of &lt;code&gt;AuthLayoutComponent&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Go to your application in the browser and click the &lt;em&gt;Login&lt;/em&gt; link in the header.&lt;/p&gt;

&lt;p&gt;The login page renders the form in the center of the screen, and we don't need to add the route to the &lt;code&gt;children&lt;/code&gt; array.&lt;/p&gt;

&lt;p&gt;There is one last thing to fix. If you click the &lt;em&gt;Home&lt;/em&gt; link in the login page, you will be taken back to the &lt;em&gt;root&lt;/em&gt; of the application, which is blank.&lt;/p&gt;

&lt;p&gt;Wouldn't it be great if we could go to the Home page instead?&lt;/p&gt;

&lt;h3&gt;
  
  
  5.4 Redirect the root route
&lt;/h3&gt;

&lt;p&gt;Open &lt;code&gt;src/app/app-routing.module.ts&lt;/code&gt; and add the following object on the top of the &lt;code&gt;routes&lt;/code&gt; array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Routes&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="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// If this path is the 'full' match...&lt;/span&gt;
    &lt;span class="na"&gt;pathMatch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;full&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// ...redirect to this route.&lt;/span&gt;
    &lt;span class="na"&gt;redirectTo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;home&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="c1"&gt;// The other routes go here&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Where to go from here?
&lt;/h2&gt;

&lt;p&gt;As stated in the introduction, this app is a starting point and should be fairly straight-forward to enhance it to your liking.&lt;/p&gt;

&lt;h3&gt;
  
  
  Additional libraries
&lt;/h3&gt;

&lt;p&gt;Use either &lt;a href="https://ng-bootstrap.github.io/"&gt;ng-bootstrap&lt;/a&gt; or &lt;a href="https://valor-software.com/ngx-bootstrap/"&gt;ngx-bootstrap&lt;/a&gt; if you want to use Angular implementations of Bootstrap components like dropdowns, tabs, collapse, etc. Both libraries are great options, pick the one you like best.&lt;/p&gt;

&lt;p&gt;If your apps have a lot of forms, use &lt;a href="https://formly.dev"&gt;formly&lt;/a&gt; for a declarative way of defining your forms, without writing any of the form templates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Themes and colors
&lt;/h3&gt;

&lt;p&gt;To tweak Bootstrap's appearance, open &lt;code&gt;src/styles.scss&lt;/code&gt; and set the variables. Make sure to define the variables before importing Bootstrap:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="nv"&gt;$dark&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;hotpink&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$jumbotron-bg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mh"&gt;#333&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$secondary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;limegreen&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$body-bg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mh"&gt;#555&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s1"&gt;'~bootstrap/scss/bootstrap'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Another great option is &lt;a href="https://bootswatch.com/"&gt;Bootswatch&lt;/a&gt; which offers more than 20 different Bootstrap based layouts&lt;/p&gt;

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

&lt;p&gt;In this tutorial, you learned how to create a basic Angular application, and use Bootstrap to create a layout with header and footer.&lt;/p&gt;

&lt;p&gt;The app has several pages that are &lt;em&gt;lazy loaded&lt;/em&gt;. The Login page has a form with basic validation and a redirect back to the Home page.&lt;/p&gt;

&lt;p&gt;In case you have any questions, feel free to leave a comment on DEV or send me a message on &lt;a href="https://twitter.com/beeman_nl"&gt;Twitter&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Big thanks to &lt;a href="https://dev.to/jefiozie"&gt;Jeffrey&lt;/a&gt; and &lt;a href="https://twitter.com/nartc1410"&gt;Chau&lt;/a&gt; for reviewing this post!&lt;/p&gt;

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

&lt;p&gt;Cheers, beeman 🐝&lt;/p&gt;

</description>
      <category>angular</category>
      <category>bootstrap</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Automate your DEV Posts using GitHub Actions</title>
      <dc:creator>beeman 🐝</dc:creator>
      <pubDate>Sun, 05 Jul 2020 09:03:50 +0000</pubDate>
      <link>https://forem.com/beeman/automate-your-dev-posts-using-github-actions-4hp3</link>
      <guid>https://forem.com/beeman/automate-your-dev-posts-using-github-actions-4hp3</guid>
      <description>&lt;p&gt;Over the last few days I've been working on getting &lt;a href="https://beeman.dev"&gt;my website&lt;/a&gt; online. The most important part of my site is the blog, and my idea is that I cross-post&lt;sup id="fnref1"&gt;1&lt;/sup&gt; my content between my website and DEV.&lt;/p&gt;

&lt;p&gt;DEV makes this super easy as it &lt;a href="https://dev.to/settings/integrations"&gt;integrates&lt;/a&gt; with &lt;a href="https://stackbit.com/"&gt;Stackbit&lt;/a&gt;. Within a few clicks I was up and running with a fresh GitHub repo containing a Gatsby app connected to Netlify for building and hosting.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sXK-DkNl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mx7mf925iheuzj3yhk6l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sXK-DkNl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mx7mf925iheuzj3yhk6l.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The build on Netlify happens in one of two occasions: when my content on DEV updates or when the GitHub repo updates.&lt;/p&gt;

&lt;p&gt;With this setup in place I moved a lot of potential obstacles out of the way, there is very little for me to worry about. Most importantly though, I can manage a big part of my site using Git, which I love!&lt;/p&gt;


&lt;blockquote class="ltag__twitter-tweet"&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--9JNFJj8J--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/1273326122302935041/l1UbPwKu_normal.jpg" alt="beeman 🐝 profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        beeman 🐝
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        @beeman_nl
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P4t6ys1m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      I moved some of my Medium posts to &lt;a href="https://t.co/2zartuv0SH"&gt;dev.to&lt;/a&gt; and I'm blown away at how great it is.&lt;br&gt;&lt;br&gt;The markdown based blog by itself is awesome, but the integration with &lt;a href="https://twitter.com/stackbithq"&gt;@stackbithq&lt;/a&gt; is the cherry on top, it allows you to generate a static site from your blog in a few clicks 🔥
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      14:30 PM - 04 Jul 2020
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1279422434387640320" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="/assets/twitter-reply-action.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1279422434387640320" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="/assets/twitter-retweet-action.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      0
      &lt;a href="https://twitter.com/intent/like?tweet_id=1279422434387640320" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="/assets/twitter-like-action.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
      14
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


&lt;p&gt;After declaring my love to this amazingly easy to use stack on Twitter, I got a reply from &lt;a href="https://dev.to/maxime1992"&gt;Maxime&lt;/a&gt;. He told me about a tool he created to publish your blogs from GitHub to DEV, which means my I can manage my complete site using Git, even better!&lt;/p&gt;


&lt;blockquote class="ltag__twitter-tweet"&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--mM9Z65TC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/1183480313730732032/IZYhSViS_normal.jpg" alt="Maxime Robert profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Maxime Robert
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        &lt;a class="comment-mentioned-user" href="https://dev.to/maxime1992"&gt;@maxime1992&lt;/a&gt;

      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P4t6ys1m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      &lt;a href="https://twitter.com/beeman_nl"&gt;@beeman_nl&lt;/a&gt; &lt;a href="https://twitter.com/stackbithq"&gt;@stackbithq&lt;/a&gt; I guess you're all setup now but I built a small cli to publish on dev to which you can use locally or on CI. Setup once, then just git push your changes on github and it'll be kept in sync 😁&lt;br&gt;&lt;a href="https://t.co/UDaqaIYBT0"&gt;dev.to/maxime1992/man…&lt;/a&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      19:56 PM - 04 Jul 2020
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1279504406162087937" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="/assets/twitter-reply-action.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1279504406162087937" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="/assets/twitter-retweet-action.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      0
      &lt;a href="https://twitter.com/intent/like?tweet_id=1279504406162087937" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="/assets/twitter-like-action.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
      1
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


&lt;p&gt;In &lt;a href="https://dev.to/maxime1992/manage-your-dev-to-blog-posts-from-a-git-repo-and-use-continuous-deployment-to-auto-publish-update-them-143j"&gt;his post&lt;/a&gt; you can find the all the steps you need to set this up. The process is pretty straightforward and very well described. In the guide he explains how to use Travis CI to set up automatic publishing, but I'd rather use GitHub Actions.&lt;/p&gt;

&lt;p&gt;In order to get started you need to finish the 2 steps of &lt;a href="https://dev.to/maxime1992/manage-your-dev-to-blog-posts-from-a-git-repo-and-use-continuous-deployment-to-auto-publish-update-them-143j"&gt;Maxim's tutorial&lt;/a&gt; then come back here and continue below. I'll wait.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Set the DEV API Token in the repo settings.
&lt;/h2&gt;

&lt;p&gt;Navigate to the &lt;code&gt;Settings&lt;/code&gt; page of the repo and select &lt;code&gt;Secrets&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Click &lt;code&gt;New Secret&lt;/code&gt; and set the name to &lt;code&gt;DEV_TO_GIT_TOKEN&lt;/code&gt; and paste the DEV API key in the value field, then click &lt;code&gt;Add Secret&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fKBgvpMy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/fqdglbh4ys58g3qp7t8b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fKBgvpMy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/fqdglbh4ys58g3qp7t8b.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Create the GitHub Actions Workflow file.
&lt;/h2&gt;

&lt;p&gt;Create the file &lt;code&gt;.github/workflows/build.yml&lt;/code&gt; and add this content:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  3. That's it!
&lt;/h2&gt;

&lt;p&gt;After your next push, GitHub picks up the workflow and starts executing it. You can follow the process in the Actions tab.&lt;/p&gt;

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

&lt;p&gt;Maxim's tool is an amazing addition to my publishing setup, which consists of a repo for my site and another for my content. I'll probably merge them at some point but at this moment I have bigger fish to fry.&lt;/p&gt;

&lt;p&gt;I have created a small helper script that syncs content from DEV back my local repo, so I now have a full sync. This comes in handy after creating a new draft on DEV and allows you to make changes to the blog through their UI too.&lt;/p&gt;

&lt;p&gt;I'm considering to wrap the syncing up in a tool that I can just run in the background while publishing, and I'd love to have a local preview of the blog that I'm writing so stay tuned for more!&lt;/p&gt;

&lt;h2&gt;
  
  
  Thanks!
&lt;/h2&gt;

&lt;p&gt;Thanks for reading my post! In case you have any questions, feel free to leave a comment on DEV or send me a message on &lt;a href="https://twitter.com/beeman_nl"&gt;Twitter&lt;/a&gt;!&lt;/p&gt;

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

&lt;p&gt;Cheers, beeman 🐝&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Cross-posting is &lt;a href="https://support.google.com/webmasters/answer/139066?hl=en"&gt;considered bad&lt;/a&gt; for your SEO score. To address this issue, DEV &lt;a href="https://dev.to/page/faq#what-about-my-posts-google-ranking"&gt;conveniently supports&lt;/a&gt; the &lt;strong&gt;canonical_url&lt;/strong&gt; property. Another reason to ❤️ DEV! ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>devto</category>
      <category>publication</category>
      <category>stackbit</category>
      <category>github</category>
    </item>
    <item>
      <title>Using yarn with Angular CLI</title>
      <dc:creator>beeman 🐝</dc:creator>
      <pubDate>Fri, 03 Jul 2020 05:03:28 +0000</pubDate>
      <link>https://forem.com/beeman/using-yarn-with-angular-cli-1n73</link>
      <guid>https://forem.com/beeman/using-yarn-with-angular-cli-1n73</guid>
      <description>&lt;p&gt;When running &lt;code&gt;ng new&lt;/code&gt; the Angular CLI uses &lt;code&gt;npm&lt;/code&gt; as the default package manager. In this tutorial you will learn how you can set a different package manager so that your project gets created with the correct lock file.&lt;/p&gt;

&lt;p&gt;&lt;small class="crayons-article__subheader"&gt;This tutorial should work for Angular version 6 and higher&lt;/small&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure the package manager
&lt;/h3&gt;

&lt;p&gt;To enable &lt;code&gt;yarn&lt;/code&gt; for Angular CLI you have to run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng config -g cli.packageManager yarn
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Additionally, Angular CLI has support for &lt;a href="https://npm.taobao.org/"&gt;cnpm&lt;/a&gt;, a package manager that works behind the Chinese firewall. As expected, you can activate it with this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng config -g cli.packageManager cnpm
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If at any point you want to revert back to &lt;code&gt;npm&lt;/code&gt; run this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng config -g cli.packageManager npm
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Global Angular CLI config file
&lt;/h3&gt;

&lt;p&gt;Because we passed in the &lt;code&gt;-g&lt;/code&gt; flag in our &lt;code&gt;ng config&lt;/code&gt; command, the changes are stored in the global Angular CLI configuration. If for whatever reason you like to change the package manager for the current project only, you can simply leave out the &lt;code&gt;-g&lt;/code&gt; flag.&lt;/p&gt;

&lt;p&gt;The global configuration file is stored in &lt;code&gt;&amp;lt;YOUR_HOMEDIR&amp;gt;/.angular-config.json&lt;/code&gt; and in the snippet below you can see how the settings are stored.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cat ~/.angular-config.json
{
  "version": 1,
  "cli": {
    "packageManager": "yarn"
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Thanks!
&lt;/h3&gt;

&lt;p&gt;Thanks for reading my article, I hope it was useful. Feel free to reach out and follow me on &lt;a href="https://twitter.com/beeman_nl/"&gt;Twitter&lt;/a&gt; or leave a comment on DEV! 🐝&lt;/p&gt;

</description>
      <category>angular</category>
      <category>yarn</category>
      <category>tutorial</category>
      <category>cli</category>
    </item>
  </channel>
</rss>
