├── 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 | --------------------------------------------------------------------------------