From 4b0467ed42952c02065c9ed1d0a19040abd7a68e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Xalambr=C3=AD?= Date: Wed, 9 Aug 2017 00:56:23 -0500 Subject: [PATCH] Add Electron example (#1430) * Add Electron usage example * Remove the deploy part * Only allow GET request to our HTTP server * Only allow request from an electron app (checking the user agent) * Add warning about the local HTTP server * Update package.json * Update example to use Next.js v3 * Added required package.json fields with placeholders * Use next:// file protocol to open internal built files * Create next.config.js * Update set-menu.js * Update example to merge it with electron-next-skeleton ideas --- examples/with-electron/README.md | 25 ++++++++ examples/with-electron/main/index.js | 36 ++++++++++++ examples/with-electron/package.json | 31 ++++++++++ .../with-electron/renderer/next.config.js | 14 +++++ .../with-electron/renderer/pages/start.js | 57 +++++++++++++++++++ 5 files changed, 163 insertions(+) create mode 100644 examples/with-electron/README.md create mode 100644 examples/with-electron/main/index.js create mode 100644 examples/with-electron/package.json create mode 100644 examples/with-electron/renderer/next.config.js create mode 100644 examples/with-electron/renderer/pages/start.js diff --git a/examples/with-electron/README.md b/examples/with-electron/README.md new file mode 100644 index 00000000..799a498c --- /dev/null +++ b/examples/with-electron/README.md @@ -0,0 +1,25 @@ +# Electron application example + +## How to use + +Download the example [or clone the repo](https://github.com/zeit/next.js): + +```bash +curl https://codeload.github.com/zeit/next.js/tar.gz/master | tar -xz --strip=2 next.js-master/examples/with-electron +cd with-electron +``` + +Install it and run: + +```bash +npm install +npm start +``` + +## The idea behind the example + +This example show how you can use Next.js inside an Electron application to avoid a lot of configuration, use Next.js router as view and use server-render to speed up the initial render of the application. + +For development it's going to run a HTTP server and let Next.js handle routing. In production it use `next export` to pre-generate HTML static files and use them in your app instead of running an HTTP server. + +You can create the production app using `npm run dist`. diff --git a/examples/with-electron/main/index.js b/examples/with-electron/main/index.js new file mode 100644 index 00000000..2cbf0869 --- /dev/null +++ b/examples/with-electron/main/index.js @@ -0,0 +1,36 @@ +// Native +const { join } = require('path') +const { format } = require('url') + +// Packages +const { BrowserWindow, app, ipcMain } = require('electron') +const isDev = require('electron-is-dev') +const prepareNext = require('electron-next') + +// Prepare the renderer once the app is ready +app.on('ready', async () => { + await prepareNext('./renderer') + + const mainWindow = new BrowserWindow({ + width: 800, + height: 600 + }) + + const url = isDev + ? 'http://localhost:8000/start' + : format({ + pathname: join(__dirname, '../renderer/start/index.html'), + protocol: 'file:', + slashes: true + }) + + mainWindow.loadURL(url) +}) + +// Quit the app once all windows are closed +app.on('window-all-closed', app.quit) + +// listen the channel `message` and resend the received message to the renderer process +ipcMain.on('message', (event, message) => { + event.sender.send('message', message) +}) diff --git a/examples/with-electron/package.json b/examples/with-electron/package.json new file mode 100644 index 00000000..1667f039 --- /dev/null +++ b/examples/with-electron/package.json @@ -0,0 +1,31 @@ +{ + "name": "electron-next-skeleton", + "productName": "ElectronNext", + "version": "1.0.0", + "main": "main/index.js", + "scripts": { + "start": "electron .", + "build": "next build renderer && next export renderer", + "dist": "npm run build && build --dir" + }, + "build": { + "asar": false, + "extraResources": [ + { + "from": "renderer/out", + "to": "app/renderer" + } + ] + }, + "devDependencies": { + "electron": "^1.6.11", + "electron-builder": "^19.19.1", + "next": "beta", + "react": "15.6.1", + "react-dom": "15.6.1" + }, + "dependencies": { + "electron-is-dev": "0.3.0", + "electron-next": "3.0.8" + } +} diff --git a/examples/with-electron/renderer/next.config.js b/examples/with-electron/renderer/next.config.js new file mode 100644 index 00000000..3bc97cd5 --- /dev/null +++ b/examples/with-electron/renderer/next.config.js @@ -0,0 +1,14 @@ +module.exports = { + webpack (config, { dev }) { + config.target = 'electron-renderer' + return config + }, + exportPathMap () { + // Let Next.js know where to find the entry page + // when it's exporting the static bundle for the use + // in the production version of your app + return { + '/start': { page: '/start' } + } + } +} diff --git a/examples/with-electron/renderer/pages/start.js b/examples/with-electron/renderer/pages/start.js new file mode 100644 index 00000000..1025a5fa --- /dev/null +++ b/examples/with-electron/renderer/pages/start.js @@ -0,0 +1,57 @@ +import { Component } from 'react' +import { ipcRenderer } from 'electron' + +export default class extends Component { + state = { + input: '', + message: null + } + + componentDidMount () { + // start listening the channel message + ipcRenderer.on('message', this.handleMessage) + } + + componentWillUnmount () { + // stop listening the channel message + ipcRenderer.removeListener('message', this.handleMessage) + } + + handleMessage = (event, message) => { + // receive a message from the main process and save it in the local state + this.setState({ message }) + } + + handleChange = event => { + this.setState({ input: event.target.value }) + } + + handleSubmit = event => { + event.preventDefault() + ipcRenderer.send('message', this.state.input) + this.setState({ message: null }) + } + + render () { + return ( +
+

Hello Electron!

+ + {this.state.message && +

{this.state.message}

+ } + +
+ +
+ + +
+ ) + } +}