{"id":1390,"date":"2019-01-19T02:25:38","date_gmt":"2019-01-19T02:25:38","guid":{"rendered":"https:\/\/blog.hassler.ec\/wp\/?p=1390"},"modified":"2019-01-06T09:31:14","modified_gmt":"2019-01-06T09:31:14","slug":"how-to-easily-build-desktop-apps-with-html-css-and-javascript","status":"publish","type":"post","link":"https:\/\/blog.hassler.ec\/wp\/2019\/01\/19\/how-to-easily-build-desktop-apps-with-html-css-and-javascript\/","title":{"rendered":"How to Easily Build Desktop Apps with HTML, CSS and Javascript"},"content":{"rendered":"<figure id=\"5d03\" class=\"graf graf--figure graf-after--h3\">\n<div class=\"aspectRatioPlaceholder is-locked\">\n<div class=\"progressiveMedia js-progressiveMedia graf-image is-canvasLoaded is-imageLoaded\" data-image-id=\"0*mwIqsFZSbnweFQuv\" data-width=\"4272\" data-height=\"2848\" data-unsplash-photo-id=\"dPgPoiUIiXk\" data-is-featured=\"true\" data-action=\"zoom\" data-action-value=\"0*mwIqsFZSbnweFQuv\" data-scroll=\"native\"><img decoding=\"async\" class=\"progressiveMedia-image js-progressiveMedia-image\" src=\"https:\/\/cdn-images-1.medium.com\/max\/800\/0*mwIqsFZSbnweFQuv\" data-src=\"https:\/\/cdn-images-1.medium.com\/max\/800\/0*mwIqsFZSbnweFQuv\"><\/div>\n<\/div><figcaption class=\"imageCaption\">Photo by&nbsp;<a class=\"markup--anchor markup--figure-anchor\" href=\"https:\/\/unsplash.com\/@robinpierre?utm_source=medium&amp;utm_medium=referral\" target=\"_blank\" rel=\"photo-creator noopener\" data-href=\"https:\/\/unsplash.com\/@robinpierre?utm_source=medium&amp;utm_medium=referral\">Robin Pierre<\/a>&nbsp;on&nbsp;<a class=\"markup--anchor markup--figure-anchor\" href=\"https:\/\/unsplash.com\/?utm_source=medium&amp;utm_medium=referral\" target=\"_blank\" rel=\"photo-source noopener\" data-href=\"https:\/\/unsplash.com?utm_source=medium&amp;utm_medium=referral\">Unsplash<\/a><\/figcaption><\/figure>\n<p id=\"f5f1\" class=\"graf graf--p graf-after--figure\">Can HTML, CSS and Javascript really be used to build Desktop Applications?<\/p>\n<p id=\"6a2e\" class=\"graf graf--p graf-after--p\">The answer is yes. ?<\/p>\n<p id=\"40ec\" class=\"graf graf--p graf-after--p\">In this Article we will be focussing mainly on how Electron can be used to create desktop applications with Web Technologies like HTML, CSS and Javascript.<\/p>\n<h3 id=\"4904\" class=\"graf graf--h3 graf-after--p\">Electron<\/h3>\n<p id=\"84a4\" class=\"graf graf--p graf-after--h3\"><a class=\"markup--anchor markup--p-anchor\" href=\"https:\/\/electronjs.org\/\" target=\"_blank\" rel=\"noopener\" data-href=\"https:\/\/electronjs.org\/\">Electron<\/a>&nbsp;can be used to build Desktop Apps with HTML, CSS and Javascript. Also these apps work for multiple platforms like Windows, Mac, Linux and so on.<\/p>\n<p id=\"844b\" class=\"graf graf--p graf-after--p\">Electron combines Chromium and NodeJS into a single runtime. This enables us to run the HTML, CSS and Javascript code as a desktop application.<\/p>\n<h3 id=\"e801\" class=\"graf graf--h3 graf-after--p\">Electron Forge<\/h3>\n<p id=\"54c3\" class=\"graf graf--p graf-after--h3\">If Electron is used directly, then some manual setup is needed before building your application. Also if you want to use Angular, React, Vue or any other framework or library, you will need to manually configure for that.<\/p>\n<p id=\"e1b6\" class=\"graf graf--p graf-after--p\"><a class=\"markup--anchor markup--p-anchor\" href=\"https:\/\/electronforge.io\/\" target=\"_blank\" rel=\"noopener\" data-href=\"https:\/\/electronforge.io\/\">Electron Forge<\/a>&nbsp;makes the above things much easier.<\/p>\n<p id=\"4ecc\" class=\"graf graf--p graf-after--p\">It provides template applications with Angular, React, Vue and other frameworks which avoids the extra manual setups.<\/p>\n<p id=\"ae12\" class=\"graf graf--p graf-after--p\">Also it provides an easy way to build and package the application. It also provides many other features which can be found in their&nbsp;<a class=\"markup--anchor markup--p-anchor\" href=\"https:\/\/docs.electronforge.io\/\" target=\"_blank\" rel=\"noopener\" data-href=\"https:\/\/docs.electronforge.io\/\">documenation<\/a>.<\/p>\n<h3 id=\"e371\" class=\"graf graf--h3 graf-after--p\">Pre-requisites<\/h3>\n<p id=\"ce87\" class=\"graf graf--p graf-after--h3\">Ensure you have NodeJS installed. It can be installed from&nbsp;<a class=\"markup--anchor markup--p-anchor\" href=\"https:\/\/nodejs.org\/en\/\" target=\"_blank\" rel=\"noopener\" data-href=\"https:\/\/nodejs.org\/en\/\">here<\/a>.<\/p>\n<p id=\"96ce\" class=\"graf graf--p graf-after--p\">Install Electron Forge globally using the following command:<\/p>\n<pre id=\"d21f\" class=\"graf graf--pre graf-after--p\"><code class=\"markup--code markup--pre-code\">npm install -g electron-forge<\/code><\/pre>\n<h3 id=\"3290\" class=\"graf graf--h3 graf-after--pre\">Let\u2019s get started with the application<\/h3>\n<p id=\"101a\" class=\"graf graf--p graf-after--h3\">Use the following command to create your application:<\/p>\n<pre id=\"2761\" class=\"graf graf--pre graf-after--p\"><code class=\"markup--code markup--pre-code\">electron-forge init simple-desktop-app-electronjs<\/code><\/pre>\n<p id=\"6346\" class=\"graf graf--p graf-after--pre\"><strong class=\"markup--strong markup--p-strong\">simple-desktop-app-electronjs<\/strong>&nbsp;is the name of the application.<\/p>\n<p id=\"3ed8\" class=\"graf graf--p graf-after--p\">The above command will take some time to run.<\/p>\n<p id=\"f174\" class=\"graf graf--p graf-after--p\">Once it finishes running, start the application using the following commands:<\/p>\n<pre id=\"35f1\" class=\"graf graf--pre graf-after--p\"><code class=\"markup--code markup--pre-code\">cd simple-desktop-app-electronjs\nnpm start<\/code><\/pre>\n<p id=\"6d3e\" class=\"graf graf--p graf-after--pre\">This should open up a window like the one shown below:<\/p>\n<figure id=\"3bdf\" class=\"graf graf--figure graf-after--p\">\n<div class=\"aspectRatioPlaceholder is-locked\">\n<div class=\"aspectRatioPlaceholder-fill\"><\/div>\n<div class=\"progressiveMedia js-progressiveMedia graf-image is-canvasLoaded is-imageLoaded\" data-image-id=\"0*0GItlhn34oza9bq8.jpg\" data-width=\"756\" data-height=\"380\" data-action=\"zoom\" data-action-value=\"0*0GItlhn34oza9bq8.jpg\" data-scroll=\"native\"><canvas class=\"progressiveMedia-canvas js-progressiveMedia-canvas\" width=\"75\" height=\"37\"><\/canvas><img decoding=\"async\" class=\"progressiveMedia-image js-progressiveMedia-image\" src=\"https:\/\/cdn-images-1.medium.com\/max\/800\/0*0GItlhn34oza9bq8.jpg\" data-src=\"https:\/\/cdn-images-1.medium.com\/max\/800\/0*0GItlhn34oza9bq8.jpg\"><\/div>\n<\/div>\n<\/figure>\n<h3 id=\"880d\" class=\"graf graf--h3 graf-after--figure\">Understanding the Existing Folder Structure and&nbsp;Code<\/h3>\n<p id=\"526f\" class=\"graf graf--p graf-after--h3\">The application has a particular folder structure. Here I will be mentioning some of the important things in this folder structure.<\/p>\n<h4 id=\"8122\" class=\"graf graf--h4 graf-after--p\">package.json<\/h4>\n<p id=\"ceb1\" class=\"graf graf--p graf-after--h4\">It has information about the application you are creating, all the dependencies needed for the app, and some scripts. Some of the scripts are already pre configured, and you can add new scripts as well.<\/p>\n<p id=\"8f80\" class=\"graf graf--p graf-after--p\">The&nbsp;<strong class=\"markup--strong markup--p-strong\">config.forge<\/strong>&nbsp;path has all the configurations which are specific to ElectronJS. For example&nbsp;<strong class=\"markup--strong markup--p-strong\">make-targets<\/strong>&nbsp;is used to specify the target make files for various platforms like Windows, Mac or Linux.<\/p>\n<p id=\"57c7\" class=\"graf graf--p graf-after--p\">Also package.json has&nbsp;<code class=\"markup--code markup--p-code\">\"main\": \"src\/index.js\"<\/code>&nbsp;which indicates that src\/index.js is the starting point of the application<\/p>\n<h4 id=\"7714\" class=\"graf graf--h4 graf-after--p\">src\/index.js<\/h4>\n<p id=\"049f\" class=\"graf graf--p graf-after--h4\">According to package.json,&nbsp;<strong class=\"markup--strong markup--p-strong\">index.js<\/strong>&nbsp;is the main script. The process which runs the main script is known as the&nbsp;<strong class=\"markup--strong markup--p-strong\">main process<\/strong>. So the main process runs the index.js script.<\/p>\n<p id=\"ff5e\" class=\"graf graf--p graf-after--p\">The main process is used to display GUI elements. It does this by creating web pages.<\/p>\n<p id=\"5596\" class=\"graf graf--p graf-after--p\">Each web page created runs in a process called the&nbsp;<strong class=\"markup--strong markup--p-strong\">renderer process.<\/strong><\/p>\n<h4 id=\"5718\" class=\"graf graf--h4 graf-after--p\">Main process and renderer&nbsp;process<\/h4>\n<p id=\"f8d9\" class=\"graf graf--p graf-after--h4\">The purpose of the&nbsp;<strong class=\"markup--strong markup--p-strong\">main process<\/strong>&nbsp;is to create web pages using a&nbsp;<code class=\"markup--code markup--p-code\">BrowserWindow<\/code>&nbsp;Instance.<\/p>\n<p id=\"b2f9\" class=\"graf graf--p graf-after--p\">The&nbsp;<code class=\"markup--code markup--p-code\">BrowserWindow<\/code>&nbsp;Instance uses a&nbsp;<strong class=\"markup--strong markup--p-strong\">renderer process<\/strong>&nbsp;to run each web page.<\/p>\n<p id=\"17ba\" class=\"graf graf--p graf-after--p\"><strong class=\"markup--strong markup--p-strong\">Each app can have only one main process but can have many renderer processes.<\/strong><\/p>\n<p id=\"a95e\" class=\"graf graf--p graf-after--p\">It is possible to communicate between the main and the renderer process as well. This, however, will not be covered in this article.<\/p>\n<figure id=\"2fc0\" class=\"graf graf--figure graf-after--p\">\n<div class=\"aspectRatioPlaceholder is-locked\">\n<div class=\"aspectRatioPlaceholder-fill\"><\/div>\n<div class=\"progressiveMedia js-progressiveMedia graf-image is-canvasLoaded is-imageLoaded\" data-image-id=\"0*_KAbfHP3uc1f21bf.jpg\" data-width=\"848\" data-height=\"498\" data-action=\"zoom\" data-action-value=\"0*_KAbfHP3uc1f21bf.jpg\" data-scroll=\"native\"><canvas class=\"progressiveMedia-canvas js-progressiveMedia-canvas\" width=\"75\" height=\"42\"><\/canvas><img decoding=\"async\" class=\"progressiveMedia-image js-progressiveMedia-image\" src=\"https:\/\/cdn-images-1.medium.com\/max\/800\/0*_KAbfHP3uc1f21bf.jpg\" data-src=\"https:\/\/cdn-images-1.medium.com\/max\/800\/0*_KAbfHP3uc1f21bf.jpg\"><\/div>\n<\/div><figcaption class=\"imageCaption\"><em class=\"markup--em markup--figure-em\">Electron Architecture showing main and renderer process. The file names can&nbsp;vary.<\/em><\/figcaption><\/figure>\n<p id=\"ea1d\" class=\"graf graf--p graf-after--figure\"><strong class=\"markup--strong markup--p-strong\">abcd.html<\/strong>&nbsp;is shown as a second webpage in the above architecture. But in our code we won\u2019t be having a second web page.<\/p>\n<h4 id=\"284c\" class=\"graf graf--h4 graf-after--p\">src\/index.html<\/h4>\n<p id=\"47b1\" class=\"graf graf--p graf-after--h4\">index.js loads the index.html file into a new BrowerWindow Instance.<\/p>\n<p id=\"1309\" class=\"graf graf--p graf-after--p\">What this basically means is that index.js creates a new GUI Window, and loads it with index.html web page. The index.html web page runs in its own renderer process.<\/p>\n<h4 id=\"e21c\" class=\"graf graf--h4 graf-after--p\">Code in index.js explained<\/h4>\n<p id=\"fd25\" class=\"graf graf--p graf-after--h4\">Most of the code created in index.js has good comments explaining what it does. Here I will mention a few key points to note in index.js:<\/p>\n<pre id=\"2132\" class=\"graf graf--pre graf-after--p\"><code class=\"markup--code markup--pre-code u-paddingRight0 u-marginRight0\">mainWindow <strong class=\"markup--strong markup--pre-strong\">=<\/strong> <strong class=\"markup--strong markup--pre-strong\">new<\/strong> BrowserWindow({\n    width: 800,\n    height: 600,\n  });\n\n  <em class=\"markup--em markup--pre-em\">\/\/ and load the index.html of the app.<\/em>\n  mainWindow.loadURL(`file:\/\/${__dirname}\/index.html`);<\/code><\/pre>\n<p id=\"6afb\" class=\"graf graf--p graf-after--pre\">The above code snippet basically creates a&nbsp;<strong class=\"markup--strong markup--p-strong\">BrowserWindow<\/strong>&nbsp;Instance and loads&nbsp;<strong class=\"markup--strong markup--p-strong\">index.html<\/strong>&nbsp;into the BrowserWindow.<\/p>\n<p id=\"6e29\" class=\"graf graf--p graf-after--p\">You will see&nbsp;<strong class=\"markup--strong markup--p-strong\">app<\/strong>&nbsp;used often in the code. For example take the below code snippet:<\/p>\n<pre id=\"494e\" class=\"graf graf--pre graf-after--p\"><code class=\"markup--code markup--pre-code\">app.on('ready', createWindow);<\/code><\/pre>\n<p id=\"8ba6\" class=\"graf graf--p graf-after--pre\"><strong class=\"markup--strong markup--p-strong\">app<\/strong>&nbsp;is used to control the application\u2019s event life cycle.<\/p>\n<p id=\"0519\" class=\"graf graf--p graf-after--p\">The above code snippet says that when the application is ready, load the first window.<\/p>\n<p id=\"1297\" class=\"graf graf--p graf-after--p\">Similarly,&nbsp;<strong class=\"markup--strong markup--p-strong\">app<\/strong>&nbsp;can be used to perform other actions on various events. For example it can be used to perform some action right before the application closes and so on.<\/p>\n<h3 id=\"6901\" class=\"graf graf--h3 graf-after--p\">Let\u2019s create a Temperature Converter Desktop Application<\/h3>\n<p id=\"885a\" class=\"graf graf--p graf-after--h3\">Let us use the same application we used before and modify it slightly to create a temperature converter application.<\/p>\n<p id=\"47ce\" class=\"graf graf--p graf-after--p\">First let us install Bootstrap with the following command:<\/p>\n<pre id=\"15ca\" class=\"graf graf--pre graf-after--p\"><code class=\"markup--code markup--pre-code\">npm install bootstrap --save<\/code><\/pre>\n<p id=\"5507\" class=\"graf graf--p graf-after--pre\">Copy the following code into src\/index.html:<\/p>\n<pre id=\"82fc\" class=\"graf graf--pre graf-after--p\"><code class=\"markup--code markup--pre-code u-paddingRight0 u-marginRight0\"><strong class=\"markup--strong markup--pre-strong\">&lt;!DOCTYPE html&gt;<\/strong>\n&lt;html&gt;\n  &lt;head&gt;\n    &lt;meta charset=\"utf-8\"&gt;\n    &lt;title&gt;Temperature Converter&lt;\/title&gt;\n    &lt;link rel=\"stylesheet\" type=\"text\/css\" href=\"..\/node_modules\/bootstrap\/dist\/css\/bootstrap.min.css\"&gt;\n\n  &lt;\/head&gt;\n  &lt;body&gt;\n    &lt;h1&gt;Temperature Converter&lt;\/h1&gt;\n    &lt;div class=\"form-group col-md-3\"&gt;\n      &lt;label for=\"usr\"&gt;Celcius:&lt;\/label&gt;\n      &lt;input type=\"text\" class=\"form-control\" id=\"celcius\" onkeyup=\"celciusToFahrenheit()\"&gt;\n    &lt;\/div&gt;\n    &lt;div class=\"form-group col-md-3\"&gt;\n      &lt;label for=\"pwd\"&gt;Fahrenheit:&lt;\/label&gt;\n      &lt;input type=\"text\" class=\"form-control\" id=\"fahrenheit\" onkeyup=\"fahrenheitToCelcius()\"&gt;\n    &lt;\/div&gt;\n    &lt;script src='.\/renderer.js'&gt;&lt;\/script&gt;\n  &lt;\/body&gt;\n  &lt;\/body&gt;\n&lt;\/html&gt;<\/code><\/pre>\n<p id=\"a65e\" class=\"graf graf--p graf-after--pre\">The above code does the following:<\/p>\n<ol class=\"postList\">\n<li id=\"7531\" class=\"graf graf--li graf-after--p\">Creates a text box with id&nbsp;<strong class=\"markup--strong markup--li-strong\">Celcius<\/strong>. Whenever anything is typed in this textbox, the&nbsp;<strong class=\"markup--strong markup--li-strong\">celciusToFahrenheit()<\/strong>&nbsp;function is called.<\/li>\n<li id=\"42ea\" class=\"graf graf--li graf-after--li\">Creates a text box with id&nbsp;<strong class=\"markup--strong markup--li-strong\">Fahrenheit<\/strong>. Whenever anything is typed in this textbox, the&nbsp;<strong class=\"markup--strong markup--li-strong\">fahrenheitToCelcius()<\/strong>&nbsp;function is called.<\/li>\n<li id=\"22d3\" class=\"graf graf--li graf-after--li\">Whenever a new value is typed in the Celcius text box, the value in the Fahrenheit text box displays the same temperature in Fahrenheit<\/li>\n<li id=\"6751\" class=\"graf graf--li graf-after--li\">Whenever a new value is typed in the Fahrenheit text box, the value in the Celcius text box displays the same temperature in Celcius<\/li>\n<\/ol>\n<p id=\"2b4f\" class=\"graf graf--p graf-after--li\">The 2 functions which do the temperature conversion are present in&nbsp;<strong class=\"markup--strong markup--p-strong\">renderer.js.<\/strong><\/p>\n<p id=\"fff2\" class=\"graf graf--p graf-after--p\">Create a file called&nbsp;<strong class=\"markup--strong markup--p-strong\">renderer.js<\/strong>&nbsp;inside&nbsp;<strong class=\"markup--strong markup--p-strong\">src<\/strong>. Copy the following code into it:<\/p>\n<pre id=\"7274\" class=\"graf graf--pre graf-after--p\"><code class=\"markup--code markup--pre-code u-paddingRight0 u-marginRight0\"><strong class=\"markup--strong markup--pre-strong\">function<\/strong> celciusToFahrenheit(){\n    <strong class=\"markup--strong markup--pre-strong\">let<\/strong> celcius <strong class=\"markup--strong markup--pre-strong\">=<\/strong> document.getElementById('celcius').value;\n    <strong class=\"markup--strong markup--pre-strong\">let<\/strong> fahrenheit <strong class=\"markup--strong markup--pre-strong\">=<\/strong> (celcius<strong class=\"markup--strong markup--pre-strong\">*<\/strong> 9<strong class=\"markup--strong markup--pre-strong\">\/<\/strong>5) <strong class=\"markup--strong markup--pre-strong\">+<\/strong> 32;\n    document.getElementById('fahrenheit').value <strong class=\"markup--strong markup--pre-strong\">=<\/strong> fahrenheit;\n\n}\n\n<strong class=\"markup--strong markup--pre-strong\">function<\/strong> fahrenheitToCelcius(){\n    <strong class=\"markup--strong markup--pre-strong\">let<\/strong> fahrenheit <strong class=\"markup--strong markup--pre-strong\">=<\/strong> document.getElementById('fahrenheit').value;\n    <strong class=\"markup--strong markup--pre-strong\">let<\/strong> celcius <strong class=\"markup--strong markup--pre-strong\">=<\/strong> (fahrenheit <strong class=\"markup--strong markup--pre-strong\">-<\/strong> 32) <strong class=\"markup--strong markup--pre-strong\">*<\/strong> 5<strong class=\"markup--strong markup--pre-strong\">\/<\/strong>9\n    document.getElementById('celcius').value <strong class=\"markup--strong markup--pre-strong\">=<\/strong> celcius;\n}<\/code><\/pre>\n<p id=\"7b52\" class=\"graf graf--p graf-after--pre\">The<strong class=\"markup--strong markup--p-strong\">&nbsp;celciusToFahrenheit()<\/strong>&nbsp;function reads the value in the&nbsp;<strong class=\"markup--strong markup--p-strong\">Celcius<\/strong>&nbsp;text box, converts it to Fahrenheit, and writes the new temperature into the&nbsp;<strong class=\"markup--strong markup--p-strong\">Fahrenheit<\/strong>text box.<\/p>\n<p id=\"17ef\" class=\"graf graf--p graf-after--p\">The<strong class=\"markup--strong markup--p-strong\">&nbsp;fahrenheitToCelcius()<\/strong>&nbsp;function does the exact opposite of this.<\/p>\n<h3 id=\"dcbd\" class=\"graf graf--h3 graf-after--p\">Running the application<\/h3>\n<p id=\"5334\" class=\"graf graf--p graf-after--h3\">Run the application using the following command:<\/p>\n<pre id=\"1a9f\" class=\"graf graf--pre graf-after--p\"><code class=\"markup--code markup--pre-code\">npm start<\/code><\/pre>\n<p id=\"5831\" class=\"graf graf--p graf-after--pre\">This should display the following window. Try it out with different values.<\/p>\n<figure id=\"094e\" class=\"graf graf--figure graf-after--p\">\n<div class=\"aspectRatioPlaceholder is-locked\">\n<div class=\"aspectRatioPlaceholder-fill\"><\/div>\n<div class=\"progressiveMedia js-progressiveMedia graf-image is-canvasLoaded is-imageLoaded\" data-image-id=\"0*YRm0cLilFtYLE2Q0.jpg\" data-width=\"593\" data-height=\"335\" data-scroll=\"native\"><canvas class=\"progressiveMedia-canvas js-progressiveMedia-canvas\" width=\"75\" height=\"40\"><\/canvas><img decoding=\"async\" class=\"progressiveMedia-image js-progressiveMedia-image\" src=\"https:\/\/cdn-images-1.medium.com\/max\/800\/0*YRm0cLilFtYLE2Q0.jpg\" data-src=\"https:\/\/cdn-images-1.medium.com\/max\/800\/0*YRm0cLilFtYLE2Q0.jpg\"><\/div>\n<\/div>\n<\/figure>\n<h3 id=\"8eaa\" class=\"graf graf--h3 graf-after--figure\">Packaging the application<\/h3>\n<p id=\"23ea\" class=\"graf graf--p graf-after--h3\">The command to package the application is:<\/p>\n<pre id=\"71f6\" class=\"graf graf--pre graf-after--p\"><code class=\"markup--code markup--pre-code\">npm run package<\/code><\/pre>\n<p id=\"7099\" class=\"graf graf--p graf-after--pre\">This command will take some time to run. Once it finishes check the&nbsp;<strong class=\"markup--strong markup--p-strong\">out<\/strong>folder within the project folder.<\/p>\n<p id=\"13c9\" class=\"graf graf--p graf-after--p\">I tested this in a Windows machine. This creates a folder called&nbsp;<strong class=\"markup--strong markup--p-strong\">simple-desktop-app-electronjs-win32-x64<\/strong>&nbsp;inside the&nbsp;<strong class=\"markup--strong markup--p-strong\">out<\/strong>&nbsp;folder<\/p>\n<p id=\"86e5\" class=\"graf graf--p graf-after--p\">So in the&nbsp;<strong class=\"markup--strong markup--p-strong\">out\/simple-desktop-app-electronjs-win32-x64<\/strong>&nbsp;folder, the command creates an&nbsp;<strong class=\"markup--strong markup--p-strong\">.exe<\/strong>&nbsp;file for this application. Clicking on the exe file automatically starts the desktop application.<\/p>\n<p id=\"d313\" class=\"graf graf--p graf-after--p\">The folder name&nbsp;<strong class=\"markup--strong markup--p-strong\">simple-desktop-app-electronjs-win32-x64<\/strong>&nbsp;can be broken down as&nbsp;<strong class=\"markup--strong markup--p-strong\">appname-platform-architecture<\/strong>&nbsp;where<\/p>\n<ul class=\"postList\">\n<li id=\"22f5\" class=\"graf graf--li graf-after--p\">appname = simple-desktop-app-electronjs<\/li>\n<li id=\"b158\" class=\"graf graf--li graf-after--li\">platform = win32<\/li>\n<li id=\"0416\" class=\"graf graf--li graf-after--li\">architecture = x64<\/li>\n<\/ul>\n<p id=\"4d7a\" class=\"graf graf--p graf-after--li\"><strong class=\"markup--strong markup--p-strong\">When you run this command without any parameters, by default it packages for the platform which you are using for development.<\/strong><\/p>\n<p id=\"591b\" class=\"graf graf--p graf-after--p\">Let\u2019s say you want to package for a different platform and architecture. Then you can use the following syntax:<\/p>\n<pre id=\"7f85\" class=\"graf graf--pre graf-after--p\"><code class=\"markup--code markup--pre-code\">npm run package -- --platform=&lt;platform&gt; arch=&lt;architecture&gt;<\/code><\/pre>\n<p id=\"6b9f\" class=\"graf graf--p graf-after--pre\">For example, in order to package for linux you can use the following command:<\/p>\n<pre id=\"60cd\" class=\"graf graf--pre graf-after--p\"><code class=\"markup--code markup--pre-code u-paddingRight0 u-marginRight0\">npm run package -- --platform<strong class=\"markup--strong markup--pre-strong\">=<\/strong>linux --arch<strong class=\"markup--strong markup--pre-strong\">=<\/strong>x64<\/code><\/pre>\n<p id=\"0c6b\" class=\"graf graf--p graf-after--pre\">This will create a folder called&nbsp;<strong class=\"markup--strong markup--p-strong\">simple-desktop-app-electronjs-linux-x64<\/strong>inside the&nbsp;<strong class=\"markup--strong markup--p-strong\">out<\/strong>&nbsp;folder.<\/p>\n<h3 id=\"ea09\" class=\"graf graf--h3 graf-after--p\">Creating a make&nbsp;File<\/h3>\n<p id=\"5792\" class=\"graf graf--p graf-after--h3\">In order to create a make file or an installer for the application, use the following command:<\/p>\n<pre id=\"7c40\" class=\"graf graf--pre graf-after--p\">npm run make<\/pre>\n<p id=\"c796\" class=\"graf graf--p graf-after--pre\">This command will take some time to run. Once it finishes check the&nbsp;<strong class=\"markup--strong markup--p-strong\">out<\/strong>folder within the project folder.<\/p>\n<p id=\"3f92\" class=\"graf graf--p graf-after--p\">The&nbsp;<strong class=\"markup--strong markup--p-strong\">out\/make<\/strong>&nbsp;folder will have a Windows installer for the desktop application.<\/p>\n<p id=\"ef01\" class=\"graf graf--p graf-after--p\"><strong class=\"markup--strong markup--p-strong\">When you run this command without any parameters, by default it creates the installer for the platform which you are using for development.<\/strong><\/p>\n<h3 id=\"2e85\" class=\"graf graf--h3 graf-after--p\">Code<\/h3>\n<p id=\"ec7b\" class=\"graf graf--p graf-after--h3\">The code for this desktop application is available in my GitHub repo:<\/p>\n<p id=\"0aaf\" class=\"graf graf--p graf-after--p\"><a class=\"markup--anchor markup--p-anchor\" href=\"https:\/\/github.com\/aditya-sridhar\/simple-desktop-app-electronjs\" target=\"_blank\" rel=\"noopener\" data-href=\"https:\/\/github.com\/aditya-sridhar\/simple-desktop-app-electronjs\">https:\/\/github.com\/aditya-sridhar\/simple-desktop-app-electronjs<\/a><\/p>\n<h3 id=\"aefc\" class=\"graf graf--h3 graf-after--p\">Congrats ?<\/h3>\n<p id=\"38b8\" class=\"graf graf--p graf-after--h3\">You now know how to create desktop applications using HTML, CSS and Javascript.<\/p>\n<p id=\"527f\" class=\"graf graf--p graf-after--p\">This article covered very basic concepts of Electron and Electron-Forge.<\/p>\n<p id=\"02fc\" class=\"graf graf--p graf-after--p\">To know more about them, you can check out their documentation.<\/p>\n<h3 id=\"fd70\" class=\"graf graf--h3 graf-after--p\">About the&nbsp;author<\/h3>\n<p id=\"8f94\" class=\"graf graf--p graf-after--h3\">I love technology and follow the advancements in the field. I also like helping others with my technology knowledge.<\/p>\n<p id=\"9779\" class=\"graf graf--p graf-after--p\">Feel free to connect with me on my LinkedIn account&nbsp;<a class=\"markup--anchor markup--p-anchor\" href=\"https:\/\/www.linkedin.com\/in\/aditya1811\/\" target=\"_blank\" rel=\"nofollow noopener noopener noopener noopener noopener noopener noopener noopener noopener noopener\" data-href=\"https:\/\/www.linkedin.com\/in\/aditya1811\/\">https:\/\/www.linkedin.com\/in\/aditya1811\/<\/a><\/p>\n<p id=\"f09e\" class=\"graf graf--p graf-after--p\">You can also follow me on twitter&nbsp;<a class=\"markup--anchor markup--p-anchor\" href=\"https:\/\/twitter.com\/adityasridhar18\" target=\"_blank\" rel=\"nofollow noopener noopener noopener noopener noopener noopener noopener noopener\" data-href=\"https:\/\/twitter.com\/adityasridhar18\">https:\/\/twitter.com\/adityasridhar18<\/a><\/p>\n<p id=\"6d2b\" class=\"graf graf--p graf-after--p graf--trailing\">My Website:&nbsp;<a class=\"markup--anchor markup--p-anchor\" href=\"https:\/\/adityasridhar.com\/\" target=\"_blank\" rel=\"nofollow noopener noopener noopener noopener noopener noopener noopener\" data-href=\"https:\/\/adityasridhar.com\/\">https:\/\/adityasridhar.com\/<\/a><\/p>\n<p>&nbsp;<\/p>\n<p>Source:<strong>&nbsp;<a href=\"https:\/\/medium.freecodecamp.org\/how-to-easily-build-desktop-apps-with-html-css-and-javascript-d3e3f03f95a5\">https:\/\/medium.freecodecamp.org\/how-to-easily-build-desktop-apps-with-html-css-and-javascript-d3e3f03f95a5<\/a><\/strong><\/p>\n<p><strong>Written by<\/strong><\/p>\n<div class=\"u-tableCell\"><a class=\"link u-baseColor--link avatar\" dir=\"auto\" title=\"Go to the profile of Aditya Sridhar\" href=\"https:\/\/medium.freecodecamp.org\/@aditya_sridhar?source=footer_card\" aria-label=\"Go to the profile of Aditya Sridhar\" data-action-source=\"footer_card\" data-user-id=\"40655dbea7f6\" data-collection-slug=\"free-code-camp\"><img decoding=\"async\" class=\"avatar-image avatar-image--small alignleft\" src=\"https:\/\/cdn-images-1.medium.com\/fit\/c\/60\/60\/1*VhljkaK2UHL3MU9dDdTyag.jpeg\" alt=\"Go to the profile of Aditya Sridhar\"><\/a><\/div>\n<div class=\"u-tableCell u-verticalAlignMiddle u-breakWord u-paddingLeft15\">\n<h3 class=\"ui-h3 u-fontSize18 u-lineHeightTighter u-marginBottom4\"><a class=\"link link--primary u-accentColor--hoverTextNormal\" dir=\"auto\" title=\"Go to the profile of Aditya Sridhar\" href=\"https:\/\/medium.freecodecamp.org\/@aditya_sridhar\" rel=\"author cc:attributionUrl\" aria-label=\"Go to the profile of Aditya Sridhar\" data-user-id=\"40655dbea7f6\" data-collection-slug=\"free-code-camp\">Aditya Sridhar<\/a><\/h3>\n<p class=\"ui-body u-fontSize14 u-lineHeightBaseSans u-textColorDark u-marginBottom4\">I love Technology and Like to Help Others with any knowledge that I have. My Website:&nbsp;<a href=\"https:\/\/adityasridhar.com\/\" rel=\"nofollow\">https:\/\/adityasridhar.com\/<\/a><\/p>\n<\/div>\n<p>&nbsp;<\/p>\n<div class=\"u-tableCell \"><a class=\"link u-baseColor--link avatar avatar--roundedRectangle\" title=\"Go to freeCodeCamp.org\" href=\"https:\/\/medium.freecodecamp.org\/?source=footer_card\" aria-label=\"Go to freeCodeCamp.org\" data-action-source=\"footer_card\" data-collection-slug=\"free-code-camp\"><img decoding=\"async\" class=\"avatar-image u-size60x60 alignleft\" src=\"https:\/\/cdn-images-1.medium.com\/fit\/c\/60\/60\/1*MotlWcSa2n6FrOx3ul89kw.png\" alt=\"freeCodeCamp.org\"><\/a><\/div>\n<div class=\"u-tableCell u-verticalAlignMiddle u-breakWord u-paddingLeft15\">\n<h3 class=\"ui-h3 u-fontSize18 u-lineHeightTighter u-marginBottom4\"><a class=\"link link--primary u-accentColor--hoverTextNormal\" href=\"https:\/\/medium.freecodecamp.org\/?source=footer_card\" rel=\"collection\" data-action-source=\"footer_card\" data-collection-slug=\"free-code-camp\">freeCodeCamp.org<\/a><\/h3>\n<p class=\"ui-body u-fontSize14 u-lineHeightBaseSans u-textColorDark u-marginBottom4\">Stories worth reading about programming and technology from our open source community.<\/p>\n<\/div>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Photo by&nbsp;Robin Pierre&nbsp;on&nbsp;Unsplash Can HTML, CSS and Javascript really be used to build Desktop Applications? The answer is yes. ? [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":1392,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[12,50,138,48,119,118,44,29,115,116],"tags":[],"class_list":["post-1390","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-bloghassler-ec","category-css","category-electron","category-front-end","category-html","category-internet","category-javascript","category-programacion","category-progresisive-web-apps","category-pwa"],"_links":{"self":[{"href":"https:\/\/blog.hassler.ec\/wp\/wp-json\/wp\/v2\/posts\/1390","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.hassler.ec\/wp\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.hassler.ec\/wp\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.hassler.ec\/wp\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.hassler.ec\/wp\/wp-json\/wp\/v2\/comments?post=1390"}],"version-history":[{"count":2,"href":"https:\/\/blog.hassler.ec\/wp\/wp-json\/wp\/v2\/posts\/1390\/revisions"}],"predecessor-version":[{"id":1394,"href":"https:\/\/blog.hassler.ec\/wp\/wp-json\/wp\/v2\/posts\/1390\/revisions\/1394"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.hassler.ec\/wp\/wp-json\/wp\/v2\/media\/1392"}],"wp:attachment":[{"href":"https:\/\/blog.hassler.ec\/wp\/wp-json\/wp\/v2\/media?parent=1390"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.hassler.ec\/wp\/wp-json\/wp\/v2\/categories?post=1390"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.hassler.ec\/wp\/wp-json\/wp\/v2\/tags?post=1390"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}