From d0e00a4f07e5226a9a1e41c851299d8c40faa1a3 Mon Sep 17 00:00:00 2001 From: EGOIST <0x142857@gmail.com> Date: Wed, 15 Feb 2017 14:56:18 +0800 Subject: [PATCH] add electron template --- README.md | 1 + bin/vbuild-init | 15 +++++++-- docs/recipes/electron-app.md | 31 +++++++++++++++++++ lib/index.js | 2 +- template/app/index.js | 59 ++++++++++++++++++++++++++++++++++++ template/app/package.json | 14 +++++++++ template/package.json | 24 +++++++++++++++ template/vbuild.config.js | 8 ++++- 8 files changed, 150 insertions(+), 4 deletions(-) create mode 100644 docs/recipes/electron-app.md create mode 100644 template/app/index.js create mode 100644 template/app/package.json diff --git a/README.md b/README.md index 81b7cd71..c9b4fe43 100644 --- a/README.md +++ b/README.md @@ -334,6 +334,7 @@ module.exports = { ## Recipes - [Progressive web app](./docs/recipes/progressive-web-app.md) +- [Electron app](./docs/recipes/electron-app.md) ## FAQ diff --git a/bin/vbuild-init b/bin/vbuild-init index a60d27ba..b1bc1526 100755 --- a/bin/vbuild-init +++ b/bin/vbuild-init @@ -14,6 +14,7 @@ const cli = meow(` ${chalk.bold('Options:')} ${chalk.yellow('--force, -f')} ${chalk.dim('Override existing folder')} + ${chalk.yellow('--electron')} ${chalk.dim('Generated Electron app')} ${chalk.yellow('--help, -h')} ${chalk.dim('Output help (You are here!)')} ${chalk.yellow('--version, -v')} ${chalk.dim('Output version')} @@ -40,9 +41,15 @@ if (!cli.flags.force && fs.existsSync(dest)) { logger.fatal(`${chalk.yellow(tildify(dest))} already exists, you can use \`--force\` option to override it`) } +const data = Object.assign({ + name, + electron: false +}, cli.flags) + kopy(_.ownDir('template'), dest, { - data: { - name + data, + filters: { + 'app/**': data.electron } }).then(({files}) => { console.log() @@ -62,6 +69,10 @@ kopy(_.ownDir('template'), dest, { console.log(chalk.bold('To get started:')) console.log(`\n cd ${name}`) console.log(' npm run dev\n') + if (data.electron) { + console.log(chalk.bold('In another tab:\n')) + console.log(' npm run app\n') + } console.log(chalk.bold('To build for production:')) console.log('\n npm run build\n') diff --git a/docs/recipes/electron-app.md b/docs/recipes/electron-app.md new file mode 100644 index 00000000..d8473fea --- /dev/null +++ b/docs/recipes/electron-app.md @@ -0,0 +1,31 @@ +# Electron app + +The simplest way is to run `vbuild init my-app --electron` to generate an Electron app. + +Basically, comparing to a normal web app, it: + +- Set webpack [target](https://webpack.js.org/configuration/target/#target) to `electron-renderer` to exclude native electron modules +- The dist folder is set to `app/dist`, app folder contains the code for electron main process, and you may distribute the folder using [electron-builder](https://github.com/electron-userland/electron-builder) +- The main process load different `index.html` in different mode: + - In dev mode, it loads `http://localhost:port/index.html` (for hot reloading) + - In production mode, where your distributed app runs, it loads `app/dist/index.html` + +To develop an Electron with vbuild: + +```bash +# start the dev server +# you won't need to open url in browser +npm run dev + +# open electron app +npm run app + +# to distribute +npm run build +# distribute for all platforms: mac/linux/windows +npm run dist +# or separate process +npm run dist:win +npm run dist:mac +npm run dist:linux +``` diff --git a/lib/index.js b/lib/index.js index dc0f6575..341a6257 100644 --- a/lib/index.js +++ b/lib/index.js @@ -134,7 +134,7 @@ function start(cliOptions) { // eslint-disable-line complexity } }), new webpack.DefinePlugin({ - 'proess.env.NODE_ENV': JSON.stringify(options.dev ? 'development' : 'production') + 'process.env.NODE_ENV': JSON.stringify(options.dev ? 'development' : 'production') }), new webpack.LoaderOptionsPlugin({ minimize: !options.dev, diff --git a/template/app/index.js b/template/app/index.js new file mode 100644 index 00000000..be2cccbd --- /dev/null +++ b/template/app/index.js @@ -0,0 +1,59 @@ +const electron = require('electron') +// Module to control application life. +const app = electron.app +// Module to create native browser window. +const BrowserWindow = electron.BrowserWindow + +const path = require('path') +const url = require('url') + +const isDev = require('electron-is-dev') + +// Keep a global reference of the window object, if you don't, the window will +// be closed automatically when the JavaScript object is garbage collected. +let mainWindow + +function createWindow () { + // Create the browser window. + mainWindow = new BrowserWindow({width: 800, height: 600}) + + // and load the index.html of the app. + const index = isDev ? `http://localhost:4000` : `file://${path.join(__dirname, 'dist/index.html')}` + mainWindow.loadURL(index) + + // Open the DevTools. + mainWindow.webContents.openDevTools() + + // Emitted when the window is closed. + mainWindow.on('closed', function () { + // Dereference the window object, usually you would store windows + // in an array if your app supports multi windows, this is the time + // when you should delete the corresponding element. + mainWindow = null + }) +} + +// This method will be called when Electron has finished +// initialization and is ready to create browser windows. +// Some APIs can only be used after this event occurs. +app.on('ready', createWindow) + +// Quit when all windows are closed. +app.on('window-all-closed', function () { + // On OS X it is common for applications and their menu bar + // to stay active until the user quits explicitly with Cmd + Q + if (process.platform !== 'darwin') { + app.quit() + } +}) + +app.on('activate', function () { + // On OS X it's common to re-create a window in the app when the + // dock icon is clicked and there are no other windows open. + if (mainWindow === null) { + createWindow() + } +}) + +// In this file you can include the rest of your app's specific main process +// code. You can also put them in separate files and require them here. diff --git a/template/app/package.json b/template/app/package.json new file mode 100644 index 00000000..c49e1c36 --- /dev/null +++ b/template/app/package.json @@ -0,0 +1,14 @@ +{ + "name": "<%= name %>", + "productionName": "<%= name %>", + "description": "Electron app built with vbuild", + "version": "0.0.0", + "repository": {}, + "dependencies": { + <%_ if (electron) { -%> + "electron-is-dev": "^0.1.2" + <%_ } -%> + }, + "author": "Your Name ", + "license": "MIT" +} diff --git a/template/package.json b/template/package.json index e4c35b21..a33d14ea 100644 --- a/template/package.json +++ b/template/package.json @@ -5,10 +5,34 @@ "repository": {}, "scripts": { "test": "echo lol", + <%_ if (electron) { -%> + "app": "electron app/index.js", + "dist": "npm run dist:mac && npm run dist:win && npm run dist:linux", + "dist:mac": "build --mac", + "dist:win": "build --win --ia32", + "dist:linux": "build --linux deb tar.xz", + "postinstall": "install-app-deps", + <%_ } -%> "dev": "vbuild -dc", "build": "vbuild -c" }, + <%_ if (electron) { -%> + "build": { + "appId": "com.egoistian.devdocs-app", + "category": "public.app-category.developer-tools", + "asar": true, + "win": { + "target": [ + "squirrel" + ] + } + }, + <%_ } -%> "devDependencies": { + <%_ if (electron) { -%> + "electron": "^1.4.15", + "electron-builder": "^13.7.0", + <%_ } -%> "vbuild": "^6.0.0" }, "license": "MIT" diff --git a/template/vbuild.config.js b/template/vbuild.config.js index 6e203f76..cf375775 100644 --- a/template/vbuild.config.js +++ b/template/vbuild.config.js @@ -2,6 +2,7 @@ const path = require('path') module.exports = (options, req) => ({ entry: 'src/index.js', + dist: '<% if (electron) { %>app/dist<% } else { %>dist<% } %>', html: { title: '<%= name %>' }, @@ -10,9 +11,14 @@ module.exports = (options, req) => ({ browsers: ['ie > 8', 'last 4 versions'] }) ], - vendor: ['vue'], webpack(cfg) { cfg.resolve.modules.push(path.resolve('src')) + <% if (electron) { %> + if (!options.dev) { + cfg.output.publicPath = './' + } + cfg.target = 'electron-renderer' + <% } %> return cfg } })