DEV Community

Cover image for Angular-CLI and NW.js for development
The Jared Wilcurt
The Jared Wilcurt

Posted on • Edited on

Angular-CLI and NW.js for development

Angular, NW.js, and Angular-CLI Logos

This will walk you through setting up NW.js and Angular-CLI from scratch.

"Why not just do all this for me and just give me a boilerplate"

Do you want a fish, or do you want to learn how to fish? Plus, boilerplates already exist, you can look around for them.


Editors Note:

Due to the limitations of Dev.to some codeblocks below are not formatted well. Sorry about that, out of my control.


Step 1: Angular CLI

Angular is pretty complex, there's a lot of tooling required to get your standard Angular app up off the ground. Fortunately they offer a tool to generate and scaffold your projects.

  1. npm install -g @angular/cli
  2. ng new
    • Fill out the options for app name, routing, Sass pre-processing, etc
    • It will auto-create a folder with your app name
    • The CLI will produce a default project with files and install its dependencies

Step 2: Verify Angular CLI worked

Before we add anything else, let's just make sure everything is working as expected. We'll navigate to the project folder, start the server and look at it in the browser.

  1. cd your-app-name
  2. npm start
    • This will run a local webserver with a note of what port it is running on. For me it was port 4200.
  3. Visit the local server in your browser.
  4. Open the file src/app/app.component.ts
  5. Change the title = 'your-app-name'; to title = 'Does this update automatically?';
  6. Save the file and look in the browser, after a second or two, you should see the text on the page change automatically!

Step 3: Adding in NW.js

Now that we know the basic Angular project works as expected, we can start adding NW.js and set this up for development.

  1. Kill the local webserver you had running
  2. npm install --save-dev nw@sdk concurrently
  3. Open the package.json file
  4. In the "scripts" section, change:
    • "start": "ng serve",
    • to:
    • "start": "concurrently \"ng serve --port=8964\" \"nw .\"",
  5. On the root of the package.json object add these values:

    "main": "http://localhost:8964",
    "node-remote": "http://localhost:8964",
    "window": {
      "width": 960,
      "height": 600,
      "min_width": 700,
      "min_height": 500,
      "icon": "your-app-logo.png"
    },
    
  6. For some (assumingly stupid) reason Angular adds a "global" object when it loads. Since Node.js uses a global object in a similar way to how browsers use a window object, NW.js exposes it for easy access. We need to move the Node global object somewhere else so that Angular can selfishly use that name space.

  7. Open the src/index.html file

  8. In the <head> section add this in:

    <script>
      window.nw_global = window.global;
      window.global = undefined;
    </script>
    
  9. NW.js stores all of it's API in the window.nw object, because Angular has this weird thing for Typescript, we need to inform it of the existence of window.nw.

  10. Open the src/polyfill.ts and add this:

    declare global {
      interface Window {
        nw: any;
      }
    }
    

Step 4: Verifying NW.js loads

  1. Now you can run npm start
  2. NW.js should pop up and try to load the localhost address specified in the "main" of package.json. Since Webpack takes a while to spin up the local server, you should see a message that the page couldn't load. Once the server is up you can refresh the page in NW.js to see the app.
  3. The window size will match what was placed in the "window" section of package.json. There are many other settings that can be added here as well.
  4. Important Note: Normally in NW.js you would just access nw directly, but due to the glories of Typescript, you must instead access it with window.nw. Similarly you would normally be able to access process and require directly (Node.js specific features), but now you will need to get them from window.nw.process and window.nw.require. But you still have access to them and can alias them with variables however you like.
  5. Let's go back to the file your-app-name/src/app/app.component.ts
  6. Change the title = 'Does this update automatically?'; to title = String(window.nw.require('fs').readFileSync('./package.json'));
  7. Save and you should see the app automatically reload and display the contents of the package.json file on the page which was accessed using Node's built-in file system module fs. You can also access any 3rd-party node_modules this way.

The End

And that's it! You now have a dev environment that runs normally, but inside your desktop app. You can write Angular code and access Node commands right from the DOM!

But what about packaging for distribution

We'll have to save that for another time. For now you can look at the NW.js documentation and maybe try it out on a simpler "Hello World" app first, then apply those ideas. Who knows, maybe you'll be the one to write up those instructions for others.

If you have any other issues with Angular and NW.js, look at this Github Issue:

References:

Top comments (10)

Collapse
 
redmission84 profile image
Andy

This is the best tutorial I've seen for integrating Angular and NW JS (learning the latter now) and it's helpful to be able to launch them both with a simple "npm start". I also love how you can simply specify the window options in package.json and it just works. Thanks for this tutorial!

Collapse
 
fprijate profile image
Franček Prijatelj

The problem with using
"main": "localhost:8964",
is that you can't debug bg code,because there isn't any
(only front end code from "remote" page).
Try to inspect process or global variable in devtools.

Collapse
 
fprijate profile image
Franček Prijatelj

Sorry

It works with "node-remote" set.

Collapse
 
vinayd profile image
Vinaykumar Devarkond

Thanks for the tutorial. But when I used window.nw, i am getting nw as undefined. Please help.

Collapse
 
thejaredwilcurt profile image
The Jared Wilcurt

You can see examples here: github.com/nwutils/nw-angular-cli-...

Either you aren't running your code in NW.js or you are running it from a Node.js context (in which case you could use nw directly, or global.nw).

Collapse
 
hnguyen48206 profile image
hnguyen48206

Thank you sir for this great tutorial. I'm trying to use my pre-existing angular project (with ngx-admin) in an nw.js app. Following your instruction, I've been able to run the angular local server and nw app just fine for development but the problem is that in nw.js context, the UI cannot get pass the index.html file and got stuck there while this is not the case when running the web in browser.

This is my package.json.

{
"main": "localhost:8964",
"node-remote": "localhost:8964",
"window": {
"width": 960,
"height": 600,
"min_width": 700,
"min_height": 500
},
"name": "ngx-admin",
"version": "7.0.0",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+github.com/akveo/ngx-admin.git"
},
"bugs": {
"url": "github.com/akveo/ngx-admin/issues"
},
"scripts": {
"ng": "ng",
"conventional-changelog": "conventional-changelog",
"start": "concurrently \"npm run start:web\" \"wait-on localhost:8964 && nw .\"",
"start:web": "ng serve --port=8964",
"build": "ng build",
"build:prod": "npm run build -- --prod --aot",
"test": "ng test",
"test:coverage": "rimraf coverage && npm run test -- --code-coverage",
"lint": "ng lint",
"lint:fix": "ng lint ngx-admin-demo --fix",
"lint:styles": "stylelint ./src/*/.scss",
"lint:ci": "npm run lint && npm run lint:styles",
"pree2e": "webdriver-manager update --standalone false --gecko false",
"e2e": "ng e2e",
"docs": "compodoc -p src/tsconfig.app.json -d docs",
"docs:serve": "compodoc -p src/tsconfig.app.json -d docs -s",
"prepush": "npm run lint:ci",
"release:changelog": "npm run conventional-changelog -- -p angular -i CHANGELOG.md -s",
"postinstall": "ngcc --properties es2015 es5 browser module main --first-only --create-ivy-entry-points --tsconfig \"./src/tsconfig.app.json\""
},
"dependencies": {
"@akveo/ng2-completer": "^9.0.1",
"@angular/animations": "^11.0.9",
"@angular/cdk": "11.0.4",
"@angular/common": "^11.0.9",
"@angular/compiler": "^11.0.9",
"@angular/core": "^11.0.9",
"@angular/forms": "^11.0.9",
"@angular/google-maps": "^11.0.4",
"@angular/material": "^11.0.4",
"@angular/material-moment-adapter": "^11.2.13",
"@angular/platform-browser": "^11.0.9",
"@angular/platform-browser-dynamic": "^11.0.9",
"@angular/router": "^11.0.9",
"@asymmetrik/ngx-leaflet": "3.0.1",
"@nebular/auth": "7.0.0",
"@nebular/eva-icons": "7.0.0",
"@nebular/security": "7.0.0",
"@nebular/theme": "7.0.0",
"@swimlane/ngx-charts": "^14.0.0",
"@swimlane/ngx-datatable": "^20.0.0",
"angular2-chartjs": "0.4.1",
"axiom-ngx-tree": "^1.0.1",
"bootstrap": "4.3.1",
"chart.js": "2.7.1",
"ckeditor": "4.7.3",
"classlist.js": "1.1.20150312",
"core-js": "2.5.1",
"echarts": "^4.0.2",
"eva-icons": "^1.1.3",
"intl": "1.2.5",
"ionicons": "2.0.1",
"js-sha256": "^0.9.0",
"leaflet": "1.2.0",
"moment": "^2.29.1",
"nebular-icons": "1.1.0",
"ng-otp-input": "^1.8.1",
"ng2-ckeditor": "^1.2.9",
"ng2-smart-table": "^1.6.0",
"ngx-echarts": "^4.2.2",
"node-sass": "^4.12.0",
"normalize.css": "6.0.0",
"pace-js": "1.0.2",
"roboto-fontface": "0.8.0",
"rxjs": "6.6.2",
"rxjs-compat": "6.3.0",
"socicon": "3.0.5",
"style-loader": "^1.1.3",
"tinymce": "4.5.7",
"tslib": "^2.0.0",
"typeface-exo": "0.0.22",
"wait-on": "^6.0.1",
"web-animations-js": "^2.3.2",
"zone.js": "~0.10.3"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.1100.7",
"@angular/cli": "^11.0.7",
"@angular/compiler-cli": "^11.0.9",
"@angular/language-service": "11.0.9",
"@compodoc/compodoc": "1.0.1",
"@fortawesome/fontawesome-free": "^5.2.0",
"@types/d3-color": "1.0.5",
"@types/googlemaps": "^3.39.3",
"@types/jasmine": "^3.3.0",
"@types/jasminewd2": "2.0.3",
"@types/leaflet": "1.2.3",
"@types/node": "^12.11.1",
"codelyzer": "^6.0.0",
"concurrently": "^7.0.0",
"conventional-changelog-cli": "1.3.4",
"husky": "0.13.3",
"jasmine-core": "~3.6.0",
"jasmine-spec-reporter": "~5.0.0",
"karma": "~5.1.1",
"karma-chrome-launcher": "~3.1.0",
"karma-cli": "1.0.1",
"karma-coverage-istanbul-reporter": "~3.0.2",
"karma-jasmine": "~4.0.0",
"karma-jasmine-html-reporter": "^1.5.0",
"npm-run-all": "4.0.2",
"nw": "^0.18.7",
"protractor": "~7.0.0",
"rimraf": "2.6.1",
"stylelint": "7.13.0",
"ts-node": "3.2.2",
"tslint": "~6.1.0",
"tslint-language-service": "^0.9.9",
"typescript": "4.0.5"
}
}

Collapse
 
cissasgot profile image
Jan Roman Cisowski

and how do you use it to work with nw-builder, or something else?

Collapse
 
thejaredwilcurt profile image
The Jared Wilcurt

github.com/nwutils/nw-angular-cli-...

All set up! npm install && npm run build

Collapse
 
kriefsacha profile image
kriefsacha

Hi , how do you get the release when you finished your angular nw.js application ? Thanks for everything !

Collapse
 
thejaredwilcurt profile image
The Jared Wilcurt