Skip to content

Commit 56c9922

Browse files
react-redux-elctron-boilerplate
0 parents  commit 56c9922

36 files changed

+11478
-0
lines changed

Diff for: .editorconfig

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# EditorConfig is awesome: https://EditorConfig.org
2+
3+
# top-most EditorConfig file
4+
root = true
5+
6+
[*]
7+
charset = utf-8
8+
insert_final_newline = true
9+
trim_trailing_whitespace = true
10+
11+
[*.{js,json,css,html}]
12+
indent_style = space
13+
indent_size = 2

Diff for: .eslintignore

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
node_modules
2+
build
3+
cache
4+
lib
5+
dist
6+
webpack.*.js
7+
server.js
8+
build.js
9+
init.js

Diff for: .eslintrc

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"root": true,
3+
"extends": [
4+
"eslint:recommended",
5+
"plugin:react/recommended",
6+
"prettier"
7+
],
8+
"parser": "babel-eslint",
9+
"parserOptions": {
10+
"ecmaFeatures": {
11+
"jsx": true,
12+
"modules": true
13+
}
14+
},
15+
"plugins": [ "react" ],
16+
"rules": {
17+
"prefer-const": "warn",
18+
"no-console": "off",
19+
"no-loop-func": "warn",
20+
"new-cap": "off",
21+
"no-param-reassign": "warn",
22+
"func-names": "off",
23+
"no-unused-expressions" : "error",
24+
"block-scoped-var": "error",
25+
"react/prop-types": "off"
26+
},
27+
"settings": {
28+
"react": {
29+
"pragma": "React",
30+
"version": "16.2"
31+
}
32+
},
33+
"env": {
34+
"es6": true,
35+
"node": true
36+
}
37+
}

Diff for: .gitignore

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
node_modules
2+
dist
3+
build
4+
.DS_Store
5+
*.log

Diff for: .prettierrc.yml

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# .prettierrc.yml
2+
# see: https://prettier.io/docs/en/options.html
3+
printWidth: 100
4+
semi: true
5+
singleQuote: true
6+
trailingComma: all
7+
bracketSpacing: true
8+
jsxBracketSameLine: true
9+
arrowParens: always
10+
proseWrap: always

Diff for: .travis.yml

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
sudo: false
2+
3+
language: node_js
4+
5+
node_js:
6+
- '10'
7+
cache: npm
8+
services:
9+
- xvfb
10+
11+
install:
12+
- npm install
13+
14+
script:
15+
- npm run check-format
16+
- npm run lint
17+
- npm test

Diff for: .vscode/settings.json

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"search.exclude": {
3+
"build/": true,
4+
"dist/": true
5+
}
6+
}

Diff for: README.md

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# electron-react-redux-boilerplate
2+
[![Build Status](https://api.travis-ci.org/jschr/electron-react-redux-boilerplate.svg)](https://travis-ci.org/jschr/electron-react-redux-boilerplate)
3+
[![dependencies Status](https://david-dm.org/jschr/electron-react-redux-boilerplate/status.svg)](https://david-dm.org/jschr/electron-react-redux-boilerplate)
4+
[![devDependencies Status](https://david-dm.org/jschr/electron-react-redux-boilerplate/dev-status.svg)](https://david-dm.org/jschr/electron-react-redux-boilerplate?type=dev)
5+
6+
A minimal boilerplate to get started with [Electron](http://electron.atom.io/), [React](https://facebook.github.io/react/) and [Redux](http://redux.js.org/).
7+
8+
Including:
9+
10+
* [React Router](https://reacttraining.com/react-router/)
11+
* [Redux Thunk](https://github.com/gaearon/redux-thunk/)
12+
* [Redux Actions](https://github.com/acdlite/redux-actions/)
13+
* [Redux Local Storage](https://github.com/elgerlambert/redux-localstorage/)
14+
* [Electron Packager](https://github.com/electron-userland/electron-packager)
15+
* [Electron DevTools Installer](https://github.com/MarshallOfSound/electron-devtools-installer)
16+
* [Electron Mocha](https://github.com/jprichardson/electron-mocha)
17+
* [Browsersync](https://browsersync.io/)
18+
19+
## Quick start
20+
21+
Clone the repository
22+
```bash
23+
git clone --depth=1 https://github.com/jschr/electron-react-redux-boilerplate
24+
```
25+
26+
Install dependencies
27+
```bash
28+
cd electron-react-redux-boilerplate
29+
npm install
30+
```
31+
32+
Development
33+
```bash
34+
npm run develop
35+
```
36+
37+
## DevTools
38+
39+
Toggle DevTools:
40+
41+
* macOS: <kbd>Cmd</kbd> <kbd>Alt</kbd> <kbd>I</kbd> or <kbd>F12</kbd>
42+
* Linux: <kbd>Ctrl</kbd> <kbd>Shift</kbd> <kbd>I</kbd> or <kbd>F12</kbd>
43+
* Windows: <kbd>Ctrl</kbd> <kbd>Shift</kbd> <kbd>I</kbd> or <kbd>F12</kbd>
44+
45+
## Packaging
46+
47+
Modify [electron-builder.yml](./electron-builder.yml) to edit package info.
48+
49+
For a full list of options see: https://www.electron.build/configuration/configuration
50+
51+
Create a package for macOS, Windows or Linux using one of the following commands:
52+
53+
```
54+
npm run pack:mac
55+
npm run pack:win
56+
npm run pack:linux
57+
```
58+
59+
## Tests
60+
61+
```
62+
npm run test
63+
```
64+
65+
## Maintainers
66+
67+
- [@jschr](https://github.com/jschr)
68+
- [@pronebird](https://github.com/pronebird)
69+
70+
## Apps using this boilerplate
71+
72+
- [Mullvad VPN app](https://github.com/mullvad/mullvadvpn-app)
73+
- [YouTube Downloader Electron](https://github.com/vanzylv/youtube-downloader-electron)
74+
- [Martian: A Websocket test tool](https://github.com/drex44/martian)

Diff for: app/main/index.js

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import path from 'path';
2+
import { app, crashReporter, BrowserWindow, Menu } from 'electron';
3+
4+
const isDevelopment = process.env.NODE_ENV === 'development';
5+
6+
let mainWindow = null;
7+
let forceQuit = false;
8+
9+
const installExtensions = async () => {
10+
const installer = require('electron-devtools-installer');
11+
const extensions = ['REACT_DEVELOPER_TOOLS', 'REDUX_DEVTOOLS'];
12+
const forceDownload = !!process.env.UPGRADE_EXTENSIONS;
13+
for (const name of extensions) {
14+
try {
15+
await installer.default(installer[name], forceDownload);
16+
} catch (e) {
17+
console.log(`Error installing ${name} extension: ${e.message}`);
18+
}
19+
}
20+
};
21+
22+
crashReporter.start({
23+
productName: 'YourName',
24+
companyName: 'YourCompany',
25+
submitURL: 'https://your-domain.com/url-to-submit',
26+
uploadToServer: false,
27+
});
28+
29+
app.on('window-all-closed', () => {
30+
// On OS X it is common for applications and their menu bar
31+
// to stay active until the user quits explicitly with Cmd + Q
32+
if (process.platform !== 'darwin') {
33+
app.quit();
34+
}
35+
});
36+
37+
app.on('ready', async () => {
38+
if (isDevelopment) {
39+
await installExtensions();
40+
}
41+
42+
mainWindow = new BrowserWindow({
43+
width: 1000,
44+
height: 800,
45+
minWidth: 640,
46+
minHeight: 480,
47+
show: false,
48+
webPreferences: {
49+
nodeIntegration: true,
50+
},
51+
});
52+
53+
mainWindow.loadFile(path.resolve(path.join(__dirname, '../renderer/index.html')));
54+
55+
// show window once on first load
56+
mainWindow.webContents.once('did-finish-load', () => {
57+
mainWindow.show();
58+
});
59+
60+
mainWindow.webContents.on('did-finish-load', () => {
61+
// Handle window logic properly on macOS:
62+
// 1. App should not terminate if window has been closed
63+
// 2. Click on icon in dock should re-open the window
64+
// 3. ⌘+Q should close the window and quit the app
65+
if (process.platform === 'darwin') {
66+
mainWindow.on('close', function (e) {
67+
if (!forceQuit) {
68+
e.preventDefault();
69+
mainWindow.hide();
70+
}
71+
});
72+
73+
app.on('activate', () => {
74+
mainWindow.show();
75+
});
76+
77+
app.on('before-quit', () => {
78+
forceQuit = true;
79+
});
80+
} else {
81+
mainWindow.on('closed', () => {
82+
mainWindow = null;
83+
});
84+
}
85+
});
86+
87+
if (isDevelopment) {
88+
// auto-open dev tools
89+
mainWindow.webContents.openDevTools();
90+
91+
// add inspect element on right click menu
92+
mainWindow.webContents.on('context-menu', (e, props) => {
93+
Menu.buildFromTemplate([
94+
{
95+
label: 'Inspect element',
96+
click() {
97+
mainWindow.inspectElement(props.x, props.y);
98+
},
99+
},
100+
]).popup(mainWindow);
101+
});
102+
}
103+
});

Diff for: app/renderer/.eslintrc

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"env": {
3+
"browser": true
4+
}
5+
}

Diff for: app/renderer/actions/user.js

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { createAction } from 'redux-actions';
2+
3+
export default {
4+
login: createAction('USER_LOGIN'),
5+
logout: createAction('USER_LOGOUT'),
6+
};

Diff for: app/renderer/app.js

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import React from 'react';
2+
import ReactDOM from 'react-dom';
3+
import { Provider } from 'react-redux';
4+
import { ConnectedRouter } from 'connected-react-router';
5+
import { createMemoryHistory } from 'history';
6+
import routes from './routes';
7+
import configureStore from './store';
8+
9+
const syncHistoryWithStore = (store, history) => {
10+
const { router } = store.getState();
11+
if (router && router.location) {
12+
history.replace(router.location);
13+
}
14+
};
15+
16+
const initialState = {};
17+
const routerHistory = createMemoryHistory();
18+
const store = configureStore(initialState, routerHistory);
19+
syncHistoryWithStore(store, routerHistory);
20+
21+
const rootElement = document.querySelector(document.currentScript.getAttribute('data-container'));
22+
23+
ReactDOM.render(
24+
<Provider store={store}>
25+
<ConnectedRouter history={routerHistory}>{routes}</ConnectedRouter>
26+
</Provider>,
27+
rootElement,
28+
);

Diff for: app/renderer/components/LoggedIn.js

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import React, { Component } from 'react';
2+
import PropTypes from 'prop-types';
3+
4+
export default class LoggedIn extends Component {
5+
static propTypes = {
6+
onLogout: PropTypes.func.isRequired,
7+
};
8+
9+
handleLogout = () => {
10+
this.props.onLogout({
11+
username: '',
12+
loggedIn: false,
13+
});
14+
};
15+
16+
render() {
17+
return (
18+
<div>
19+
<h2>Logged in as {this.props.user.username}</h2>
20+
<button onClick={this.handleLogout}>Logout</button>
21+
</div>
22+
);
23+
}
24+
}

Diff for: app/renderer/components/Login.js

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import React, { Component } from 'react';
2+
import PropTypes from 'prop-types';
3+
4+
export default class Login extends Component {
5+
static propTypes = {
6+
onLogin: PropTypes.func.isRequired,
7+
};
8+
9+
state = {
10+
username: '',
11+
};
12+
13+
handleLogin = () => {
14+
this.props.onLogin({
15+
username: this.state.username,
16+
loggedIn: true,
17+
});
18+
};
19+
20+
handleChange = (e) => {
21+
this.setState({
22+
username: e.target.value,
23+
});
24+
};
25+
26+
render() {
27+
return (
28+
<div>
29+
<h2>Login</h2>
30+
<input onChange={this.handleChange} type="text" value={this.state.username} />
31+
<button onClick={this.handleLogin}>Log In</button>
32+
</div>
33+
);
34+
}
35+
}

0 commit comments

Comments
 (0)