Create an Angular component library for npm

  1. ng new xxx-app that will be our testing application for our new library
  2. cd xxx-app
  3. ng g library xxx-lib --prefix=awesome
    • Mind that the components/services/modules that you would like to public expose must be specified in the file public-api.ts
  4. Rename the folder xxx-app to xxx-lib
  5. ng build xxx-lib
  6. cd dist\xxx-lib
  7. npm init to create the project.json file, that will contains the specs about your library
  8. Before publish:
    • You can create the file .npmrc if you need to push to a custom/private gallery. If you omit this, npm will try to push to the community gallery npmjs.com
    • The npm gallery authentication token must be saved in the user folder $HOME in the global file .npmrc
    • You can use the command npm login to automatically generate and save the token for npmjs.com (service like azure devops creates this token from the web interface and you save it to the global .npmrc there are also tools to do this, but I prefer to simply copy and paste the token myself)
  9. npm publish
  10. You can test the component directly from the application and the run ng serve as usual, this will execute the default application as if you had executed ng serve xxx-app. Now from the application you can use the component of your library without needing to install it from the gallery, and of course you can also debug it. From the app.module.ts imports the module XxxLibModule like this import { XxxLibModule } from 'projects/xxx-lib/src/public-api';

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { XxxLibModule } from 'projects/xxx-lib/src/public-api';

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, XxxLibModule, AppRoutingModule],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {}

app.component.html

<awesome-xxx-lib></awesome-xxx-lib>

and the final result is…..

amazing!! 🙂

library-running

Npm tilde(~) and caret(^) in package.json version

The tilde matches the most recent patch version in the specified minor version.

~1.2.3 will match all 1.2.x versions but will miss 1.3.0.

The caret, on the other hand, is more relaxed. It will update you to the most recent minor version in the specified major version.

^1.2.3 will match any 1.x.x release including 1.3.0, but will hold off on 2.0.0.

Resources:

Build Angular Desktop Apps With Electron

Based on Jeff Delaney post. You can also check the video lesson on youtube and the original source code on github.

You can also find my source code on github.

Generate the angular app

You can follow the Angular – QuickStart or just do these steps:

npm install -g @angular/cli
ng new angular-electron
cd angular-electron

Update base tag on index.html

The generated root page in Angular points the base href to / – this will cause problems with Electron later on, so let’s update it now.

<base href="./">

Install Electron

npm install electron --save-dev

Configure Electron

Create a new file named main.js in the root of your project – this is the Electron NodeJS backend. This is the entry point for Electron and defines how our desktop app will react to various events performed via the desktop operating system.

const { app, BrowserWindow } = require('electron')

let win;

function createWindow () {
  // Create the browser window.
  win = new BrowserWindow({
    width: 600, 
    height: 600,
    backgroundColor: '#ffffff',
    icon: `file://${__dirname}/dist/assets/logo.png`
  })


  win.loadURL(`file://${__dirname}/dist/index.html`)

  //// uncomment below to open the DevTools.
  // win.webContents.openDevTools()

  // Event when the window is closed.
  win.on('closed', function () {
    win = null
  })
}

// Create window on electron intialization
app.on('ready', createWindow)

// Quit when all windows are closed.
app.on('window-all-closed', function () {

  // On macOS specific close process
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', function () {
  // macOS specific close process
  if (win === null) {
    createWindow()
  }
})

The createWindow function defines the properties of the program window that the user will see.

Notice we are loading the window by pointing it to the index.html file in the dist/ folder. Do NOT confuse this with the index file in the src/ folder. At this point, this file does not exist, but it will be created automatically in the next step by running ng build –prod

Custom Build Command

The deployed desktop app will be an Angular AOT build – this happens by default when you run ng build –prod. It’s useful to have a command that will run an AOT production build and start Electron at the same time. This can be easily configured in the package.json file.

{
  "name": "angular-electron",
  "version": "0.0.0",
  "license": "MIT",
  "main": "main.js", // <-- add this
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e",
    "electron": "electron .", // <-- add this to run electron 
    "electron-build": "ng build --prod && electron ." // <-- add this to build app in prod with AOT and then run electron 
  },
  // ...omitted
}

Run the electron app

You can run your angular app as an native desktop app with the following command.

npm run electron-build

At this point, you can run the command (it will take a few seconds) and it will create the dist/ folder and will automatically bring up a window on your operating system with default Angular app.

This setup does not support hot code reloads. Whenever you change some Angular code, you need to rerun the electron-build command. It is possible to setup hot reloads by pointing the window to a remote URL (such as https://localhost:4200) and running npm start in a separate terminal and then running npm run electron.

Build you Angular App

This section is up to you, if you want something ready, check the Jeff’s post.

Packaging for Desktop Operating Systems

This section is slightly different from the original post, because I had to add –no-prune and a series of –ignore to let electron-packager works as expected.

The electron packager tool will allow to package our code into an executable for desktop platforms – including Windows (win32), MacOS (darwin), and Linux. Keep in mind, there are several other electron packaging tools that might better fit your needs.

npm install electron-packager -g
npm install electron-packager --save-dev

Build an executable for Windows:

electron-packager . --platform=win32 --no-prune --ignore=/node_modules --ignore=/e2e --ignore=/src

Build an executable for MaxOS:

electron-packager . --platform=darwin --no-prune --ignore=/node_modules --ignore=/e2e --ignore=/src

The you can add an npm script electron-package-win to easy package for Windows:

{
 "name": "angular-electron",
 "version": "0.0.0",
 "license": "MIT",
 "main": "main.js",
 "scripts": {
 "ng": "ng",
 "start": "ng serve",
 "build": "ng build --prod",
 "test": "ng test",
 "lint": "ng lint",
 "e2e": "ng e2e",
 "electron": "electron .",
 "electron-build": "ng build --prod && electron .",
 "electron-package-win": "ng build --prod && electron-packager . --no-prune --ignore=/node_modules --ignore=/e2e --ignore=/src --overwrite" // <-- add this script
 }
 // ...omitted
}

Then call it like this:

npm run electron-package-win