<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jakob von der Haar</title>
    <description>The latest articles on DEV Community by Jakob von der Haar (@jakob_vdh).</description>
    <link>https://dev.to/jakob_vdh</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%2F173663%2F512b5846-e341-4e9c-97fa-f319e15c88b7.jpeg</url>
      <title>DEV Community: Jakob von der Haar</title>
      <link>https://dev.to/jakob_vdh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jakob_vdh"/>
    <language>en</language>
    <item>
      <title>[Fix][Azure DevOps] React with babel - No "exports" main resolved in @babel/helper-compilation-targets/package.json</title>
      <dc:creator>Jakob von der Haar</dc:creator>
      <pubDate>Sat, 06 Jun 2020 15:16:42 +0000</pubDate>
      <link>https://dev.to/jakob_vdh/fix-azure-devops-react-with-babel-no-exports-main-resolved-in-babel-helper-compilation-targets-package-json-55m7</link>
      <guid>https://dev.to/jakob_vdh/fix-azure-devops-react-with-babel-no-exports-main-resolved-in-babel-helper-compilation-targets-package-json-55m7</guid>
      <description>&lt;h2&gt;
  
  
  Situation
&lt;/h2&gt;

&lt;p&gt;Having a react app setup with create-react-app, using babel v7.8.3 and having a CI/CD pipeline in Azure DevOps, I noticed builds failing whilst trying to run &lt;code&gt;npm install&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What happened?
&lt;/h2&gt;

&lt;p&gt;The standard node version in Azure DevOps was increased from v12.16.3 to v12.17.0 which resulted in the error.&lt;/p&gt;

&lt;p&gt;Trying to locate the actual problem I stumbled upon the following issue in the babel repository:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/babel/babel/issues/11216" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        No "exports" main resolved in @babel/helper-compilation-targets/package.json
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#11216&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/Drogglbecher" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars1.githubusercontent.com%2Fu%2F20406591%3Fv%3D4" alt="Drogglbecher avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/Drogglbecher" rel="noopener noreferrer"&gt;Drogglbecher&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/babel/babel/issues/11216" rel="noopener noreferrer"&gt;&lt;time&gt;Mar 05, 2020&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Bug Report&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Current Behavior&lt;/strong&gt;
Since an update to node 13.10.1 I have a problem while building an application with &lt;code&gt;babel-loader&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: No "exports" main resolved in node_modules/@babel/helper-compilation-targets/package.json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Expected behavior/code&lt;/strong&gt;
It should build correctly&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Babel Configuration (babel.config.js, .babelrc, package.json#babel, cli command, .eslintrc)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Filename: &lt;code&gt;babel.config.js&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight highlight-source-js js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;baseConfig&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
  &lt;span class="pl-c1"&gt;presets&lt;/span&gt;: &lt;span class="pl-kos"&gt;[&lt;/span&gt;
    &lt;span class="pl-kos"&gt;[&lt;/span&gt;
      &lt;span class="pl-s"&gt;'&lt;a class="mentioned-user" href="https://dev.to/babel"&gt;@babel&lt;/a&gt;/preset-env'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
      &lt;span class="pl-kos"&gt;{&lt;/span&gt;
        &lt;span class="pl-c1"&gt;useBuiltIns&lt;/span&gt;: &lt;span class="pl-s"&gt;'entry'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
        &lt;span class="pl-c1"&gt;corejs&lt;/span&gt;: &lt;span class="pl-c1"&gt;3&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
      &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-kos"&gt;]&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-s"&gt;'&lt;a class="mentioned-user" href="https://dev.to/babel"&gt;@babel&lt;/a&gt;/preset-react'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-s"&gt;'&lt;a class="mentioned-user" href="https://dev.to/babel"&gt;@babel&lt;/a&gt;/preset-flow'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-s"&gt;'&lt;a class="mentioned-user" href="https://dev.to/babel"&gt;@babel&lt;/a&gt;/preset-typescript'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
  &lt;span class="pl-kos"&gt;]&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
  &lt;span class="pl-c1"&gt;plugins&lt;/span&gt;: &lt;span class="pl-kos"&gt;[&lt;/span&gt;
    &lt;span class="pl-s"&gt;'react-hot-loader/babel'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-s"&gt;'babel-plugin-styled-components'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-kos"&gt;[&lt;/span&gt;&lt;span class="pl-s"&gt;'&lt;a class="mentioned-user" href="https://dev.to/babel"&gt;@babel&lt;/a&gt;/plugin-proposal-class-properties'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-c1"&gt;loose&lt;/span&gt;: &lt;span class="pl-c1"&gt;true&lt;/span&gt; &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;]&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-s"&gt;'&lt;a class="mentioned-user" href="https://dev.to/babel"&gt;@babel&lt;/a&gt;/plugin-syntax-dynamic-import'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-s1"&gt;isTesting&lt;/span&gt; &lt;span class="pl-c1"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="pl-s"&gt;'babel-plugin-dynamic-import-node-babel-7'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
  &lt;span class="pl-kos"&gt;]&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;filter&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-v"&gt;Boolean&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
&lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

&lt;span class="pl-smi"&gt;module&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;exports&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
  &lt;span class="pl-c1"&gt;sourceType&lt;/span&gt;: &lt;span class="pl-s"&gt;'unambiguous'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
  ...&lt;span class="pl-s1"&gt;baseConfig&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
  &lt;span class="pl-c1"&gt;plugins&lt;/span&gt;: &lt;span class="pl-kos"&gt;[&lt;/span&gt;
    &lt;span class="pl-s"&gt;'idx'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-s"&gt;'&lt;a class="mentioned-user" href="https://dev.to/babel"&gt;@babel&lt;/a&gt;/plugin-syntax-import-meta'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-s"&gt;'&lt;a class="mentioned-user" href="https://dev.to/babel"&gt;@babel&lt;/a&gt;/plugin-proposal-json-strings'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-kos"&gt;[&lt;/span&gt;
      &lt;span class="pl-s"&gt;'&lt;a class="mentioned-user" href="https://dev.to/babel"&gt;@babel&lt;/a&gt;/plugin-proposal-decorators'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
      &lt;span class="pl-kos"&gt;{&lt;/span&gt;
        &lt;span class="pl-c1"&gt;legacy&lt;/span&gt;: &lt;span class="pl-c1"&gt;true&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
      &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-kos"&gt;]&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-s"&gt;'&lt;a class="mentioned-user" href="https://dev.to/babel"&gt;@babel&lt;/a&gt;/plugin-proposal-function-sent'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-s"&gt;'&lt;a class="mentioned-user" href="https://dev.to/babel"&gt;@babel&lt;/a&gt;/plugin-proposal-export-namespace-from'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-s"&gt;'&lt;a class="mentioned-user" href="https://dev.to/babel"&gt;@babel&lt;/a&gt;/plugin-proposal-numeric-separator'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-s"&gt;'&lt;a class="mentioned-user" href="https://dev.to/babel"&gt;@babel&lt;/a&gt;/plugin-proposal-optional-chaining'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-s"&gt;'&lt;a class="mentioned-user" href="https://dev.to/babel"&gt;@babel&lt;/a&gt;/plugin-proposal-throw-expressions'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-s"&gt;'babel-plugin-macros'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-kos"&gt;[&lt;/span&gt;
      &lt;span class="pl-en"&gt;require&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;resolve&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'babel-plugin-module-resolver'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
      &lt;span class="pl-kos"&gt;{&lt;/span&gt;
        &lt;span class="pl-c1"&gt;root&lt;/span&gt;: &lt;span class="pl-kos"&gt;[&lt;/span&gt;&lt;span class="pl-s"&gt;'./'&lt;/span&gt;&lt;span class="pl-kos"&gt;]&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
        &lt;span class="pl-c1"&gt;alias&lt;/span&gt;: &lt;span class="pl-kos"&gt;{&lt;/span&gt;
          &lt;span class="pl-s"&gt;'react-router-dom'&lt;/span&gt;: &lt;span class="pl-s"&gt;'./packages/components/Router'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
          &lt;span class="pl-s"&gt;'@@react-router-dom'&lt;/span&gt;: &lt;span class="pl-s"&gt;'./node_modules/react-router-dom'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
        &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
      &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-kos"&gt;]&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
  &lt;span class="pl-kos"&gt;]&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
  &lt;span class="pl-c1"&gt;env&lt;/span&gt;: &lt;span class="pl-kos"&gt;{&lt;/span&gt;
    &lt;span class="pl-c1"&gt;test&lt;/span&gt;: &lt;span class="pl-kos"&gt;{&lt;/span&gt;
      &lt;span class="pl-c1"&gt;plugins&lt;/span&gt;: &lt;span class="pl-kos"&gt;[&lt;/span&gt;
        ...&lt;span class="pl-s1"&gt;baseConfig&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;plugins&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
        &lt;span class="pl-s"&gt;'&lt;a class="mentioned-user" href="https://dev.to/babel"&gt;@babel&lt;/a&gt;/plugin-transform-modules-commonjs'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
      &lt;span class="pl-kos"&gt;]&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
  &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
&lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Environment&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  System:
    OS: macOS Mojave 10.14.6
  Binaries:
    Node: 13.10.1 - /usr/local/bin/node
    Yarn: 1.22.0 - /usr/local/bin/yarn
    npm: 6.14.2 - /usr/local/bin/npm
  Monorepos:
    Yarn Workspaces: 1.22.0
  npmPackages:
    @babel/core: ^7.8.3 =&amp;gt; 7.8.3
    @babel/plugin-proposal-class-properties: ^7.8.3 =&amp;gt; 7.8.3
    @babel/plugin-proposal-decorators: ^7.8.3 =&amp;gt; 7.8.3
    @babel/plugin-proposal-export-namespace-from: ^7.8.3 =&amp;gt; 7.8.3
    @babel/plugin-proposal-function-sent: ^7.8.3 =&amp;gt; 7.8.3
    @babel/plugin-proposal-json-strings: ^7.8.3 =&amp;gt; 7.8.3
    @babel/plugin-proposal-numeric-separator: ^7.8.3 =&amp;gt; 7.8.3
    @babel/plugin-proposal-optional-chaining: ^7.8.3 =&amp;gt; 7.8.3
    @babel/plugin-proposal-throw-expressions: ^7.8.3 =&amp;gt; 7.8.3
    @babel/plugin-syntax-dynamic-import: ^7.8.3 =&amp;gt; 7.8.3
    @babel/plugin-syntax-import-meta: ^7.8.3 =&amp;gt; 7.8.3
    @babel/preset-env: ^7.8.3 =&amp;gt; 7.8.3
    @babel/preset-flow: ^7.8.3 =&amp;gt; 7.8.3
    @babel/preset-react: ^7.8.3 =&amp;gt; 7.8.3
    @babel/preset-typescript: ^7.8.3 =&amp;gt; 7.8.3
    babel-eslint: ^10.0.3 =&amp;gt; 10.0.3
    babel-loader: ^8.0.6 =&amp;gt; 8.0.6
    babel-plugin-idx: ^2.4.0 =&amp;gt; 2.4.0
    babel-plugin-lodash: ^3.3.4 =&amp;gt; 3.3.4
    babel-plugin-macros: ^2.8.0 =&amp;gt; 2.8.0
    babel-plugin-module-resolver: ^4.0.0 =&amp;gt; 4.0.0
    babel-plugin-styled-components: ^1.10.7 =&amp;gt; 1.10.7
    eslint: ^6.8.0 =&amp;gt; 6.8.0
    jest: ^25.1.0 =&amp;gt; 25.1.0
    webpack: ^4.41.5 =&amp;gt; 4.41.5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Possible Solution&lt;/strong&gt;
&lt;a href="https://github.com/pikapkg/snowpack" rel="noopener noreferrer"&gt;snowpack&lt;/a&gt; resolved the error like &lt;a href="https://github.com/pikapkg/snowpack/commit/7de9470a515113ec495472909208c42e59241830" rel="noopener noreferrer"&gt;this&lt;/a&gt;. Maybe this could work here too.&lt;/p&gt;

&lt;p&gt;Edits by &lt;a class="mentioned-user" href="https://dev.to/jlhwung"&gt;@jlhwung&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;
This is a regression in Node.js. If you hit this issue from search engines, please choose &lt;em&gt;one&lt;/em&gt; of the following solutions&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;update &lt;code&gt;@babel&lt;/code&gt; deps to v7.8.7&lt;/li&gt;
&lt;li&gt;use Node &amp;lt; 13.9&lt;/li&gt;
&lt;li&gt;wait until nodejs/node#32107 is fixed! (Probably in the next Node.js patch release).&lt;/li&gt;
&lt;/ol&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/babel/babel/issues/11216" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Fastest Solution
&lt;/h2&gt;

&lt;p&gt;The fastest solution was to simply define the node.js version in the build pipeline.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Add Node.js tool installer
&lt;/h3&gt;

&lt;p&gt;Before running any npm comands in your pipeline add te &lt;code&gt;Node.js tool installer&lt;/code&gt; as a task.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  2. Configure Task
&lt;/h3&gt;

&lt;p&gt;In the &lt;code&gt;Node.js tool installer&lt;/code&gt; you are able to simply set the node version to for example 12.16.3.&lt;/p&gt;

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

&lt;p&gt;Using the &lt;code&gt;Node.js tool installer&lt;/code&gt; can add up to 10 seconds to your build process depending on the used agent.&lt;/p&gt;

</description>
      <category>react</category>
      <category>babel</category>
      <category>node</category>
    </item>
    <item>
      <title>React js ➡ Azure Devops ➡ Azure Storage ➡ Azure CDN (Part 1/2)</title>
      <dc:creator>Jakob von der Haar</dc:creator>
      <pubDate>Wed, 20 May 2020 20:09:09 +0000</pubDate>
      <link>https://dev.to/jakob_vdh/react-js-azure-devops-azure-storage-azure-cdn-part-1-2-k70</link>
      <guid>https://dev.to/jakob_vdh/react-js-azure-devops-azure-storage-azure-cdn-part-1-2-k70</guid>
      <description>&lt;h1&gt;
  
  
  How to use Azure DevOps to build and release your static React js Web App to an Azure Storage Account which is made public using an Azure CDN profile, part 1:
&lt;/h1&gt;

&lt;p&gt;Part 1 guides you step by step through a simple process of using Azure DevOps to build and release a static React js Web App (or any other Node.js based Web App), which is then hosted using an Azure Storage Account.&lt;/p&gt;

&lt;p&gt;&lt;del&gt;Part 2 guides you through creating an Azure CDN profile and connecting it to our storage account and release pipeline.&lt;/del&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠ &lt;strong&gt;Part 2 is not yet available and might not will be finalized, as of writing this post in January 2020, &lt;a href="https://docs.microsoft.com/en-us/azure/static-web-apps/overview" rel="noopener noreferrer"&gt;Azure Static Web Apps&lt;/a&gt; was not yet publicly announced. Azure Static Web Apps was globally announced yesterday at the BUILD 2020 (19th of May, 2020) and is basically a very similar approach to the approach explained in this post with the difference that &lt;a href="https://docs.microsoft.com/en-us/azure/static-web-apps/overview" rel="noopener noreferrer"&gt;Azure Static Web Apps&lt;/a&gt; might be more comfortable to use, as it has all components of the explained approach in a single service. At the writing of this (20th of May, 2o20) &lt;a href="https://docs.microsoft.com/en-us/azure/static-web-apps/overview" rel="noopener noreferrer"&gt;Azure Static Web Apps&lt;/a&gt; is in preview and able to use, give it a try. I will not remove this blog post yet, so this alternative approach is explained for the moment. Please keep this in mind when reading this post, thank you!&lt;/strong&gt; ⚠&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  ✅ Requirements:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Azure Account (&lt;a href="https://link.medium.com/ANGMMY2P5T" rel="noopener noreferrer"&gt;If you are a student, click here to find out how to get free Azure Ressources&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;A React Web App&lt;/li&gt;
&lt;li&gt;&lt;a href="https://azure.microsoft.com/de-de/services/devops/" rel="noopener noreferrer"&gt;An Azure DevOps Service Account&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Azure Storage Account&lt;/li&gt;
&lt;li&gt;Build Pipeline&lt;/li&gt;
&lt;li&gt;Release Pipeline&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  1. Azure Storage Account
&lt;/h2&gt;

&lt;p&gt;First we need to create an Azure Storage Account that is used to host our React Web App later on using the static website feature of the Storage Account.&lt;/p&gt;

&lt;p&gt;Login to the Azure portal and start the process of creating an new Storage Account. Choose the wanted subscription, name, location, replication level etc. Just make sure, to choose &lt;code&gt;StorageV2&lt;/code&gt; as account type.&lt;/p&gt;

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

&lt;p&gt;When the Storage Account is created, open the resource and open the &lt;code&gt;Static Website&lt;/code&gt; settings in the left sidebar.&lt;br&gt;
Enable the feature and set the 'Index document name' and 'Error document path' to your index file of your react js build. In my case it is &lt;code&gt;index.html&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;After saving the settings, Azure will give you an primary endpoint under which the website will be available in the end. Moreover, it gives you the Azure Storage container in which the website's files need be uploaded for being available at the endpoint later on.&lt;/p&gt;

&lt;p&gt;Before setting up our build and release pipeline we need to save a few keys and ids of the storage account.&lt;br&gt;
We should remember the following settings for our release process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the &lt;code&gt;STORAGE_ACCOUNT_NAME&lt;/code&gt; you set when creating the Storage Account&lt;/li&gt;
&lt;li&gt;the &lt;code&gt;STORAGE_ACCOUNT_KEY&lt;/code&gt; which can be found in the &lt;code&gt;Access Keys&lt;/code&gt; settings of the Storage Account. You can either pick key1 or key2. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can either leave the page open or save these settings. I will refer to them later on as &lt;code&gt;STORAGE_ACCOUNT_NAME&lt;/code&gt; and &lt;code&gt;STORAGE_ACCOUNT_KEY&lt;/code&gt;.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  2. Build Pipeline
&lt;/h2&gt;

&lt;p&gt;Now, let's head over to our Azure DevOps Account to create a build pipeline.&lt;/p&gt;

&lt;p&gt;Open the pipelines menu and create a new pipeline.&lt;/p&gt;

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

&lt;p&gt;To make creating the build process for the first time a bit easier choose &lt;code&gt;Use the classic editor&lt;/code&gt;. You can still get the Yaml file of our build process afterwards for future processes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FJakob-vdH%2FBlogPosts%2Fblob%2Fmaster%2FdevTo%2FreactStorageAccount%2Fmedia%2F05.classciEditor.jpg%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FJakob-vdH%2FBlogPosts%2Fblob%2Fmaster%2FdevTo%2FreactStorageAccount%2Fmedia%2F05.classciEditor.jpg%3Fraw%3Dtrue" alt="Activating the classic editor" width="685" height="572"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After that, choose the your respository for example on Github and set a default branch for manual and scheduled builds (for example &lt;code&gt;master&lt;/code&gt;, depending on your branch structure).&lt;br&gt;
Having set up the source of our build, we are able to choose a template, but we want to build our pipeline from an empty job, as seen in the screenshot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FJakob-vdH%2FBlogPosts%2Fblob%2Fmaster%2FdevTo%2FreactStorageAccount%2Fmedia%2F06-emptyJob.jpg%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FJakob-vdH%2FBlogPosts%2Fblob%2Fmaster%2FdevTo%2FreactStorageAccount%2Fmedia%2F06-emptyJob.jpg%3Fraw%3Dtrue" alt="Start with an empty job" width="1113" height="316"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Set the name of your pipeline (for example &lt;code&gt;Build react-&amp;lt;app name&amp;gt;&lt;/code&gt;) and set an agent specification. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ℹ: I like to use &lt;code&gt;vs2017-win2016&lt;/code&gt;, but you can also choose &lt;code&gt;ubuntu-18.04&lt;/code&gt; for example, which will also work with the standard setup we are doing in this guide.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then click on add task (take a look at the screenshot if you have not build a pipeline with the visual editor before).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FJakob-vdH%2FBlogPosts%2Fblob%2Fmaster%2FdevTo%2FreactStorageAccount%2Fmedia%2F07-pipenlineSettings.jpg%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FJakob-vdH%2FBlogPosts%2Fblob%2Fmaster%2FdevTo%2FreactStorageAccount%2Fmedia%2F07-pipenlineSettings.jpg%3Fraw%3Dtrue" alt="Adding a new task" width="1673" height="443"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By using the search in the task list, you can find and add the &lt;code&gt;npm&lt;/code&gt; task which allows you to run all npm commands.&lt;br&gt;
For the sample project of this guide I only need to run &lt;code&gt;npm install&lt;/code&gt; and &lt;code&gt;npm run build&lt;/code&gt;. If you have further commands that need to be run before the build you can add them here, like setting environmental variables or running additional npm commands.&lt;/p&gt;

&lt;p&gt;Add &lt;code&gt;npm install&lt;/code&gt; and &lt;code&gt;npm run build&lt;/code&gt; as npm task as shown in the screenshots below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FJakob-vdH%2FBlogPosts%2Fblob%2Fmaster%2FdevTo%2FreactStorageAccount%2Fmedia%2F08-npmInstall.jpg%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FJakob-vdH%2FBlogPosts%2Fblob%2Fmaster%2FdevTo%2FreactStorageAccount%2Fmedia%2F08-npmInstall.jpg%3Fraw%3Dtrue" alt="Npm install" width="1676" height="505"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FJakob-vdH%2FBlogPosts%2Fblob%2Fmaster%2FdevTo%2FreactStorageAccount%2Fmedia%2F09-npmRunBuild.jpg%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FJakob-vdH%2FBlogPosts%2Fblob%2Fmaster%2FdevTo%2FreactStorageAccount%2Fmedia%2F09-npmRunBuild.jpg%3Fraw%3Dtrue" alt="Npm run build" width="1689" height="541"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the npm run build command finished, the build files will be available in the Build.SourcesDirectory of the build process. In this sample the build will be available in the &lt;code&gt;build&lt;/code&gt; folder accessible via &lt;code&gt;$(Build.SourcesDirectory)/build&lt;/code&gt;. Depending of your project the build files could also lie for example under &lt;code&gt;$(Build.SourcesDirectory)/dist&lt;/code&gt;.&lt;br&gt;
This is important for our next step as we will archive the build folder and drop it as artifact, which the release then will be able to use.&lt;/p&gt;

&lt;p&gt;Firstly, add the &lt;code&gt;Archive files&lt;/code&gt; task and configure it with the reference to the build folder as &lt;code&gt;Root folder or file to archive&lt;/code&gt; - in our case &lt;code&gt;$(Build.SourcesDirectory)/build&lt;/code&gt; - and $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip&lt;code&gt;as the&lt;/code&gt;Archive file to create`. Take the screenshot below as reference.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FJakob-vdH%2FBlogPosts%2Fblob%2Fmaster%2FdevTo%2FreactStorageAccount%2Fmedia%2F10-archiveFiles.jpg%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FJakob-vdH%2FBlogPosts%2Fblob%2Fmaster%2FdevTo%2FreactStorageAccount%2Fmedia%2F10-archiveFiles.jpg%3Fraw%3Dtrue" alt="Archive Files" width="1672" height="692"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Secondly, add the &lt;code&gt;Publish build artifacts&lt;/code&gt; task, which has no settings that we need to change.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FJakob-vdH%2FBlogPosts%2Fblob%2Fmaster%2FdevTo%2FreactStorageAccount%2Fmedia%2F11-drop.jpg%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FJakob-vdH%2FBlogPosts%2Fblob%2Fmaster%2FdevTo%2FreactStorageAccount%2Fmedia%2F11-drop.jpg%3Fraw%3Dtrue" alt="Publish Artifact: drop" width="1669" height="593"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now our build pipeline is finished and we create our release. &lt;br&gt;
‼ Do not forget to save the pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Release Pipeline
&lt;/h2&gt;

&lt;p&gt;To create a release choose the &lt;code&gt;Releases&lt;/code&gt; menu in the left sidebar and create a new release pipeline (shown in the screenshot below).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FJakob-vdH%2FBlogPosts%2Fblob%2Fmaster%2FdevTo%2FreactStorageAccount%2Fmedia%2F12-releases.jpg%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FJakob-vdH%2FBlogPosts%2Fblob%2Fmaster%2FdevTo%2FreactStorageAccount%2Fmedia%2F12-releases.jpg%3Fraw%3Dtrue" alt="Create a new release pipeline" width="980" height="674"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After creating a new release pipeline start with an &lt;code&gt;Empty job&lt;/code&gt; again and add an artifact.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FJakob-vdH%2FBlogPosts%2Fblob%2Fmaster%2FdevTo%2FreactStorageAccount%2Fmedia%2F13-artifact.jpg%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FJakob-vdH%2FBlogPosts%2Fblob%2Fmaster%2FdevTo%2FreactStorageAccount%2Fmedia%2F13-artifact.jpg%3Fraw%3Dtrue" alt="Add an artifact" width="1862" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Choose the build pipeline we just created as source for the release's artifact.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FJakob-vdH%2FBlogPosts%2Fblob%2Fmaster%2FdevTo%2FreactStorageAccount%2Fmedia%2F14-artifactMenu.jpg%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FJakob-vdH%2FBlogPosts%2Fblob%2Fmaster%2FdevTo%2FreactStorageAccount%2Fmedia%2F14-artifactMenu.jpg%3Fraw%3Dtrue" alt="Choose build pipeline" width="670" height="712"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add a trigger to the release by enabling the &lt;code&gt;Continuous deployment trigger&lt;/code&gt; and open the taks of the first and currently only stage of our release pipeline, as shown in the screenshot below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FJakob-vdH%2FBlogPosts%2Fblob%2Fmaster%2FdevTo%2FreactStorageAccount%2Fmedia%2F15-trigger.jpg%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FJakob-vdH%2FBlogPosts%2Fblob%2Fmaster%2FdevTo%2FreactStorageAccount%2Fmedia%2F15-trigger.jpg%3Fraw%3Dtrue" alt="Add a trigger" width="1861" height="499"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add a &lt;code&gt;Extract files&lt;/code&gt; tasks and set the &lt;code&gt;Archive file patterns&lt;/code&gt; to &lt;code&gt;**/$(Build.BuildId).zip&lt;/code&gt; and the &lt;code&gt;Destination folder&lt;/code&gt; to &lt;code&gt;$(System.DefaultWorkingDirectory)/build&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FJakob-vdH%2FBlogPosts%2Fblob%2Fmaster%2FdevTo%2FreactStorageAccount%2Fmedia%2F16-extractFile.jpg%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FJakob-vdH%2FBlogPosts%2Fblob%2Fmaster%2FdevTo%2FreactStorageAccount%2Fmedia%2F16-extractFile.jpg%3Fraw%3Dtrue" alt="Extract files" width="1667" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we will deal with updating the files in our Azure Storage Account. Before uplaoding the files we first have to remove all files that are currently in the $web container of the Storage Account.&lt;/p&gt;

&lt;p&gt;We can do that via the Azure CLI. Add the &lt;code&gt;Azure CLI&lt;/code&gt; task and set the following properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Azure subscription&lt;/strong&gt;: Choose the Azure subscription of your storage account. (ℹ You might have to authorize a connector.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Script Location&lt;/strong&gt;: 'Inline Script'&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inline Script&lt;/strong&gt;: &lt;code&gt;az storage blob delete-batch --account-name &amp;lt;STORAGE_ACCOUNT_NAME&amp;gt; --account-key  &amp;lt;STORAGE_ACCOUNT_KEY&amp;gt;  --source $web&lt;/code&gt; - remember the storage account information from step 1? You need to set these here.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FJakob-vdH%2FBlogPosts%2Fblob%2Fmaster%2FdevTo%2FreactStorageAccount%2Fmedia%2F17-removeFilesStorage.jpg%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FJakob-vdH%2FBlogPosts%2Fblob%2Fmaster%2FdevTo%2FreactStorageAccount%2Fmedia%2F17-removeFilesStorage.jpg%3Fraw%3Dtrue" alt="Delete current files" width="1662" height="818"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For uploading our build files we will use another &lt;code&gt;Azure CLI&lt;/code&gt; task with the following properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Azure subscription&lt;/strong&gt;: Choose the Azure subscription of your storage account. (ℹ You might have to authorize a connector.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Script Location&lt;/strong&gt;: 'Inline Script'&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inline Script&lt;/strong&gt;: &lt;code&gt;az storage blob upload-batch --account-name &amp;lt;STORAGE_ACCOUNT_NAME&amp;gt; --account-key  &amp;lt;STORAGE_ACCOUNT_KEY&amp;gt; --destination $web --source $(System.DefaultWorkingDirectory)\build\build&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FJakob-vdH%2FBlogPosts%2Fblob%2Fmaster%2FdevTo%2FreactStorageAccount%2Fmedia%2F18-uploadingFilesStorage.jpg%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FJakob-vdH%2FBlogPosts%2Fblob%2Fmaster%2FdevTo%2FreactStorageAccount%2Fmedia%2F18-uploadingFilesStorage.jpg%3Fraw%3Dtrue" alt="Upload new build" width="1686" height="701"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you can access your React app via the primary endpoint. The next step would be to connect the static website with a content delivery network, which additionally gives us the option to connect a custom domain and a SSL certificate for the custom domain.  &lt;/p&gt;

</description>
      <category>azure</category>
      <category>react</category>
      <category>devops</category>
    </item>
    <item>
      <title>React js ➡ Azure DevOps ➡ Azure App Service</title>
      <dc:creator>Jakob von der Haar</dc:creator>
      <pubDate>Fri, 31 May 2019 07:18:05 +0000</pubDate>
      <link>https://dev.to/jakob_vdh/react-js-azure-devops-azure-app-service-56oo</link>
      <guid>https://dev.to/jakob_vdh/react-js-azure-devops-azure-app-service-56oo</guid>
      <description>&lt;h1&gt;
  
  
  How to use Azure DevOps to build and deploy your React js Web App to Azure
&lt;/h1&gt;

&lt;p&gt;This Post guides you step by step through a simple process of using Azure DevOps to deploy a React js Web App (or any other Node.js based Web App) to an Azure Web App Service.&lt;/p&gt;

&lt;h2&gt;
  
  
  ✅ Requirements:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Azure Account (&lt;a href="https://link.medium.com/ANGMMY2P5T" rel="noopener noreferrer"&gt;If you are a student, click here to find out how to get free Azure Ressources&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;A running Azure Web App Service&lt;/li&gt;
&lt;li&gt;A React Web App&lt;/li&gt;
&lt;li&gt;&lt;a href="https://azure.microsoft.com/de-de/services/devops/" rel="noopener noreferrer"&gt;An Azure DevOps Service Account&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Build and Deployment
&lt;/h2&gt;

&lt;p&gt;In the Azure DevOps portal go to the &lt;code&gt;Builds&lt;/code&gt; tab of the &lt;code&gt;Pipelines&lt;/code&gt; page. There you will have an overview of your previous builds and will later on also find the build status of your React Web App builds.&lt;/p&gt;

&lt;p&gt;Create a new build pipeline and choose the location/service of your web app's repository. You will have to authorize the repository access if you are not using Azure Repository and do not have authorized your access before. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkbtzeq84zzjkusnsx9v8.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkbtzeq84zzjkusnsx9v8.jpg" alt="Screenshot of the possible repository services" width="800" height="535"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then select the repository of your web app from the list (in the screenshot I am using Azure repositories, so the look of this menu might vary depending on your repository).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzkwv5pwiwifqja8st8pl.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzkwv5pwiwifqja8st8pl.jpg" alt="Screenshot of the menu to choose your single repository" width="800" height="501"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After choosing the repository Azure DevOps is trying to automatically create a Yaml file. In our case, it first defines which kind of VM-Pool we will be using to build our web app. Then it defines the steps of our build starting with installing Node.js and going on with installing the dependencies of our web app (&lt;code&gt;npm install&lt;/code&gt;) and then running the build command of our web app (&lt;code&gt;npm run build&lt;/code&gt;).&lt;br&gt;
In end, the standard output is set to archiving the working directory or in other words our build.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqp1yzw3exld6cjc3jeaq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqp1yzw3exld6cjc3jeaq.jpg" alt="Screenshot of the automatically generated azure-pipelines Yaml file" width="800" height="561"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our goal is to also directly trigger a deployment to our Azure Web App Service, so we need to change the last task to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- task: AzureRmWebAppDeployment@3
  displayName: 'Azure App Service Deploy: &amp;lt;YourWebAppNameHere&amp;gt;'
  inputs:
    azureSubscription: &amp;lt;YourAzureSubscriptionId&amp;gt;
    WebAppName: &amp;lt;YourWebAppNameHere&amp;gt;
    Package: '$(System.DefaultWorkingDirectory)/build'

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

&lt;/div&gt;



&lt;p&gt;You still need to put in your Azure Subscription Id and the name of your web app, so Azure DevOps knows where you want to deploy the build. Moreover, we define in the last line where our build is located, to make sure only our final build is deployed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3xm5wmwls4tf1428uqax.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3xm5wmwls4tf1428uqax.jpg" alt="Screenshot of the edited azure-pipelines Yaml to deploy to Azure file" width="800" height="531"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Yaml file you just created will be added to the repository as &lt;code&gt;azure-pipelines.yml&lt;/code&gt;. So if you need to configure additional steps like tests you just have to edit the Yaml file in your repository. Furthermore, if you are editing the file online in Azure DevOps it will show you a list of tasks to add in which you also are able to configure each task using a UI.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjo2m3ldeyvssr4m66eft.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjo2m3ldeyvssr4m66eft.jpg" alt="Screenshot of the task list provided by Azure DevOps" width="352" height="842"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ej3ivpt7n8wwsc8yxbf.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ej3ivpt7n8wwsc8yxbf.jpg" alt="Screenshot of deploy to Azure task configuration using a GUI" width="338" height="772"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Of course, you could (and for bigger projects should) explicitly divide the build and deployment. &lt;br&gt;
Now every time you merge new commits into your production branch, a new build will be triggered.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fltqgd4qy71t1hguzqbxn.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fltqgd4qy71t1hguzqbxn.jpg" alt="Screenshot of an automatically triggered build" width="800" height="111"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And that is everything you need to do to have a basic build and deployment process running, have fun! 🐱‍💻&lt;/p&gt;

</description>
      <category>azure</category>
      <category>devops</category>
      <category>react</category>
    </item>
    <item>
      <title>How to: Let's Encrypt Certificates for Azure Web App Service</title>
      <dc:creator>Jakob von der Haar</dc:creator>
      <pubDate>Thu, 30 May 2019 19:01:36 +0000</pubDate>
      <link>https://dev.to/jakob_vdh/how-to-let-s-encrypt-certificates-for-azure-web-app-service-524a</link>
      <guid>https://dev.to/jakob_vdh/how-to-let-s-encrypt-certificates-for-azure-web-app-service-524a</guid>
      <description>&lt;h1&gt;
  
  
  How to secure your Azure Website with SSL for free in minutes 🔒
&lt;/h1&gt;

&lt;p&gt;In this post, I will guide you step by step through the process of including free &lt;a href="https://letsencrypt.org/" rel="noopener noreferrer"&gt;Let's Encrypt Certificates&lt;/a&gt; for any Web App hosted by the &lt;a href="https://azure.microsoft.com/en-us/services/app-service/web/" rel="noopener noreferrer"&gt;Web App Service on Azure&lt;/a&gt;.&lt;br&gt;
The catch with Let's Encrypt SSL Certificates is that they only last for 90 days. But hey, nothing automation couldn't solve.&lt;/p&gt;

&lt;p&gt;This tutorial will be based on the Azure Web App Site Extension "Azure Let's Encrypt" by Simon J.K. Pedersen. &lt;br&gt;
(Small Disclaimer: The site extension is &lt;strong&gt;not&lt;/strong&gt; supported by Microsoft, I am using it for many smaller projects and it is working great so far).&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/sjkp" rel="noopener noreferrer"&gt;
        sjkp
      &lt;/a&gt; / &lt;a href="https://github.com/sjkp/letsencrypt-siteextension" rel="noopener noreferrer"&gt;
        letsencrypt-siteextension
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Azure Web App Site Extension for easy installation and configuration of Let's Encrypt issued SSL certifcates for custom domain names.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-alert markdown-alert-important"&gt;
&lt;p class="markdown-alert-title"&gt;Important&lt;/p&gt;
&lt;p&gt;You should migrate off this extension and instead use the free SSL certificates offered by Microsoft &lt;a href="https://learn.microsoft.com/en-us/azure/app-service/configure-ssl-certificate?tabs=apex#create-a-free-managed-certificate" rel="nofollow noopener noreferrer"&gt;https://learn.microsoft.com/en-us/azure/app-service/configure-ssl-certificate?tabs=apex#create-a-free-managed-certificate&lt;/a&gt;
If you feel like you still need the extension, let me know why.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Let's Encrypt Site Extension&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://dev.azure.com/letsencrypt/letsencrypt/_build/latest?definitionId=2" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/4acecf85cacde7ccbef048854e0915ea1f0d9efd18c57c45944a2d238be845d6/68747470733a2f2f6465762e617a7572652e636f6d2f6c657473656e63727970742f6c657473656e63727970742f5f617069732f6275696c642f7374617475732f4c657473456e63727970742e53697465457874656e73696f6e2e46756c6c4672616d65776f726b" alt="Build status"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This Azure Web App Site Extension enables easy installation and configuration of &lt;a href="https://letsencrypt.org/" rel="nofollow noopener noreferrer"&gt;Let's Encrypt&lt;/a&gt; issued SSL certificates for you custom domain names.&lt;/p&gt;
&lt;p&gt;The site extension requires that you have configured a DNS entry for your custom domain to point to Azure Web App.&lt;/p&gt;
&lt;p&gt;November 2019 - Microsoft finally acknowledge that maybe it is in due time that they add first level support for free SSL certificates, see this announcement about &lt;a href="https://azure.microsoft.com/en-us/updates/secure-your-custom-domains-at-no-cost-with-app-service-managed-certificates-preview/" rel="nofollow noopener noreferrer"&gt;App Service Managed Certificates&lt;/a&gt;, be aware that it is in preview and currently &lt;strong&gt;doesn't support&lt;/strong&gt; the apex/naked domain.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;How to install&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://github.com/sjkp/letsencrypt-siteextension/wiki/How-to-install" rel="noopener noreferrer"&gt;https://github.com/sjkp/letsencrypt-siteextension/wiki/How-to-install&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Known Issues&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;This site-extension is &lt;strong&gt;NOT&lt;/strong&gt; supported by Microsoft it is my own work based on &lt;a href="https://github.com/fszlin/certes" rel="noopener noreferrer"&gt;https://github.com/fszlin/certes&lt;/a&gt; - this means don't expect…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/sjkp/letsencrypt-siteextension" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  ✅ Requirements:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;An Azure Account (&lt;a href="//bit.ly/tutorial-azure-for-students"&gt;If you are a student, click here to find out how to get free Azure Ressources.&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;A Web Application hosted using the App Service Web Apps (Could be simple HTML and CSS or something like React)&lt;/li&gt;
&lt;li&gt;Your own custom DNS entry configured to point to your Web App. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;⚠ Ideally, your App Service Plan and your App Service are in the same resource group.&lt;/p&gt;

&lt;h2&gt;
  
  
  Azure Storage Account
&lt;/h2&gt;

&lt;p&gt;First of all, we are going to create an Azure Storage Account so the extension is able to renew the Let's Encrypt Certificates every 3 months by using Azure WebJobs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frqlrk9w7khol84yl0pc5.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frqlrk9w7khol84yl0pc5.PNG" alt="Screenshot of an Azure Storage Account" width="705" height="282"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;"The storage account must be of kind &lt;code&gt;Storage&lt;/code&gt; or &lt;code&gt;StorageV2&lt;/code&gt;, &lt;code&gt;BlobStorage&lt;/code&gt; will not work."&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnah9fuox8342sgmttxmo.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnah9fuox8342sgmttxmo.jpg" alt="Screenshot of the configuration of the application settings" width="800" height="526"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we will need to add 2 application settings called &lt;code&gt;AzureWebJobsDashboard&lt;/code&gt; and &lt;code&gt;AzureWebJobsStorage&lt;/code&gt; with the connection string of our previously created Storage Account. The connection string should look for example like this: &lt;code&gt;DefaultEndpointsProtocol=https;AccountName=[myaccount];AccountKey=[mykey];&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Azure Service Principle
&lt;/h2&gt;

&lt;p&gt;For the extension to work unattended and without our manual interference we need to create an Azure Service Principle, which works basically as an "on behalf of" delegate Azure AD entry.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go into the Azure Active Directory (AAD) directory you want to use to create your new application.&lt;/li&gt;
&lt;li&gt;In the panel of the directory select &lt;code&gt;App Registrations&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a new application and set it up like shown in the picture.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjyj9422k3ibblkm9i14x.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjyj9422k3ibblkm9i14x.jpg" alt="Screenshot of the creation of a Service Principle" width="800" height="494"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a new client secret for the application. Make sure you save the generated secret, as you will &lt;strong&gt;not&lt;/strong&gt; be able to access it in clear text again!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzv7zw2dvtfe7r14ic787.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzv7zw2dvtfe7r14ic787.jpg" alt="Screenshot of the creation of the Service Principle client secret" width="800" height="388"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Go back to the Overview tab and also save the Application (Client) ID. To continue you should now have the &lt;strong&gt;client secret&lt;/strong&gt; and the &lt;strong&gt;Application ID&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now the Service Principle needs "Contribute" Access &lt;strong&gt;for the Resource Group&lt;/strong&gt; of your App Service and App Service Plan. &lt;br&gt;
This is done by accessing the &lt;code&gt;Access control (IAM)&lt;/code&gt; menu of the resource group and then clicking the 'Add' button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyesr4sf023zfxalmtwgj.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyesr4sf023zfxalmtwgj.jpg" alt="Screenshot of adding access rights for the Service Principle in the access control (IAM) menu" width="640" height="273"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the upcoming menu, choose the &lt;code&gt;Contributor&lt;/code&gt; role and add it to the created service principle.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxixje9y4jv3xq0joedqi.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxixje9y4jv3xq0joedqi.jpg" alt="Screenshot of adding the 'Contributor' role to the Service Principle in the access control (IAM) menu" width="421" height="426"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;⚠ If you have further services in the resource group, you are also able to add the &lt;code&gt;Contributor&lt;/code&gt; role only to the App Service and Service Plan.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing the Lets Encrypt Site Extension
&lt;/h2&gt;

&lt;p&gt;Now that we set up all the necessities for the extension to work, we are able to install and configure it.&lt;/p&gt;

&lt;p&gt;Head over to your App Service and search in the App Service menu for the extensions site. On the site add the extension &lt;code&gt;Azure Let's Encrypt&lt;/code&gt; by SJKP.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmvwbhftba9icqbpseyrs.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmvwbhftba9icqbpseyrs.jpg" alt="Screenshot of the App Service extensions menu" width="800" height="266"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring the Lets Encrypt Site Extension
&lt;/h2&gt;

&lt;p&gt;To configure the extension we need to head over to the &lt;code&gt;Advanced Tools&lt;/code&gt; page of our App Service. You find it by searching for &lt;code&gt;Advanced Tools&lt;/code&gt; in the menu's search bar and it will take you to a site like &lt;code&gt;https://&amp;lt;yourDomain&amp;gt;.scm.azurewebsites.net&lt;/code&gt;. &lt;br&gt;
To get to the extension settings you just have to click at the &lt;code&gt;Site extensions&lt;/code&gt; button in the menu at the top and click on the 'Launch' button of the extension. It will take you to the configuration page of the extension, shown in the picture below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fns80ikr4a62r6wj3sfwc.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fns80ikr4a62r6wj3sfwc.jpg" alt="Screenshot of the extension configuration settings" width="592" height="592"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tenant&lt;/strong&gt;: is the Azure AD directory (tenant) that the service principal was created in - &lt;code&gt;&amp;lt;yourTenantDomain&amp;gt;.onmicrosoft.com&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SubscriptionId&lt;/strong&gt;: is the Id of the subscription you used for the resource group (the Id is also displayed on the 'Overview' page of your Resource Group). Also, you can get the Ids you are able to access from (&lt;a href="https://portal.azure.com/#blade/Microsoft_Azure_Billing/SubscriptionsBlade)%5Bhttps://portal.azure.com/#blade/Microsoft_Azure_Billing/SubscriptionsBlade%5D" rel="noopener noreferrer"&gt;https://portal.azure.com/#blade/Microsoft_Azure_Billing/SubscriptionsBlade)[https://portal.azure.com/#blade/Microsoft_Azure_Billing/SubscriptionsBlade]&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ClienId and ClientSecret&lt;/strong&gt;: are the Id and secret you hopefully still got from the &lt;strong&gt;Service Principle&lt;/strong&gt; we created.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ResourceGroupName&lt;/strong&gt;: is the name of the Resource Group of your App Service.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ServicePlanResourceGroupName&lt;/strong&gt;: if the Service Plan and the App Service are in the same Resource Group, this name is identical to the &lt;code&gt;ResourceGroupName&lt;/code&gt;. Otherwise, you have to enter the name of the Resource Group that the Service Plan is located in (if so, remember to grant the Service Principle access to this Resource Group as well). &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Update Application Settings&lt;/strong&gt;: should be set to true at the first run to save all the settings as web application settings. This is required so the settings are available when the WebJob renews the certificates.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After you have done so, you will see an overview of your custom domains, SSL Bindings, and Certificates. Since you still need to generate them, you should continue to the next page. There you are able to choose your domains (you can select several by holding the Ctrl key) you want to request an SSL certificate for.&lt;br&gt;
Before doing so, you need to provide an email address, which will receive warnings by Let's Encrypt, for example in case a certificate was not renewed.&lt;/p&gt;

&lt;p&gt;And that is everything you need to do, have fun! 🐱‍💻&lt;/p&gt;

&lt;h2&gt;
  
  
  ⚠ Troubleshooting ⚠
&lt;/h2&gt;

&lt;p&gt;Because Let's Encrypt needs to reach your page, to authorize your domain, make sure this URL is accessible to the public: &lt;code&gt;http://&amp;lt;yourDomain&amp;gt;.com/.well-known/acme-challenge/&lt;/code&gt;. In most cases of an error, this URL cannot be reached, for example, because of a rule-set in a web.config or because https is enforced in the App Service Settings.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fklo7yxpbkvdzse8d1zn6.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fklo7yxpbkvdzse8d1zn6.jpg" alt="Screenshot of an error example, where Lets Encrypt was not able to reach the needed URL" width="800" height="63"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>azure</category>
    </item>
  </channel>
</rss>
