├── .gitignore ├── README.md ├── app ├── build │ ├── bundle.css │ ├── bundle.js │ ├── electron.png │ ├── react.png │ └── webpack.png ├── index.html └── src │ ├── App.jsx │ ├── assets │ ├── electron.png │ ├── react.png │ └── webpack.png │ ├── components │ ├── Link │ │ ├── index.jsx │ │ └── styles.css │ └── Logo │ │ ├── index.jsx │ │ └── styles.css │ ├── global.css │ └── renderer_process.js ├── main_process.js ├── package.json └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | # 2 | *-lock.json 3 | 4 | # Logs 5 | logs 6 | *.log 7 | npm-debug.log* 8 | 9 | # Runtime data 10 | pids 11 | *.pid 12 | *.seed 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # node-waf configuration 27 | .lock-wscript 28 | 29 | # Compiled binary addons (http://nodejs.org/api/addons.html) 30 | build/Release 31 | 32 | # Dependency directories 33 | node_modules 34 | jspm_packages 35 | 36 | # Optional npm cache directory 37 | .npm 38 | 39 | # Optional REPL history 40 | .node_repl_history 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # electron-react-webpack 2 | Try this Electron & React 16 & Webpack 4 template for a quick development and prototyping. 3 | 4 | ![w10 sample](https://user-images.githubusercontent.com/11739632/37350993-59ad48d4-26da-11e8-9ac5-d3539cf1e2f9.PNG) 5 | 6 | ## Install 7 | ``` bash 8 | # Clone the repository 9 | $ git clone https://github.com/pastahito/electron-react-webpack 10 | 11 | # Go into the repository 12 | $ cd electron-react-webpack 13 | 14 | # Install dependencies 15 | $ npm install 16 | ``` 17 | 18 | ## Develop 19 | Just run this command to start developing with hot reloading. 20 | ``` bash 21 | $ npm start 22 | ``` 23 | 24 | ## What's included 25 | - JSX support for React. 26 | - CSS modules support. 27 | - JS, CSS and assets automatic bundling. 28 | - Hot reloading via Webpack 4. 29 | 30 | 31 | ## Folder structure 32 | ``` 33 | ├── electron-react-webpack/ # Your project's name, you can rename it 34 | 35 | ├── app/ 36 | 37 | ├── build/ # Webpack 4 will manage this folder for you 38 | ├── bundle.css # Bundled CSS 39 | ├── bundle.js # Bundled JS 40 | ├── ... # Your images will be copied here 41 | 42 | ├── src/ 43 | 44 | ├── assets/ # Images 45 | ├── electron.png 46 | ├── react.png 47 | ├── webpack.png 48 | 49 | ├── components/ # React Components 50 | ├── Link/ # To keep them modularized follow this structure: 51 | ├── index.jsx # Your component's React code 52 | ├── styles.css # Your component's scoped CSS 53 | ├── Logo/ 54 | ├── index.jsx 55 | ├── styles.css 56 | 57 | ├── App.jsx # React main component where everything is tied up 58 | ├── renderer_process.js # Electron's renderer-process, where you React app is called. 59 | ├── global.css # Global CSS and global constants go here 60 | 61 | ├── index.html # This HTML only uses build/ folder's files 62 | 63 | ├── main_process.js # Electron's main process. Whole app is launched from here 64 | ├── package.json 65 | ├── webpack.config.js # Webpack 4 setup 66 | ``` 67 | 68 | ## Related 69 | - [electron-vue-webpack](https://github.com/pastahito/electron-vue-webpack) - 70 | Minimal Electron template using Vue 2 instead of React. 71 | -------------------------------------------------------------------------------- /app/build/bundle.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Every class name will be hashed so it can be used their own component scoped 3 | * Use classes instead of ids 4 | */ 5 | 6 | ._1WcHgGtKrxqKCsGYj62eVK { 7 | height: 100px; 8 | } 9 | /* 10 | * Every class name will be hashed so it can be used their own component scoped 11 | * Use classes instead of ids 12 | */ 13 | 14 | .sFVP9dDAE84wfL1CUC_NG { 15 | color: var(--primary-color); /* Using global constants example */ 16 | } 17 | 18 | ._1FRk9e-PmvCebL7xwPN-Hf { /* Composition example */ 19 | text-decoration: none; 20 | } 21 | /* 22 | * Global constants goes here 23 | */ 24 | :root { 25 | --primary-color: #42b983; 26 | } 27 | 28 | 29 | /* 30 | * Global CSS goes here, it requires to use :global before each style 31 | */ 32 | html { 33 | height: 100%; 34 | } 35 | body { 36 | display: flex; 37 | align-items: center; 38 | justify-content: center; 39 | height: 100%; 40 | margin: auto; 41 | } 42 | #app { 43 | color: #2c3e50; 44 | max-width: 600px; 45 | font-family: Source Sans Pro, Helvetica, sans-serif; 46 | text-align: center; 47 | } 48 | #app p { 49 | text-align: justify; 50 | } 51 | .hello { 52 | color: var(--primary-color); 53 | } 54 | -------------------------------------------------------------------------------- /app/build/electron.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renato-rg/electron-react-webpack/d0dd52b6103b007479baab4e45d442b784710138/app/build/electron.png -------------------------------------------------------------------------------- /app/build/react.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renato-rg/electron-react-webpack/d0dd52b6103b007479baab4e45d442b784710138/app/build/react.png -------------------------------------------------------------------------------- /app/build/webpack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renato-rg/electron-react-webpack/d0dd52b6103b007479baab4e45d442b784710138/app/build/webpack.png -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Electron + React + Webpack 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/App.jsx: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react' 2 | import {render} from 'react-dom' 3 | import Logo from './components/Logo/' 4 | import Link from './components/Link/' 5 | 6 | import ElectronImg from './assets/electron.png' 7 | import ReactImg from './assets/react.png' 8 | import WebpackImg from './assets/webpack.png' 9 | 10 | const logos = [ 11 | ElectronImg, 12 | ReactImg, 13 | WebpackImg 14 | ] 15 | 16 | 17 | export default class App extends Component { 18 | render() { 19 | const logosRender = logos.map( (logo, index) => { 20 | return 21 | }) 22 | 23 | return ( 24 |
25 | {logosRender} 26 | 27 |
28 |

Hello React!

29 |
30 | 31 |

32 | If you are trying to build Electron apps using React, or you just 33 | want to play around with them, feel free to use this 34 | seed as a starting point. 35 |

36 | 37 |

38 | Pay attention to how everything inside src/ folder is bundled 39 | into build/ folder, how global and scoped CSS work, how to compose 40 | React components, or simply how Webpack changes relative 41 | image paths to public paths after bundling the assets. 42 |

43 | 44 |

45 | Check out the docs for  46 | Electron,  47 | React and  48 | Webpack 4. 49 | Customize this template as you wish by adding any fancy tool 50 | you are used to. If you have any issue, please file an issue at this seed's  51 | 52 | repository. 53 |

54 |
55 | ) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /app/src/assets/electron.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renato-rg/electron-react-webpack/d0dd52b6103b007479baab4e45d442b784710138/app/src/assets/electron.png -------------------------------------------------------------------------------- /app/src/assets/react.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renato-rg/electron-react-webpack/d0dd52b6103b007479baab4e45d442b784710138/app/src/assets/react.png -------------------------------------------------------------------------------- /app/src/assets/webpack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renato-rg/electron-react-webpack/d0dd52b6103b007479baab4e45d442b784710138/app/src/assets/webpack.png -------------------------------------------------------------------------------- /app/src/components/Link/index.jsx: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react' 2 | import {shell} from 'electron' 3 | import styles from './styles.css' 4 | 5 | export default class Link extends Component { 6 | 7 | link (url) { 8 | shell.openExternal(url) 9 | } 10 | 11 | render () { 12 | console.log(styles); 13 | return ( 14 | {this.link(this.props.to)} } className={styles.link} > 15 | {this.props.children} 16 | 17 | ) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/src/components/Link/styles.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Every class name will be hashed so it can be used their own component scoped 3 | * Use classes instead of ids 4 | */ 5 | 6 | .tone { 7 | color: var(--primary-color); /* Using global constants example */ 8 | } 9 | 10 | .link { 11 | composes: tone; /* Composition example */ 12 | text-decoration: none; 13 | } 14 | -------------------------------------------------------------------------------- /app/src/components/Logo/index.jsx: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react' 2 | import styles from './styles.css' 3 | 4 | export default class Logo extends Component { 5 | render() { 6 | return 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /app/src/components/Logo/styles.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Every class name will be hashed so it can be used their own component scoped 3 | * Use classes instead of ids 4 | */ 5 | 6 | .logo { 7 | height: 100px; 8 | } 9 | -------------------------------------------------------------------------------- /app/src/global.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Global constants goes here 3 | */ 4 | :root { 5 | --primary-color: #42b983; 6 | } 7 | 8 | 9 | /* 10 | * Global CSS goes here, it requires to use :global before each style 11 | */ 12 | :global html { 13 | height: 100%; 14 | } 15 | :global body { 16 | display: flex; 17 | align-items: center; 18 | justify-content: center; 19 | height: 100%; 20 | margin: auto; 21 | } 22 | :global #app { 23 | color: #2c3e50; 24 | max-width: 600px; 25 | font-family: Source Sans Pro, Helvetica, sans-serif; 26 | text-align: center; 27 | } 28 | :global #app p { 29 | text-align: justify; 30 | } 31 | :global .hello { 32 | color: var(--primary-color); 33 | } 34 | -------------------------------------------------------------------------------- /app/src/renderer_process.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {render} from 'react-dom' 3 | import App from './App.jsx' 4 | import './global.css' 5 | 6 | render( 7 | , 8 | document.getElementById('app') 9 | ) 10 | -------------------------------------------------------------------------------- /main_process.js: -------------------------------------------------------------------------------- 1 | // Basic init 2 | const electron = require('electron') 3 | const {app, BrowserWindow} = electron 4 | 5 | // Let electron reloads by itself when webpack watches changes in ./app/ 6 | require('electron-reload')(__dirname) 7 | 8 | // To avoid being garbage collected 9 | let mainWindow 10 | 11 | app.on('ready', () => { 12 | 13 | mainWindow = new BrowserWindow({width: 800, height: 600}) 14 | 15 | mainWindow.loadURL(`file://${__dirname}/app/index.html`) 16 | 17 | }) 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "electron-react-webpack", 3 | "version": "1.0.0", 4 | "description": "Electron + React 16 + Webpack 4 template.", 5 | "main": "main_process.js", 6 | "scripts": { 7 | "bundle": "webpack --mode development", 8 | "serve": "electron .", 9 | "start": "npm-run-all --parallel bundle serve" 10 | }, 11 | "author": "J. Renato Ramos González ", 12 | "repository": "pastahito/electron-react-webpack", 13 | "license": "WTFPL", 14 | "devDependencies": { 15 | "babel-core": "^6.26.0", 16 | "babel-loader": "^7.1.4", 17 | "babel-preset-react": "^6.24.1", 18 | "css-loader": "^0.28.10", 19 | "electron": "^1.8.2", 20 | "electron-reload": "^1.2.2", 21 | "extract-text-webpack-plugin": "^4.0.0-beta.0", 22 | "file-loader": "^1.1.10", 23 | "npm-run-all": "^4.1.2", 24 | "webpack": "^4.1.1", 25 | "webpack-cli": "^2.0.11" 26 | }, 27 | "dependencies": { 28 | "react": "^16.2.0", 29 | "react-dom": "^16.2.0" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 2 | 3 | module.exports = { 4 | 5 | watch: true, 6 | 7 | target: 'electron-renderer', 8 | 9 | entry: './app/src/renderer_process.js', 10 | 11 | output: { 12 | path: __dirname + '/app/build', 13 | publicPath: 'build/', 14 | filename: 'bundle.js' 15 | }, 16 | 17 | module: { 18 | rules: [ 19 | { 20 | test: /\.jsx?$/, 21 | loader: 'babel-loader', 22 | options: { 23 | presets: ['react'] 24 | } 25 | }, 26 | { 27 | test: /\.css$/, 28 | loader: ExtractTextPlugin.extract({ 29 | loader: 'css-loader', 30 | options: { 31 | modules: true 32 | } 33 | }) 34 | }, 35 | { 36 | test: /\.(png|jpg|gif|svg)$/, 37 | loader: 'file-loader', 38 | query: { 39 | name: '[name].[ext]?[hash]' 40 | } 41 | } 42 | ] 43 | }, 44 | 45 | plugins: [ 46 | new ExtractTextPlugin({ 47 | filename: 'bundle.css', 48 | disable: false, 49 | allChunks: true 50 | }) 51 | ], 52 | 53 | resolve: { 54 | extensions: ['.js', '.json', '.jsx'] 55 | } 56 | 57 | } 58 | --------------------------------------------------------------------------------