{"@attributes":{"version":"2.0"},"channel":{"title":"Radomir Sohlich","link":"https:\/\/sohlich.github.io\/categories\/angular\/index.xml","description":"Recent content on Radomir Sohlich","generator":"Hugo -- gohugo.io","copyright":"\u00a9 2017 Radomir Sohlich","item":[{"title":"Angular on Electron, part 2","link":"https:\/\/sohlich.github.io\/post\/angular_electron_2\/","pubDate":"Sun, 20 Aug 2017 20:33:51 +0200","guid":"https:\/\/sohlich.github.io\/post\/angular_electron_2\/","description":"\n\n<p>In the previous post the bootstrap of Angular project on Electron platform was described. In this one, the process of application packaging will be presented.<\/p>\n\n<p>One of the benefits of Electron is that it runs on all major platforms. Each platform has naturally its needs regarding to creating the distribution package. Fortunately, the packaging and all that stuff do not need to be done manually. There are few tools which will help you. But first things first.<\/p>\n\n<h2 id=\"get-ready\">Get ready<\/h2>\n\n<p>Before we begin this tutorial there will be one small change to an existing project from part 1. Because the folder &ldquo;dist&rdquo; will be used for another purpose, the Angular default build folder will be changed to &ldquo;build&rdquo;. This is done by modification of &ldquo;angular-cli.json&rdquo; config file. The property &ldquo;outDir&rdquo; of &ldquo;apps&rdquo; section will change the default output directory.<\/p>\n\n<p>${PROJECT_FOLDER}\/angular-cli.json:<\/p>\n\n<pre><code>    &quot;apps&quot;: [\n        {\n          ...\n          &quot;root&quot;: &quot;src&quot;,\n          &quot;outDir&quot;: &quot;build&quot;\n          ...}\n          ],\n      ...\n<\/code><\/pre>\n\n<p>After this change, test the configuration by building the project. The folder &ldquo;build&rdquo; should be created with all the content. If everything is OK, we are good to go.<\/p>\n\n<pre><code>    &gt; ng build\n    &gt; tree build\/\n    build\/\n        \u251c\u2500\u2500 favicon.ico\n        \u251c\u2500\u2500 index.html\n        \u251c\u2500\u2500 inline.bundle.js\n        \u251c\u2500\u2500 inline.bundle.js.map\n        \u251c\u2500\u2500 main.bundle.js\n        \u251c\u2500\u2500 main.bundle.js.map\n        \u251c\u2500\u2500 polyfills.bundle.js\n        \u251c\u2500\u2500 polyfills.bundle.js.map\n        \u251c\u2500\u2500 styles.bundle.js\n        \u251c\u2500\u2500 styles.bundle.js.map\n        \u251c\u2500\u2500 vendor.bundle.js\n        \u2514\u2500\u2500 vendor.bundle.js.map\n<\/code><\/pre>\n\n<h2 id=\"assets-packaging\">Assets packaging<\/h2>\n\n<p>All the assets of application need to be bundled in the distribution somehow. Naturally there are several ways how to accomplish that. The first option is to bundle the files ( js, css bundles) as they are. Your install folder that will contain the build folder with all the files.  Sometimes it is better to hide the raw files from user. So the next option is to use archive. As this si preferred way, the asar archive were designed.<\/p>\n\n<p><em>Asar archive<\/em><\/p>\n\n<p>The asar archive (<a href=\"https:\/\/github.com\/electron\/asar\">https:\/\/github.com\/electron\/asar<\/a>) is tar-like format very easy to use. Following example demonstrates the basic usage.<\/p>\n\n<pre><code>    &gt; npm install -g asar\n    &gt; asar pack app app.asar\n<\/code><\/pre>\n\n<p>The benefit of asar archive is that it could be read as simple as a folder in the filesystem. One way how to achieve it is via Node API. (<a href=\"https:\/\/electron.atom.io\/docs\/tutorial\/application-packaging\/#using-asar-archives\">https:\/\/electron.atom.io\/docs\/tutorial\/application-packaging\/#using-asar-archives<\/a>)<\/p>\n\n<pre><code>    const fs = require('fs')\n    fs.readdirSync('\/path\/to\/example.asar')\n<\/code><\/pre>\n\n<p>There is more. The Electron BrowserWindow class provides the ability to access the archive too. So it can load the &ldquo;index.html&rdquo; file in the application the common way via the BrowserWindow#loadURL method. In this case, the &ldquo;__dirname&rdquo; would be the path to the .asar file.<\/p>\n\n<pre><code>        var path = require('path');\n        var url = require('url');\n        win = new BrowserWindow({ width: 1280, height: 960 });\n        \/\/ __dirname is a current working directory\n        win.loadURL(url.format({\n                pathname: path.join(__dirname, 'build', 'index.html'),\n                protocol: 'file:',\n                slashes: true\n        }));\n<\/code><\/pre>\n\n<p>Now after the packaging and the ways how to use the asar were described, let&rsquo;s move to an installer. Don&rsquo;t worry you would not need to create the archives and config files manually. The tools for this purpose are there for you.<\/p>\n\n<h2 id=\"electron-builder\">Electron builder<\/h2>\n\n<p>For this tutorial, the <a href=\"https:\/\/github.com\/electron-userland\/electron-builder\">electron-builder<\/a> tool will be used.  The utility simplifies the creation of distribution package for all major platforms, even the cross platform build is possible.<\/p>\n\n<pre><code>    npm install electron-builder --save-dev\n<\/code><\/pre>\n\n<p>The electron-builder tool needs a little bit of configuration, so the final changes in &ldquo;package.json&rdquo; file looks like this (This is a minimal configuration)\n${PROJECT_FOLDER}\/package.json<\/p>\n\n<pre><code>      &quot;author&quot;: {\n        &quot;name&quot;: &quot;Radomir Sohlich&quot;,\n        &quot;email&quot;: &quot;sohlich@example.com&quot;\n      },\n      &quot;description&quot;: &quot;Example application.&quot;,\n      &quot;devDependencies&quot;: {\n         &quot;electron-builder&quot;: &quot;^19.22.0&quot;,\n      },\n      &quot;build&quot;: {\n        &quot;appId&quot;: &quot;com.example.app&quot;,\n        &quot;files&quot;: [\n          &quot;main.js&quot;,\n          &quot;build&quot;\n        ],\n        &quot;mac&quot;: {\n          &quot;category&quot;: &quot;productivity&quot;\n        }\n      }\n<\/code><\/pre>\n\n<p>The build-&gt;files section defines which files\/folders will be included in asar archive. The archive works as the application folder. The electron executes the main.js directly from the archive. The build folder contains application build with index.html and bundles. The &ldquo;author&rdquo; and &ldquo;description&rdquo; properties are not mandatory, but it is always better to provide this info. (The electron-builder will produce less warning messages :) )<\/p>\n\n<p>The final step is to add a npm command to run the electron-builder build.<\/p>\n\n<p>${PROJECT_FOLDER}\/package.json<\/p>\n\n<pre><code>    &quot;scripts&quot;: {\n        &quot;dist&quot;: &quot;build --mac&quot;\n      },\n<\/code><\/pre>\n\n<p>The &ldquo;dist&rdquo; command will build the application and subsequently build a distribution package. In this case, the MacOS is configured. The platform is defined by the switch. The available values are in the following figure. (stolen from project documentation <a href=\"https:\/\/github.com\/electron-userland\/electron-builder#cli-usage\">https:\/\/github.com\/electron-userland\/electron-builder#cli-usage<\/a>)<\/p>\n\n<pre><code>      --mac, -m, -o, --macos   Build for macOS, accepts target list (see\n                               https:\/\/goo.gl\/HAnnq8).                       [array]\n      --linux, -l              Build for Linux, accepts target list (see\n                               https:\/\/goo.gl\/O80IL2)                        [array]\n      --win, -w, --windows     Build for Windows, accepts target list (see\n                               https:\/\/goo.gl\/dL4i8i)                        [array]\n<\/code><\/pre>\n\n<p>To execute the build, call the command in terminal and the output should look like this.<\/p>\n\n<pre><code>    &gt; npm run dist\n    &gt; electron_app@0.0.0 distmac \/Users\/radek\/Junk\/electron_app\n    &gt; ng build &amp;&amp; build --mac\n    \n    Hash: ee6c31ccdab8735b740c\n    Time: 10199ms\n    chunk    {0} polyfills.bundle.js, polyfills.bundle.js.map (polyfills) 177 kB {4} [initial] [rendered]\n    chunk    {1} main.bundle.js, main.bundle.js.map (main) 5.27 kB {3} [initial] [rendered]\n    chunk    {2} styles.bundle.js, styles.bundle.js.map (styles) 10.5 kB {4} [initial] [rendered]\n    chunk    {3} vendor.bundle.js, vendor.bundle.js.map (vendor) 1.89 MB [initial] [rendered]\n    chunk    {4} inline.bundle.js, inline.bundle.js.map (inline) 0 bytes [entry] [rendered]\n    electron-builder 19.22.1\n    No native production dependencies\n    Packaging for darwin x64 using electron 1.7.5 to dist\/mac\n    Building macOS zip\n    Building DMG\n    Application icon is not set, default Electron icon will be used\n<\/code><\/pre>\n\n<p>After the successful command run, the dist folder should be created in the working directory and the installer should be there.<\/p>\n\n<pre><code>    dist\/\n    --- electron_app-0.0.0-mac.zip\n    --- electron_app-0.0.0.dmg\n    --- mac\n        --- electron_app.app\n<\/code><\/pre>\n\n<p>The &ldquo;electron_app.app\/Resources&rdquo; folder contains the asar archive with &ldquo;app.asar&rdquo; file. That is our bundled application. If you need to debug, what is packed into &ldquo;app.asar&rdquo; file and what is included in the installer. The &ldquo;build &ndash;dir&rdquo; command could be used. It will create only the expanded distribution folder (same as dist\/mac).<\/p>\n\n<p>Note:\nIf you encounter the error by executing the &ldquo;build &ndash;dir&rdquo; command.<\/p>\n\n<pre><code>    Error: Cannot find electron dependency to get electron version\n<\/code><\/pre>\n\n<p>The electron dependency need to be add to project.<\/p>\n\n<pre><code>    npm install electron --save-dev\n<\/code><\/pre>\n\n<p>The repository with example project <a href=\"https:\/\/github.com\/sohlich\/angular_on_electron\">https:\/\/github.com\/sohlich\/angular_on_electron<\/a><\/p>\n\n<h3 id=\"series\">Series:<\/h3>\n\n<ul>\n<li><a href=\"https:\/\/sohlich.github.io\/post\/angular_electron\/\">Angular on Electron, part 1<\/a><\/li>\n<li><a href=\"https:\/\/sohlich.github.io\/post\/angular_electron_2\/\">Angular on Electron, part 2<\/a><\/li>\n<\/ul>\n"},{"title":"Angular on Electron, part 1","link":"https:\/\/sohlich.github.io\/post\/angular_electron\/","pubDate":"Sat, 29 Jul 2017 08:48:41 +0200","guid":"https:\/\/sohlich.github.io\/post\/angular_electron\/","description":"\n\n<p>Today it is possible to have almost all the applications as a service online. Literally you don&rsquo;t have to install any of it on you computer. Even if this is possible, but for me it is still more comfortable to have a dedicated desktop application. I believe I&rsquo;m not the only one. There are a lot of ways how to create a desktop application. Utilizing the native frameworks like Qt, WxWidgets is always an option. For Java people, there are two useful options: swing and java fx.\nBut for me as web developer, though java based, it means to learn a new library or whole framework, all its features and pitfalls&hellip; But what If anybody tells you that you can use your good &ldquo;old&rdquo; javascript and HTML? Me, I\u2019m totally IN.<\/p>\n\n<p>So here comes the Electron platform (<a href=\"https:\/\/electron.atom.io\/\">https:\/\/electron.atom.io\/<\/a>) based on Chromium browser. It provides presentation layer and runtime for your application.\nThe Electron accompanied by Angular framework is a very solid foundation for desktop application development in most of use cases. By the way lot of well known applications are based on electron: VS Code, Slack, WhatsApp&hellip;<\/p>\n\n<p>I&rsquo;ll try to show you how to start your own project, or &ldquo;Electronify&rdquo; the existing one.<\/p>\n\n<h1 id=\"bootstrap-your-project\">Bootstrap your project<\/h1>\n\n<p>Using an Angular CLI generate a new application and test the first run. After following command you should be able to see the result in the browser on URL <a href=\"http:\/\/localhost:4200\">http:\/\/localhost:4200<\/a>.<\/p>\n\n<pre><code>&gt; ng new electron_app\n&gt; ng serve\n<\/code><\/pre>\n\n<p>Add main file for the electron called main.js<\/p>\n\n<p>${PROJECT_FOLDER}\/main.js:<\/p>\n\n<pre><code>    const { app, BrowserWindow } = require('electron');\n    \n    \/\/ Executes when the application \n    \/\/ is initialized.\n    app.on('ready', function() {\n        console.log('Starting application!');\n        \/\/ Create browser window \n        \/\/ with given parameters\n        mainWindow = new BrowserWindow({ width: 1280, height: 960 });\n        mainWindow.loadURL(&quot;http:\/\/localhost:4200&quot;);\n    \n        \/\/ It is useful to open dev tools\n        \/\/ for debug.\n        mainWindow.webContents.openDevTools();\n        mainWindow.on('closed', function() {\n            mainWindow = null;\n        });\n    });\n    \n    \/\/ Defines the behavior on close.\n    app.on('window-all-closed', function() {\n        app.quit();\n    });\n<\/code><\/pre>\n\n<p>And update the package.json file by few additional properties:\n${PROJECT_FOLDER}\/package.json:<\/p>\n\n<pre><code>    {\n        &quot;name&quot;: &quot;electron_app&quot;,\n        &quot;version&quot;: &quot;0.0.0&quot;,\n        &quot;main&quot;: &quot;main.js&quot;,\n        &quot;license&quot;: &quot;MIT&quot;,\n        &quot;scripts&quot;: {\n            &quot;ng&quot;: &quot;ng&quot;,\n            &quot;start&quot;: &quot;ng serve&quot;,\n            &quot;build&quot;: &quot;ng build&quot;,\n            &quot;test&quot;: &quot;ng test&quot;,\n            &quot;lint&quot;: &quot;ng lint&quot;,\n            &quot;e2e&quot;: &quot;ng e2e&quot;\n        },\n        &quot;private&quot;: true,\n        &quot;dependencies&quot;: {\n            &quot;@angular\/animations&quot;: &quot;^4.0.0&quot;,\n            &quot;@angular\/common&quot;: &quot;^4.0.0&quot;,\n            &quot;@angular\/compiler&quot;: &quot;^4.0.0&quot;,\n            &quot;@angular\/core&quot;: &quot;^4.0.0&quot;,\n            &quot;@angular\/forms&quot;: &quot;^4.0.0&quot;,\n            &quot;@angular\/http&quot;: &quot;^4.0.0&quot;,\n            &quot;@angular\/platform-browser&quot;: &quot;^4.0.0&quot;,\n            &quot;@angular\/platform-browser-dynamic&quot;: &quot;^4.0.0&quot;,\n            &quot;@angular\/router&quot;: &quot;^4.0.0&quot;,\n            &quot;core-js&quot;: &quot;^2.4.1&quot;,\n            &quot;rxjs&quot;: &quot;^5.4.1&quot;,\n            &quot;zone.js&quot;: &quot;^0.8.14&quot;\n        },\n        &quot;devDependencies&quot;: {\n            &quot;@angular\/cli&quot;: &quot;1.2.4&quot;,\n            &quot;@angular\/compiler-cli&quot;: &quot;^4.0.0&quot;,\n            &quot;@angular\/language-service&quot;: &quot;^4.0.0&quot;,\n            &quot;@types\/jasmine&quot;: &quot;~2.5.53&quot;,\n            &quot;@types\/jasminewd2&quot;: &quot;~2.0.2&quot;,\n            &quot;@types\/node&quot;: &quot;~6.0.60&quot;,\n            &quot;codelyzer&quot;: &quot;~3.0.1&quot;,\n            &quot;jasmine-core&quot;: &quot;~2.6.2&quot;,\n            &quot;jasmine-spec-reporter&quot;: &quot;~4.1.0&quot;,\n            &quot;karma&quot;: &quot;~1.7.0&quot;,\n            &quot;karma-chrome-launcher&quot;: &quot;~2.1.1&quot;,\n            &quot;karma-cli&quot;: &quot;~1.0.1&quot;,\n            &quot;karma-coverage-istanbul-reporter&quot;: &quot;^1.2.1&quot;,\n            &quot;karma-jasmine&quot;: &quot;~1.1.0&quot;,\n            &quot;karma-jasmine-html-reporter&quot;: &quot;^0.2.2&quot;,\n            &quot;protractor&quot;: &quot;~5.1.2&quot;,\n            &quot;ts-node&quot;: &quot;~3.0.4&quot;,\n            &quot;tslint&quot;: &quot;~5.3.2&quot;,\n            &quot;typescript&quot;: &quot;~2.3.3&quot;\n        }\n    }\n<\/code><\/pre>\n\n<p>I recommend to install the electron platform globaly with command:<\/p>\n\n<pre><code>    &gt; npm install -g electron\n<\/code><\/pre>\n\n<p>The first simple manual run could be done by calling following commands (these must be run in separate terminal windows as the \u201cng serve\u201d is blocking)<\/p>\n\n<pre><code>    &gt; ng serve\n    &gt; electron .\n<\/code><\/pre>\n\n<p>Command \u201cng serve\u201d will start development server on <a href=\"http:\/\/localhost:4200\">http:\/\/localhost:4200<\/a>, you can notice the this url is used in main.js file. The &ldquo;electron .&rdquo; will start the electron app by executing the main.js file.<\/p>\n\n<p>You can use <a href=\"https:\/\/www.npmjs.com\/package\/concurrently\">concurrently<\/a> tool to run these two commands concurrently. Also it can be incorporated to package.json file as an npm script.<\/p>\n\n<pre><code>npm install -g concurrently\n<\/code><\/pre>\n\n<p>${PROJECT_FOLDER}\/package.json<\/p>\n\n<pre><code>&quot;scripts&quot;: {\n        ...\n        &quot;electrondev&quot;: &quot;concurrently -k \\&quot;ng serve\\&quot; \\&quot;electron .\\&quot;&quot;\n    },\n<\/code><\/pre>\n\n<h1 id=\"serving-static-files\">Serving static files<\/h1>\n\n<p>Serving angular application via development server is not very comfortable and permanent solution. Better approach is serving a static files from the build output folder (let&rsquo;s call it distribution folder). The main.js file need to be changed to open the index.html file located in distribution folder of your angular application.<\/p>\n\n<p>${PROJECT_FOLDER}\/main.js<\/p>\n\n<pre><code>    const { app, BrowserWindow } = require('electron');\n    path = require('path');\n    url = require('url');\n    app.on('ready', function() {\n        console.log('Starting application!');\n        mainWindow = new BrowserWindow({ width: 1280, height: 960 });\n        \n        \/\/ Change loadUrl to load index.html\n        \/\/ using url and path package \n        \/\/ to format the file url\n        mainWindow.loadURL(url.format({\n            \/\/__dirname is the current working dir\n            pathname: path.join(__dirname, 'dist', 'index.html'),\n            protocol: 'file:',\n            slashes: true\n        }));\n    \n        \/\/ Opens dev tools\n        mainWindow.webContents.openDevTools();\n        mainWindow.on('closed', function() {\n            mainWindow = null;\n        });\n    });\n    app.on('window-all-closed', function() {\n        app.quit();\n    });\n<\/code><\/pre>\n\n<p>After you open electron you will receive \u201cFailed to load resource\u201d error.\nThere is one step missing to get the change work.\n<img src =\"https:\/\/d2mxuefqeaa7sj.cloudfront.net\/s_F68920300BC018EB3E1E88614B689BAD376E939D730AA4BF30888F46A4DF2F8A_1501387336733_image.png\"\/><\/p>\n\n<p>The one small change that need to be done is in your index.html file. We need to define the base for the file as absolute but from the actual working directory like \u201c.\/\u201d. This is done in <base> element in head tag of index.html . After the modification you can try \u201celectron .\u201d in your ${PROJECT_FOLDER}<\/p>\n\n<p>${PROJECT_FOLDER}\/index.html :<\/p>\n\n<pre><code>    &lt;!doctype html&gt;\n    &lt;html lang=&quot;en&quot;&gt;\n    &lt;head&gt;\n        &lt;meta charset=&quot;utf-8&quot;&gt;\n        &lt;title&gt;Electron&lt;\/title&gt;\n        &lt;!-- Change the href attribute \n        to reference to cur. working dir --&gt;\n        &lt;base href=&quot;.\/&quot;&gt;\n        &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&gt;\n        &lt;link rel=&quot;icon&quot; type=&quot;image\/x-icon&quot; href=&quot;favicon.ico&quot;&gt;\n    &lt;\/head&gt;\n    &lt;body&gt;\n        &lt;app-root&gt;&lt;\/app-root&gt;\n    &lt;\/body&gt;\n    &lt;\/html&gt;\n<\/code><\/pre>\n\n<p>That&rsquo;s it. Desktop application with Angular. The same approach could be used with other JS frameworks or just pure static HTML. I was excited how easy it is.<\/p>\n\n<p>The repository with example project <a href=\"https:\/\/github.com\/sohlich\/angular_on_electron\">https:\/\/github.com\/sohlich\/angular_on_electron<\/a><\/p>\n\n<h3 id=\"series\">Series:<\/h3>\n\n<ul>\n<li><a href=\"https:\/\/sohlich.github.io\/post\/angular_electron\/\">Angular on Electron, part 1<\/a><\/li>\n<li><a href=\"https:\/\/sohlich.github.io\/post\/angular_electron_2\/\">Angular on Electron, part 2<\/a><\/li>\n<\/ul>\n"}]}}