├── .babelrc
├── .gitignore
├── src
├── assets
│ └── css
│ │ └── App.css
├── index.js
├── components
│ └── App
│ │ └── HelloWorld.js
└── containers
│ └── App.js
├── config
└── helpers.js
├── public
└── index.html
├── LICENSE
├── package.json
├── webpack.build.config.js
├── webpack.dev.config.js
├── README.md
└── main.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["react"]
3 | }
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | *npm-debug.log
3 | *.DS_Store
4 | dist/
5 | builds/
6 |
--------------------------------------------------------------------------------
/src/assets/css/App.css:
--------------------------------------------------------------------------------
1 | h1 {
2 | font-family: helvetica;
3 | font-weight: 200;
4 | }
5 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from 'react-dom';
3 | import App from './containers/App';
4 |
5 | // Now we can render our application into it
6 | render( , document.getElementById('app') );
7 |
--------------------------------------------------------------------------------
/config/helpers.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | // Helper functions
4 | function root(args) {
5 | args = Array.prototype.slice.call(arguments, 0);
6 | return path.join.apply(path, [__dirname].concat('../', ...args));
7 | }
8 |
9 | exports.root = root;
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Your App Name
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/components/App/HelloWorld.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const HelloWorld = () => (
4 |
5 |
Hello, Electron!
6 |
I hope you enjoy using basic-electron-react-boilerplate to start your dev off right!
7 |
8 | );
9 |
10 | export default HelloWorld;
--------------------------------------------------------------------------------
/src/containers/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | import '../assets/css/App.css';
4 |
5 | import HelloWorld from '../components/App/HelloWorld';
6 |
7 | class App extends Component {
8 | render() {
9 | return (
10 |
11 |
12 |
13 | );
14 | }
15 | }
16 |
17 | export default App;
18 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Phillip Barbiero
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 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "basic-electron-react-boilerplate",
3 | "version": "0.7.0",
4 | "description": "Minimal and modern react+electron+webpack boilerplate",
5 | "author": "Keith Weaver",
6 | "homepage": "https://github.com/keithweaver/basic-electron-react-boilerplate",
7 | "repository": {
8 | "type": "git",
9 | "url": "https://github.com/keithweaver/basic-electron-react-boilerplate.git"
10 | },
11 | "contributors": [
12 | "Phillip Barbiero ",
13 | "Keith Weaver ",
14 | "Denys Dovhan ",
15 | "Willy Ovalle "
16 | ],
17 | "license": "MIT",
18 | "main": "main.js",
19 | "scripts": {
20 | "prod": "webpack --config webpack.build.config.js && electron --noDevServer .",
21 | "dev": "webpack-dev-server --hot --host 0.0.0.0 --port 4000 --config=./webpack.dev.config.js",
22 | "build": "webpack --config webpack.build.config.js",
23 | "package": "webpack --config webpack.build.config.js",
24 | "postpackage": "electron-packager ./ --out=./builds"
25 | },
26 | "devDependencies": {
27 | "babel-core": "^6.24.1",
28 | "babel-loader": "^7.1.2",
29 | "babel-preset-react": "^6.24.1",
30 | "babili-webpack-plugin": "^0.1.2",
31 | "css-loader": "^0.28.1",
32 | "electron": "^1.7.8",
33 | "electron-packager": "^9.1.0",
34 | "extract-text-webpack-plugin": "^3.0.1",
35 | "file-loader": "^1.1.5",
36 | "html-webpack-plugin": "^2.28.0",
37 | "react": "^16.0.0",
38 | "react-dom": "^16.0.0",
39 | "style-loader": "^0.19.0",
40 | "webpack": "^3.6.0",
41 | "webpack-dev-server": "^2.4.5"
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/webpack.build.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 | const path = require('path');
3 | const HtmlWebpackPlugin = require('html-webpack-plugin');
4 | const BabiliPlugin = require('babili-webpack-plugin');
5 | const ExtractTextPlugin = require('extract-text-webpack-plugin');
6 |
7 | // Config directories
8 | const SRC_DIR = path.resolve(__dirname, 'src');
9 | const OUTPUT_DIR = path.resolve(__dirname, 'dist');
10 |
11 | // Any directories you will be adding code/files into, need to be added to this array so webpack will pick them up
12 | const defaultInclude = [SRC_DIR];
13 |
14 | module.exports = {
15 | entry: SRC_DIR + '/index.js',
16 | output: {
17 | path: OUTPUT_DIR,
18 | publicPath: './',
19 | filename: 'bundle.js'
20 | },
21 | module: {
22 | rules: [
23 | {
24 | test: /\.css$/,
25 | use: ExtractTextPlugin.extract({
26 | fallback: 'style-loader',
27 | use: 'css-loader'
28 | }),
29 | include: defaultInclude
30 | },
31 | {
32 | test: /\.jsx?$/,
33 | use: [{ loader: 'babel-loader' }],
34 | include: defaultInclude
35 | },
36 | {
37 | test: /\.(jpe?g|png|gif)$/,
38 | use: [{ loader: 'file-loader?name=img/[name]__[hash:base64:5].[ext]' }],
39 | include: defaultInclude
40 | },
41 | {
42 | test: /\.(eot|svg|ttf|woff|woff2)$/,
43 | use: [{ loader: 'file-loader?name=font/[name]__[hash:base64:5].[ext]' }],
44 | include: defaultInclude
45 | }
46 | ]
47 | },
48 | target: 'electron-renderer',
49 | plugins: [
50 | new HtmlWebpackPlugin(),
51 | new ExtractTextPlugin('bundle.css'),
52 | new webpack.DefinePlugin({
53 | 'process.env.NODE_ENV': JSON.stringify('production')
54 | }),
55 | new BabiliPlugin()
56 | ],
57 | stats: {
58 | colors: true,
59 | children: false,
60 | chunks: false,
61 | modules: false
62 | }
63 | };
64 |
--------------------------------------------------------------------------------
/webpack.dev.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 | const path = require('path');
3 | const HtmlWebpackPlugin = require('html-webpack-plugin');
4 | const { spawn } = require('child_process');
5 | const helpers = require('./config/helpers');
6 |
7 |
8 | // Config directories
9 | const SRC_DIR = path.resolve(__dirname, 'src');
10 | const OUTPUT_DIR = path.resolve(__dirname, 'dist');
11 |
12 | // Any directories you will be adding code/files into, need to be added to this array so webpack will pick them up
13 | const defaultInclude = [SRC_DIR];
14 |
15 | module.exports = {
16 | entry: SRC_DIR + '/index.js',
17 | output: {
18 | path: OUTPUT_DIR,
19 | publicPath: '/',
20 | filename: 'bundle.js'
21 | },
22 | module: {
23 | rules: [
24 | {
25 | test: /\.css$/,
26 | use: [{ loader: 'style-loader' }, { loader: 'css-loader' }],
27 | include: defaultInclude
28 | },
29 | {
30 | test: /\.jsx?$/,
31 | use: [{ loader: 'babel-loader' }],
32 | include: defaultInclude
33 | },
34 | {
35 | test: /\.(jpe?g|png|gif)$/,
36 | use: [{ loader: 'file-loader?name=img/[name]__[hash:base64:5].[ext]' }],
37 | include: defaultInclude
38 | },
39 | {
40 | test: /\.(eot|svg|ttf|woff|woff2)$/,
41 | use: [{ loader: 'file-loader?name=font/[name]__[hash:base64:5].[ext]' }],
42 | include: defaultInclude
43 | }
44 | ]
45 | },
46 | target: 'electron-renderer',
47 | plugins: [
48 | new HtmlWebpackPlugin({
49 | template: helpers.root('public/index.html'),
50 | inject: 'body'
51 | }),
52 | new webpack.DefinePlugin({
53 | 'process.env.NODE_ENV': JSON.stringify('development')
54 | })
55 | ],
56 | devtool: 'cheap-source-map',
57 | devServer: {
58 | contentBase: OUTPUT_DIR,
59 | stats: {
60 | colors: true,
61 | chunks: false,
62 | children: false
63 | },
64 | setup() {
65 | spawn(
66 | 'electron',
67 | ['.'],
68 | { shell: true, env: process.env, stdio: 'inherit' }
69 | )
70 | .on('close', code => process.exit(0))
71 | .on('error', spawnError => console.error(spawnError));
72 | }
73 | }
74 | };
75 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Modern and Minimal Electron + React Starter Kit
2 | _Electron, React, Webpack -- Modern and up-to-date, with a handful of quality of life features included_
3 |
4 | I made this starter kit as most boilerplates were either out-of-date, heavy handed, or enforced a structure on me that I just didnt like.
5 | With a very select assortment of modules, this starter kit is designed to get you up and running very quickly, and to let you easily drop in your own structure and tools on top of it.
6 | The basic structure of `src/` is intentionally minimal to make it easier to allow you to put your own twist on how you like things laid out.
7 |
8 | Production builds babel-minify is used, and ES2015/ES6 transpilation is provided -- As modern node and chromium versions support 99%+ of the ES6 feature set, I feel those steps are unnecessary.
9 |
10 | If you like this project, check out [enhanced-electron-react-boilerplate](https://github.com/pbarbiero/enhanced-electron-react-boilerplate) which is this project with my take on additional modules (photon, redux, less, css modules etc) and my personal project structure (based on the redux ducks proposal) I suggest you give it a look if you want less of a minimalistic take on my starter kit.
11 |
12 | ### To get started:
13 | * Run `npm install`
14 |
15 | ##### Development
16 | * Run `npm run dev` to start webpack-dev-server. Electron will launch automatically after compilation.
17 |
18 | ##### Production
19 | _You have two options, an automatic build or two manual steps_
20 |
21 | ###### One Shot
22 | * Run `npm run package` to have webpack compile your application into `dist/bundle.js` and `dist/index.html`, and then an electron-packager run will be triggered for the current platform/arch, outputting to `builds/`
23 |
24 | ###### Manual
25 | _Recommendation: Update the "postpackage" script call in package.json to specify parameters as you choose and use the `npm run package` command instead of running these steps manually_
26 | * Run `npm run build` to have webpack compile and output your bundle to `dist/bundle.js`
27 | * Then you can call electron-packager directly with any commands you choose
28 |
29 | If you want to test the production build (In case you think Babili might be breaking something) after running `npm run build` you can then call `npm run prod`. This will cause electron to load off of the `dist/` build instead of looking for the webpack-dev-server instance. Electron will launch automatically after compilation.
30 |
--------------------------------------------------------------------------------
/main.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // Import parts of electron to use
4 | const {app, BrowserWindow} = require('electron');
5 | const path = require('path')
6 | const url = require('url')
7 |
8 | // Keep a global reference of the window object, if you don't, the window will
9 | // be closed automatically when the JavaScript object is garbage collected.
10 | let mainWindow;
11 |
12 | // Keep a reference for dev mode
13 | let dev = false;
14 | if ( process.defaultApp || /[\\/]electron-prebuilt[\\/]/.test(process.execPath) || /[\\/]electron[\\/]/.test(process.execPath) ) {
15 | dev = true;
16 | }
17 |
18 | function createWindow() {
19 | // Create the browser window.
20 | mainWindow = new BrowserWindow({
21 | width: 1024, height: 768, show: false
22 | });
23 |
24 | // and load the index.html of the app.
25 | let indexPath;
26 | if ( dev && process.argv.indexOf('--noDevServer') === -1 ) {
27 | indexPath = url.format({
28 | protocol: 'http:',
29 | host: 'localhost:4000',
30 | pathname: 'index.html',
31 | slashes: true
32 | });
33 | } else {
34 | indexPath = url.format({
35 | protocol: 'file:',
36 | pathname: path.join(__dirname, 'dist', 'index.html'),
37 | slashes: true
38 | });
39 | }
40 | mainWindow.loadURL( indexPath );
41 |
42 | // Don't show until we are ready and loaded
43 | mainWindow.once('ready-to-show', () => {
44 | mainWindow.show();
45 | // Open the DevTools automatically if developing
46 | if ( dev ) {
47 | mainWindow.webContents.openDevTools();
48 | }
49 | });
50 |
51 | // Emitted when the window is closed.
52 | mainWindow.on('closed', function() {
53 | // Dereference the window object, usually you would store windows
54 | // in an array if your app supports multi windows, this is the time
55 | // when you should delete the corresponding element.
56 | mainWindow = null;
57 | });
58 | }
59 |
60 | // This method will be called when Electron has finished
61 | // initialization and is ready to create browser windows.
62 | // Some APIs can only be used after this event occurs.
63 | app.on('ready', createWindow);
64 |
65 | // Quit when all windows are closed.
66 | app.on('window-all-closed', () => {
67 | // On macOS it is common for applications and their menu bar
68 | // to stay active until the user quits explicitly with Cmd + Q
69 | if (process.platform !== 'darwin') {
70 | app.quit();
71 | }
72 | });
73 |
74 | app.on('activate', () => {
75 | // On macOS it's common to re-create a window in the app when the
76 | // dock icon is clicked and there are no other windows open.
77 | if (mainWindow === null) {
78 | createWindow();
79 | }
80 | });
81 |
--------------------------------------------------------------------------------