├── app
├── package.json
├── hello-world.html
├── app.js
└── main.js
├── package.json
├── LICENCE
└── README.md
/app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "koa-hello-world",
3 | "description": "Koa 'hello world' app",
4 | "version": "0.0.0",
5 | "author": "Chris Veness",
6 | "license": "MIT",
7 | "main": "main.js",
8 | "scripts": {
9 | "start-dev": "node app.js"
10 | },
11 | "dependencies": {
12 | "koa": "^1.2.4",
13 | "koa-handlebars": "^0.5.7",
14 | "koa-router": "^5.4.0"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/app/hello-world.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Hello World
5 |
6 |
7 |
8 |
13 |
14 |
15 |
16 |
17 |
18 | Hello World!
19 | Running on Node {{version}} ({{env}}); {{time}}
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "electron-koa-hello-world",
3 | "description": "Builder for Electron Koa App",
4 | "version": "0.0.0",
5 | "author": "Chris Veness",
6 | "license": "MIT",
7 | "repository": {
8 | "type": "git",
9 | "url": "https://github.com/chrisveness/electron-koa-app"
10 | },
11 | "scripts": {
12 | "start": "electron app/main.js",
13 | "build": "build",
14 | "postinstall": "install-app-deps"
15 | },
16 | "build": {
17 | "appId": "koa-app.id",
18 | "category": "public.app-category.developer-tools",
19 | "win": {
20 | "iconUrl": "http://eatodo.s3.amazonaws.com/icon.ico"
21 | }
22 | },
23 | "devDependencies": {
24 | "electron": "^1.4.2",
25 | "electron-builder": "^7.10.2"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/LICENCE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Chris Veness
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/app/app.js:
--------------------------------------------------------------------------------
1 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2 | /* app.js; minimal 'hello world' app (using router & handlebars) */
3 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
4 |
5 | const koa = require('koa'); // koa framework
6 | const router = require('koa-router')(); // router middleware for koa
7 | const handlebars = require('koa-handlebars'); // handlebars templating
8 |
9 | const app = koa();
10 |
11 | app.use(handlebars({
12 | extension: [ 'html', 'hbs', 'handlebars' ],
13 | root: __dirname, // required for running app from electron build directory
14 | viewsDir: '/',
15 | }));
16 |
17 | router.get('/', function*() {
18 | const context = { version: process.version, env: app.env, time: new Date() };
19 | console.log('router.get /', context);
20 | yield this.render('hello-world.html', context);
21 | });
22 |
23 | app.use(router.routes());
24 |
25 | app.listen(3000); // note: don't use "if (!module.parent)"!
26 | console.log('listening on port 3000');
27 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Electron Koa App
2 | ================
3 |
4 | Minimal example of running a [Koa](http://koajs.com/) app from within
5 | [Electron](http://electron.atom.io/), for creating multi-platform distributable executables.
6 |
7 | The Koa app is trivially simple (just a single page, using koa-router and koa-handlebars to ensure
8 | such basic architecture works). Replace the *app* with your own! (Note using NAN – native
9 | abstractions – will probably make life harder).
10 |
11 | Setup
12 | -----
13 |
14 | git clone https://github.com/chrisveness/electron-koa-app.git
15 | cd electron-koa-app
16 | npm install
17 |
18 | To run the app in browser
19 | -------------------------
20 |
21 | cd app
22 | npm run start-dev
23 |
24 | and open `localhost:3000` in your browser.
25 |
26 | To run the app in Electron
27 | --------------------------
28 |
29 | npm start
30 |
31 | To build a stand-alone Windows executable
32 | -----------------------------------------
33 |
34 | npm run build -- --win --x64
35 |
36 | which generates a setup file in the `dist\win` directory (only tested on Windows for Windows).
37 |
38 | Thx to [JDM](http://github.com/theallmightyjohnmanning/electron-express),
39 | [eriedl](https://github.com/electron-userland/electron-builder/issues/796#issuecomment-252152108),
40 | [electron-builder](https://github.com/electron-userland/electron-builder).
41 |
42 | Koa and Electron are still both rather moving targets. This was developed with Koa v1.2.4 and
43 | Electron v1.4.2, electron-builder v7.10.2.
44 |
--------------------------------------------------------------------------------
/app/main.js:
--------------------------------------------------------------------------------
1 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2 | /* main.js; adapted from electron.atom.io/docs/tutorial/quick-start with mods to run Koa.js app */
3 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
4 |
5 | const { app, BrowserWindow } = require('electron'); // www.npmjs.com/package/electron
6 | const spawn = require('child_process').spawn; // nodejs.org/api/child_process.html
7 | const path = require('path'); // nodejs.org/api/path.html
8 |
9 | if (handleSquirrelCommand()) return; // squirrel event handled, app will exit in 1000ms
10 |
11 | let win = null; // keep global reference to window object to avoid automatic closing on JS GC
12 |
13 | process.env.NODE_ENV = process.env.NODE_ENV || 'production'; // default to production environment
14 |
15 | const shouldQuit = app.makeSingleInstance(function(otherInstArgv, otherInstWorkingDir) {
16 | // someone tried to run a second instance, we should focus our window
17 | if (win != null) {
18 | if (win.isMinimized()) win.restore();
19 | win.focus();
20 | }
21 | });
22 |
23 | if (shouldQuit) app.quit();
24 |
25 | function createWindow() {
26 | console.log('createWindow');
27 | app.server = require('./app.js'); // instantiate Koa app
28 | win = new BrowserWindow({ width: 800, height: 600 }); // create browser window
29 | win.loadURL('http://localhost:3000'); // load koa-app home page
30 | win.on('closed', () => { win = null; }); // dereference window object
31 | }
32 |
33 | app.on('ready', createWindow); // create window after Electron initialisation complete
34 |
35 | app.on('window-all-closed', () => { // quit when all windows are closed
36 | if (process.platform != 'darwin') app.quit(); // (except leave MacOS app active until Cmd+Q)
37 | });
38 |
39 | app.on('activate', () => { // re-recreate window when dock icon is clicked and no other windows open
40 | if (win == null) createWindow();
41 | });
42 |
43 |
44 | // qv www.npmjs.com/package/electron-windows-installer
45 | function handleSquirrelCommand() {
46 | if (process.platform != 'win32') return false; // only applies to Windows (win32 is both 32- & 64-bit)
47 |
48 | const command = process.argv[1];
49 | const target = path.basename(process.execPath);
50 |
51 | switch (command) {
52 | case '--squirrel-install':
53 | case '--squirrel-updated':
54 | update(['--createShortcut=' + target + ''], app.quit);
55 | return true;
56 | case '--squirrel-uninstall':
57 | update(['--removeShortcut=' + target + ''], app.quit);
58 | return true;
59 | case '--squirrel-obsolete':
60 | app.quit();
61 | return true;
62 | }
63 |
64 | return false;
65 | }
66 |
67 | function update(args, done) {
68 | const updateExe = path.resolve(path.dirname(process.execPath), '..', 'Update.exe');
69 | spawn(updateExe, args, { detached: true }).on('close', done);
70 | }
71 |
--------------------------------------------------------------------------------