├── public ├── favicon.ico ├── index.html └── electron.js ├── src ├── index.css ├── components │ ├── Home │ │ ├── Home.css │ │ ├── Home.test.js │ │ └── Home.js │ ├── About │ │ ├── About.css │ │ ├── About.test.js │ │ └── About.js │ └── Header │ │ ├── Header.test.js │ │ ├── Header.css │ │ ├── Header.js │ │ └── logo.svg └── index.js ├── .gitignore ├── README.md └── package.json /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcmunder/electron-create-react-app/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | text-align: center; 6 | } 7 | -------------------------------------------------------------------------------- /src/components/Home/Home.css: -------------------------------------------------------------------------------- 1 | .link-container { 2 | margin-top: 50px; 3 | } 4 | 5 | .link { 6 | padding: 10px; 7 | border: 1px solid black; 8 | border-radius: 3px; 9 | color: black; 10 | text-decoration: none; 11 | } 12 | -------------------------------------------------------------------------------- /src/components/About/About.css: -------------------------------------------------------------------------------- 1 | .link-container { 2 | margin-top: 50px; 3 | } 4 | 5 | .link { 6 | padding: 10px; 7 | border: 1px solid black; 8 | border-radius: 3px; 9 | color: black; 10 | text-decoration: none; 11 | } 12 | -------------------------------------------------------------------------------- /src/components/Header/Header.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import Header from './Header' 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div') 7 | ReactDOM.render(
, div) 8 | }) 9 | -------------------------------------------------------------------------------- /src/components/Header/Header.css: -------------------------------------------------------------------------------- 1 | .logo { 2 | animation: logo infinite 20s linear; 3 | height: 80px; 4 | } 5 | 6 | .header { 7 | background-color: #222; 8 | height: 150px; 9 | padding: 20px; 10 | color: white; 11 | } 12 | 13 | @keyframes logo { 14 | from { transform: rotate(0deg); } 15 | to { transform: rotate(360deg); } 16 | } 17 | -------------------------------------------------------------------------------- /src/components/Header/Header.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import logo from './logo.svg' 3 | import './Header.css' 4 | 5 | const Header = props => { 6 | return ( 7 |
8 | logo 9 |

{props.headerText}

10 |
11 | ) 12 | } 13 | 14 | export default Header 15 | -------------------------------------------------------------------------------- /src/components/About/About.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import {MemoryRouter} from 'react-router-dom' 4 | import About from './About' 5 | 6 | it('renders without crashing', () => { 7 | const div = document.createElement('div') 8 | ReactDOM.render( 9 | 10 | 11 | , 12 | div 13 | ) 14 | }) 15 | -------------------------------------------------------------------------------- /src/components/Home/Home.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import {MemoryRouter} from 'react-router-dom' 4 | import Home from './Home' 5 | 6 | it('renders without crashing', () => { 7 | const div = document.createElement('div') 8 | 9 | ReactDOM.render( 10 | 11 | 12 | , 13 | div 14 | ) 15 | }) 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | /dist 12 | 13 | # misc 14 | .DS_Store 15 | .env.local 16 | .env.development.local 17 | .env.test.local 18 | .env.production.local 19 | 20 | npm-debug.log* 21 | yarn-debug.log* 22 | yarn-error.log* 23 | .idea 24 | -------------------------------------------------------------------------------- /src/components/Home/Home.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {Link} from 'react-router-dom' 3 | import Header from '../Header/Header' 4 | import './Home.css' 5 | 6 | const Home = props => ( 7 |
8 |
9 |
10 | 13 | Go to About 14 | 15 |
16 |
17 | ) 18 | 19 | export default Home 20 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import Home from './components/Home/Home' 4 | import About from './components/About/About' 5 | import {HashRouter as Router, Route} from 'react-router-dom' 6 | import './index.css' 7 | 8 | ReactDOM.render( 9 | 10 |
11 | 12 | 13 |
14 |
, 15 | document.getElementById('root') 16 | ) 17 | -------------------------------------------------------------------------------- /src/components/About/About.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {Link} from 'react-router-dom' 3 | import Header from '../Header/Header' 4 | import './About.css' 5 | 6 | const About = props => { 7 | return ( 8 |
9 |
10 |
11 | 14 | Go to Home 15 | 16 |
17 |
18 | ) 19 | } 20 | 21 | export default About 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # electron-create-react-app 2 | 3 | Boilerplate linking [electron](http://electron.atom.io/) with [create-react-app](https://github.com/facebookincubator/create-react-app). 4 | 5 | **Many things were shamelessly copied from 6 | [here](https://github.com/kitze/react-electron-example). See [this article](https://medium.com/@kitze/%EF%B8%8F-from-react-to-an-electron-app-ready-for-production-a0468ecb1da3) 7 | for very good background information.** 8 | 9 | ## Usage 10 | 11 | Run tests: 12 | 13 | ```bash 14 | npm test 15 | ``` 16 | 17 | Run in dev mode: 18 | 19 | ```bash 20 | npm run electron-dev 21 | ``` 22 | 23 | Build: 24 | 25 | ```bash 26 | npm run build 27 | ``` 28 | 29 | Package: 30 | 31 | ```bash 32 | npm run electron-pack 33 | ``` 34 | 35 | ## Copyright and license 36 | 37 | Copyright 2017, Matthias Munder. 38 | Licensed under the [MIT license](./LICENSE). 39 | 40 | [![js-standard-style](https://cdn.rawgit.com/feross/standard/master/badge.svg)](https://github.com/feross/standard) 41 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "electron-create-react-app", 3 | "description": "Boilerplate linking electron and create-react-app", 4 | "version": "0.1.0", 5 | "private": true, 6 | "author": { 7 | "name": "mcmunder", 8 | "email": "matthiasmunder@gmail.com", 9 | "url": "https://mcmunder.de" 10 | }, 11 | "dependencies": { 12 | "cross-env": "5.1.3", 13 | "electron-is-dev": "0.3.0", 14 | "react": "16.2.0", 15 | "react-dom": "16.2.0", 16 | "react-router-dom": "^4.2.2" 17 | }, 18 | "devDependencies": { 19 | "chalk": "^2.3.1", 20 | "concurrently": "3.5.1", 21 | "electron": "1.8.2", 22 | "electron-builder": "20.2.0", 23 | "electron-devtools-installer": "^2.2.3", 24 | "react-scripts": "1.1.1", 25 | "wait-on": "2.1.0" 26 | }, 27 | "main": "public/electron.js", 28 | "homepage": "./", 29 | "build": { 30 | "appId": "com.example.electron-create-react-app" 31 | }, 32 | "scripts": { 33 | "start": "react-scripts start", 34 | "debug": "npm run electron-dev -- --inspect=5858", 35 | "build": "react-scripts build", 36 | "test": "react-scripts test --env=jsdom", 37 | "eject": "react-scripts eject", 38 | "electron-dev": 39 | "concurrently \"cross-env BROWSER=none npm start\" \"wait-on http://localhost:3000 && electron .\"", 40 | "electron-pack": "build -- --em.main=build/electron.js", 41 | "preelectron-pack": "npm run build" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 22 | React App 23 | 24 | 25 | 26 | 29 |
30 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /public/electron.js: -------------------------------------------------------------------------------- 1 | const electron = require('electron') 2 | const path = require('path') 3 | const url = require('url') 4 | const isDev = require('electron-is-dev') 5 | const chalk = require('chalk') 6 | const installExtension = require('electron-devtools-installer').default 7 | const { 8 | REACT_DEVELOPER_TOOLS, 9 | REDUX_DEVTOOLS 10 | } = require('electron-devtools-installer') 11 | 12 | const app = electron.app 13 | const BrowserWindow = electron.BrowserWindow 14 | 15 | // Keep a global reference of the window object, if you don't, the window will 16 | // be closed automatically when the JavaScript object is garbage collected. 17 | let mainWindow 18 | 19 | const createWindow = () => { 20 | mainWindow = new BrowserWindow({width: 900, height: 680}) 21 | 22 | mainWindow.loadURL( 23 | isDev 24 | ? 'http://localhost:3000' 25 | : `file://${path.join(__dirname, '../build/index.html')}` 26 | ) 27 | 28 | if (isDev) { 29 | mainWindow.webContents.openDevTools() 30 | } 31 | 32 | mainWindow.on('closed', () => { 33 | // Dereference the window object, usually you would store windows 34 | // in an array if your app supports multi windows, this is the time 35 | // when you should delete the corresponding element. 36 | mainWindow = null 37 | }) 38 | } 39 | 40 | const installExtensions = async () => { 41 | try { 42 | const extensions = { 43 | REACT_DEVELOPER_TOOLS: REACT_DEVELOPER_TOOLS, 44 | REDUX_DEVTOOLS: REACT_DEVELOPER_TOOLS 45 | } 46 | 47 | await Object.keys(extensions).forEach(extensionName => { 48 | installExtension(extensions[extensionName]) 49 | console.log(chalk.green(`Added Extension: ${extensionName}`)) 50 | }) 51 | 52 | console.log(chalk.green('All extensions installed successfully!')) 53 | createWindow() 54 | } catch (err) { 55 | console.log(chalk.red(err)) 56 | } 57 | } 58 | 59 | app.on('ready', isDev ? installExtensions : createWindow) 60 | 61 | app.on('window-all-closed', () => { 62 | if (process.platform !== 'darwin') { 63 | app.quit() 64 | } 65 | }) 66 | 67 | app.on('activate', () => { 68 | if (mainWindow === null) { 69 | createWindow() 70 | } 71 | }) 72 | -------------------------------------------------------------------------------- /src/components/Header/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | --------------------------------------------------------------------------------