├── .eslintignore ├── .gitignore ├── src ├── layouts │ ├── MainLayout.scss │ ├── ContentRoutes.scss │ ├── HeaderBar.scss │ ├── SideMenu.scss │ ├── HeaderBar.js │ ├── MainLayout.js │ ├── ContentRoutes.js │ └── SideMenu.js ├── styles │ ├── index.js │ ├── default.less │ └── default.scss ├── pages │ ├── HomePage.scss │ ├── NotFoundPage.js │ ├── AboutPage.js │ └── HomePage.js ├── index.js ├── App.js └── components │ ├── PieChart.js │ └── LineChart.js ├── .vscode ├── settings.json └── launch.json ├── screenshot └── screen.png ├── template └── index.html ├── .babelrc ├── .compilerc ├── LICENSE ├── webpack.common.js ├── .eslintrc ├── webpack.prod.js ├── README.md ├── webpack.dev.js ├── app └── index.js └── package.json /.eslintignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | out 3 | dist 4 | .eslintcache 5 | .cache 6 | -------------------------------------------------------------------------------- /src/layouts/MainLayout.scss: -------------------------------------------------------------------------------- 1 | .layout { 2 | height: 100%; 3 | } 4 | -------------------------------------------------------------------------------- /src/styles/index.js: -------------------------------------------------------------------------------- 1 | import './default.less'; 2 | import './default.scss'; 3 | -------------------------------------------------------------------------------- /src/layouts/ContentRoutes.scss: -------------------------------------------------------------------------------- 1 | .content { 2 | margin: 24px 24px 0px; 3 | height: 100%; 4 | } 5 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.eol": "\n", 3 | "editor.insertSpaces": true, 4 | "editor.tabSize": 4 5 | } -------------------------------------------------------------------------------- /screenshot/screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/douglasjunior/electron-webpack-react-boilerplate/HEAD/screenshot/screen.png -------------------------------------------------------------------------------- /src/layouts/HeaderBar.scss: -------------------------------------------------------------------------------- 1 | .bar { 2 | background-color: #fff; 3 | padding-left: 16px; 4 | font-size: 18px; 5 | } 6 | -------------------------------------------------------------------------------- /src/styles/default.less: -------------------------------------------------------------------------------- 1 | @import "~antd/dist/antd.less"; // import official less entry file 2 | 3 | @primary-color: green; 4 | -------------------------------------------------------------------------------- /src/styles/default.scss: -------------------------------------------------------------------------------- 1 | :global { 2 | html body #root { 3 | background-color: #fff; 4 | margin: 0px; 5 | padding: 0px; 6 | height: 100%; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/pages/HomePage.scss: -------------------------------------------------------------------------------- 1 | .titleCard { 2 | padding-left: 12px; 3 | padding-right: 12px; 4 | margin-bottom: 24px; 5 | } 6 | 7 | .tileRow { 8 | margin-left: -12px; 9 | margin-right: -12px; 10 | } 11 | -------------------------------------------------------------------------------- /src/layouts/SideMenu.scss: -------------------------------------------------------------------------------- 1 | .logo { 2 | height: 48px; 3 | line-height: 48px; 4 | background: rgba(255, 255, 255, 0.2); 5 | margin: 16px; 6 | padding: 16; 7 | text-align: center; 8 | 9 | a { 10 | color: #fff; 11 | text-decoration: none; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/pages/NotFoundPage.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | export default class NotFoundPage extends Component { 4 | 5 | state = {} 6 | 7 | render() { 8 | return ( 9 |
10 | 404 11 |
12 | ); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /template/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | <%= htmlWebpackPlugin.options.title %> 8 | 9 | 10 | 11 |
Loading...
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "react", 4 | "es2015", 5 | "stage-2" 6 | ], 7 | "plugins": [ 8 | "transform-class-properties" 9 | ], 10 | "env": { 11 | "development": { 12 | "plugins": [ 13 | "react-hot-loader/babel" 14 | ] 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | 4 | import './styles'; 5 | import App from './App'; 6 | 7 | window.Promise = require('bluebird'); 8 | window.axios = require('axios').default; 9 | window.moment = require('moment-timezone'); 10 | require('moment/locale/pt-br'); // eslint-disable-line import/no-extraneous-dependencies 11 | 12 | ReactDOM.render( 13 | , 14 | document.getElementById('root'), 15 | ); 16 | -------------------------------------------------------------------------------- /.compilerc: -------------------------------------------------------------------------------- 1 | { 2 | "application/javascript": { 3 | "presets": [ 4 | "react", 5 | "es2015", 6 | "stage-2" 7 | ], 8 | "plugins": [ 9 | "transform-class-properties" 10 | ], 11 | "env": { 12 | "development": { 13 | "plugins": [ 14 | "react-hot-loader/babel" 15 | ], 16 | "sourceMaps": "both" 17 | }, 18 | "production": { 19 | "sourceMaps": "none" 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/layouts/HeaderBar.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | import { Layout, Icon } from 'antd'; 4 | 5 | import styles from './HeaderBar.scss'; 6 | 7 | const { Header } = Layout; 8 | 9 | export default class HeaderBar extends Component { 10 | 11 | state = {} 12 | 13 | render() { 14 | return ( 15 |
16 | 17 | 18 | 19 | 20 | My Project 21 | 22 | 23 |
24 | ); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | import { HashRouter } from 'react-router-dom'; 4 | import { hot } from 'react-hot-loader'; 5 | import { LocaleProvider } from 'antd'; 6 | import ptBR from 'antd/lib/locale-provider/pt_BR'; 7 | 8 | import MainLayout from './layouts/MainLayout'; 9 | 10 | class App extends Component { 11 | 12 | state = {}; 13 | 14 | render() { 15 | return ( 16 | 17 | 18 | 19 | 20 | 21 | ); 22 | } 23 | 24 | } 25 | 26 | export default hot(module)(App); 27 | -------------------------------------------------------------------------------- /src/layouts/MainLayout.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | import { Layout } from 'antd'; 4 | 5 | import styles from './MainLayout.scss'; 6 | import HeaderBar from './HeaderBar'; 7 | import ContentRoutes from './ContentRoutes'; 8 | import SideMenu from './SideMenu'; 9 | 10 | export default class MainLayout extends Component { 11 | 12 | state = {} 13 | 14 | render() { 15 | return ( 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | ); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Electron Debug", 11 | "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron-forge-vscode-nix", 12 | "windows": { 13 | "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron-forge-vscode-win.cmd" 14 | }, 15 | // runtimeArgs will be passed directly to your Electron application 16 | "runtimeArgs": [], 17 | "cwd": "${workspaceRoot}" 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /src/pages/AboutPage.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | import { Layout } from 'antd'; 4 | 5 | const { Content } = Layout; 6 | 7 | export default class AboutPage extends Component { 8 | 9 | state = {} 10 | 11 | render() { 12 | return ( 13 | 14 |

About

15 | 16 |

17 | Sample project using Electron Forge + webpack + React + React Router 18 | + Ant Design + Recharts + Sass and Less. 19 |

20 |

21 | Source code on 22 | 23 | GitHib Repo 24 | 25 | . 26 |

27 |
28 | ); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Douglas Nassif Roma Junior 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 | -------------------------------------------------------------------------------- /webpack.common.js: -------------------------------------------------------------------------------- 1 | const HtmlWebpackPlugin = require('html-webpack-plugin'); // eslint-disable-line 2 | const CleanWebpackPlugin = require('clean-webpack-plugin'); // eslint-disable-line 3 | 4 | module.exports = { 5 | entry: ['babel-polyfill', './src/index.js'], 6 | target: 'electron-main', 7 | plugins: [ 8 | new CleanWebpackPlugin(['dist/**/*']), 9 | new HtmlWebpackPlugin({ 10 | template: './template/index.html', 11 | title: 'My Project', 12 | }), 13 | ], 14 | module: { 15 | rules: [ 16 | { 17 | test: /\.(png|svg|jpg|gif)$/, 18 | use: ['file-loader'], 19 | }, 20 | { 21 | enforce: 'pre', 22 | test: /\.jsx?$/, 23 | exclude: /(node_modules|bower_components)/, 24 | loader: 'eslint-loader', 25 | }, 26 | { 27 | test: /\.jsx?$/, 28 | exclude: /(node_modules|bower_components)/, 29 | use: { 30 | loader: 'babel-loader', 31 | }, 32 | }, 33 | ], 34 | }, 35 | resolve: { 36 | extensions: ['.js', '.jsx', '.less', '.json'], 37 | }, 38 | }; 39 | -------------------------------------------------------------------------------- /src/layouts/ContentRoutes.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | import { Layout } from 'antd'; 4 | import { Switch, Route } from 'react-router-dom'; 5 | 6 | import styles from './ContentRoutes.scss'; 7 | 8 | import HomePage from '../pages/HomePage'; 9 | import AboutPage from '../pages/AboutPage'; 10 | import NotFoundPage from '../pages/NotFoundPage'; 11 | 12 | const { Content } = Layout; 13 | 14 | export const ROUTES_ITEMS = [ 15 | { 16 | to: '/', 17 | text: 'Home', 18 | icon: 'home', 19 | exact: true, 20 | component: HomePage, 21 | }, { 22 | to: '/about', 23 | text: 'About', 24 | icon: 'info-circle-o', 25 | component: AboutPage, 26 | }, 27 | ]; 28 | 29 | const ROUTES = ROUTES_ITEMS.map(route => ( 30 | 31 | )); 32 | 33 | export default class ContentRoutes extends Component { 34 | 35 | state = {}; 36 | 37 | render() { 38 | return ( 39 | 40 | 41 | 42 | {ROUTES} 43 | 44 | 45 | 46 | 47 | 48 | ); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/components/PieChart.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | import { 4 | PieChart as PC, Pie, 5 | ResponsiveContainer, Cell, 6 | } from 'recharts'; 7 | 8 | const data = [ 9 | { name: 'Group A', value: 400 }, 10 | { name: 'Group B', value: 300 }, 11 | { name: 'Group C', value: 300 }, 12 | { name: 'Group D', value: 200 }, 13 | ]; 14 | 15 | const COLORS = ['#0088FE', '#00C49F', '#FFBB28', '#FF8042']; 16 | 17 | export default class PieChart extends Component { 18 | 19 | constructor(props) { 20 | super(props); 21 | 22 | this.state = {}; 23 | } 24 | 25 | render() { 26 | return ( 27 | 28 | 29 | 41 | { 42 | data.map((entry, index) => ( 43 | 44 | )) 45 | } 46 | 47 | 48 | 49 | ); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/pages/HomePage.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | import { Card, Row, Col } from 'antd'; 4 | 5 | import styles from './HomePage.scss'; 6 | import LineChart from '../components/LineChart'; 7 | import PieChart from '../components/PieChart'; 8 | 9 | export default class HomePage extends Component { 10 | 11 | constructor(props) { 12 | super(props); 13 | this.state = {}; 14 | } 15 | 16 | render() { 17 | return ( 18 |
19 |

Dashboard

20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 | ); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": [ 4 | "airbnb" 5 | ], 6 | "globals": { 7 | "document": false, 8 | "window": false 9 | }, 10 | "rules": { 11 | "indent": [ 12 | "error", 13 | 4, 14 | { 15 | "SwitchCase": 1 16 | } 17 | ], 18 | "semi": [ 19 | "error", 20 | "always" 21 | ], 22 | "no-underscore-dangle": [ 23 | "error", 24 | { 25 | "allowAfterThis": true 26 | } 27 | ], 28 | "arrow-parens": [ 29 | "warn", 30 | "as-needed" 31 | ], 32 | "max-len": [ 33 | "warn", 34 | 120 35 | ], 36 | "padded-blocks": [ 37 | "error", 38 | { 39 | "classes": "always" 40 | } 41 | ], 42 | "no-nested-ternary": "off", 43 | "global-require": "off", 44 | "no-unused-vars": [ 45 | "error", 46 | { 47 | "args": "none" 48 | } 49 | ], 50 | "react/require-default-props": "warn", 51 | "react/prop-types": "warn", 52 | "react/no-string-refs": "warn", 53 | "react/jsx-filename-extension": [ 54 | "error", 55 | { 56 | "extensions": [ 57 | ".js", 58 | ".jsx" 59 | ] 60 | } 61 | ], 62 | "react/jsx-indent": [ 63 | "error", 64 | 4 65 | ], 66 | "react/jsx-indent-props": [ 67 | "error", 68 | 4 69 | ], 70 | "react/no-unused-state": "warn", 71 | "jsx-a11y/anchor-is-valid": "off", 72 | "jsx-a11y/click-events-have-key-events": "off", 73 | "no-console": [ 74 | "error", 75 | { 76 | "allow": [ 77 | "warn" 78 | ] 79 | } 80 | ], 81 | "import/no-extraneous-dependencies": "off" 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/components/LineChart.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | import { 4 | LineChart as LC, Line, XAxis, YAxis, CartesianGrid, 5 | Tooltip, Legend, ResponsiveContainer, 6 | } from 'recharts'; 7 | 8 | const data = [ 9 | { 10 | name: 'Page A', uv: 4000, pv: 2400, amt: 2400, 11 | }, 12 | { 13 | name: 'Page B', uv: 3000, pv: 1398, amt: 2210, 14 | }, 15 | { 16 | name: 'Page C', uv: 2000, pv: 9800, amt: 2290, 17 | }, 18 | { 19 | name: 'Page D', uv: 2780, pv: 3908, amt: 2000, 20 | }, 21 | { 22 | name: 'Page E', uv: 1890, pv: 4800, amt: 2181, 23 | }, 24 | { 25 | name: 'Page F', uv: 2390, pv: 3800, amt: 2500, 26 | }, 27 | { 28 | name: 'Page G', uv: 3490, pv: 4300, amt: 2100, 29 | }, 30 | ]; 31 | 32 | export default class LineChart extends Component { 33 | 34 | constructor(props) { 35 | super(props); 36 | this.state = {}; 37 | } 38 | 39 | render() { 40 | return ( 41 | 42 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | ); 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /webpack.prod.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const merge = require('webpack-merge'); 3 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 4 | const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); 5 | const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); 6 | 7 | const common = require('./webpack.common.js'); 8 | 9 | module.exports = merge(common, { 10 | output: { 11 | path: path.resolve(__dirname, 'dist'), 12 | filename: 'bundle.js', 13 | }, 14 | mode: 'production', 15 | plugins: [ 16 | new MiniCssExtractPlugin({ 17 | filename: 'bundle.css', 18 | }), 19 | new OptimizeCSSAssetsPlugin(), 20 | new UglifyJsPlugin({ 21 | parallel: true, 22 | }), 23 | ], 24 | module: { 25 | rules: [ 26 | { 27 | test: /\.s?css$/, 28 | use: [ 29 | MiniCssExtractPlugin.loader, 30 | { 31 | loader: 'css-loader', 32 | options: { 33 | modules: true, 34 | localIdentName: '[name]_[local]_[hash:base64:10]', 35 | importLoaders: 2, 36 | }, 37 | }, { 38 | loader: 'sass-loader', 39 | }, 40 | ], 41 | }, { 42 | test: /\.less$/, 43 | use: [ 44 | MiniCssExtractPlugin.loader, 45 | { 46 | loader: 'css-loader', 47 | }, { 48 | loader: 'less-loader', 49 | options: { 50 | javascriptEnabled: true, 51 | }, 52 | }, 53 | ], 54 | }, 55 | ], 56 | }, 57 | }); 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Complete Electron, webpack and React boilerplate 2 | 3 | Sample project containing Electron Forge + webpack + React + React Router + Ant Design + Recharts + Sass and Less. 4 | 5 | ## Screenshot 6 | 7 | ![Screenshot](https://raw.githubusercontent.com/douglasjunior/electron-webpack-react-boilerplate/master/screenshot/screen.png) 8 | 9 | ## Technologies included 10 | 11 | - [Electron Forge](https://electronforge.io/) 12 | - The command line interface for ambitious Electron applications. 13 | - [webpack](https://webpack.js.org/) 14 | - A bundler for javascript and friends. 15 | - [React JS](https://reactjs.org/) 16 | - A JavaScript library for building user interfaces. 17 | - [React Router](https://reacttraining.com/react-router/) 18 | - Declarative routing for React. 19 | - [Ant Design](https://ant.design/) 20 | - A design system with values of Nature and Determinacy for better user experience of enterprise applications. 21 | - [Recharts](http://recharts.org/) 22 | - A composable charting library built on React components. 23 | 24 | ## Download 25 | 26 | ```bash 27 | $ git clone https://github.com/douglasjunior/electron-webpack-react-boilerplate.git 28 | $ cd electron-webpack-react-boilerplate 29 | $ npm install 30 | ``` 31 | 32 | ## Usage: 33 | 34 | Start development mode: 35 | ```bash 36 | $ npm start 37 | ``` 38 | 39 | Create package for the current platform: 40 | ```bash 41 | $ npm run build 42 | ``` 43 | 44 | Build for Mac OSX: (only works on Mac) 45 | ```bash 46 | $ npm run make:mac 47 | ``` 48 | 49 | Build for Linux (deb and dpkg): (works on Linux or Mac) 50 | ```bash 51 | $ npm run make:linux 52 | ``` 53 | 54 | Build for Windows: (only works on Windows) 55 | ```bash 56 | $ npm run make:windows 57 | ``` 58 | 59 | _For a complete list of *Electron Forge* options and requirements, visit the [official docs](https://github.com/electron-userland/electron-forge#usage)._ 60 | 61 | ## License 62 | 63 | MIT License 64 | 65 | Copyright (c) 2018 Douglas Nassif Roma Junior 66 | -------------------------------------------------------------------------------- /src/layouts/SideMenu.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | import PropTypes from 'prop-types'; 4 | import { Layout, Menu, Icon } from 'antd'; 5 | import { Link, withRouter } from 'react-router-dom'; 6 | 7 | import styles from './SideMenu.scss'; 8 | import { ROUTES_ITEMS } from './ContentRoutes'; 9 | 10 | const { Sider } = Layout; 11 | 12 | class SideMenu extends Component { 13 | 14 | state = { 15 | collapsed: false, 16 | }; 17 | 18 | _onCollapse = (collapsed, type) => { 19 | this.setState({ collapsed }); 20 | } 21 | 22 | render() { 23 | const { collapsed } = this.state; 24 | const { location } = this.props; 25 | 26 | const menuItems = ROUTES_ITEMS.map(item => ( 27 | 28 | 29 | 30 | 31 | {item.text} 32 | 33 | 34 | 35 | )); 36 | 37 | return ( 38 | 44 | 45 |
46 |

47 | Project 48 |

49 |
50 | 51 | 57 | 58 | {menuItems} 59 | 60 | 61 | 62 |
63 | ); 64 | } 65 | 66 | } 67 | 68 | PropTypes.toString(); 69 | 70 | SideMenu.propTypes = { 71 | location: PropTypes.shape({ 72 | pathname: PropTypes.string.isRequired, 73 | }).isRequired, 74 | }; 75 | 76 | export default withRouter(SideMenu); 77 | -------------------------------------------------------------------------------- /webpack.dev.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const webpack = require('webpack'); // eslint-disable-line 3 | const merge = require('webpack-merge'); // eslint-disable-line 4 | const common = require('./webpack.common.js'); 5 | 6 | module.exports = merge(common, { 7 | output: { 8 | path: path.resolve(__dirname, 'dist'), 9 | filename: 'bundle.js', 10 | }, 11 | mode: 'development', 12 | devtool: 'eval-source-map', 13 | devServer: { 14 | contentBase: './dist', 15 | port: 8081, 16 | hot: true, 17 | }, 18 | plugins: [ 19 | new webpack.NamedModulesPlugin(), 20 | new webpack.HotModuleReplacementPlugin(), 21 | ], 22 | module: { 23 | rules: [ 24 | { 25 | test: /\.s?css$/, 26 | use: [ 27 | { 28 | loader: 'style-loader', 29 | options: { 30 | sourceMap: true, 31 | }, 32 | }, { 33 | loader: 'css-loader', 34 | options: { 35 | sourceMap: true, 36 | modules: true, 37 | localIdentName: '[name]_[local]_[hash:base64:10]', 38 | importLoaders: 1, 39 | }, 40 | }, { 41 | loader: 'sass-loader', 42 | options: { 43 | sourceMap: true, 44 | }, 45 | }, 46 | ], 47 | }, { 48 | test: /\.less$/, 49 | use: [ 50 | { 51 | loader: 'style-loader', 52 | options: { 53 | sourceMap: true, 54 | }, 55 | }, { 56 | loader: 'css-loader', 57 | options: { 58 | sourceMap: true, 59 | }, 60 | }, { 61 | loader: 'less-loader', 62 | options: { 63 | sourceMap: true, 64 | javascriptEnabled: true, 65 | }, 66 | }, 67 | ], 68 | }, 69 | ], 70 | }, 71 | }); 72 | -------------------------------------------------------------------------------- /app/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable global-require */ 2 | 3 | import path from 'path'; 4 | import { app, BrowserWindow } from 'electron'; 5 | 6 | // Handle creating/removing shortcuts on Windows when installing/uninstalling. 7 | if (require('electron-squirrel-startup')) { 8 | app.quit(); 9 | } 10 | 11 | const isDevMode = process.execPath.match(/[\\/]node_modules\/electron/); 12 | 13 | // Keep a global reference of the window object, if you don't, the window will 14 | // be closed automatically when the JavaScript object is garbage collected. 15 | let mainWindow; 16 | 17 | const createWindow = () => { 18 | // Create the browser window. 19 | mainWindow = new BrowserWindow({ 20 | width: 800, 21 | height: 600, 22 | }); 23 | 24 | // mainWindow.maximize(); 25 | 26 | // and load the index.html of the app. 27 | if (isDevMode) { 28 | mainWindow.loadURL('http://localhost:8081/'); 29 | } else { 30 | mainWindow.loadURL(`file://${path.resolve(__dirname, '..', 'dist')}/index.html`); 31 | } 32 | 33 | // Emitted when the window is closed. 34 | mainWindow.on('closed', () => { 35 | // Dereference the window object, usually you would store windows 36 | // in an array if your app supports multi windows, this is the time 37 | // when you should delete the corresponding element. 38 | mainWindow = null; 39 | }); 40 | 41 | // Open the DevTools. 42 | if (isDevMode) { 43 | const { enableLiveReload } = require('electron-compile'); 44 | const { REACT_DEVELOPER_TOOLS, default: installExtension } = require('electron-devtools-installer'); 45 | 46 | enableLiveReload({ strategy: 'react-hmr' }); 47 | installExtension(REACT_DEVELOPER_TOOLS).then(() => { 48 | mainWindow.webContents.openDevTools(); 49 | }); 50 | } 51 | }; 52 | 53 | // This method will be called when Electron has finished 54 | // initialization and is ready to create browser windows. 55 | // Some APIs can only be used after this event occurs. 56 | app.on('ready', createWindow); 57 | 58 | // Quit when all windows are closed. 59 | app.on('window-all-closed', () => { 60 | // On OS X it is common for applications and their menu bar 61 | // to stay active until the user quits explicitly with Cmd + Q 62 | if (process.platform !== 'darwin') { 63 | app.quit(); 64 | } 65 | }); 66 | 67 | app.on('activate', () => { 68 | // On OS X it's common to re-create a window in the app when the 69 | // dock icon is clicked and there are no other windows open. 70 | if (mainWindow === null) { 71 | createWindow(); 72 | } 73 | }); 74 | 75 | // In this file you can include the rest of your app's specific main process 76 | // code. You can also put them in separate files and import them here. 77 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "electron-webpack-react-boilerplate", 3 | "productName": "My Project", 4 | "version": "1.0.0", 5 | "description": "My Project", 6 | "main": "app/index.js", 7 | "private": true, 8 | "scripts": { 9 | "start": "run-p webpack forge:start", 10 | "build": "run-s webpack:build forge:package", 11 | "forge:start": "electron-forge start", 12 | "forge:package": "electron-forge package", 13 | "make:mac": "electron-forge make --platform=darwin", 14 | "make:linux": "electron-forge make --platform=linux --arch=ia32,x64", 15 | "make:windows": "electron-forge make --platform=win32 --arch=ia32,x64", 16 | "webpack": "webpack-dev-server --config webpack.dev.js", 17 | "webpack:build": "webpack --progress --config webpack.prod.js", 18 | "publish": "electron-forge publish", 19 | "lint": "eslint . --cache --color" 20 | }, 21 | "keywords": [], 22 | "author": { 23 | "name": "Douglas Nassif Roma Junior", 24 | "email": "nassifrroma@gmail.com", 25 | "url": "http://douglasjunior.me" 26 | }, 27 | "license": "MIT", 28 | "config": { 29 | "forge": { 30 | "make_targets": { 31 | "win32": [ 32 | "wix" 33 | ], 34 | "darwin": [ 35 | "dmg" 36 | ], 37 | "linux": [ 38 | "deb", 39 | "rpm" 40 | ] 41 | }, 42 | "electronPackagerConfig": { 43 | "packageManager": "yarn", 44 | "asar": true, 45 | "arch": "all", 46 | "ignore": [ 47 | ".vscode", 48 | ".cache", 49 | "src", 50 | "template", 51 | "out", 52 | "screenshot" 53 | ] 54 | }, 55 | "electronWinstallerConfig": { 56 | "name": "My Project" 57 | }, 58 | "electronWixMSIConfig": { 59 | "name": "My Project", 60 | "appUserModelId": "com.my-project", 61 | "manufacturer": "My Project", 62 | "ui": { 63 | "enabled": true, 64 | "chooseDirectory": true 65 | } 66 | }, 67 | "electronInstallerDebian": {}, 68 | "electronInstallerRedhat": {}, 69 | "github_repository": { 70 | "owner": "douglasjunior", 71 | "name": "electron-webpack-react-boilerplate" 72 | }, 73 | "windowsStoreConfig": { 74 | "packageName": "com.my-project", 75 | "name": "My Project" 76 | } 77 | } 78 | }, 79 | "husky": { 80 | "hooks": { 81 | "pre-push": "npm run lint" 82 | } 83 | }, 84 | "dependencies": { 85 | "electron-compile": "6.4.3", 86 | "electron-squirrel-startup": "1.0.0", 87 | "react-hot-loader": "4.3.5" 88 | }, 89 | "devDependencies": { 90 | "antd": "3.8.4", 91 | "axios": "0.18.0", 92 | "bluebird": "3.5.1", 93 | "moment-timezone": "0.5.21", 94 | "prop-types": "15.6.2", 95 | "react": "16.4.2", 96 | "react-dom": "16.4.2", 97 | "react-router-dom": "4.3.1", 98 | "recharts": "1.1.0", 99 | "babel-core": "6.26.3", 100 | "babel-eslint": "9.0.0", 101 | "babel-loader": "7.1.5", 102 | "babel-plugin-import": "1.8.0", 103 | "babel-plugin-transform-class-properties": "6.24.1", 104 | "babel-polyfill": "6.26.0", 105 | "babel-preset-es2015": "6.24.1", 106 | "babel-preset-react": "6.24.1", 107 | "babel-preset-stage-2": "6.24.1", 108 | "clean-webpack-plugin": "0.1.19", 109 | "cross-env": "5.2.0", 110 | "css-loader": "1.0.0", 111 | "electron-devtools-installer": "2.2.4", 112 | "electron-forge": "5.2.2", 113 | "electron-prebuilt-compile": "2.0.7", 114 | "electron-wix-msi": "1.3.0", 115 | "eslint": "5.5.0", 116 | "eslint-config-airbnb": "17.1.0", 117 | "eslint-loader": "2.1.0", 118 | "eslint-plugin-import": "2.14.0", 119 | "eslint-plugin-jsx-a11y": "6.1.1", 120 | "eslint-plugin-react": "7.11.1", 121 | "html-webpack-plugin": "3.2.0", 122 | "husky": "1.0.0-rc.13", 123 | "less": "3.8.1", 124 | "less-loader": "4.1.0", 125 | "mini-css-extract-plugin": "0.4.1", 126 | "node-sass": "4.9.3", 127 | "npm-run-all": "4.1.3", 128 | "optimize-css-assets-webpack-plugin": "5.0.0", 129 | "sass-loader": "7.1.0", 130 | "style-loader": "0.23.0", 131 | "uglifyjs-webpack-plugin": "1.3.0", 132 | "webpack": "4.17.1", 133 | "webpack-cli": "3.1.0", 134 | "webpack-dev-server": "3.1.7", 135 | "webpack-merge": "4.1.4" 136 | } 137 | } 138 | --------------------------------------------------------------------------------