Angular Electron Dream Starter with Webpack
A starter kit for Electron and Angular 4 featuring Webpack 3, AoT compile, @ngrx 4, Electron unit tests, native E2E tests in Spectron, and a powerful development workflow with Hot Module Replacement and Electron Connect.
Forked from AngularClass/angular-starter.
I designed this seed repo to demonstrate an ideal development workflow and the most powerful tools for developing desktop applications using Angular and Electron. npm start
launches a powerful development workflow which uses Hot Module Replacement (HMR) for nearly instant updates inside the browser window, while also restarting your app automatically every time you update the code of the main process.
- Best practices in desktop application development with Angular and Electron.
- Ready to go build system using Webpack 2 for working with TypeScript.
- Automated bundling of app dependencies, including rebuilding native modules
- Easily package your app for release on Mac, Linux or Windows and create installers
- Ahead of Time (AoT) compile for rapid page loads of your production builds.
- Tree shaking to automatically remove unused code from your production bundle.
- Webpack DLLs dramatically speed your development builds.
- Testing Angular code inside Electron with Jasmine and Karma.
- Coverage with Istanbul and Karma
- End-to-end application testing with Spectron (using Mocha and Chai).
- Bundled with Devtron and Redux DevTools extensions for debugging in development mode
- Type manager with @types
- Hot Module Replacement with Webpack and @angularclass/hmr and @angularclass/hmr-loader
Quick start
Make sure you have Node version >= 6.0 and NPM >= 3
Clone/Download the repo then edit
app.component.ts
inside/src/app/app.component.ts
# clone our repo
# --depth 1 removes all but one .git commit history
git clone --depth 1 https://github.com/colinskow/angular-electron-dream-starter.git
# change directory to our repo
cd angular-electron-dream-starter
# install the repo with npm
npm install
# launch the development build
npm start
# if you're in China use cnpm
# https://github.com/cnpm/cnpm
Electron will automatically launch and update itself when your source code changes.
Table of Contents
- File Structure
- Getting Started
- Configuration
- Managing Dependencies
- AoT Don'ts
- External Stylesheets
- Lazy Loading
- Contributing
- TypeScript
- @Types
- Frequently asked questions
- Support, Questions, or Feedback
- License
File Structure
We use the component approach in our starter. This is the new standard for developing Angular apps and a great way to ensure maintainable code by encapsulation of our behavior logic. A component is basically a self contained app usually in a single file or a folder with each concern as a file: style, template, specs, e2e, and component class. Here's how it looks:
angular-electron-dream-starter/
├──config/ * our configuration
| ├──helpers.js * helper functions for our configuration files
| ├──spec-bundle.js * ignore this magic that sets up our Angular testing environment
| ├──karma.conf.js * karma config for our unit tests
| ├──webpack.electron.js * webpack config for our Electron main process
│ ├──webpack.dev.js * our development webpack config
│ ├──webpack.prod.js * our production webpack config
│ ├──webpack.test.js * our testing webpack config
│ └──electron-dev.js * our development server for the Electron renderer
│
├──src/ * our source files that will be compiled to javascript
| ├──main.browser.ts * our entry file for our browser environment
│ │
│ ├──main.electron.ts * our entry file for Electron
│ │
| ├──index.html * Index.html: where we generate our index page
│ │
| ├──polyfills.ts * our polyfills file
│ │
│ ├──app/ * WebApp folder (Angular / renderer process code)
│ │ ├──app.component.spec.ts * a simple test of components in app.component.ts
│ │ ├──app.e2e.ts * a simple end-to-end test for /
│ │ └──app.component.ts * a simple version of our App component components
│ │
│ ├──electron/ * source code for the main Electron process
│ │
│ ├──resources/ * icons and resources for Electron Builder
│ │ ├──icon.icns * Mac / Linux icon
│ │ ├──icon.ico * Windows icon
│ │ └──background.png * background icon for Mac DMG installer
│ │
│ └──assets/ * static assets are served here
│ ├──icon/ * our list of icons from www.favicon-generator.org
│ ├──service-worker.js * ignore this. Web App service worker that's not complete yet
│ ├──robots.txt * for search engines to crawl your website
│ └──humans.txt * for humans to know who the developers are
│
│
├──tslint.json * typescript lint config
├──typedoc.json * typescript documentation generator
├──tsconfig.json * typescript config used outside webpack
├──tsconfig.webpack.json * config that webpack uses for typescript
├──package.json * what npm uses to manage it's dependencies
└──webpack.config.js * webpack main configuration file
Getting Started
Dependencies
What you need to run this app:
node
andnpm
(brew install node
)- Ensure you're running the latest versions Node
v6.x.x
+ (orv7.x.x
) and NPM3.x.x
+
If you have
nvm
installed, which is highly recommended (brew install nvm
) you can do anvm install --lts && nvm use
in$
to run with the latest Node LTS. You can also have thiszsh
done for you automatically
Once you have those, you should install these globals with npm install --global
:
electron
(npm install --global electron
)webpack
(npm install --global webpack
)karma
(npm install --global karma-cli
)typescript
(npm install --global typescript
)
Installing
fork
this repoclone
your forknpm install
to install all dependencies oryarn
npm start
to start the development workflow
Building
# development
npm run build:dev
# production (jit)
npm run build:prod
# AoT
npm run build:aot
Launching Your Build
npm run launch
Generating Release Packages
Make sure to build your app first. Application packages files will be generated inside the /packages
directory.
# all platforms
npm run package
# Linux
npm run package:linux
# Mac
npm run package:mac
# Windows
npm run package:windows
Other Commands
run unit tests
npm run test
watch and run our tests
npm run watch:test
When you watch tests you can debug them using the Chrome Debugger tools. To do this, run the above command, after the tests run, click on the Debug button in the Karma Electron instance. This opens the Karma Debug Runner window. Open the Chrome dev tools in this window (Ctrl-Shift-i). Open the Sources tab, navigate the webpack:// item to find the test case you want to debug. Set a breakpoint, then refresh the view (Ctrl-R) to reload the page. Your break point should hit and you can debug and step through your code.
watch and run all tests in a directory
npm run watch:test:grep -- app/about/
watch and run a single test
npm run watch:test:grep -- app/about/about.component.spec.ts
This is useful for debugging a failing test case. You can further narrow to just a single "it" function by placing an "f" (means focus on this test) in front of the failing test case see Jasmine Focused. Then only this file will be run while you debug.
run end-to-end tests
# this will start a test server and launch Protractor
npm run e2e
continuous integration (run unit tests and e2e tests together)
# this will test both your JIT and AoT builds
npm run ci
run Webdriver.io's live debug (for end-to-end)
This allows you to debug e2e tests and explore your app while it is running. See the WebDriver.io documentation for details.
npm run e2e:live
clean application data
# this will delete all data from localStorage, indexedDB etc.
npm run clean:appdata
Configuration
Configuration files live in config/
. You can modify the settings for Webpack and Karma here.
The configuration for your Electron build lives inside package.json
under build
. You can read the docs here.
Managing Dependencies
Each package listed in package.json
under dependencies
will automatically be packaged with your app and rebuilt for Electron if it contains native bindings. Only list packages here that are necessary for your app's runtime. Angular, CoreJS and related packages are compiled by Webpack and therefore not necessary at runtime. These and anything else not needed to run your app should go under devDependencies
.
Any time you run npm install
or yarn install
, your app dependencies will automatically be built and packaged for your current operating system and architecture. After you run npm update
or yarn upgrade
, you will need to manually update app's dependencies are up-to-date as well:
# if you use yarn
yarn run install-app-deps
# otherwise
npm run install-app-deps
AoT Don'ts
The following are some things that will make AoT compile fail.
- Don’t use require statements for your templates or styles, use styleUrls and templateUrls, the angular2-template-loader plugin will change it to require at build time.
- Don’t use default exports.
- Don’t use
form.controls.controlName
, useform.get(‘controlName’)
- Don’t use
control.errors?.someError
, usecontrol.hasError(‘someError’)
- Don’t use functions in your providers, routes or declarations, export a function and then reference that function name
- @Inputs, @Outputs, View or Content Child(ren), Hostbindings, and any field you use from the template or annotate for Angular should be public
External Stylesheets
Any stylesheets (Sass or CSS) placed in the src/styles
directory and imported into your project will automatically be compiled into an external .css
and embedded in your production builds.
For example to use Bootstrap as an external stylesheet:
- Create a
styles.scss
file (name doesn't matter) in thesrc/styles
directory. npm install
the version of Boostrap you want.- In
styles.scss
add@import 'bootstrap/scss/bootstrap.scss';
- In
src/app/app.module.ts
add underneath the other import statements:import '../styles/styles.scss';
Lazy Loading
When you lazy load a module in your router config, it will go into a separate chunk and the browser will download the code after your main application is finished loading. This results in faster start-up time.
You can make a module lazy load by using the loadChildren
syntax in your route definitions:
{ path: 'detail', loadChildren: './+detail#DetailModule'}
To make sure TypeScript compiles your lazy-loaded modules, declare them in ./src/app/lazy-loaded.ts
with an import statement. Declaring the modules allows TypeScript to only compile the necessary files. Previously TS would compile every single .ts
file in your project tree on every single build which was inefficient and lead to issues.
Contributing
You can include more examples as components but they must introduce a new concept such as Home
component (separate folders), and Todo (services). I'll accept pretty much everything so feel free to open a Pull-Request
TypeScript
To take full advantage of TypeScript with autocomplete you would have to install it globally and use an editor with the correct TypeScript plugins.
Use latest TypeScript compiler
TypeScript 2.1.x includes everything you need. Make sure to upgrade, even if you installed TypeScript previously.
npm install --global typescript
Use a TypeScript-aware editor
We have good experience using these editors:
Visual Studio Code + Debugger for Chrome
Install Debugger for Chrome and see docs for instructions to launch Chrome
The included .vscode
automatically connects to the webpack development server on port 3000
.
Types
When you include a module that doesn't include Type Definitions inside of the module you can include external Type Definitions with @types
i.e, to have youtube api support, run this command in terminal:
npm i @types/youtube @types/gapi @types/gapi.youtube
In some cases where your code editor doesn't support Typescript 2 yet or these types weren't listed in tsconfig.json
, add these to "src/custom-typings.d.ts" to make peace with the compile check:
import '@types/gapi.youtube';
import '@types/gapi';
import '@types/youtube';
Custom Type Definitions
When including 3rd party modules you also need to include the type definition for the module if they don't provide one within the module. You can try to install it with @types
npm install @types/node
npm install @types/lodash
If you can't find the type definition in the registry we can make an ambient definition in this file for now. For example
declare module "my-module" {
export function doesSomething(value: string): string;
}
If you're prototyping and you will fix the types later you can also declare it as type any
declare var assert: any;
declare var _: any;
declare var $: any;
If you're importing a module that uses Node.js modules which are CommonJS you need to import as
import * as _ from 'lodash';
Frequently asked questions
See the FAQ at
AngularClass/angular2-webpack-starter
.
enjoy — Colin Skow & AngularClass