<?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: Corentin Le Berre</title>
    <description>The latest articles on DEV Community by Corentin Le Berre (@corentinleberre).</description>
    <link>https://dev.to/corentinleberre</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%2F787899%2F2ed596a8-c8ce-4427-af1e-a1c3c41cfdb9.jpeg</url>
      <title>DEV Community: Corentin Le Berre</title>
      <link>https://dev.to/corentinleberre</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/corentinleberre"/>
    <language>en</language>
    <item>
      <title>Plasmo - a new way to create modern browser extensions</title>
      <dc:creator>Corentin Le Berre</dc:creator>
      <pubDate>Thu, 07 Sep 2023 20:21:43 +0000</pubDate>
      <link>https://dev.to/corentinleberre/plasmo-a-new-way-to-create-modern-browser-extensions-19m3</link>
      <guid>https://dev.to/corentinleberre/plasmo-a-new-way-to-create-modern-browser-extensions-19m3</guid>
      <description>&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%2Fuploads%2Farticles%2Fzlicplku1illg6eha3ch.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%2Fuploads%2Farticles%2Fzlicplku1illg6eha3ch.png" alt="article banner"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Context
&lt;/h2&gt;

&lt;p&gt;I have had the opportunity to develop a new AI-based solution recently to enhance sellers' performance when using online conferencing platforms such as Zoom. After technical analysis, we concluded that the most effective approach is to create a browser extension for Chrome. &lt;/p&gt;

&lt;p&gt;Okay, but how do I create a Chrome extension? Can I use React or other tools I'm accustomed to? It is entirely possible, but setting one up can be time consuming and diverge from the standard configuration. While researching how to integrate React easily into my project, I encountered Plasmo. This framework promises to &lt;strong&gt;supercharge&lt;/strong&gt; your extension with a set of features that I'll detail in this article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Plasmo is an open-source tool with great documentation. It has a strong opinion on project architecture and configuration (no, you don't need to touch the usual manifest file). I don't think it is for everyone, but I found it pleasant to work with, especially if your codebase is growing rapidly. The team also offers SaaS for easier extension testing and deployment but is not included in today's topic.&lt;/p&gt;

&lt;p&gt;Currently in version 0.82, Plasmo supports React, Svelte, and Vue &lt;strong&gt;out of the box&lt;/strong&gt; providing live reloading and Hot Module Replacement for the ease of use. The tool makes it easy to compile the code, therefore enabling the compatibility with Chrome, Firefox and Safari, ensuring interoperability and consistency across platforms. &lt;/p&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%2Fuploads%2Farticles%2Fvrvbid2uehvutod94ctc.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%2Fuploads%2Farticles%2Fvrvbid2uehvutod94ctc.png" alt="Plasmo production build"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this article, I'll show you how to quickly create your first Plasmo project with React and Typescript. &lt;em&gt;The code will be provided on this &lt;a href="https://github.com/corentinleberre/hiver" rel="noopener noreferrer"&gt;repo&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create your first extension
&lt;/h2&gt;

&lt;p&gt;Today, we're going to work together on creating a straightforward and enjoyable Plasmo extension – something fun like replacing the 𝕏 logo with the old blue and black Twitter logo, or even using a logo of your choice. The goal is to familiarize ourselves with the sharing mechanics of storage and understand how Plasmo allows us to interact with content scripts and popups easily.&lt;/p&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%2Fuploads%2Farticles%2Fg54pwvpdf493n2uqqqib.gif" 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%2Fuploads%2Farticles%2Fg54pwvpdf493n2uqqqib.gif" alt="Gif illustrating the final plasmo project"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our focus will be on the &lt;strong&gt;Popup&lt;/strong&gt; and &lt;strong&gt;Content Script&lt;/strong&gt; aspects. We will explore these specific components in detail (you can also interact with the Background service worker, Tabs and Options easily). Our primary attention will be paid to understanding how modifications of the popup interface should be made in &lt;strong&gt;popup.tsx&lt;/strong&gt;, and how content script enhancements belong in &lt;strong&gt;content.tsx&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;👉 Create the project&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm create plasmo plasmo-intro
&lt;span class="nb"&gt;cd &lt;/span&gt;plasmo-intro
npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will then have the following file structure :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;📦 plasmo-intro  
┣ 📂 assets  
┣ 📂 build
┣ 📜 package.json  
┣ 📜 popup.tsx
┣ 📜 README.md  
┗ 📜 tsconfig.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can &lt;a href="https://docs.plasmo.com/framework#loading-the-extension-in-chrome" rel="noopener noreferrer"&gt;load the extension in your favorite browser&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;👉 Customise the Popup&lt;/p&gt;

&lt;p&gt;The popup is what shows up when you click on the extension in your browser. All the code needed can be found in &lt;strong&gt;popup.tsx&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This code defines an UI component that displays a set of radio buttons, each representing a different Twitter logo.&lt;/p&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%2Fuploads%2Farticles%2Fpuq9xxm4ci52cu3k7l63.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%2Fuploads%2Farticles%2Fpuq9xxm4ci52cu3k7l63.png" alt="popup without styling and useStorage"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;👉 Add the logic and styling&lt;/p&gt;

&lt;p&gt;Plasmo provides utilities to ease communication between your popup, content script and the rest of your extension. We're going to add Plasmo Storage to our project to preserve a state in the browser. It will be used to pass the icon we want to display on &lt;em&gt;x.com&lt;/em&gt; between the popup and the content script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @plasmohq/storage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;more docs about Plasmo storage &lt;a href="https://docs.plasmo.com/framework/storage" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;package.json&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;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"plasmo-intro"&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;"manifest"&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;"host_permissions"&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;"https://twitter.com/*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"https://x.com/*"&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;"permissions"&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;"storage"&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;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;Browsers and Mobile apps need to explicitly declare features that you want to use for security reasons. That's why you will need to specify it in the permissions section of the manifest in the &lt;strong&gt;package.json&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Now we can use the &lt;strong&gt;useStorage&lt;/strong&gt; hook to manipulate a preserved state in our react components.&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;useStorage&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;@plasmohq/storage/hook&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;logo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLogo&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useStorage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;logo&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;original&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;To make our application more user-friendly, we can add our different &lt;a href="https://github.com/corentinleberre/hiver/tree/main/assets/svg" rel="noopener noreferrer"&gt;SVG&lt;/a&gt; and custom &lt;a href="https://github.com/corentinleberre/hiver/blob/main/popup.css" rel="noopener noreferrer"&gt;styles&lt;/a&gt; in &lt;code&gt;popup.tsx&lt;/code&gt;.&lt;/p&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%2Fuploads%2Farticles%2Futf66n5v9h0663oa288g.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%2Fuploads%2Farticles%2Futf66n5v9h0663oa288g.png" alt="Popup.tsx file with styles and useStorage hook"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Users can now select a logo, and the chosen option will be stored and managed using the &lt;code&gt;useStorage&lt;/code&gt; hook from the &lt;code&gt;@plasmohq/storage&lt;/code&gt; library. &lt;/p&gt;

&lt;p&gt;To make this code type safe you should define a type LogoType in &lt;code&gt;types.ts&lt;/code&gt; containing all of your different logo.&lt;/p&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%2Fuploads%2Farticles%2Ft6kgd8808b4a1y5pgcki.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%2Fuploads%2Farticles%2Ft6kgd8808b4a1y5pgcki.png" alt="Logo types file"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally your popup should look like this👇&lt;/p&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%2Fuploads%2Farticles%2Fy1bx7cnazy6s8owsrga0.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%2Fuploads%2Farticles%2Fy1bx7cnazy6s8owsrga0.png" alt="Final popup result"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we've managed the popup, we'll move on to the more important task which is to modify the &lt;code&gt;x.com&lt;/code&gt; page.&lt;/p&gt;

&lt;p&gt;👉 Customise the Content Script to modify &lt;code&gt;x.com&lt;/code&gt; behaviors&lt;/p&gt;

&lt;p&gt;To modify the integrity of a web page you will need to add the &lt;strong&gt;"scripting"&lt;/strong&gt; permission to the manifest.&lt;/p&gt;

&lt;p&gt;Plasmo manages different lifecycles to help you mount and unmount components in the content script. The global process is well described in their &lt;a href="https://docs.plasmo.com/framework/content-scripts-ui/life-cycle" rel="noopener noreferrer"&gt;docs&lt;/a&gt;. &lt;/p&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%2Fuploads%2Farticles%2F7vhkm1z1eh7ck7qxj73x.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%2Fuploads%2Farticles%2F7vhkm1z1eh7ck7qxj73x.png" alt="Content.tsx"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To make it concise, you need to create or locate an anchor on the website. In our case, it will be the &lt;code&gt;x.com&lt;/code&gt; logo with the selector &lt;em&gt;[aria-label="X"]&lt;/em&gt;. You can then access the local element to modify or replace it by mounting your own component.&lt;/p&gt;

&lt;p&gt;In summary, the code below defines a custom &lt;code&gt;getRootContainer&lt;/code&gt; function that asynchronously looks for a specific HTML, with the attribute &lt;code&gt;aria-label&lt;/code&gt; set to "X". Once the element appears on the page, the interval is cleared and our new logo is replaced. &lt;/p&gt;

&lt;p&gt;The SVG logos are being dynamically rendered by the components mounted on the page, based on the value that we stored in local storage using &lt;code&gt;popup.tsx&lt;/code&gt;.&lt;/p&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%2Fuploads%2Farticles%2Ftjglpewf4yfb1buddo4d.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%2Fuploads%2Farticles%2Ftjglpewf4yfb1buddo4d.png" alt="DisplaySvg.tsx"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that everything's configured, the extension should be fully functional and will allow you to replace the &lt;code&gt;x.com&lt;/code&gt; logo dynamically according to your preferences. The final step is to build your project and make it available to the world. 🥳&lt;/p&gt;

&lt;p&gt;👉 Build the project&lt;/p&gt;

&lt;p&gt;Plasmo provides the ability to build your project for different browsers, through the &lt;code&gt;plasmo package&lt;/code&gt; command. By default, only the Chrome artifact is built.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the build, you will then have the following file structure :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;📦 plasmo-intro  
┣ 📂 build
 ┣ 📂 chrome-mv3-dev 
 ┗ 📂 chrome-mv3-prod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, you can zip the prod folders and share it as is or &lt;a href="https://developer.chrome.com/docs/webstore/publish/" rel="noopener noreferrer"&gt;publish it on the Chrome web store&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  To go further
&lt;/h2&gt;

&lt;p&gt;In this article, I chose a relatively simple example to illustrate Plasmo's key features. If you're interested in the subject, I implore you to take a closer look at their well structured documentation. They also provide a &lt;a href="https://github.com/PlasmoHQ/examples" rel="noopener noreferrer"&gt;Github repository with over 50 powerful templates&lt;/a&gt;, including Supabase, Tailwind, NextJS, Svelte, React-Router etc.&lt;/p&gt;

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

&lt;p&gt;Plasmo shows great potential for developing modern extensions without compromising the browsing experience. It allows you to create extensions for different platforms, but you need to be aware of cross-browser API limitations. Despite some unexpected behavior in dev mode, the tool offers several benefits, including rich documentation, an active community, and simplified manifest management. Additionally, it provides SaaS for testing and deployment of extensions across different online stores. This can be very valuable for development teams. &lt;/p&gt;

&lt;p&gt;Despite some challenges, Plasmo framework presents itself as a promising solution for the development of modern extensions!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>chrome</category>
      <category>plasmo</category>
    </item>
    <item>
      <title>Streamline your CI/CD Pipeline with Git-diff-script-exclusions</title>
      <dc:creator>Corentin Le Berre</dc:creator>
      <pubDate>Tue, 05 Sep 2023 20:01:54 +0000</pubDate>
      <link>https://dev.to/corentinleberre/streamline-your-cicd-pipeline-with-git-diff-script-exclusions-5ebj</link>
      <guid>https://dev.to/corentinleberre/streamline-your-cicd-pipeline-with-git-diff-script-exclusions-5ebj</guid>
      <description>&lt;p&gt;If you've ever experienced the pain of running a build pipeline or test suite only to realize that none of the modified files affected the functionality you're testing, you'll appreciate the usefulness of &lt;a href="https://github.com/corentinleberre/git-diff-script-exclusions"&gt;git-diff-script-exclusions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This command-line interface (CLI) tool allows you to compare two git commits and see if the modified files are strictly limited to the excluded paths you've configured. If so, you can &lt;strong&gt;avoid running unnecessary scripts, saving valuable time&lt;/strong&gt; in your CI pipeline.&lt;/p&gt;

&lt;p&gt;The CLI is simple to use, and it can be installed globally or used via npx. Before running the tool, you'll need to configure the exceptions in the &lt;em&gt;git-diff-script-exclusions.conf.json&lt;/em&gt; file. This file stores the paths to the files and directories that should be excluded from consideration.&lt;/p&gt;

&lt;p&gt;The format is straightforward, as shown below 👇&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&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;"exceptions"&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;"docs/*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s2"&gt;"git-diff-script-exclusions.conf.json"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s2"&gt;"src/ressource/application.yml"&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;You can specify folders or files for exceptions, and the CLI will check whether any modified files fall within these paths.&lt;/p&gt;

&lt;p&gt;To use the tool, simply execute the following command, replacing &lt;code&gt;source_commit_sha&lt;/code&gt; and &lt;code&gt;target_commit_sha&lt;/code&gt; with the relevant SHA or branch name 👇&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$:&lt;/span&gt; npx git-diff-script-exclusions &lt;span class="nt"&gt;--source&lt;/span&gt; source_commit_sha &lt;span class="nt"&gt;--target&lt;/span&gt; targe_commit_sha
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Target argument is optional, by default it will take the head of your branch.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The CLI will output the modified files in the newest commit and whether they're strictly contained within the configured exceptions. For instance, if you see &lt;code&gt;onlyExceptions: true&lt;/code&gt;, it means the modified files are within the exceptions you've specified, and you can safely skip the script.&lt;/p&gt;

&lt;p&gt;The tool can also be integrated into your CI pipeline. The examples below show how to use it in GitLab and GitHub Actions.&lt;/p&gt;

&lt;p&gt;👉 GitLab&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;

&lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node:lts&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npm install -g git-diff-script-exclusions&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo 'Checking if tests need to be executed...'&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;GIT_DIFF_SCRIPT_EXCLUSIONS=$(npx git-diff-script-exclusions --source $CI_COMMIT_SHA)&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo $GIT_DIFF_SCRIPT_EXCLUSIONS&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="s"&gt;if grep -q "onlyExceptions: true" &amp;lt;&amp;lt;&amp;lt; "$GIT_DIFF_SCRIPT_EXCLUSIONS"; then&lt;/span&gt;
        &lt;span class="s"&gt;echo 'Tests are not required';&lt;/span&gt;
      &lt;span class="s"&gt;else&lt;/span&gt;
        &lt;span class="s"&gt;echo 'Launching tests...';&lt;/span&gt;
        &lt;span class="s"&gt;npm ci&lt;/span&gt;
        &lt;span class="s"&gt;npm test&lt;/span&gt;
      &lt;span class="s"&gt;fi;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 GitHub&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run Test&lt;/span&gt;

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

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v3&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;16&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install dependencies&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm install -g git-diff-script-exclusions&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Launch tests if needed&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;echo "Checking if tests need to be executed..."&lt;/span&gt;
        &lt;span class="s"&gt;GIT_DIFF_SCRIPT_EXCLUSIONS=$(npx git-diff-script-exclusions --source $GITHUB_REF)&lt;/span&gt;
        &lt;span class="s"&gt;echo $GIT_DIFF_SCRIPT_EXCLUSIONS&lt;/span&gt;
        &lt;span class="s"&gt;if grep -q "onlyExceptions: true" &amp;lt;&amp;lt;&amp;lt; "$GIT_DIFF_SCRIPT_EXCLUSIONS"; then&lt;/span&gt;
          &lt;span class="s"&gt;echo "Tests are not required"&lt;/span&gt;
        &lt;span class="s"&gt;else&lt;/span&gt;
          &lt;span class="s"&gt;echo "Launching tests..."&lt;/span&gt;
          &lt;span class="s"&gt;npm ci&lt;/span&gt;
          &lt;span class="s"&gt;npm test&lt;/span&gt;
        &lt;span class="s"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you wish to contribute to this project, you may do so as the repository is open for contributions. If you have an idea for a new feature or bug fix, please open an issue on our GitHub page. We appreciate contributions. Thank you!&lt;/p&gt;

&lt;p&gt;Thank you for reading this article. If you need more information, feel free to check out the &lt;a href="https://github.com/corentinleberre/git-diff-script-exclusions"&gt;Git-diff-script-exclusions repo&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>cicd</category>
      <category>devops</category>
      <category>git</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Enhance your Docsify experience with your own plugin</title>
      <dc:creator>Corentin Le Berre</dc:creator>
      <pubDate>Mon, 09 Jan 2023 20:28:55 +0000</pubDate>
      <link>https://dev.to/corentinleberre/enhance-your-docsify-experience-with-your-own-plugin-33aj</link>
      <guid>https://dev.to/corentinleberre/enhance-your-docsify-experience-with-your-own-plugin-33aj</guid>
      <description>&lt;p&gt;Docsify is a popular and lightweight documentation generator that allows you to &lt;strong&gt;easily create beautiful, intuitive documentation sites&lt;/strong&gt; based on your markdown documentations. It includes features like a search function, a table of contents, and the ability to customize the look and feel of the site using templates and custom CSS. Thanks to that it's a popular choice for open-source documentation sites and other purposes.&lt;/p&gt;

&lt;p&gt;If you want to extend Docsify's features, you can use &lt;a href="https://github.com/docsifyjs/awesome-docsify#plugins"&gt;community plugins&lt;/a&gt; or &lt;strong&gt;create your own Docsify plugin&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this post I'll guide you to &lt;strong&gt;create your first Docsify plugin&lt;/strong&gt; and deploy it to NPM.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Requirements : Node 16&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To simplify the process, I've made a preconfigured workspace. To use it just clone the repository below and use it as a starting point for your own plugin 👇&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx degit corentinleberre/create-docsify-plugin my-plugin
&lt;span class="nb"&gt;cd &lt;/span&gt;my-plugin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Structure of the project
&lt;/h2&gt;

&lt;p&gt;Here is the structure of this template. The code is stored in the &lt;strong&gt;src&lt;/strong&gt; folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;📦create-docsify-plugin
┣ 📂src
┃ ┣ 📂plugin
┃ ┃ ┣ 📜main.js
┃ ┃ ┗ 📜my-plugin.js
┃ ┣ 📂test
┃ ┃ ┗ 📜my-plugin.spec.js
┃ ┣ 📜README.md
┃ ┗ 📜index.html
┣ 📜package.json
┣ 📜README.md
┗ 📜vite-config.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We use &lt;a href="https://github.com/vitejs/vite"&gt;Vite&lt;/a&gt; as a dev server. This allows you to take advantage of hot reloading in development and easily build and minify code with &lt;a href="https://rollupjs.org/"&gt;Rollup&lt;/a&gt; integration. Vitest is also provided, so you can write tests in the matching folder.&lt;/p&gt;

&lt;h2&gt;
  
  
  Write your plugin
&lt;/h2&gt;

&lt;p&gt;👉 Run the dev server&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Pass props to your plugin
&lt;/h3&gt;

&lt;p&gt;You can pass props to your plugin this way 👇&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;// src/index.html

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$docsify&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;My plugin documentation website&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

      &lt;span class="c1"&gt;// props&lt;/span&gt;
      &lt;span class="na"&gt;myPlugin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;world&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="p"&gt;...&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These props will be accessible through the docsify global object in your plugin 👇&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/plugin/main.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;docsify&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$docsify&lt;/span&gt; &lt;span class="o"&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;props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;docsify&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;myPlugin&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Interact with Docsify lifecycle hooks
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Docsify lifecycle hooks are provided threw the &lt;strong&gt;hook argument&lt;/strong&gt; passed to the plugin function. To have more detail about lifecycle hooks check out the &lt;a href="https://docsify.js.org/#/write-a-plugin?id=lifecycle-hooks"&gt;official doc&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can attach your function to &lt;strong&gt;6 differents lifecycle hooks&lt;/strong&gt; allowing your to modify the state of the app.&lt;/p&gt;

&lt;p&gt;Below is the example included in the template for this project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myPlugin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;hello&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hook&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;hook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;init&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="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="s2"&gt;`hello &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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 is a function that will be called once when the Docsify script is &lt;strong&gt;initialized&lt;/strong&gt; on the first load of the application. This function will simply display the parameter provided in the browser console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AyXxqxie--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uwi78xh8ecgp3sfv80vn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AyXxqxie--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uwi78xh8ecgp3sfv80vn.png" alt="Plugin result after init" width="880" height="560"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The example is deliberately &lt;strong&gt;very simple&lt;/strong&gt; here, but it's possible to modify the rendering of Docsify. By example you can add a button to copy and paste the current paragraph when hovering the content or add a custom footer on each page.&lt;/p&gt;

&lt;h3&gt;
  
  
  Detailed example
&lt;/h3&gt;

&lt;p&gt;Here is a detailed example coming from the &lt;a href="https://docsify.js.org/#/write-a-plugin?id=examples"&gt;official documentation&lt;/a&gt; interacting with two different Hooks &lt;strong&gt;beforeEach&lt;/strong&gt; and &lt;strong&gt;afterEach&lt;/strong&gt;. The goal is to add an edit button and a footer to each of your page.&lt;/p&gt;

&lt;p&gt;Replace &lt;strong&gt;my-plugin.js&lt;/strong&gt; with this content 👇&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;editOnGitPlugin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;repoUrl&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="nx"&gt;hook&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;vm&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;hook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;html&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;let&lt;/span&gt; &lt;span class="nx"&gt;editUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;repoUrl&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;editLinkMarkdown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[📝 Edit on Github](&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;editUrl&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="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&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;editLinkMarkdown&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;html&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;customFooterPlugin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&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="nx"&gt;link&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="nx"&gt;hook&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;hook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;afterEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;html&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;let&lt;/span&gt; &lt;span class="nx"&gt;footer&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;&amp;lt;hr/&amp;gt;&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;&amp;lt;footer&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;`&amp;lt;span&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;props&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="s2"&gt;&amp;lt;/span&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;`&amp;lt;span&amp;gt;&amp;lt;a href="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;" target="_blank"&amp;gt;✨&amp;lt;/a&amp;gt;&amp;lt;/span&amp;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;&amp;lt;/footer&amp;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="nx"&gt;join&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;footer&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;editOnGitPlugin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;customFooterPlugin&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may noticed that we pass the &lt;strong&gt;vm&lt;/strong&gt; property to the plugin, it's the current Docsify instance. It give us access to some property as the current file rendered.&lt;/p&gt;

&lt;p&gt;Replace &lt;strong&gt;main.js&lt;/strong&gt; with this content 👇&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&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;editOnGitPlugin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;customFooterPlugin&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;./my-plugin&lt;/span&gt;&lt;span class="dl"&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;docsify&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$docsify&lt;/span&gt; &lt;span class="o"&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;props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;editOnGitPlugin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;docsify&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;editOnGitPlugin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;customFooterPlugin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;docsify&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;customFooterPlugin&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

&lt;span class="nx"&gt;docsify&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;plugins&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[].&lt;/span&gt;&lt;span class="nx"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;docsify&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;plugins&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;editOnGitPlugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;editOnGitPlugin&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;customFooterPlugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;customFooterPlugin&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace the Docsify script section in &lt;strong&gt;index.html&lt;/strong&gt; with this content 👇&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$docsify&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Docsify-plugin-playground&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;repo&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;editOnGitPlugin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;repoUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://github.com/docsifyjs/docsify/blob/master/docs/&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="na"&gt;customFooterPlugin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;My awesome custom footer &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;link&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://github.com/docsifyjs/awesome-docsify&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="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now see the edit button on top of the page. On click you'll be redirect to the markdown file you want to modify on your Git repo.&lt;br&gt;
The second plugin add a footer providing some informations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--m1ub4GB1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kr4ayvtxi7ralx7t7nnm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--m1ub4GB1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kr4ayvtxi7ralx7t7nnm.png" alt="Illustration of the Docsify plugin to add edit button and footer to each page" width="880" height="626"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here are detailed examples of plugins made that I've made using this template if you need some inspiration👇&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/corentinleberre/docsify-mermaid-zoom"&gt;docsify-mermaid-zoom&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/corentinleberre/docsify-replace-pattern"&gt;docsify-replace-pattern&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Test your plugin
&lt;/h3&gt;

&lt;p&gt;You can test your plugin using &lt;a href="https://github.com/microsoft/playwright"&gt;Playwright&lt;/a&gt;. We provide a simple test file that test the plugin function in &lt;strong&gt;src/my-plugin.spec.js&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;👉 Run the tests&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deploy your plugin
&lt;/h2&gt;

&lt;p&gt;To deploy this package on &lt;strong&gt;npm&lt;/strong&gt;, you will need to have an account on npmjs.com. Once you have an account, follow these steps:&lt;/p&gt;

&lt;p&gt;👉 Build the project with &lt;strong&gt;npm run build&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You have the choice to deliver it as a CommonJS, ESModule, IIFE or UMD. By default, two artifacts CJS and ESM are generated. You can modify that in &lt;strong&gt;vite-config.js&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;📦dist
 ┣ 📜my-plugin.cjs
 ┗ 📜my-plugin.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 Run &lt;strong&gt;npm publish&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can now access your package on npm with this url 👉 &lt;a href="https://www.npmjs.com/package/my-docsify-plugin"&gt;https://www.npmjs.com/package/my-docsify-plugin&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To use this package on your website we will use Jsdelivr.com. It will act as &lt;a href="https://en.wikipedia.org/wiki/Content_delivery_network"&gt;Content Delivery Network&lt;/a&gt; proxying your npm package enabling you to use this script directly in the browser.&lt;/p&gt;

&lt;p&gt;You can get your plugin threw this url 👉&lt;a href="https://cdn.jsdelivr.net/npm/my-docsify-plugin@version/dist/my-plugin.js"&gt;https://cdn.jsdelivr.net/npm/my-docsify-plugin@version/dist/my-plugin.js&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now your users just have to add this url directly in their Docsify &lt;strong&gt;index.html&lt;/strong&gt; page to use your plugin 👇&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"//cdn.jsdelivr.net/npm/my-docsify-plugin@version/dist/my-plugin.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you specified &lt;strong&gt;"main": "dist/my-plugin.js"&lt;/strong&gt; in package.json, you could also access it directly with this url 👉 &lt;a href="https://cdn.jsdelivr.net/npm/my-docsify-plugin@version"&gt;https://cdn.jsdelivr.net/npm/my-docsify-plugin@1.0.0&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Thank you for reading this article. If you need more information, feel free to check out the Docsify's plugin documentation.&lt;/p&gt;

</description>
      <category>docsify</category>
      <category>javascript</category>
      <category>tutorial</category>
      <category>documentation</category>
    </item>
    <item>
      <title>Deploy your side project in 10 minutes with Fly.io</title>
      <dc:creator>Corentin Le Berre</dc:creator>
      <pubDate>Mon, 28 Nov 2022 21:29:13 +0000</pubDate>
      <link>https://dev.to/corentinleberre/deploy-your-side-project-in-10-minutes-with-flyio-2ca1</link>
      <guid>https://dev.to/corentinleberre/deploy-your-side-project-in-10-minutes-with-flyio-2ca1</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;In this post, I will aim on giving your the keys to &lt;strong&gt;deploy quickly&lt;/strong&gt; your API online using Fly.io platform.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;First, what is Fly.io ? Like classic cloud platform as AWS/GCP/Azure, Fly.io enables you to deploy your application/api/microservices/database on the cloud. But unlike these, it stands out for its simplicity.&lt;/p&gt;

&lt;p&gt;You can deploy a lot of different technologies such as Php/Python/Deno/Node/Go etc threw automatic templates or even use a Dockerfile. It's really easy to use thanks to the CLI and documentation provided. This enables you to deploy and scale your app worldwide and close to your users without worrying about network, DNS or security. It also provides lots of metrics about your application with an integrated Graphana on your dashboard. With the free tier, you can host 2 projects.&lt;/p&gt;

&lt;p&gt;👉 To have more details about those features just check their &lt;a href="https://fly.io" rel="noopener noreferrer"&gt;website&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this article, I will deploy a simple Node.js server written in Typescript, &lt;strong&gt;focusing only on the steps necessary for deployment&lt;/strong&gt;. For more information feel free to consult their documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Have a &lt;a href="https://nodejs.org/en/" rel="noopener noreferrer"&gt;Node&lt;/a&gt; environment installed and &lt;a href="https://www.docker.com" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; if you want to test your build locally.&lt;/p&gt;

&lt;p&gt;👉 Install &lt;a href="https://fly.io/docs/hands-on/install-flyctl/" rel="noopener noreferrer"&gt;fly cli tools&lt;/a&gt; 👇&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Flyctl is a command-line utility that lets you work with the Fly.io platform, from creating your account to deploying your applications.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$:&lt;/span&gt; brew &lt;span class="nb"&gt;install &lt;/span&gt;flyctl

🐧&lt;span class="nv"&gt;$:&lt;/span&gt; curl &lt;span class="nt"&gt;-L&lt;/span&gt; https://fly.io/install.sh | sh

🪟&lt;span class="nv"&gt;$:&lt;/span&gt; iwr https://fly.io/install.ps1 &lt;span class="nt"&gt;-useb&lt;/span&gt; | iex
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create our app
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;You can clone this project on &lt;a href="https://github.com/corentinleberre/beekeeper" rel="noopener noreferrer"&gt;Github&lt;/a&gt; or copy the code below 👇&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;📦 Structure of the project&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;📦beekeeper
 ┣ 📂src
 ┃ ┗ 📜main.ts
 ┣ 📜Dockerfile
 ┣ 📜fly.toml
 ┣ 📜package-lock.json
 ┣ 📜package.json
 ┗ 📜tsconfig.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Part 1 : Create the Node.JS API
&lt;/h3&gt;

&lt;p&gt;👉 Init a npm project&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$:&lt;/span&gt; npm init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 Add this configuration in &lt;strong&gt;package.json&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&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;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&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="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ts-node src/main.ts"&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;"rm -rf dist &amp;amp;&amp;amp; tsc --build"&lt;/span&gt;&lt;span class="p"&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/src/main.js"&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="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;👉 Install dependencies&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$:&lt;/span&gt; npm &lt;span class="nb"&gt;install &lt;/span&gt;express
&lt;span class="nv"&gt;$:&lt;/span&gt; npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-D&lt;/span&gt; typescript ts-node @types/node @types/express
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 Configure Typescript compiler in &lt;strong&gt;tsconfig.json&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-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;"compilerOptions"&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;"module"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ESNext"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"moduleResolution"&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"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"esModuleInterop"&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;"rootDir"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./src"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"outDir"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./dist/src"&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;"ts-node"&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;"esm"&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="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;👉 Create the express api in &lt;strong&gt;src/main.ts&lt;/strong&gt;. It's a simple server made for a beekeeper that allows him to know the state of his hives. It exposes a single access point via &lt;strong&gt;/api/hives&lt;/strong&gt;.&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="nx"&gt;express&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;express&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;Express&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Response&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;express&lt;/span&gt;&lt;span class="dl"&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;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&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;port&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;PORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;8080&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;bees&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&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="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&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="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;join&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getHives&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&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="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&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;hives&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;🇫🇷&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;bees&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&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="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;bees&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&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="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;bees&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;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hives&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/hives&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getHives&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`🍯 Beekeeper is running on http://localhost:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;You can now run the app with &lt;strong&gt;npm run dev&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Part 2 : Build the app with Docker
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;⚠️ Your Docker Daemon need to be working to execute these commands&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;👉 Build the image locally&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$:&lt;/span&gt; docker build &lt;span class="nt"&gt;-t&lt;/span&gt; beekeeper &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 Verify if the image has been created&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$:&lt;/span&gt; docker images | &lt;span class="nb"&gt;grep &lt;/span&gt;beekeeper
beekeeper    latest    2dc2439eaec3   1 min ago      118MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 Test the server locally&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$:&lt;/span&gt; docker run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 8080:8080 beekeeper
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should get the state of the Hives when fetching your local endpoint 👇&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%2Fvj5ad79usuidn1zluyiw.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%2Fvj5ad79usuidn1zluyiw.png" title="Result when fetching the api" alt="Result when fetching the api" width="800" height="702"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Part 3 : Deploy the app worldwide
&lt;/h3&gt;

&lt;p&gt;👉 Log-in or create your Fly.io account&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$:&lt;/span&gt; flyctl auth login
&lt;span class="nv"&gt;$:&lt;/span&gt; flyctl auth signup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 Use the cli to the app and follow the steps below 👇&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$:&lt;/span&gt; flyctl launch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Answer &lt;strong&gt;no&lt;/strong&gt; to .dockerignore&lt;/li&gt;
&lt;li&gt;Define the app name to the name of your project&lt;/li&gt;
&lt;li&gt;Deploy the app in the region of your choice. You can add more or change it later&lt;/li&gt;
&lt;li&gt;Answer &lt;strong&gt;no&lt;/strong&gt; to Postgresql and Redis database&lt;/li&gt;
&lt;li&gt;Answer &lt;strong&gt;yes&lt;/strong&gt; to deploy now&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It may take 1 or 2 minutes to create your project and build your Docker image with Fly remote builders &lt;em&gt;(optional)&lt;/em&gt;. If it succeed, you should see this in your terminal 👇&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;--&amp;gt; Building image done
==&amp;gt; Pushing image to fly
The push refers to repository [registry.fly.io/beekeeper]
deployment-01GJY6F3Y3707JXJ7PTZQKFS57: digest: sha256:722fe804f091c9fd33b789ac9c06ae68af87d1e6c6720025bdb33da0bf13fe1d size: 1991
--&amp;gt; Pushing image done
image: registry.fly.io/beekeeper:deployment-01GJY6F3Y3707JXJ7PTZQKFS57
image size: 118 MB
==&amp;gt; Creating release
--&amp;gt; release v1 created

--&amp;gt; You can detach the terminal anytime without stopping the deployment
==&amp;gt; Monitoring deployment

 1 desired, 1 placed, 0 healthy, 1 unhealthy [health checks: 1 total, 1 critical]
Failed Instances
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can detach the terminal now and check the status of your app with &lt;strong&gt;flyctl status&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Your app is now online ! Lets try to access it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to your &lt;a href="https://fly.io/dashboard" rel="noopener noreferrer"&gt;dashboard&lt;/a&gt; and click on the app you created.&lt;/li&gt;
&lt;li&gt;You should see a lot of information about your app including the bandwidth and cpu/ram used.&lt;/li&gt;
&lt;li&gt;You should find your app url in the "&lt;strong&gt;Hostname&lt;/strong&gt;" box. Click on it and add &lt;strong&gt;/api/hives&lt;/strong&gt; at the end. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tadaam, you should see lots of bees, your app is deployed 🥳 !&lt;/p&gt;

&lt;p&gt;To redeploy the app after a change in your code or conf use &lt;strong&gt;fly deploy&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;I hope you learned some new stuff in this post. I focused on a simple case and the mandatory steps to deploy our application. If you need more information, feel free to check out the bonus section or the fly.io documentation.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Configurations
&lt;/h3&gt;

&lt;p&gt;The CLI tools generate for you &lt;strong&gt;fly.toml&lt;/strong&gt; a configuration file used to describe your app on their platform. Here you can define ports, env variables, deploy and runtime options, the protocol used, etc. &lt;a href="https://fly.io/docs/reference/configuration/" rel="noopener noreferrer"&gt;More info here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Example of fly.toml generated for this project 👇&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="c"&gt;# fly.toml file generated for beekeeper&lt;/span&gt;

&lt;span class="py"&gt;app&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"beekeeper"&lt;/span&gt;
&lt;span class="py"&gt;kill_signal&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"SIGINT"&lt;/span&gt;
&lt;span class="py"&gt;kill_timeout&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;span class="py"&gt;processes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

&lt;span class="nn"&gt;[env]&lt;/span&gt;
  &lt;span class="py"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8080&lt;/span&gt;

&lt;span class="nn"&gt;[experimental]&lt;/span&gt;
  &lt;span class="py"&gt;allowed_public_ports&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="py"&gt;auto_rollback&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="nn"&gt;[[services]]&lt;/span&gt;
  &lt;span class="py"&gt;http_checks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="py"&gt;internal_port&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt;
  &lt;span class="py"&gt;processes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"app"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="py"&gt;protocol&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"tcp"&lt;/span&gt;
  &lt;span class="py"&gt;script_checks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="nn"&gt;[services.concurrency]&lt;/span&gt;
    &lt;span class="py"&gt;hard_limit&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;
    &lt;span class="py"&gt;soft_limit&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;
    &lt;span class="py"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"connections"&lt;/span&gt;

  &lt;span class="nn"&gt;[[services.ports]]&lt;/span&gt;
    &lt;span class="py"&gt;force_https&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="py"&gt;handlers&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"http"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="py"&gt;port&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;

  &lt;span class="nn"&gt;[[services.ports]]&lt;/span&gt;
    &lt;span class="py"&gt;handlers&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"tls"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"http"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="py"&gt;port&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;443&lt;/span&gt;

  &lt;span class="nn"&gt;[[services.tcp_checks]]&lt;/span&gt;
    &lt;span class="py"&gt;grace_period&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1s"&lt;/span&gt;
    &lt;span class="py"&gt;interval&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"15s"&lt;/span&gt;
    &lt;span class="py"&gt;restart_limit&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="py"&gt;timeout&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"2s"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Regions
&lt;/h3&gt;

&lt;p&gt;You can currently deploy your apps in &lt;a href="https://fly.io/docs/reference/regions/#fly-io-regions" rel="noopener noreferrer"&gt;26 differents regions&lt;/a&gt; with the command &lt;strong&gt;flyctl regions add&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;👉 Add Paris and Tokyo as new regions&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;flyctl regions add cdg nrt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 Check regions&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;flyctl regions list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  CI/CD
&lt;/h3&gt;

&lt;p&gt;Fly provide remote builder so it's easy to integrate it with Gitlab or Github CI/CD pipelines. &lt;a href="https://fly.io/docs/app-guides/continuous-deployment-with-github-actions/" rel="noopener noreferrer"&gt;More info here&lt;/a&gt; and &lt;a href="https://medium.com/geekculture/deploy-docker-images-on-fly-io-free-tier-afbfb1d390b1" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>design</category>
      <category>watercooler</category>
    </item>
  </channel>
</rss>
