<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Electron - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Electron - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Tue, 19 May 2026 10:28:55 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/electron/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Integrate Tailwind with Electron – With Code Examples ]]>
                </title>
                <description>
                    <![CDATA[ In this article, you’ll learn how to integrate Tailwind CSS with Electron to build stylish, responsive desktop applications. You’ll set up Tailwind in an Electron project, configure your project, style the components, and optimize the development wor... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/integrate-tailwind-with-electron/</link>
                <guid isPermaLink="false">689cc9ce08eeb0d54c95cff1</guid>
                
                    <category>
                        <![CDATA[ Tailwind CSS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Electron ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Abhijeet Dave ]]>
                </dc:creator>
                <pubDate>Wed, 13 Aug 2025 17:22:22 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1755102784797/0a2d19f0-3539-47c6-a29d-68fab3d430ba.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this article, you’ll learn how to integrate Tailwind CSS with Electron to build stylish, responsive desktop applications.</p>
<p>You’ll set up Tailwind in an Electron project, configure your project, style the components, and optimize the development workflow. This is perfect for developers who are looking to combine Tailwind's utility-first CSS framework with Electron's cross-platform capabilities.</p>
<h2 id="heading-table-of-content">Table of Content</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-a-quick-overview-of-electron">A Quick Overview of Electron</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-tailwind-css">What is Tailwind CSS?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-why-electron-and-tailwind-work-so-well-together">Why Electron and Tailwind Work So Well Together</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-well-build">What We’ll Build?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-initialize-an-electron-project">How to Initialize an Electron Project</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-integrate-tailwind-css-with-electron">How to Integrate Tailwind CSS with Electron?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-a-tailwind-component-library-a-practical-example">How to Use a Tailwind Component Library – a Practical Example</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-lets-test-flyonui-js-components">Let’s Test FlyonUI JS Components</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-a-quick-overview-of-electron">A Quick Overview of Electron</h2>
<p><a target="_blank" href="https://www.electronjs.org/"><strong>Electron</strong></a> is a framework that lets developers create desktop applications for Windows, macOS, and Linux using familiar web technologies like HTML, CSS, and JavaScript, along with Node.js for backend features.</p>
<p>It's open-source, MIT-licensed, and completely free to use – whether you're building personal projects or commercial apps.</p>
<p>In this guide, we’ll look at why so many developers and companies choose Electron for building modern desktop apps.</p>
<h2 id="heading-what-is-tailwind-css"><strong>What is Tailwind CSS?</strong></h2>
<p><a target="_blank" href="https://tailwindcss.com/"><strong>Tailwind CSS</strong></a> is essentially a utility-first framework for styling web interfaces. Unlike frameworks that provide full-blown, pre-designed UI components, Tailwind offers a comprehensive set of single-purpose utility classes. You apply these classes directly to your HTML elements, which means you can rapidly build out custom layouts and designs without diving into separate CSS files.</p>
<p>The big advantage? Precision and flexibility – you can assemble unique, responsive interfaces by combining these classes however you see fit, all while keeping you markup lean and maintainable.</p>
<h2 id="heading-why-electron-and-tailwind-work-so-well-together"><strong>Why Electron and Tailwind Work So Well Together</strong></h2>
<p>Electron uses HTML, CSS, and JavaScript to build desktop applications. Essentially, it runs a web app in a desktop shell. This makes it easy to integrate modern frontend tools like Tailwind CSS.</p>
<p>Tailwind's utility-first approach allows you to style interfaces directly in you HTML, which can speed up UI development. Instead of writing custom styles or managing large CSS files, you apply predefined classes directly to elements. This aligns well with Electron's structure, where layout and styles are tightly connected within the same HTML environment.</p>
<p>Tailwind also provides sensible defaults and a consistent design system out of the box. This helps you prototype and build visually consistent desktop apps faster. While some familiarity with CSS is still helpful, Tailwind's approach can reduce the overhead of setting up and managing styles, especially in smaller or design-light projects.</p>
<p>Together, Electron and Tailwind offer a straightforward path to building desktop apps.</p>
<h2 id="heading-what-well-build">What We’ll Build?</h2>
<p>In this tutorial, we will create a basic Electron desktop app styled with Tailwind CSS and improved with FlyonUI components. You don’t need any prior experience with Electron or Tailwind.</p>
<p>By the end of the guide, you'll have:</p>
<ul>
<li><p>A working desktop window (Electron)</p>
</li>
<li><p>Styled UI with Tailwind CSS</p>
</li>
<li><p>A reusable button component</p>
</li>
<li><p>A fully functional modal dialog powered by FlyonUI</p>
</li>
</ul>
<p>This will provide a solid base for building more complex apps in the future.</p>
<h2 id="heading-prerequisites"><strong>Prerequisites</strong></h2>
<p>Before we dive in, make sure you have the following:</p>
<ul>
<li><p><strong>Basic knowledge of HTML, CSS, and JavaScript</strong>. You don’t need to be an expert, but understanding how to structure HTML and use basic JavaScript will help you follow along.</p>
</li>
<li><p><strong>Familiarity with Node.js and npm</strong>. We'll use npm (Node Package Manager) to install dependencies and run build commands.</p>
</li>
<li><p><strong>Node.js installed on your machine</strong>. You can download it from <a target="_blank" href="http://nodejs.org">nodejs.org</a><a target="_blank" href="https://nodejs.org/">.</a></p>
</li>
<li><p><strong>A code editor</strong>. I recommend <a target="_blank" href="https://code.visualstudio.com/">Visual Studio Code.</a></p>
</li>
<li><p><strong>Terminal / Command Line Access</strong>. You’ll need to run commands in the terminal to set things up.</p>
</li>
</ul>
<h2 id="heading-how-to-initialize-an-electron-project"><strong>How to Initialize an Electron Project</strong></h2>
<p>Let’s set up a basic Electron app from scratch. This will launch a simple desktop window that loads an HTML file, serving as the foundation for your UI.</p>
<h3 id="heading-1-create-your-project-folder">1. <strong>Create Your Project Folder</strong></h3>
<p>First, open your terminal and create a new project folder:</p>
<pre><code class="lang-bash">mkdir my-electron-app
<span class="hljs-built_in">cd</span> my-electron-app
</code></pre>
<p>This creates a new folder called <code>my-electron-app</code> and changes the directory to it. This folder will be your project workspace.</p>
<h3 id="heading-2-install-electron">2. <strong>Install Electron</strong></h3>
<p>Next, install Electron as a development dependency:</p>
<pre><code class="lang-bash">npm install electron --save-dev
</code></pre>
<p>This will add Electron to your project’s <code>node_modules</code> and update your <code>package.json</code> file.</p>
<p>This command installs Electron as a development dependency. Electron allows you to build desktop apps across different platforms using web technologies like HTML, CSS, and JavaScript.</p>
<h3 id="heading-3-configure-packagejson">3. <strong>Configure</strong> <code>package.json</code></h3>
<p>Update your <code>package.json</code> to point to a file named <code>main.js</code>, and add a script for easily starting the app.</p>
<p><strong>Edit your</strong> <code>package.json</code> like this:</p>
<pre><code class="lang-json"><span class="hljs-string">"main"</span>: <span class="hljs-string">"main.js"</span>,
<span class="hljs-string">"scripts"</span>: {
  <span class="hljs-attr">"start"</span>: <span class="hljs-string">"electron ."</span>
}
</code></pre>
<ul>
<li><p><code>"main"</code> defines the entry point of your Electron app (the main process).</p>
</li>
<li><p><code>"start"</code> is a shortcut to launch the app using <code>npm start</code>.</p>
</li>
</ul>
<h3 id="heading-4-create-mainjs">4. <strong>Create</strong> <code>main.js</code></h3>
<p>Create a file named <code>main.js</code> in your root folder and add the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> { app, BrowserWindow } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"electron/main"</span>);

<span class="hljs-keyword">const</span> createWindow = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> win = <span class="hljs-keyword">new</span> BrowserWindow({
    <span class="hljs-attr">width</span>: <span class="hljs-number">800</span>,
    <span class="hljs-attr">height</span>: <span class="hljs-number">600</span>,
  });

  win.loadFile(<span class="hljs-string">"index.html"</span>);
};

app.whenReady().then(<span class="hljs-function">() =&gt;</span> {
  createWindow();

  app.on(<span class="hljs-string">"activate"</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (BrowserWindow.getAllWindows().length === <span class="hljs-number">0</span>) {
      createWindow();
    }
  });
});

app.on(<span class="hljs-string">"window-all-closed"</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">if</span> (process.platform !== <span class="hljs-string">"darwin"</span>) {
    app.quit();
  }
});
</code></pre>
<p>This is your <strong>main process</strong>. It creates and manages the app window while loading your HTML file.</p>
<h3 id="heading-5-create-indexhtml-renderer-process">5. <strong>Create</strong> <code>index.html</code> <strong>(Renderer Process)</strong></h3>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">http-equiv</span>=<span class="hljs-string">"Content-Security-Policy"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"default-src 'self'; script-src 'self'"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Hello from Electron renderer!<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Hello from Electron renderer!<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"info"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"./renderer.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>This is the <strong>frontend (renderer)</strong> of your Electron app. You can use standard HTML, CSS, and JavaScript here, just like in a browser.</p>
<blockquote>
<p>Optional: Create a renderer.js file if you want to add JavaScript interactivity.</p>
</blockquote>
<h3 id="heading-6-run-the-electron-app">6. <strong>Run the Electron App</strong></h3>
<p>Now, create a file called <code>main.js</code> in the root of your project. This is the main process that starts your Electron app:</p>
<pre><code class="lang-bash">npm start
</code></pre>
<p>This command runs the app using the script you set up in <code>package.json</code>. A desktop window should open, displaying your HTML content.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1754292319523/58168908-40ed-4aca-920f-fbab7435b580.webp" alt="hello form electron renderer" class="image--center mx-auto" width="824" height="638" loading="lazy"></p>
<h2 id="heading-how-to-integrate-tailwind-css-with-electron"><strong>How to Integrate Tailwind CSS with Electron?</strong></h2>
<p>For this guide, we’ll be using the <a target="_blank" href="https://tailwindcss.com/docs/installation/tailwind-cli">Tailwind CLI</a> approach.</p>
<p>The Tailwind CLI is a command-line tool that allows you to generate and compile Tailwind utility classes directly into a CSS file. You don’t need complex build tools like Webpack or PostCSS. This makes it perfect for simple projects like Electron apps, where you’d want minimal setup and quick styling. The CLI also has a <code>--watch</code> mode that automatically rebuilds CSS when files change. This feature helps you stay productive.</p>
<h3 id="heading-1-install-tailwind-css">1. <strong>Install Tailwind CSS</strong></h3>
<p>First, install Tailwind CSS. Make sure Node.js is installed as well, then run:</p>
<pre><code class="lang-bash">npm install tailwindcss @tailwindcss/cli
</code></pre>
<p>This command installs Tailwind and its CLI tool as a development dependency in your project. We’ll use the CLI to build and monitor our Tailwind styles.</p>
<h3 id="heading-2-set-up-tailwind-css">2. <strong>Set Up Tailwind CSS</strong></h3>
<p>Create a <code>input.css</code> file with the following content to set up Tailwind:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@import</span> <span class="hljs-string">"tailwindcss"</span>;
</code></pre>
<p>This line instructs Tailwind to generate all its utility classes into one output file, which we’ll compile next.</p>
<h3 id="heading-3-add-a-build-script">3. <strong>Add a Build Script</strong></h3>
<p>Then update your <code>package.json</code> to include a build script:</p>
<pre><code class="lang-json"><span class="hljs-string">"scripts"</span>: {  
 <span class="hljs-attr">"watch:css"</span>:<span class="hljs-string">"npx @tailwindcss/cli -i ./input.css -o ./output.css --watch"</span>,
}
</code></pre>
<p>This command watches your <code>input.css</code> file and continuously builds a compiled CSS file (<code>output.css</code>) whenever it detects changes. You’ll include this file in your HTML.</p>
<h3 id="heading-4-link-outputcss-in-indexhtml">4. <strong>Link</strong> <code>output.css</code> <strong>in</strong> <code>index.html</code></h3>
<p>Open your <code>index.html</code> file and add this inside the <code>&lt;head&gt;</code></p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"./output.css"</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span>&gt;</span>
</code></pre>
<p>Then compile Tailwind CSS with this command:</p>
<pre><code class="lang-bash">npm run watch:css
</code></pre>
<p>This step includes the compiled Tailwind styles in your Electron app UI.</p>
<h3 id="heading-5-compile-tailwind-css">5. <strong>Compile Tailwind CSS</strong></h3>
<p>Run this script to start watching for changes and generate your CSS:</p>
<pre><code class="lang-bash">npm run watch:css
</code></pre>
<p>Keep this process running in a terminal window. It updates <code>output.css</code> live as you work.</p>
<h3 id="heading-6-update-the-ui-with-tailwind-classes">6. <strong>Update the UI with Tailwind Classes</strong></h3>
<p>Replace your <code>&lt;body&gt;</code> content with this example layout:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">body</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex items-center justify-center h-screen bg-gray-100"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span>
    <span class="hljs-attr">class</span>=<span class="hljs-string">"py-3 px-4 inline-flex items-center gap-x-2 text-sm font-medium rounded-lg border border-transparent bg-purple-600 text-white hover:bg-purple-700 focus:outline-hidden cursor-pointer focus:bg-purple-700 disabled:opacity-50 disabled:pointer-events-none"</span>&gt;</span>
    Hello Tailwindcss
  <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
</code></pre>
<h3 id="heading-7-run-the-electron-app">7. <strong>Run the Electron App</strong></h3>
<p>Run the electron server with this command:</p>
<pre><code class="lang-bash">npm start
</code></pre>
<p>Your Electron window should now open with a well-styled button in the center, thanks to Tailwind CSS.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1754374369750/f79a6c6d-bc59-4a2b-a6eb-f3b63f8bccc4.png" alt="run electron server" class="image--center mx-auto" width="278" height="238" loading="lazy"></p>
<h2 id="heading-how-to-use-a-tailwind-component-library-a-practical-example">How to Use a Tailwind Component Library – a Practical Example</h2>
<p>We are going to use <a target="_blank" href="https://flyonui.com/">FlyonUI</a>, an open source Tailwind component library. It includes a mix of utility classes in addition to JavaScript plugins. FlyonUI draws ideas from daisyUI but also from Preline, and combines flexibility and simplicity. It also helps you build interfaces that respond well and appear consistent.</p>
<h3 id="heading-1-install-flyonui">1. <strong>Install FlyonUI</strong></h3>
<p>You can install FlyonUI with the command below. Make sure Node.js is installed, then run:</p>
<pre><code class="lang-bash">npm install -D flyonui@latest
</code></pre>
<p>Installs FlyonUI into your project as a development dependency, making its CSS and JS functionality available for integration.</p>
<h3 id="heading-2-add-flyonui-as-plugin-in-the-inputcss">2. Add FlyonUI as plugin in the <code>input.css</code>:</h3>
<pre><code class="lang-css"><span class="hljs-keyword">@import</span> <span class="hljs-string">"tailwindcss"</span>;
<span class="hljs-keyword">@plugin</span> <span class="hljs-string">"flyonui"</span>;
<span class="hljs-keyword">@import</span> <span class="hljs-string">"./node_modules/flyonui/variants.css"</span>; <span class="hljs-comment">/* Needed for JS components */</span>
<span class="hljs-keyword">@source</span> <span class="hljs-string">"./node_modules/flyonui/dist/index.js"</span>; <span class="hljs-comment">/* Needed for JS components */</span>
</code></pre>
<ul>
<li><p><code>@plugin "flyonui"</code> injects FlyonUI’s semantic classes into your build.</p>
</li>
<li><p>The <code>@import</code> includes custom variants created for the JS Components.</p>
</li>
<li><p>The <code>@source</code> line is required for the classes used in the js gets generated.</p>
</li>
</ul>
<h3 id="heading-3-include-flyonui-javascript-for-interactivity">3. <strong>Include FlyonUI JavaScript for Interactivity</strong></h3>
<p>Right before closing the <code>&lt;/body&gt;</code> tag in your HTML, include:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"../node_modules/flyonui/flyonui.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>This script enables the interactive behaviors for FlyonUI components, such as overlays, modals, and dropdowns.</p>
<h3 id="heading-4-use-a-flyonui-component">4. <strong>Use a FlyonUI Component</strong></h3>
<p>For example, update your UI with:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">body</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex items-center justify-center h-screen bg-gray-100"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-primary"</span>&gt;</span>
    Hello FlyonUI
  <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1754374843709/41f9d3e3-d0be-4a32-a569-ce0618bea0e9.png" alt="41f9d3e3-d0be-4a32-a569-ce0618bea0e9" class="image--center mx-auto" width="338" height="208" loading="lazy"></p>
<ul>
<li>The <code>.btn</code> and <code>.btn-primary</code> classes come from FlyonUI—giving you styled, semantic components without crafting custom CSS.</li>
</ul>
<h3 id="heading-why-it-matters"><strong>Why It Matters</strong></h3>
<ul>
<li><p><strong>Cleaner Code</strong>: FlyonUI’s semantic classes make your templates more readable and maintainable compared to verbose utility classes.</p>
</li>
<li><p><strong>Interactive Without the Overhead</strong>: Easily add dynamic features like modals or accordions through FlyonUI’s JS plugins—no need to code them from scratch.</p>
</li>
<li><p><strong>Effortless Styling</strong>: FlyonUI builds on Tailwind’s utility approach, so you can customize components with familiar classes instantly.</p>
</li>
</ul>
<h2 id="heading-lets-test-flyonui-js-components">Let’s Test FlyonUI JS Components</h2>
<p>To show how FlyonUI works, we’ll test one of its JavaScript-powered UI components, the <strong>Modal</strong>. Modals are common UI elements that grab user attention for alerts, confirmations, or extra information without moving away from the current page.</p>
<h3 id="heading-why-test-the-modal">Why Test the Modal?</h3>
<p>Testing the modal helps you:</p>
<ul>
<li><p>Check that FlyonUI’s JavaScript components load and work properly within your Electron and Tailwind setup.</p>
</li>
<li><p>See how simple it is to add interactive features using FlyonUI’s built-in classes and data attributes.</p>
</li>
<li><p>Understand how the modal responds to different screen sizes and how the UI reacts to user actions like opening and closing dialogs.</p>
</li>
</ul>
<h3 id="heading-how-to-test-the-modal">How to Test the Modal</h3>
<p>Copy the following example code into your <code>index.html</code> file. This button will open a modal dialog with some placeholder content:</p>
<p>We’ll use this <a target="_blank" href="https://flyonui.com/docs/overlays/modal/"><strong>Modal example</strong></a> for testing. Copy the following code in your <code>index.html</code>:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-primary"</span> <span class="hljs-attr">aria-haspopup</span>=<span class="hljs-string">"dialog"</span> <span class="hljs-attr">aria-expanded</span>=<span class="hljs-string">"false"</span> <span class="hljs-attr">aria-controls</span>=<span class="hljs-string">"basic-modal"</span> <span class="hljs-attr">data-overlay</span>=<span class="hljs-string">"#basic-modal"</span>&gt;</span>Open modal<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"basic-modal"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"overlay modal overlay-open:opacity-100 hidden overlay-open:duration-300"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"dialog"</span> <span class="hljs-attr">tabindex</span>=<span class="hljs-string">"-1"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"modal-dialog"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"modal-content"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"modal-header"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h3</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"modal-title"</span>&gt;</span>Dialog Title<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-text btn-circle btn-sm absolute end-3 top-3"</span> <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"Close"</span> <span class="hljs-attr">data-overlay</span>=<span class="hljs-string">"#basic-modal"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"icon-[tabler--x] size-4"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"modal-body"</span>&gt;</span>
        This is some placeholder content to show the scrolling behavior for modals. Instead of repeating the text in the
        modal, we use an inline style to set a minimum height, thereby extending the length of the overall modal and
        demonstrating the overflow scrolling. When content becomes longer than the height of the viewport, scrolling
        will move the modal as needed.
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"modal-footer"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-soft btn-secondary"</span> <span class="hljs-attr">data-overlay</span>=<span class="hljs-string">"#basic-modal"</span>&gt;</span>Close<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-primary"</span>&gt;</span>Save changes<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>After updating the file, restart your Electron app:</p>
<pre><code class="lang-html">npm start
</code></pre>
<p>Here’s the result:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1754374899394/4f153f2b-ca41-495f-b27e-18a2424a1952.png" alt="final result" class="image--center mx-auto" width="842" height="634" loading="lazy"></p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>You can use Tailwind CSS and Electron to build desktop applications that look good and operate well on different devices. This adds to Electron's many functions and Tailwind's good styling system, letting you stay productive and utilize clean design methods.</p>
<p>The full code and more details are in the repository here: <a target="_blank" href="https://github.com/themeselection/ts-electron-tailwind">ts-electron-tailwindcss</a>.</p>
<p>I have written this tutorial with the help of <a target="_blank" href="https://github.com/PruthviPraj00">Pruthvi Prajapati</a>, an experienced Tailwind CSS developer.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Create Desktop Apps with Electron, React, and TypeScript ]]>
                </title>
                <description>
                    <![CDATA[ Desktop applications remain important for many types of software projects, providing rich, native user experiences. If you're interested in building desktop applications but want to leverage your web development skills, Electron is an excellent solut... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/create-desktop-apps-with-electron-react-and-typescript/</link>
                <guid isPermaLink="false">670439504ab1b42ab0a1286b</guid>
                
                    <category>
                        <![CDATA[ Electron ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Mon, 07 Oct 2024 19:41:04 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1728505692610/2967a626-9f44-4ec7-a929-f5d5be33e600.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Desktop applications remain important for many types of software projects, providing rich, native user experiences. If you're interested in building desktop applications but want to leverage your web development skills, Electron is an excellent solution. By combining the power of JavaScript, React, and TypeScript, Electron allows you to create cross-platform desktop applications using familiar web technologies. Whether you're developing tools for productivity, data visualization, or custom enterprise software, Electron offers the flexibility and performance required to deliver high-quality apps.</p>
<p>We just published a course on the <a target="_blank" href="http://freeCodeCamp.org">freeCodeCamp.org</a> YouTube channel that will teach you all about using Electron, React, and TypeScript to build robust desktop applications. Created by Niklas Ziermann, this comprehensive course covers everything from setting up your development environment to implementing advanced features like data visualization, secure communication, and custom window frames. By the end of this course, you'll have the knowledge to create polished, feature-rich desktop apps with Electron, all while writing clean, type-safe code in TypeScript.</p>
<p>The course begins with an introduction to how Electron works, showing you how it integrates with Node.js to create native-like applications. You'll then set up React, followed by Electron, ensuring that your project is ready to handle front-end rendering and system interactions. TypeScript is introduced early in the course, helping you enforce strict types, which leads to fewer errors and a more maintainable codebase. Once your environment is configured, you’ll dive deeper into the inner workings of Electron, setting up Electron-Builder for packaging and distribution, and making developer experience (DX) improvements to streamline your workflow.</p>
<p>From there, the course explores more advanced features, such as reading system resources and securely communicating between your app’s front-end and back-end. You'll also learn about Inter-Process Communication (IPC) and how to make it type-safe, ensuring consistent and secure data transfer. The course even includes sections on data visualization, an important skill for developers building apps that need to display complex information in an easily digestible format.</p>
<p>Additional topics covered in the course include customizing the tray and menu bar, enabling view switching, and creating custom window frames to give your app a unique look and feel. Security is also a major focus, with lessons on securing the app to prevent malicious attacks. To ensure that your application is bug-free, you'll also learn about testing, including end-to-end (E2E) testing and unit testing, which are critical for maintaining high-quality code as your project grows.</p>
<p>If you're looking to take your web development skills to the desktop, this course is the perfect opportunity to learn how to harness Electron, React, and TypeScript. Watch the full course <a target="_blank" href="https://www.youtube.com/watch?v=fP-371MN0Ck">on the freeCodeCamp.org YouTube channel</a> (4-hour watch).</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/fP-371MN0Ck" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Things I Wish I Knew Before Working with Electron.js ]]>
                </title>
                <description>
                    <![CDATA[ By Alain Perkaz In this article, I'll share how you can avoid some of the mistakes I made when learning about Electron.js ?‍♂️. I hope it helps! Note: This wont be a coding tutorial, but rather a discussion about my personal takeaways. A couple of mo... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/lessons-learned-from-electronjs/</link>
                <guid isPermaLink="false">66d45d9a37bd2215d1e24580</guid>
                
                    <category>
                        <![CDATA[ Electron ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ lessons learned ]]>
                    </category>
                
                    <category>
                        <![CDATA[ projects ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 28 May 2020 19:11:55 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/5f9c9abd740569d1a4ca276a.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Alain Perkaz</p>
<p>In this article, I'll share how you can avoid some of the mistakes I made when learning about Electron.js ?‍♂️. I hope it helps!</p>
<p><strong>Note</strong>: This wont be a coding tutorial, but rather a discussion about my personal takeaways.</p>
<p>A couple of months back, I decided to focus more on building my side product, <a target="_blank" href="https://taggr.ai/"><em>taggr</em></a>. I was inspired to build it because of how many photos I have on my computer. </p>
<p>For those of us that keep a backup of their pictures, those collections often get so big and complex that they become a full-time job to manage. A mix of folders and sub-folders may contain instant messaging picture backups, hi-resolution pictures from your trip to Bali, your uncle's wedding, or last-year's bachelor party.</p>
<p>Always keeping such collections tidy is <strong>tedious</strong> (believe me, I have tried for years). It's also hard to discover the shots that you love the most, hidden deep within the folders. </p>
<p>So <a target="_blank" href="https://taggr.ai/"><em>taggr</em></a> is a desktop app that solves that problem. It lets users <strong>rediscover</strong> their memories while keeping their <strong>privacy</strong>.</p>
<p>I am building <em><a target="_blank" href="https://taggr.ai/">taggr</a></em> as a cross-platform desktop application. Here I'll share some of the things I've learned about cross-platform app development with <a target="_blank" href="https://www.electronjs.org/">Electron.js</a> that I wish I knew from the beginning. Let's get started!</p>
<h2 id="heading-background">Background</h2>
<p>Before presenting my takeaways on this ongoing journey with Electron, I would like to give a little more background about myself and the requirements of <a target="_blank" href="https://taggr.ai/"><em>taggr</em></a>.</p>
<p>Every developer comes from a different background, and so do the requirements of the applications they develop. </p>
<p>Contextualizing the choices I made for this project may help future developers select the right tools based on their needs and expertise (rather than what is hyped out there – GitHub ?, I am looking at you).</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/train.gif" alt="Image" width="600" height="400" loading="lazy">
<em>JavaScript development in a nutshell. Source: [giphy](https://giphy.com/gifs/train-hype-FY2ew2Zii9VOE" rel="noopener).</em></p>
<p>As mentioned earlier, from the beginning I envisioned <a target="_blank" href="https://taggr.ai/"><em>taggr</em></a> as a cross-platform application. The app would perform all the required pre-processing and machine-learning computations client-side due to the focus on privacy. </p>
<p>As a one-person show, I wanted to be able to write my app once and ship it to different systems without losing my sanity.</p>
<p>From my side, I am a front end engineer in love with the web and JavaScript. I previously worked with Java and C#, but I enjoy the flexibility that the web provides and its vibrant ecosystem. </p>
<p>Having experienced first hand the pain of using tools like <a target="_blank" href="https://wiki.eclipse.org/Rich_Client_Platform">Eclipse RCP</a> to build client-side apps before, I knew I didn’t want to work with that tech again.</p>
<p>In short, my stack requirements for taggr boiled down to something like the following:</p>
<ul>
<li>It should provide <strong>cross-platform support,</strong> ideally at the framework level. ?</li>
<li>It should allow me to <strong>write the code once</strong>, and tweak for each platform if needed. ?️</li>
<li>It should enable <strong>access to machine-learning capabilities</strong>, regardless of the host environment, without specific runtimes to be installed. It should be painless to set up. ?</li>
<li>If feasible, it should <strong>use web technologies</strong>. It would be great to leverage my existing knowledge. ?</li>
</ul>
<p>As you can see, the requirements do not read as: <strong>I should use React with Redux, observables, and WebSockets</strong>. Those are lower-level implementation details, and they should be decided upon <em>when and if</em> the need arises. </p>
<p>Pick the right tool for the job rather than picking a stack from the beginning, disregarding the problems at hand.</p>
<p>So, after furious googling, I decided to give Electron a try. I hadn’t used that framework before, but I knew that many companies were using it successfully in products such as <a target="_blank" href="https://atom.io/">Atom</a>, <a target="_blank" href="https://code.visualstudio.com/">VS Code</a>, <a target="_blank" href="https://discord.com/">Discord</a>, <a target="_blank" href="https://signal.org/#signal">Signal</a>, <a target="_blank" href="https://slack.com/">Slack</a> and more.</p>
<p>Open-source and with out-of-the-box compatibility with both the the JS and Node ecosystems (Electron is build using Chromium and Node), Electron.js was an attractive tool for the work at hand. </p>
<p>I won't go too much into detail regarding the rest of the stack, as I repeatedly changed core parts (persistence and view layers) when needed, and it falls out of the scope of this article. </p>
<p>However, I would like to mention <a target="_blank" href="https://www.tensorflow.org/js">Tensorflow.js</a>, which enables running training and deploying ML models directly in the browser (with WebGL) and Node (with C bindings), without installing specific runtimes for ML in the host.</p>
<p>So back to Electron – thinking it was perfect, the fun began. ??</p>
<p>Enough talk about the background. Let’s dive into the takeaways.</p>
<h2 id="heading-1-start-small-and-slow">1. Start small (and slow) ?</h2>
<p>This is not a new concept, but it's worth bringing up periodically. Just because there are a ton of awesome <a target="_blank" href="https://github.com/sindresorhus/awesome-electron#boilerplates">starter projects</a> with Electron available, it doesn’t mean that you should pick one right away.</p>
<p><strong>Wait. What?</strong></p>
<blockquote>
<p>Slow is smooth, and smooth is fast. — Navy saying</p>
</blockquote>
<h3 id="heading-with-convenience-comes-complexity">With convenience comes complexity</h3>
<p>While those starters include many useful integrations (Webpack, Babel, Vue, React, Angular, Express, Jest, Redux), they also have their issues. </p>
<p>As an Electron newbie, I decided to go for a lean template that included the basics for ‘creating, publishing, and installing Electron apps’ without the extra bells and whistles. Not even Webpack in the beginning.</p>
<p>I recommend starting with something similar to <a target="_blank" href="https://www.electronforge.io/">electron-forge</a> to get up and running quickly, You can set up your dependency graph and structure on top to learn the ropes of Electron. </p>
<p>When the issues come (and they will), you will be better off if you build your custom starter project rather than picking <a target="_blank" href="https://github.com/electron-react-boilerplate/electron-react-boilerplate/blob/master/package.json">one</a> with +30 npm scripts and +180 dependencies to begin with.</p>
<p>That said, once you feel comfortable with Electron’s basis, feel free to step up the game with Webpack/React/Redux/TheNextHotFramework. I did it <strong>incrementally</strong> and when needed. Don’t add a realtime database to your todo app just because you read a cool article about it somewhere.</p>
<h2 id="heading-2-mindfully-structure-your-app">2. Mindfully structure your app ?‍♂️</h2>
<p>This one took a little longer to get right than I am happy to admit. ?</p>
<p>In the beginning, <strong>it may be tempting to mix up the UI and Backend code</strong> (file access, extended CPU operations), but things get complex quite fast. As my application grew in features, size, and complexity, maintaining one tangled UI+Backend codebase became more complicated and error-prone. Also, the coupling made it hard to test each part in isolation.</p>
<p>When building a desktop app that does more than an embedded webpage (DB access, file access, intensive CPU tasks…), I recommend <strong>slicing the app into modules</strong> and reducing the coupling. Unit testing becomes a breeze, and there is a clear path towards integration testing between the modules. For <a target="_blank" href="https://taggr.ai/"><em>taggr</em></a><em>,</em> I loosely followed the structure proposed <a target="_blank" href="https://blog.axosoft.com/electron-things-to-know/">here</a>.</p>
<p>On top of that, there is <strong>performance</strong>. The requirements and user expectations on this matter may vary wildly depending on the application that you are building. But blocking the main or render threads with expensive calls is never a good idea.</p>
<h2 id="heading-3-design-with-the-threading-model-in-mind">3. Design with the threading model in mind ?</h2>
<p>I won’t go too much into detail here – I'm just mainly doubling down on what is awesomely explained in the <a target="_blank" href="https://www.electronjs.org/docs/tutorial/performance">official docs</a>.</p>
<p>In the specific case of <a target="_blank" href="https://taggr.ai/"><em>taggr</em></a>, there are many long-running CPU, GPU, and IO intensive operations. When executing those operations in Electron’s main or renderer thread, the FPS count dips from 60, making the UI feel sluggish.</p>
<p>Electron offers several alternatives to <strong>offload those operations from the main and renderer threads</strong>, such as <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Worker">WebWorkers</a>, <a target="_blank" href="https://nodejs.org/api/worker_threads.html">Node Worker Threads</a>, or <a target="_blank" href="https://www.electronjs.org/docs/api/browser-window">BrowserWindow</a> instances. Each has its advantages and caveats, and the use case you face will determine which one is the best fit.</p>
<p>Regardless of which alternative you choose for offloading the operations out of the main and renderer threads (when needed), <strong>consider how the communication interface will be</strong>. It took me a while to come up with a interface I was satisfied with, as it heavily impacts how your application is structured and functions. I found helpfull to experiment with different approaches before picking one. </p>
<p>For example, if you think WebWorkers message passing interface may not be the easiest to debug around, give <a target="_blank" href="https://github.com/GoogleChromeLabs/comlink">comlink</a> a try.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/sponge.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Sponge Bob knows best. Source: [giphy](https://giphy.com/embed/jV4wbvtJxdjnMriYmY" rel="noopener)</em></p>
<h2 id="heading-4-test-test-and-test">4. Test ❌, test ❌, and test ✔️</h2>
<p>Old news, right? I wanted to add this as the last point, due to a couple of anecdotal ‘issues’ I recently faced. Strongly linked to the first and second points, building your custom starter project and making mistakes early on will save you precious debugging time further in the development.</p>
<p>If you followed my recommendations for splitting the app’s UI and Backend into modules with a clean interface between the two, setting up automated Unit and Integration tests should be easy. As the application matures, you may want to add support for <a target="_blank" href="https://www.electronjs.org/spectron">e2e testing</a> too.</p>
<h3 id="heading-gps-location-extraction">GPS location extraction ?️</h3>
<p>Two days ago, while implementing the GPS location extraction feature for <a target="_blank" href="https://taggr.ai/"><em>taggr</em></a><em>,</em> once the unit tests were green and the feature worked in development (with Webpack), I decided to try it in the production environment. </p>
<p>While the feature worked well in development, it failed miserably in production. The EXIF information from the pictures was read as binary and processed by a third-party library. While the binary information was correctly loaded in both environments (checked with <a target="_blank" href="https://www.lifewire.com/compare-two-text-files-linux-3861434">diff</a>), the third party library failed when parsing such data in the production build. Excuse me, ??</p>
<p><strong>Solution</strong>: I found out that the encoding settings in the development and production environments set by Webpack were not the same. This caused the binary data to be parsed as UTF-8 in development but not in production. The issue was fixed by setting up the proper encoding headers in the HTML files loaded by Electron.</p>
<h3 id="heading-funky-pictures">Funky pictures ?</h3>
<p>When manipulating and working with images, you may think that if a JPEG ‘just-works’ on your computer, it is a valid JPEG. <strong>Wrong</strong>.</p>
<p>While working with the Node image processing library <a target="_blank" href="https://sharp.pixelplumbing.com/"><em>sharp</em></a>, resizing some JPEG images crashed the app. After looking closely, the cause was incorrect JPEG images generated by <a target="_blank" href="https://github.com/lovell/sharp/issues/1578">Samsung firmware</a>. ?‍♂️</p>
<p><strong>Solution</strong>: setting up improved error boundaries in the app (ex. try-catch blocks), tweak the JPEG parsing module, and suspect of everything. ?️</p>
<h2 id="heading-summary">Summary</h2>
<p>The Node and JavaScripts ecosystems are blooming, with many powerful tools being created and shared every day.</p>
<p>The amount of options makes it hard to choose a clear path to start building your new awesome Electron app. Regardless of your frameworks of choice, I would recommend focusing on the following:</p>
<ol>
<li><strong>Start small</strong> and add complexity incrementally.</li>
<li><strong>Mindfully structure your app</strong>, keeping backend, and UI concerns modularized.</li>
<li><strong>Design with the threading model in mind</strong>, even when building small apps.</li>
<li><strong>Test and test again</strong>, to catch most of the errors early on and save headaches.</li>
</ol>
<p>Thanks for sticking around until the end! ?</p>
<p><a target="_blank" href="https://taggr.ai/"><em>taggr</em></a> is a cross-platform desktop application that enables users to <strong>rediscover</strong> their digital <strong>memories</strong> while keeping their <strong>privacy</strong>. Open-alpha is coming soon to Linux, Windows, and Mac OS. So keep an eye on <a target="_blank" href="https://twitter.com/TaggrOfficial">Twitter</a> and <a target="_blank" href="https://www.instagram.com/taggrofficial/">Instagram</a>, where I post development updates, upcoming features, and news.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Writing OS-specific code in Electron ]]>
                </title>
                <description>
                    <![CDATA[ By Maciej Cieślar One of the advantages of using Electron is that — since it’s cross-platform — we don’t have to worry about the operating system on which our application is going to be run. However, sometimes we need our code to be OS-specific if, f... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-write-os-specific-code-in-electron-bf6379c62ff6/</link>
                <guid isPermaLink="false">66d4601b246e57ac83a2c791</guid>
                
                    <category>
                        <![CDATA[ Electron ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Productivity ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technology ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 28 Aug 2018 17:38:38 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*285GZjmJQbn-VF6J-qKD3A.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Maciej Cieślar</p>
<p>One of the advantages of using Electron is that — since it’s cross-platform — we don’t have to worry about the operating system on which our application is going to be run.</p>
<p>However, sometimes we need our code to be OS-specific if, for example, we are going to be using the command console or need to retrieve some information about the system.</p>
<p>Having to write multiple <em>ifs</em> each time we want to have some functionality on a given OS seems like excess work. It quickly obfuscates the code, making it difficult to be understood and analyzed.</p>
<p>In order to keep the code clean and readable, we can create a little helper and remove the <em>ifs</em> and any “OS-related” logic altogether.</p>
<h3 id="heading-implementing-platforms">Implementing Platforms</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> os = <span class="hljs-built_in">require</span>(<span class="hljs-string">'os'</span>);

<span class="hljs-keyword">const</span> platforms = {
  <span class="hljs-attr">WINDOWS</span>: <span class="hljs-string">'WINDOWS'</span>,
  <span class="hljs-attr">MAC</span>: <span class="hljs-string">'MAC'</span>,
  <span class="hljs-attr">LINUX</span>: <span class="hljs-string">'LINUX'</span>,
  <span class="hljs-attr">SUN</span>: <span class="hljs-string">'SUN'</span>,
  <span class="hljs-attr">OPENBSD</span>: <span class="hljs-string">'OPENBSD'</span>,
  <span class="hljs-attr">ANDROID</span>: <span class="hljs-string">'ANDROID'</span>,
  <span class="hljs-attr">AIX</span>: <span class="hljs-string">'AIX'</span>,
};

<span class="hljs-keyword">const</span> platformsNames = {
  <span class="hljs-attr">win32</span>: platforms.WINDOWS,
  <span class="hljs-attr">darwin</span>: platforms.MAC,
  <span class="hljs-attr">linux</span>: platforms.LINUX,
  <span class="hljs-attr">sunos</span>: platforms.SUN,
  <span class="hljs-attr">openbsd</span>: platforms.OPENBSD,
  <span class="hljs-attr">android</span>: platforms.ANDROID,
  <span class="hljs-attr">aix</span>: platforms.AIX,
};

<span class="hljs-keyword">const</span> currentPlatform = platformsNames[os.platform()];

<span class="hljs-keyword">const</span> findHandlerOrDefault = <span class="hljs-function">(<span class="hljs-params">handlerName, dictionary</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> handler = dictionary[handlerName];

  <span class="hljs-keyword">if</span> (handler) {
    <span class="hljs-keyword">return</span> handler;
  }

  <span class="hljs-keyword">if</span> (dictionary.default) {
    <span class="hljs-keyword">return</span> dictionary.default;
  }

  <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> <span class="hljs-literal">null</span>;
};

<span class="hljs-keyword">const</span> byOS = findHandlerOrDefault.bind(<span class="hljs-literal">null</span>, currentPlatform);

<span class="hljs-comment">// usage</span>
<span class="hljs-keyword">const</span> whatIsHeUsing = byOS({
  [MAC]: <span class="hljs-function"><span class="hljs-params">username</span> =&gt;</span> <span class="hljs-string">`Hi <span class="hljs-subst">${username}</span>! You are using Mac.`</span>,
  [WINDOWS]: <span class="hljs-function"><span class="hljs-params">username</span> =&gt;</span> <span class="hljs-string">`Hi <span class="hljs-subst">${username}</span>! You are using Windows.`</span>,
  [LINUX]: <span class="hljs-function"><span class="hljs-params">username</span> =&gt;</span> <span class="hljs-string">`Hi <span class="hljs-subst">${username}</span>! You are using Linux.`</span>,
  <span class="hljs-attr">default</span>: <span class="hljs-function"><span class="hljs-params">username</span> =&gt;</span> <span class="hljs-string">`Hi <span class="hljs-subst">${username}</span>! You are using something different.`</span>,
});

<span class="hljs-built_in">console</span>.log(whatIsHeUsing(<span class="hljs-string">'Maciej Cieslar'</span>)); <span class="hljs-comment">// =&gt; Hi Maciej Cieslar! You are using Mac.</span>
</code></pre>
<p>First, we see the <em>platforms</em> object which contains names of all supported operating systems. It is made only for convenience. We can then use <em>platforms.WINDOWS</em> instead of typing <em>‘WINDOWS’</em> each time into our object with handlers we pass to the <em>byOS</em> function.</p>
<p>Next, notice the <em>platformsNames</em> object. The keys are the result of calling <a target="_blank" href="https://nodejs.org/api/os.html#os_os_platform"><em>os.platform()</em></a><em>.</em> The values are the keys from the <em>platforms</em> object. We simply map it to a more user-friendly name.</p>
<p>For example, when <em>os.platform()</em> returns <em>win32,</em> we map it to <em>platforms.WINDOWS</em> by calling <em>platformsNames[os.platform()]</em>.</p>
<p>In <em>currentPlatform,</em> we save the platform that we are using right now, so then we can match it against a given object with handlers.</p>
<h3 id="heading-implementing-releases">Implementing Releases</h3>
<p>One might go even further and try to differentiate between releases of a given OS, for example, Windows 7, 8 and 10.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> os = <span class="hljs-built_in">require</span>(<span class="hljs-string">'os'</span>);

<span class="hljs-keyword">const</span> releaseTest = {
  [platforms.WINDOWS]: <span class="hljs-function">(<span class="hljs-params">version</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> [majorVersion, minorVersion] = version.split(<span class="hljs-string">'.'</span>);

    <span class="hljs-comment">// Windows 10 (10,0)</span>
    <span class="hljs-keyword">if</span> (majorVersion === <span class="hljs-string">'10'</span>) {
      <span class="hljs-keyword">return</span> releases.WIN10;
    }

    <span class="hljs-comment">// Windows 8.1 (6,3)</span>
    <span class="hljs-comment">// Windows 8 (6,2)</span>
    <span class="hljs-comment">// Windows 7 (6,1)</span>
    <span class="hljs-keyword">if</span> (majorVersion === <span class="hljs-string">'6'</span>) {
      <span class="hljs-keyword">if</span> (minorVersion === <span class="hljs-string">'3'</span> || minorVersion === <span class="hljs-string">'2'</span>) {
        <span class="hljs-keyword">return</span> releases.WIN8;
      }

      <span class="hljs-keyword">return</span> releases.WIN7;
    }

    <span class="hljs-keyword">return</span> releases.WIN7;
  },
  [platforms.MAC]: <span class="hljs-function">() =&gt;</span> releases.ANY,
  [platforms.LINUX]: <span class="hljs-function">() =&gt;</span> releases.ANY,
};

<span class="hljs-keyword">const</span> currentRelease = releaseTest[currentPlatform](os.release());

<span class="hljs-keyword">const</span> byRelease = findHandlerOrDefault.bind(<span class="hljs-literal">null</span>, currentRelease);

<span class="hljs-comment">// usage</span>
<span class="hljs-keyword">const</span> whatWindowsIsHeUsing = byOS({
  [WINDOWS]: byRelease({
    [WIN7]: <span class="hljs-function"><span class="hljs-params">username</span> =&gt;</span> <span class="hljs-string">`Hi <span class="hljs-subst">${username}</span>! You are using Windows 7.`</span>,
    [WIN8]: <span class="hljs-function"><span class="hljs-params">username</span> =&gt;</span> <span class="hljs-string">`Hi <span class="hljs-subst">${username}</span>! You are using Windows 8.`</span>,
    [WIN10]: <span class="hljs-function"><span class="hljs-params">username</span> =&gt;</span> <span class="hljs-string">`Hi <span class="hljs-subst">${username}</span>! You are using Windows 10.`</span>,
  }),
});

<span class="hljs-built_in">console</span>.log(whatWindowsIsHeUsing(<span class="hljs-string">'Maciej Cieslar'</span>)); <span class="hljs-comment">// =&gt; Hi Maciej Cieslar! You are using Windows 7.</span>
</code></pre>
<p>Now we can use <a target="_blank" href="https://nodejs.org/api/os.html#os_os_release"><em>os.release()</em></a> to check for the system’s release.</p>
<p>We can split the resulting string and check the Windows version. A complete list can be found <a target="_blank" href="https://stackoverflow.com/a/44916050/6569856">here</a>. As for Linux/Mac, I didn’t really see how that could be useful, so I left it at <em>releases.ANY</em>.</p>
<p>In <em>whatWindowsIsHeUsing</em> you can see that we are only checking for different Windows’ releases if we are running the app on Windows.</p>
<p>You can see the code in the <a target="_blank" href="https://github.com/maciejcieslar/os-specific-electron">repository</a>.</p>
<p>Thank you very much for reading! If you have better ideas on how to write OS specific code, share them down below!</p>
<p>If you have any questions or comments feel free to put them in the comment section below or send me a <a target="_blank" href="https://www.mcieslar.com/contact">message</a>.</p>
<p>Check out my <a target="_blank" href="https://www.maciejcieslar.com/about/">social media</a>!</p>
<p><a target="_blank" href="http://eepurl.com/dAKhxb">Join my newsletter</a>!</p>
<p><em>Originally published at <a target="_blank" href="https://www.mcieslar.com/writing-os-specific-code-in-electron">www.mcieslar.com</a> on August 28, 2018.</em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Building an Electron application with create-react-app ]]>
                </title>
                <description>
                    <![CDATA[ By Christian Sepulveda No webpack configuration or “ejecting” necessary. I recently built an Electron app using create-react-app. I didn’t need to muck about with Webpack, or “eject” my app, either. I’ll walk you through how I accomplished this. I wa... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/building-an-electron-application-with-create-react-app-97945861647c/</link>
                <guid isPermaLink="false">66d45e0347a8245f78752a12</guid>
                
                    <category>
                        <![CDATA[ Electron ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 12 Jan 2017 00:43:43 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*PQwgjFvq8KcaNOyjZqC5ig.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Christian Sepulveda</p>
<h3 id="heading-no-webpack-configuration-or-ejecting-necessary">No webpack configuration or “ejecting” necessary.</h3>
<p>I recently built an <a target="_blank" href="http://electron.atom.io/">Electron</a> app using <a target="_blank" href="https://github.com/facebookincubator/create-react-app">create-react-app</a><em>.</em> I didn’t need to muck about with Webpack, or “eject” my app, either. I’ll walk you through how I accomplished this.</p>
<p>I was drawn to the idea of using <a target="_blank" href="https://github.com/facebookincubator/create-react-app">create-react-app</a> because it hides the webpack configuration details. But my search for existing guides for using Electron and create-react-app together didn’t bear any fruit, so I just dove in and figured it out myself.</p>
<p>If you’re feeling impatient, you can dive right in and look at my code. Here’s the <a target="_blank" href="https://github.com/csepulv/electron-with-create-react-app">GitHub repo</a> for my app.</p>
<p>Before we get started, let me tell you about Electron and React, and why create-react-app is such a great tool.</p>
<h3 id="heading-electron-and-react">Electron and React</h3>
<p>React is Facebook’s JavaScript view framework.</p>
<p><a target="_blank" href="https://facebook.github.io/react/"><strong><em>A JavaScript library for building user interfaces</em> - React</strong></a><br><a target="_blank" href="https://facebook.github.io/react/">A JavaScript library for building user interfacesfacebook.github.io</a></p>
<p>And Electron is GitHub’s framework for building cross-platform desktop apps in JavaScript.</p>
<p><a target="_blank" href="http://electron.atom.io/"><strong>Electron</strong></a><br><a target="_blank" href="http://electron.atom.io/">_Build cross platform desktop apps with JavaScript, HTML, and CSS._electron.atom.io</a></p>
<p>Most use <a target="_blank" href="https://webpack.github.io/">webpack</a> for the configuration necessary for React development. webpack is a configuration and build tool that most of the React community has adopted over alternatives like <a target="_blank" href="http://gulpjs.com/">Gulp</a> and <a target="_blank" href="http://gruntjs.com">Grunt</a>.</p>
<p>The configuration overhead varies (more on this later), and there are many boilerplate and application generators available, but in July 2016 <a target="_blank" href="https://github.com/facebookincubator">Facebook Incubator</a> released a tool, <a target="_blank" href="https://github.com/facebookincubator/create-react-app">create-react-app</a><em>.</em> It hides most of the configuration and lets the developer use simple commands, such as <code>npm start</code> and <code>npm run build</code> to run and build their apps.</p>
<h4 id="heading-what-is-ejecting-and-why-do-you-want-to-avoid-it">What is ejecting, and why do you want to avoid it?</h4>
<p>create-react-app makes certain assumptions about a typical React setup. If these assumptions aren’t for you, there is an option to <a target="_blank" href="https://github.com/facebookincubator/create-react-app#converting-to-a-custom-setup"><strong>eject</strong></a> an application (<code>npm run eject</code>). Ejecting an application copies all the encapsulated configuration of create-react-app to the your project, providing a boilerplate configuration that you can change as you wish.</p>
<p>But this is a <em>one way</em> trip. You can’t undo ejecting and go back. There have been 49 releases (as of this post) of create-react-app, each making improvements. But for an ejected application, you would have to either forgo these improvements or figure out how to apply them.</p>
<p>An ejected configuration is over 550 lines spanning 7 files (as of this post). I don’t understand it all (well, most of it, actually) and I don’t want to.</p>
<h4 id="heading-goals">Goals</h4>
<p>My goals are simple:</p>
<ul>
<li>avoid ejecting the React app</li>
<li>minimize glue to get React and Electron working together</li>
<li>preserve the defaults, assumptions and conventions made by Electron and create-react-app/React. (This can make it easier to use other tools that assume/require such conventions.)</li>
</ul>
<h4 id="heading-basic-recipe">Basic Recipe</h4>
<ol>
<li>run <code>create-react-app</code> to generate a basic React application</li>
<li>run <code>npm install --save-dev electron</code></li>
<li>add <code>main.js</code> from <code>[electron-quick-start](https://github.com/electron/electron-quick-start)</code> (we’ll rename it to <code>electron-starter.js</code>, for clarity)</li>
<li>modify call to <code>mainWindow.loadURL</code> (in <code>electron-starter.js</code>) to use <code>localhost:3000</code> (webpack-dev-server)</li>
<li>add a main entry to <code>package.json</code> for <code>electron-starter.js</code></li>
<li>add a run target to start Electron to <code>package.json</code></li>
<li><code>npm start</code> followed by <code>npm run electron</code></li>
</ol>
<p>Steps 1 and 2 are pretty straightforward. Here’s the code for steps 3 and 4:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> electron = <span class="hljs-built_in">require</span>(<span class="hljs-string">'electron'</span>);
<span class="hljs-comment">// Module to control application life.</span>
<span class="hljs-keyword">const</span> app = electron.app;
<span class="hljs-comment">// Module to create native browser window.</span>
<span class="hljs-keyword">const</span> BrowserWindow = electron.BrowserWindow;

<span class="hljs-keyword">const</span> path = <span class="hljs-built_in">require</span>(<span class="hljs-string">'path'</span>);
<span class="hljs-keyword">const</span> url = <span class="hljs-built_in">require</span>(<span class="hljs-string">'url'</span>);

<span class="hljs-comment">// Keep a global reference of the window object, if you don't, the window will</span>
<span class="hljs-comment">// be closed automatically when the JavaScript object is garbage collected.</span>
<span class="hljs-keyword">let</span> mainWindow;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createWindow</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// Create the browser window.</span>
    mainWindow = <span class="hljs-keyword">new</span> BrowserWindow({<span class="hljs-attr">width</span>: <span class="hljs-number">800</span>, <span class="hljs-attr">height</span>: <span class="hljs-number">600</span>});

    <span class="hljs-comment">// and load the index.html of the app.</span>
    mainWindow.loadURL(<span class="hljs-string">'http://localhost:3000'</span>);

    <span class="hljs-comment">// Open the DevTools.</span>
    mainWindow.webContents.openDevTools();

    <span class="hljs-comment">// Emitted when the window is closed.</span>
    mainWindow.on(<span class="hljs-string">'closed'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
        <span class="hljs-comment">// Dereference the window object, usually you would store windows</span>
        <span class="hljs-comment">// in an array if your app supports multi windows, this is the time</span>
        <span class="hljs-comment">// when you should delete the corresponding element.</span>
        mainWindow = <span class="hljs-literal">null</span>
    })
}

<span class="hljs-comment">// This method will be called when Electron has finished</span>
<span class="hljs-comment">// initialization and is ready to create browser windows.</span>
<span class="hljs-comment">// Some APIs can only be used after this event occurs.</span>
app.on(<span class="hljs-string">'ready'</span>, createWindow);

<span class="hljs-comment">// Quit when all windows are closed.</span>
app.on(<span class="hljs-string">'window-all-closed'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// On OS X it is common for applications and their menu bar</span>
    <span class="hljs-comment">// to stay active until the user quits explicitly with Cmd + Q</span>
    <span class="hljs-keyword">if</span> (process.platform !== <span class="hljs-string">'darwin'</span>) {
        app.quit()
    }
});

app.on(<span class="hljs-string">'activate'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// On OS X it's common to re-create a window in the app when the</span>
    <span class="hljs-comment">// dock icon is clicked and there are no other windows open.</span>
    <span class="hljs-keyword">if</span> (mainWindow === <span class="hljs-literal">null</span>) {
        createWindow()
    }
});

<span class="hljs-comment">// In this file you can include the rest of your app's specific main process</span>
<span class="hljs-comment">// code. You can also put them in separate files and require them here.</span>
</code></pre>
<p>(<a target="_blank" href="https://gist.github.com/csepulv/d4a97eaf9438cb4f7f102a1b2d075b93#file-electron-starter-js">Gist</a>)</p>
<p>And for steps 5 and 6:</p>
<pre><code class="lang-javascript">{
  <span class="hljs-string">"name"</span>: <span class="hljs-string">"electron-with-create-react-app"</span>,
  <span class="hljs-string">"version"</span>: <span class="hljs-string">"0.1.0"</span>,
  <span class="hljs-string">"private"</span>: <span class="hljs-literal">true</span>,
  <span class="hljs-string">"devDependencies"</span>: {
    <span class="hljs-string">"electron"</span>: <span class="hljs-string">"^1.4.14"</span>,
    <span class="hljs-string">"react-scripts"</span>: <span class="hljs-string">"0.8.5"</span>
  },
  <span class="hljs-string">"dependencies"</span>: {
    <span class="hljs-string">"react"</span>: <span class="hljs-string">"^15.4.2"</span>,
    <span class="hljs-string">"react-dom"</span>: <span class="hljs-string">"^15.4.2"</span>
  },
  <span class="hljs-string">"main"</span>: <span class="hljs-string">"src/electron-starter.js"</span>,
  <span class="hljs-string">"scripts"</span>: {
    <span class="hljs-string">"start"</span>: <span class="hljs-string">"react-scripts start"</span>,
    <span class="hljs-string">"build"</span>: <span class="hljs-string">"react-scripts build"</span>,
    <span class="hljs-string">"test"</span>: <span class="hljs-string">"react-scripts test --env=jsdom"</span>,
    <span class="hljs-string">"eject"</span>: <span class="hljs-string">"react-scripts eject"</span>,
    <span class="hljs-string">"electron"</span>: <span class="hljs-string">"electron ."</span>
  }
}
</code></pre>
<p>(<a target="_blank" href="https://gist.github.com/csepulv/d4a97eaf9438cb4f7f102a1b2d075b93#file-package-json">Gist</a>)</p>
<p>When you run the npm commands in step 7, you should see this:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/sJ4H86R1flN7pTYswhLYhoXMwBHTa9xe3XaX" alt="Image" width="600" height="375" loading="lazy"></p>
<p>You can make live changes to the React code and you should see them reflected in the running Electron app.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/FlDGGzcvBH1uEMNToEmmBz8uDDJDV6GpsLoD" alt="Image" width="600" height="376" loading="lazy"></p>
<p>This works okay for development, but has two shortcomings:</p>
<ul>
<li>production won’t use <code>webpack-dev-server</code>. It needs to use the static file from building the React project</li>
<li>(small) nuisance to run both npm commands</li>
</ul>
<h4 id="heading-specifying-the-loadurl-in-production-and-dev">Specifying the loadURL in Production and Dev</h4>
<p>In development, an environment variable can specify the url for <code>mainWindow.loadURL</code> (in <code>electron-starter.js</code>). If the env var exists, we’ll use it; else we’ll use the production static HTML file.</p>
<p>We’ll add a npm run target (to <code>package.json</code>) as follows:</p>
<pre><code><span class="hljs-string">"electron-dev"</span>: <span class="hljs-string">"ELECTRON_START_URL=http://localhost:3000 electron ."</span>
</code></pre><p>Update: Windows users will need to do the following: (thanks to <a target="_blank" href="http://twitter.com/bfarmilo">@bfarmilo</a>)</p>
<pre><code>”electron-dev”: <span class="hljs-string">"set ELECTRON_START_URL=http://localhost:3000 &amp;&amp; electron .”</span>
</code></pre><p>In <code>electron-starter.js</code>, we’ll modify the <code>mainWindow.loadURL</code> call as follows:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> startUrl = process.env.ELECTRON_START_URL || url.format({
            <span class="hljs-attr">pathname</span>: path.join(__dirname, <span class="hljs-string">'/../build/index.html'</span>),
            <span class="hljs-attr">protocol</span>: <span class="hljs-string">'file:'</span>,
            <span class="hljs-attr">slashes</span>: <span class="hljs-literal">true</span>
        });
    mainWindow.loadURL(startUrl);
</code></pre>
<p>(<a target="_blank" href="https://gist.github.com/csepulv/d4a97eaf9438cb4f7f102a1b2d075b93#file-electron-starter-use-env-var-js">Gist</a>)</p>
<p>There is a problem with this: <code>create-react-app</code> (by default) builds an <code>index.html</code> that uses absolute paths. This will fail when loading it in Electron. Thankfully, there is a config option to change this: set a <code>homepage</code> property in <code>package.json</code>. (Facebook documentation on the property is <a target="_blank" href="https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/template/README.md#building-for-relative-paths">here</a>.)</p>
<p>So we can set this property to the current directory and <code>npm run build</code> will use it as a relative path.</p>
<pre><code><span class="hljs-string">"homepage"</span>: <span class="hljs-string">"./"</span>,
</code></pre><h4 id="heading-using-foreman-to-manage-react-and-electron-processes">Using Foreman to Manage React and Electron Processes</h4>
<p>For convenience, I prefer to not</p>
<ol>
<li>launch/manage both React dev server and Electron processes (I’d rather deal with one)</li>
<li>wait for the React dev server to start and then launch Electron</li>
</ol>
<p><a target="_blank" href="https://github.com/strongloop/node-foreman">Foremen</a> is a good process management tool. We can add it,</p>
<pre><code>npm install --save-dev foreman
</code></pre><p>and add the following <code>Procfile</code></p>
<pre><code>react: npm startelectron: npm run electron
</code></pre><p>(<a target="_blank" href="https://gist.github.com/csepulv/d4a97eaf9438cb4f7f102a1b2d075b93#file-procfile-initial-js">Gist</a>)</p>
<p>That deals with (1). For (2), we can add a simple node script (<code>electron-wait-react.js</code>) that waits for the React dev server to start, then starts Electron.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> net = <span class="hljs-built_in">require</span>(<span class="hljs-string">'net'</span>);
<span class="hljs-keyword">const</span> port = process.env.PORT ? (process.env.PORT - <span class="hljs-number">100</span>) : <span class="hljs-number">3000</span>;

process.env.ELECTRON_START_URL = <span class="hljs-string">`http://localhost:<span class="hljs-subst">${port}</span>`</span>;

<span class="hljs-keyword">const</span> client = <span class="hljs-keyword">new</span> net.Socket();

<span class="hljs-keyword">let</span> startedElectron = <span class="hljs-literal">false</span>;
<span class="hljs-keyword">const</span> tryConnection = <span class="hljs-function">() =&gt;</span> client.connect({<span class="hljs-attr">port</span>: port}, <span class="hljs-function">() =&gt;</span> {
        client.end();
        <span class="hljs-keyword">if</span>(!startedElectron) {
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'starting electron'</span>);
            startedElectron = <span class="hljs-literal">true</span>;
            <span class="hljs-keyword">const</span> exec = <span class="hljs-built_in">require</span>(<span class="hljs-string">'child_process'</span>).exec;
            exec(<span class="hljs-string">'npm run electron'</span>);
        }
    }
);

tryConnection();

client.on(<span class="hljs-string">'error'</span>, <span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> {
    <span class="hljs-built_in">setTimeout</span>(tryConnection, <span class="hljs-number">1000</span>);
});
</code></pre>
<p>(<a target="_blank" href="https://gist.github.com/csepulv/d4a97eaf9438cb4f7f102a1b2d075b93#file-electron-wait-react-js">Gist</a>)</p>
<blockquote>
<p>NOTE: Foreman will offset the port number by 100 for processes of different types. (See <a target="_blank" href="https://github.com/strongloop/node-foreman#advanced-usage">here</a>.) So, <code>electron-wait-react.js</code> subtracts 100 to set the port number of the React dev server correctly.</p>
</blockquote>
<p>Now modify the <code>Procfile</code></p>
<pre><code>react: npm startelectron: node src/electron-wait-react
</code></pre><p>(<a target="_blank" href="https://gist.github.com/csepulv/d4a97eaf9438cb4f7f102a1b2d075b93#file-profile-final-js">Gist</a>)</p>
<p>Finally, we’ll change the run targets in <code>package.json</code> to replace <code>electron-dev</code> with:</p>
<pre><code><span class="hljs-string">"dev"</span> : <span class="hljs-string">"nf start"</span>
</code></pre><p>And now, we can execute:</p>
<pre><code>npm run dev
</code></pre><blockquote>
<p>UPDATE (1/25/17) : I‘ve added the following section in response to some user comments (<a target="_blank" href="https://medium.com/@luke_schmuke/hey-there-a84bcaf41f17#.szbo7b33n">here</a> and <a target="_blank" href="https://medium.com/@bfarmilo/hi-again-christian-f2601fb40e03#.5sj6cpnih">here</a>). They need access to Electron from within the react app and a simple require or import throws an error. I note one solution below.</p>
</blockquote>
<h4 id="heading-accessing-electron-from-the-react-app">Accessing Electron from the React App</h4>
<p>An Electron app has two main processes: the Electron host/wrapper and your app. In some cases, you’d like access to Electron from within your application. For example, you might want to access the local file system or use Electron’s <code>[ipcRenderer](http://electron.atom.io/docs/api/ipc-renderer/)</code>. But if you do the following, you’ll get an error</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> electron = <span class="hljs-built_in">require</span>(<span class="hljs-string">'electron'</span>)
<span class="hljs-comment">//or</span>
<span class="hljs-keyword">import</span> electron <span class="hljs-keyword">from</span> <span class="hljs-string">'electron'</span>;
</code></pre>
<p>There is some discussion about this error in various GitHub and Stack Overflow issues, such as this <a target="_blank" href="https://github.com/electron/electron/issues/7300">one</a>. Most solutions propose webpack config changes, but this would require ejecting the application.</p>
<p>However, there is a simple workaround/hack.</p>
<pre><code><span class="hljs-keyword">const</span> electron = <span class="hljs-built_in">window</span>.require(<span class="hljs-string">'electron'</span>);
</code></pre><pre><code class="lang-javascript"><span class="hljs-keyword">const</span> electron = <span class="hljs-built_in">window</span>.require(<span class="hljs-string">'electron'</span>);
<span class="hljs-keyword">const</span> fs = electron.remote.require(<span class="hljs-string">'fs'</span>);
<span class="hljs-keyword">const</span> ipcRenderer  = electron.ipcRenderer;
</code></pre>
<h4 id="heading-wrapping-up">Wrapping Up</h4>
<p>For convenience, here is a <a target="_blank" href="https://github.com/csepulv/electron-with-create-react-app">GitHub repo</a> that has all the changes above, with tags for each step. But, there it isn’t much work to bootstrap an Electron application that uses create-react-app. (This post is much longer than the code and changes you would need to integrate the two.)</p>
<p>And if you are using create-react-app, you might want to check out my post, <a target="_blank" href="https://medium.com/justideas-io/debugging-tests-in-webstorm-and-create-react-app-b38f389ae7c8#.4qb90t1f1">Debugging tests in WebStorm and create-react-app</a>.</p>
<p>Thanks for reading. You can check out more of my posts at <a target="_blank" href="https://justideas.io">justideas.io</a></p>
<blockquote>
<p>UPDATE (2/2/17). A reader, <a target="_blank" href="https://github.com/vcarl">Carl Vitullo</a>, suggested to use <code>npm start</code> instead of <code>npm run dev</code> and submitted a pull request with the changes, on GitHub. These tweaks are available in this <a target="_blank" href="https://github.com/csepulv/electron-with-create-react-app/tree/npm-start">branch</a>.</p>
</blockquote>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
