9 |
Further Reading
10 |
11 |
12 |
13 | What is Concurrency?
14 |
18 |
19 |
20 |
21 |
22 |
23 | Setting Up Concurrent Mode
24 |
28 |
29 |
30 |
31 |
32 |
33 | What Can You Do with Concurrent Mode?
34 |
35 | Suspense for Data Fetching is a new feature that lets you use Suspense to declaratively “wait” for anything else, including data.
36 | Learn More About Concurrent Mode
37 |
38 |
39 |
40 |
41 |
42 |
43 | More on Concurrent Mode
44 |
48 |
49 |
50 |
51 | {/* export const SearchGlass = () => {
52 | return (
53 |
54 |
55 |
56 |
57 |
58 |
Further Reading
59 |
60 |
What is Concurrency?
61 |
65 |
66 |
Setting Up Concurrent Mode
67 |
71 |
72 |
What Can You Do with Concurrent Mode?
73 |
77 |
78 |
More on Concurrent Mode
79 |
83 |
84 |
85 |
86 |
*/}
87 |
88 | );
89 | };
--------------------------------------------------------------------------------
/app/components/SetUp.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import Card from "@material-ui/core/Card";
4 | import CardContent from "@material-ui/core/CardContent";
5 | import Typography from "@material-ui/core/Typography";
6 |
7 | export const SetUp = () => {
8 | return (
9 |
10 |
How to Use ReactionTime
11 | {/*step one*/}
12 |
13 |
14 |
15 | 1. Install Testing Libraries
16 |
17 |
18 | Install Jest & React-Testing-Library
19 |
20 |
21 |
22 | In your terminal, type in the following command to install the Jest and Enzyme testing libraries that you will need as dependencies: npm install jest react-testing-library
23 |
24 |
25 |
26 |
27 | {/*step two*/}
28 |
29 |
30 |
31 | 2. Create New File
32 |
33 |
34 | Add Test File
35 |
36 |
37 |
38 | In the repository of your app, create a new file in your ROOT directory for your tests that will end in .test.js. You will later paste the generated tests into this file.
39 |
40 |
41 |
42 |
43 | {/*step three*/}
44 |
45 |
46 |
47 | 3. Import Testing Libraries
48 |
49 |
50 | Bring in React-testing-library
51 |
52 |
53 |
54 | At the top of the test file ending in .test.js that was just created, import react-testing-library into the file.
55 |
56 |
57 |
58 |
59 | {/*step four*/}
60 |
61 |
62 |
63 | 4. Download ReactionTime
64 |
65 |
66 | Download the ReactionTime App for your System.
67 |
68 |
69 |
70 | Visit www.reactiontimeapp.com to download the ReactionTime App for either MacOS or Windows PC
71 |
72 |
73 |
74 |
75 | {/*step five*/}
76 |
77 |
78 |
79 | 5. Input Names
80 |
81 |
82 | Provide the Input for the Test You want Generated
83 |
84 |
85 |
86 | If testing for Concurrent Mode set up or verifying React Experimental mode, input the correct file path needed from your ROOT directory. If testing for the fallback component or to determine if the fallback component renders in the DOM tree, provide the suspenseful component and name of the fallback as inputs.
87 |
88 |
89 |
90 |
91 | {/*step six*/}
92 |
93 |
94 |
95 | 6. Copy & Paste
96 |
97 |
98 | Copy Generated Test into your File
99 |
100 |
101 |
102 | Copy the test that is generated upon providing the correct input(s) and paste the test into the test file created earlier ending in .test.js.
103 |
104 |
105 |
106 |
107 | {/*step seven*/}
108 |
109 |
110 |
111 | 7. Enjoy Your Test!
112 |
113 |
114 | Test Your Files Using the Command Line
115 |
116 |
117 |
118 | After pasting the desired tests into your testing file, type in: npm test, at the command line of your terminal and see if your tests pass and you get those green checks!
119 |
120 |
121 |
122 |
123 | );
124 | };
--------------------------------------------------------------------------------
/app/components/SuspenseTest.tsx:
--------------------------------------------------------------------------------
1 | import React, {useState, FormEvent} from "react";
2 | import Card from "@material-ui/core/Card";
3 | import Typography from "@material-ui/core/Typography";
4 | import { Button, TextField, createMuiTheme, ThemeProvider } from '@material-ui/core'
5 |
6 | export const SuspenseTest = () => {
7 | const [name, setName] = useState("");
8 |
9 | let result: string;
10 |
11 | const handleSubmit = (evt: FormEvent) => {
12 | evt.preventDefault();
13 | result = `
14 | test('renders suspense fallback on a child component', () => {
15 | \u00A0\u00A0const ComponentWrapper = (${name}) => {
16 | \u00A0\u00A0\u00A0\u00A0return (
17 | \u00A0\u00A0\u00A0\u00A0\u00A0\u00A0
18 | \u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0<${name} />
19 | \u00A0\u00A0\u00A0\u00A0\u00A0\u00A0
20 | \u00A0\u00A0\u00A0\u00A0);
21 | \u00A0\u00A0};
22 |
23 | \u00A0\u00A0const wrapper = testingLibrary.render(
);
24 |
25 | \u00A0\u00A0expect((wrapper.queryAllByText('testFallback')[0].textContent)).toMatch(/testFallback/);
26 | })
27 | `;
28 |
29 | document.getElementById('test')!.innerText = result;
30 | }
31 | const darkTheme = createMuiTheme({
32 | palette: {
33 | type: 'dark',
34 | },
35 | });
36 |
37 | return (
38 |
39 |
40 |
41 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | );
66 | };
67 |
--------------------------------------------------------------------------------
/app/components/__tests__/CreateRootTest.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import ShallowRenderer from 'react-test-renderer/shallow';
4 | import { CreateRootTest } from '../CreateRootTest'
5 |
6 | // 1) CreateRootTest Component should render contents inside the div
7 | test('renders contents of CreateRootTest Component', () => {
8 | const container = document.createElement('div');
9 | ReactDOM.render(
, container);
10 | // console.log(container.innerHTML);
11 | expect(container.textContent).toBeTruthy(); // expects that there is any content in a container to be truthy
12 | })
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/components/__tests__/FallbackTest.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import ShallowRenderer from 'react-test-renderer/shallow';
4 | import { FallbackTest } from '../FallbackTest'
5 |
6 | // 1) FallbackTest Component should render contents inside the div
7 | test('renders contents of FallbackTest Component', () => {
8 | const container = document.createElement('div');
9 | ReactDOM.render(
, container);
10 | // console.log(container.innerHTML);
11 | expect(container.textContent).toBeTruthy(); // expects that there is any content in a container to be truthy
12 | })
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/components/__tests__/Home.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import ShallowRenderer from 'react-test-renderer/shallow';
4 | import Home from '../Home.tsx'
5 |
6 | // 1) Home Component should render contents inside the div
7 | test('renders contents of Home Component', () => {
8 | const container = document.createElement('div');
9 | ReactDOM.render(
, container);
10 | // console.log(container.textContent);
11 | expect(container.textContent).toBeTruthy(); // expects that there is any content in a container to be truthy
12 | })
13 |
14 | // 2) Home component should have padding for improved UI
15 | test('uses paddingLeft for improved UI', () => {
16 |
17 | // Shallow render the component, to see what the render method returns
18 | const renderer = new ShallowRenderer();
19 | renderer.render(
)
20 | const result = renderer.getRenderOutput();
21 | // console.log(result);
22 | console.log(result.props.style.paddingLeft);
23 | expect(result.props.style.paddingLeft).toBeDefined(); // expects that our component has a paddingLeft, value designated doesn't matter
24 | })
25 |
26 |
--------------------------------------------------------------------------------
/app/components/__tests__/PackageTest.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import ShallowRenderer from 'react-test-renderer/shallow';
4 | import { PackageTest } from '../PackageTest'
5 |
6 | // 1) PackageTest Component should render contents inside the div
7 | test('renders contents of PackageTest Component', () => {
8 | const container = document.createElement('div');
9 | ReactDOM.render(
, container);
10 | // console.log(container.innerHTML);
11 | expect(container.textContent).toBeTruthy(); // expects that there is any content in a container to be truthy
12 | })
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/components/__tests__/SuspenseTest.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import ShallowRenderer from 'react-test-renderer/shallow';
4 | import { SuspenseTest } from '../SuspenseTest'
5 |
6 | // 1) SuspenseTest Component should render contents inside the div
7 | test('renders contents of SuspenseTest Component', () => {
8 | const container = document.createElement('div');
9 | ReactDOM.render(
, container);
10 | // console.log(container.innerHTML);
11 | expect(container.textContent).toBeTruthy(); // expects that there is any content in a container to be truthy
12 | })
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/dist/13685372945d816a2b474fc082fd9aaa.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/ReactionTime/4ad16b791876ee4136c8f5e584cf6a1108b26d75/app/dist/13685372945d816a2b474fc082fd9aaa.ttf
--------------------------------------------------------------------------------
/app/dist/1ab236ed440ee51810c56bd16628aef0.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/ReactionTime/4ad16b791876ee4136c8f5e584cf6a1108b26d75/app/dist/1ab236ed440ee51810c56bd16628aef0.ttf
--------------------------------------------------------------------------------
/app/dist/261d666b0147c6c5cda07265f98b8f8c.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/ReactionTime/4ad16b791876ee4136c8f5e584cf6a1108b26d75/app/dist/261d666b0147c6c5cda07265f98b8f8c.eot
--------------------------------------------------------------------------------
/app/dist/a0369ea57eb6d3843d6474c035111f29.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/ReactionTime/4ad16b791876ee4136c8f5e584cf6a1108b26d75/app/dist/a0369ea57eb6d3843d6474c035111f29.eot
--------------------------------------------------------------------------------
/app/dist/a06da7f0950f9dd366fc9db9d56d618a.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/ReactionTime/4ad16b791876ee4136c8f5e584cf6a1108b26d75/app/dist/a06da7f0950f9dd366fc9db9d56d618a.woff2
--------------------------------------------------------------------------------
/app/dist/b15db15f746f29ffa02638cb455b8ec0.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/ReactionTime/4ad16b791876ee4136c8f5e584cf6a1108b26d75/app/dist/b15db15f746f29ffa02638cb455b8ec0.woff2
--------------------------------------------------------------------------------
/app/dist/bea989e82b07e9687c26fc58a4805021.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/ReactionTime/4ad16b791876ee4136c8f5e584cf6a1108b26d75/app/dist/bea989e82b07e9687c26fc58a4805021.woff
--------------------------------------------------------------------------------
/app/dist/c1868c9545d2de1cf8488f1dadd8c9d0.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/ReactionTime/4ad16b791876ee4136c8f5e584cf6a1108b26d75/app/dist/c1868c9545d2de1cf8488f1dadd8c9d0.eot
--------------------------------------------------------------------------------
/app/dist/c20b5b7362d8d7bb7eddf94344ace33e.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/ReactionTime/4ad16b791876ee4136c8f5e584cf6a1108b26d75/app/dist/c20b5b7362d8d7bb7eddf94344ace33e.woff2
--------------------------------------------------------------------------------
/app/dist/db78b9359171f24936b16d84f63af378.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/ReactionTime/4ad16b791876ee4136c8f5e584cf6a1108b26d75/app/dist/db78b9359171f24936b16d84f63af378.ttf
--------------------------------------------------------------------------------
/app/dist/ec3cfddedb8bebd2d7a3fdf511f7c1cc.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/ReactionTime/4ad16b791876ee4136c8f5e584cf6a1108b26d75/app/dist/ec3cfddedb8bebd2d7a3fdf511f7c1cc.woff
--------------------------------------------------------------------------------
/app/dist/f89ea91ecd1ca2db7e09baa2c4b156d1.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/ReactionTime/4ad16b791876ee4136c8f5e584cf6a1108b26d75/app/dist/f89ea91ecd1ca2db7e09baa2c4b156d1.woff
--------------------------------------------------------------------------------
/app/dist/renderer.prod.js.LICENSE:
--------------------------------------------------------------------------------
1 | /**
2 | * A better abstraction over CSS.
3 | *
4 | * @copyright Oleg Isonen (Slobodskoi) / Isonen 2014-present
5 | * @website https://github.com/cssinjs/jss
6 | * @license MIT
7 | */
8 |
9 | /** @license React v16.13.1
10 | * react-is.production.min.js
11 | *
12 | * Copyright (c) Facebook, Inc. and its affiliates.
13 | *
14 | * This source code is licensed under the MIT license found in the
15 | * LICENSE file in the root directory of this source tree.
16 | */
17 |
18 | /*
19 | object-assign
20 | (c) Sindre Sorhus
21 | @license MIT
22 | */
23 |
24 | /** @license React v16.12.0
25 | * react-dom.production.min.js
26 | *
27 | * Copyright (c) Facebook, Inc. and its affiliates.
28 | *
29 | * This source code is licensed under the MIT license found in the
30 | * LICENSE file in the root directory of this source tree.
31 | */
32 |
33 | /** @license React v16.12.0
34 | * react-is.production.min.js
35 | *
36 | * Copyright (c) Facebook, Inc. and its affiliates.
37 | *
38 | * This source code is licensed under the MIT license found in the
39 | * LICENSE file in the root directory of this source tree.
40 | */
41 |
42 | /** @license React v16.12.0
43 | * react.production.min.js
44 | *
45 | * Copyright (c) Facebook, Inc. and its affiliates.
46 | *
47 | * This source code is licensed under the MIT license found in the
48 | * LICENSE file in the root directory of this source tree.
49 | */
50 |
51 | /** @license React v0.18.0
52 | * scheduler.production.min.js
53 | *
54 | * Copyright (c) Facebook, Inc. and its affiliates.
55 | *
56 | * This source code is licensed under the MIT license found in the
57 | * LICENSE file in the root directory of this source tree.
58 | */
59 |
--------------------------------------------------------------------------------
/app/dist/renderer.prod.js.LICENSE.txt:
--------------------------------------------------------------------------------
1 | /*
2 | object-assign
3 | (c) Sindre Sorhus
4 | @license MIT
5 | */
6 |
7 | /** @license React v0.19.1
8 | * scheduler.production.min.js
9 | *
10 | * Copyright (c) Facebook, Inc. and its affiliates.
11 | *
12 | * This source code is licensed under the MIT license found in the
13 | * LICENSE file in the root directory of this source tree.
14 | */
15 |
16 | /** @license React v16.13.1
17 | * react-dom.production.min.js
18 | *
19 | * Copyright (c) Facebook, Inc. and its affiliates.
20 | *
21 | * This source code is licensed under the MIT license found in the
22 | * LICENSE file in the root directory of this source tree.
23 | */
24 |
25 | /** @license React v16.13.1
26 | * react-is.production.min.js
27 | *
28 | * Copyright (c) Facebook, Inc. and its affiliates.
29 | *
30 | * This source code is licensed under the MIT license found in the
31 | * LICENSE file in the root directory of this source tree.
32 | */
33 |
34 | /** @license React v16.13.1
35 | * react.production.min.js
36 | *
37 | * Copyright (c) Facebook, Inc. and its affiliates.
38 | *
39 | * This source code is licensed under the MIT license found in the
40 | * LICENSE file in the root directory of this source tree.
41 | */
42 |
--------------------------------------------------------------------------------
/app/dist/style.css:
--------------------------------------------------------------------------------
1 | .homePage__wrapper__1eJRi{-webkit-background-size:cover;-moz-background-size:cover;-o-background-size:cover;background-size:cover;height:2000px;overflow:hidden}.homePage__logo__31tqJ{width:15px;height:15px}.homePage__title__1-zXv{padding-top:12px}.homePage__subtitle__3y2Jp,.homePage__title__1-zXv{font-weight:800;font-style:italic;text-align:center}.homePage__subtitle__3y2Jp{padding-top:3px}.homePage__text__3_mF9{padding:2px;color:#eee;font-weight:600;margin-left:40%;margin-right:40%;text-align:center}
2 | /*# sourceMappingURL=style.css.map */
--------------------------------------------------------------------------------
/app/dist/style.css.d.ts:
--------------------------------------------------------------------------------
1 | declare const styles: {
2 | readonly "homePage__wrapper__1eJRi": string;
3 | readonly "homePage__logo__31tqJ": string;
4 | readonly "homePage__title__1-zXv": string;
5 | readonly "homePage__subtitle__3y2Jp": string;
6 | readonly "homePage__text__3_mF9": string;
7 | };
8 | export = styles;
9 |
10 |
--------------------------------------------------------------------------------
/app/dist/style.css.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["homePage.css"],"names":[],"mappings":"AAAA,0BACI,6BAA8B,CAC9B,0BAA2B,CAC3B,wBAAyB,CACzB,qBAAsB,CACtB,aAAc,CACd,eACJ,CAEA,uBACI,UAAW,CACX,WACJ,CAEA,wBAEI,gBAIJ,CAEA,mDALI,eAAgB,CAChB,iBAAkB,CAClB,iBAQJ,CALA,2BAII,eACJ,CAEA,uBACI,WAAY,CACZ,UAAc,CACd,eAAgB,CAChB,eAAgB,CAChB,gBAAiB,CACjB,iBACJ","file":"style.css","sourcesContent":[".wrapper {\r\n -webkit-background-size: cover;\r\n -moz-background-size: cover;\r\n -o-background-size: cover;\r\n background-size: cover;\r\n height: 2000px;\r\n overflow: hidden;\r\n}\r\n\r\n.logo {\r\n width: 15px;\r\n height: 15px;\r\n}\r\n\r\n.title {\r\n text-align: center;\r\n padding-top: 12px;\r\n font-weight: 800;\r\n font-style: italic;\r\n text-align: center;\r\n}\r\n\r\n.subtitle {\r\n text-align: center;\r\n font-style: italic;\r\n font-weight: 800;\r\n padding-top: 3px;\r\n}\r\n\r\n.text {\r\n padding: 2px;\r\n color: #eeeeee;\r\n font-weight: 600;\r\n margin-left: 40%;\r\n margin-right: 40%;\r\n text-align: center;\r\n}"]}
--------------------------------------------------------------------------------
/app/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from 'react-dom';
3 | import Beaker from './components/Beaker';
4 | import { CreateRootTest } from './components/CreateRootTest';
5 | import { PackageTest } from './components/PackageTest';
6 | import { FallbackTest } from './components/FallbackTest';
7 | import { SuspenseTest } from './components/SuspenseTest';
8 | import { Drawer, List, ListItem } from '@material-ui/core';
9 | import { MemoryRouter as Router, Switch } from 'react-router-dom';
10 | import { Link, Route } from 'react-router-dom';
11 | import Home from './components/HomePage/homePage';
12 | import {SearchGlass} from './components/SearchGlass';
13 | import {SetUp} from './components/SetUp';
14 | import { withStyles } from '@material-ui/core/styles';
15 | import HomeOutlinedIcon from '@material-ui/icons/HomeOutlined';
16 | import TimerRoundedIcon from '@material-ui/icons/TimerRounded';
17 | import HelpOutlineRoundedIcon from '@material-ui/icons/HelpOutlineRounded';
18 | import CheckCircleOutlineRoundedIcon from '@material-ui/icons/CheckCircleOutlineRounded';
19 |
20 | const StyledDrawer = withStyles({
21 | paper: {
22 | background: '#303030'
23 | }
24 | })(Drawer);
25 |
26 | const StyledHomeOutlinedIcon = withStyles({
27 | root: {
28 | fill: '#eeeeee'
29 | }
30 | })(HomeOutlinedIcon);
31 |
32 | const StyledTimerRoundedIcon = withStyles({
33 | root: {
34 | fill: '#eeeeee'
35 | }
36 | })(TimerRoundedIcon);
37 |
38 | const StyledHelpOutlineRoundedIcon = withStyles({
39 | root: {
40 | fill: '#eeeeee'
41 | }
42 | })(HelpOutlineRoundedIcon);
43 |
44 | const StyledCheckCircleOutlineRoundedIcon = withStyles({
45 | root: {
46 | fill: '#eeeeee'
47 | }
48 | })(CheckCircleOutlineRoundedIcon);
49 |
50 | document.addEventListener('DOMContentLoaded', () =>
51 |
52 | render(
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
,
91 | document.getElementById('root')
92 |
93 | )
94 | );
95 |
--------------------------------------------------------------------------------
/app/main.dev.ts:
--------------------------------------------------------------------------------
1 | /* eslint global-require: off, no-console: off */
2 |
3 | /**
4 | * This module executes inside of electron's main process. You can start
5 | * electron renderer process from here and communicate with the other processes
6 | * through IPC.
7 | *
8 | * When running `yarn build` or `yarn build-main`, this file is compiled to
9 | * `./app/main.prod.js` using webpack. This gives us some performance wins.
10 | */
11 | import path from 'path';
12 | import { app, BrowserWindow } from 'electron';
13 | import { autoUpdater } from 'electron-updater';
14 | import log from 'electron-log';
15 | import MenuBuilder from './menu';
16 |
17 | export default class AppUpdater {
18 | constructor() {
19 | log.transports.file.level = 'info';
20 | autoUpdater.logger = log;
21 | autoUpdater.checkForUpdatesAndNotify();
22 | }
23 | }
24 |
25 | let mainWindow: BrowserWindow | null = null;
26 |
27 | if (process.env.NODE_ENV === 'production') {
28 | const sourceMapSupport = require('source-map-support');
29 | sourceMapSupport.install();
30 | }
31 |
32 | if (
33 | process.env.NODE_ENV === 'development' ||
34 | process.env.DEBUG_PROD === 'true'
35 | ) {
36 | require('electron-debug')();
37 | }
38 |
39 | const installExtensions = async () => {
40 | const installer = require('electron-devtools-installer');
41 | const forceDownload = !!process.env.UPGRADE_EXTENSIONS;
42 | const extensions = ['REACT_DEVELOPER_TOOLS'];
43 |
44 | return Promise.all(
45 | extensions.map(name => installer.default(installer[name], forceDownload))
46 | ).catch(console.log);
47 | };
48 |
49 | const createWindow = async () => {
50 | if (
51 | process.env.NODE_ENV === 'development' ||
52 | process.env.DEBUG_PROD === 'true'
53 | ) {
54 | await installExtensions();
55 | }
56 |
57 | mainWindow = new BrowserWindow({
58 | show: false,
59 | width: 1024,
60 | height: 728,
61 | backgroundColor: '#262626',
62 | // webPreferences:
63 | // process.env.NODE_ENV === 'development' || process.env.E2E_BUILD === 'true'
64 | // ? {
65 | // nodeIntegration: true
66 | // }
67 | // : {
68 | // preload: path.join(__dirname, 'dist/renderer.prod.js')
69 | // }
70 | webPreferences: {
71 | nodeIntegration: true
72 | }
73 | });
74 |
75 | mainWindow.loadURL(`file://${__dirname}/app.html`);
76 |
77 | // @TODO: Use 'ready-to-show' event
78 | // https://github.com/electron/electron/blob/master/docs/api/browser-window.md#using-ready-to-show-event
79 | mainWindow.webContents.on('did-finish-load', () => {
80 | if (!mainWindow) {
81 | throw new Error('"mainWindow" is not defined');
82 | }
83 | if (process.env.START_MINIMIZED) {
84 | mainWindow.minimize();
85 | } else {
86 | mainWindow.show();
87 | mainWindow.focus();
88 | }
89 | });
90 |
91 | mainWindow.on('closed', () => {
92 | mainWindow = null;
93 | });
94 |
95 | const menuBuilder = new MenuBuilder(mainWindow);
96 | menuBuilder.buildMenu();
97 |
98 | // Remove this if your app does not use auto updates
99 | // eslint-disable-next-line
100 | new AppUpdater();
101 | };
102 |
103 | /**
104 | * Add event listeners...
105 | */
106 |
107 | app.on('window-all-closed', () => {
108 | // Respect the OSX convention of having the application in memory even
109 | // after all windows have been closed
110 | if (process.platform !== 'darwin') {
111 | app.quit();
112 | }
113 | });
114 |
115 | app.on('ready', createWindow);
116 |
117 | app.on('activate', () => {
118 | // On macOS it's common to re-create a window in the app when the
119 | // dock icon is clicked and there are no other windows open.
120 | if (mainWindow === null) createWindow();
121 | });
122 |
--------------------------------------------------------------------------------
/app/main.prod.js.LICENSE:
--------------------------------------------------------------------------------
1 | /*! http://mths.be/fromcodepoint v0.1.0 by @mathias */
2 |
--------------------------------------------------------------------------------
/app/main.prod.js.LICENSE.txt:
--------------------------------------------------------------------------------
1 | /*! http://mths.be/fromcodepoint v0.1.0 by @mathias */
2 |
--------------------------------------------------------------------------------
/app/menu.ts:
--------------------------------------------------------------------------------
1 | /* eslint @typescript-eslint/ban-ts-ignore: off */
2 | import {
3 | app,
4 | Menu,
5 | shell,
6 | BrowserWindow,
7 | MenuItemConstructorOptions
8 | } from 'electron';
9 |
10 | interface DarwinMenuItemConstructorOptions extends MenuItemConstructorOptions {
11 | selector?: string;
12 | submenu?: DarwinMenuItemConstructorOptions[] | Menu;
13 | }
14 |
15 | export default class MenuBuilder {
16 | mainWindow: BrowserWindow;
17 |
18 | constructor(mainWindow: BrowserWindow) {
19 | this.mainWindow = mainWindow;
20 | }
21 |
22 | buildMenu() {
23 | if (
24 | process.env.NODE_ENV === 'development' ||
25 | process.env.DEBUG_PROD === 'true'
26 | ) {
27 | this.setupDevelopmentEnvironment();
28 | }
29 |
30 | const template =
31 | process.platform === 'darwin'
32 | ? this.buildDarwinTemplate()
33 | : this.buildDefaultTemplate();
34 |
35 | const menu = Menu.buildFromTemplate(template);
36 | Menu.setApplicationMenu(menu);
37 |
38 | return menu;
39 | }
40 |
41 | setupDevelopmentEnvironment() {
42 | this.mainWindow.webContents.on('context-menu', (_, props) => {
43 | const { x, y } = props;
44 |
45 | Menu.buildFromTemplate([
46 | {
47 | label: 'Inspect element',
48 | click: () => {
49 | this.mainWindow.webContents.inspectElement(x, y);
50 | }
51 | }
52 | ]).popup({ window: this.mainWindow });
53 | });
54 | }
55 |
56 | buildDarwinTemplate() {
57 | const subMenuAbout: DarwinMenuItemConstructorOptions = {
58 | label: 'Electron',
59 | submenu: [
60 | {
61 | label: 'About ElectronReact',
62 | selector: 'orderFrontStandardAboutPanel:'
63 | },
64 | { type: 'separator' },
65 | { label: 'Services', submenu: [] },
66 | { type: 'separator' },
67 | {
68 | label: 'Hide ElectronReact',
69 | accelerator: 'Command+H',
70 | selector: 'hide:'
71 | },
72 | {
73 | label: 'Hide Others',
74 | accelerator: 'Command+Shift+H',
75 | selector: 'hideOtherApplications:'
76 | },
77 | { label: 'Show All', selector: 'unhideAllApplications:' },
78 | { type: 'separator' },
79 | {
80 | label: 'Quit',
81 | accelerator: 'Command+Q',
82 | click: () => {
83 | app.quit();
84 | }
85 | }
86 | ]
87 | };
88 | const subMenuEdit: DarwinMenuItemConstructorOptions = {
89 | label: 'Edit',
90 | submenu: [
91 | { label: 'Undo', accelerator: 'Command+Z', selector: 'undo:' },
92 | { label: 'Redo', accelerator: 'Shift+Command+Z', selector: 'redo:' },
93 | { type: 'separator' },
94 | { label: 'Cut', accelerator: 'Command+X', selector: 'cut:' },
95 | { label: 'Copy', accelerator: 'Command+C', selector: 'copy:' },
96 | { label: 'Paste', accelerator: 'Command+V', selector: 'paste:' },
97 | {
98 | label: 'Select All',
99 | accelerator: 'Command+A',
100 | selector: 'selectAll:'
101 | }
102 | ]
103 | };
104 | const subMenuViewDev: MenuItemConstructorOptions = {
105 | label: 'View',
106 | submenu: [
107 | {
108 | label: 'Reload',
109 | accelerator: 'Command+R',
110 | click: () => {
111 | this.mainWindow.webContents.reload();
112 | }
113 | },
114 | {
115 | label: 'Toggle Full Screen',
116 | accelerator: 'Ctrl+Command+F',
117 | click: () => {
118 | this.mainWindow.setFullScreen(!this.mainWindow.isFullScreen());
119 | }
120 | },
121 | {
122 | label: 'Toggle Developer Tools',
123 | accelerator: 'Alt+Command+I',
124 | click: () => {
125 | this.mainWindow.webContents.toggleDevTools();
126 | }
127 | }
128 | ]
129 | };
130 | const subMenuViewProd: MenuItemConstructorOptions = {
131 | label: 'View',
132 | submenu: [
133 | {
134 | label: 'Toggle Full Screen',
135 | accelerator: 'Ctrl+Command+F',
136 | click: () => {
137 | this.mainWindow.setFullScreen(!this.mainWindow.isFullScreen());
138 | }
139 | }
140 | ]
141 | };
142 | const subMenuWindow: DarwinMenuItemConstructorOptions = {
143 | label: 'Window',
144 | submenu: [
145 | {
146 | label: 'Minimize',
147 | accelerator: 'Command+M',
148 | selector: 'performMiniaturize:'
149 | },
150 | { label: 'Close', accelerator: 'Command+W', selector: 'performClose:' },
151 | { type: 'separator' },
152 | { label: 'Bring All to Front', selector: 'arrangeInFront:' }
153 | ]
154 | };
155 | const subMenuHelp: MenuItemConstructorOptions = {
156 | label: 'Help',
157 | submenu: [
158 | {
159 | label: 'Learn More',
160 | click() {
161 | shell.openExternal('https://electronjs.org');
162 | }
163 | },
164 | {
165 | label: 'Documentation',
166 | click() {
167 | shell.openExternal(
168 | 'https://github.com/electron/electron/tree/master/docs#readme'
169 | );
170 | }
171 | },
172 | {
173 | label: 'Community Discussions',
174 | click() {
175 | shell.openExternal('https://www.electronjs.org/community');
176 | }
177 | },
178 | {
179 | label: 'Search Issues',
180 | click() {
181 | shell.openExternal('https://github.com/electron/electron/issues');
182 | }
183 | }
184 | ]
185 | };
186 |
187 | const subMenuView =
188 | process.env.NODE_ENV === 'development' ||
189 | process.env.DEBUG_PROD === 'true'
190 | ? subMenuViewDev
191 | : subMenuViewProd;
192 |
193 | return [subMenuAbout, subMenuEdit, subMenuView, subMenuWindow, subMenuHelp];
194 | }
195 |
196 | buildDefaultTemplate() {
197 | const templateDefault = [
198 | {
199 | label: '&File',
200 | submenu: [
201 | {
202 | label: '&Open',
203 | accelerator: 'Ctrl+O'
204 | },
205 | {
206 | label: '&Close',
207 | accelerator: 'Ctrl+W',
208 | click: () => {
209 | this.mainWindow.close();
210 | }
211 | }
212 | ]
213 | },
214 | {
215 | label: '&View',
216 | submenu:
217 | process.env.NODE_ENV === 'development' ||
218 | process.env.DEBUG_PROD === 'true'
219 | ? [
220 | {
221 | label: '&Reload',
222 | accelerator: 'Ctrl+R',
223 | click: () => {
224 | this.mainWindow.webContents.reload();
225 | }
226 | },
227 | {
228 | label: 'Toggle &Full Screen',
229 | accelerator: 'F11',
230 | click: () => {
231 | this.mainWindow.setFullScreen(
232 | !this.mainWindow.isFullScreen()
233 | );
234 | }
235 | },
236 | {
237 | label: 'Toggle &Developer Tools',
238 | accelerator: 'Alt+Ctrl+I',
239 | click: () => {
240 | this.mainWindow.webContents.toggleDevTools();
241 | }
242 | }
243 | ]
244 | : [
245 | {
246 | label: 'Toggle &Full Screen',
247 | accelerator: 'F11',
248 | click: () => {
249 | this.mainWindow.setFullScreen(
250 | !this.mainWindow.isFullScreen()
251 | );
252 | }
253 | }
254 | ]
255 | },
256 | {
257 | label: 'Help',
258 | submenu: [
259 | {
260 | label: 'Learn More',
261 | click() {
262 | shell.openExternal('https://electronjs.org');
263 | }
264 | },
265 | {
266 | label: 'Documentation',
267 | click() {
268 | shell.openExternal(
269 | 'https://github.com/electron/electron/tree/master/docs#readme'
270 | );
271 | }
272 | },
273 | {
274 | label: 'Community Discussions',
275 | click() {
276 | shell.openExternal('https://www.electronjs.org/community');
277 | }
278 | },
279 | {
280 | label: 'Search Issues',
281 | click() {
282 | shell.openExternal('https://github.com/electron/electron/issues');
283 | }
284 | }
285 | ]
286 | }
287 | ];
288 |
289 | return templateDefault;
290 | }
291 | }
292 |
--------------------------------------------------------------------------------
/app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "electron-react-boilerplate",
3 | "productName": "electron-react-boilerplate",
4 | "version": "1.1.0",
5 | "description": "Electron application boilerplate based on React, React Router, Webpack, React Hot Loader for rapid application development",
6 | "main": "./main.prod.js",
7 | "author": {
8 | "name": "Electron React Boilerplate Maintainers",
9 | "email": "electronreactboilerplate@gmail.com",
10 | "url": "https://github.com/electron-react-boilerplate"
11 | },
12 | "scripts": {
13 | "electron-rebuild": "node -r ../internals/scripts/BabelRegister.js ../internals/scripts/ElectronRebuild.js",
14 | "postinstall": "yarn electron-rebuild"
15 | },
16 | "license": "MIT",
17 | "dependencies": {},
18 | "devDependencies": {
19 | "@types/react-mdl": "^1.7.27"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/utils/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/ReactionTime/4ad16b791876ee4136c8f5e584cf6a1108b26d75/app/utils/.gitkeep
--------------------------------------------------------------------------------
/app/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | "@types/prop-types@*":
6 | version "15.7.3"
7 | resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7"
8 | integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==
9 |
10 | "@types/react-mdl@^1.7.27":
11 | version "1.7.27"
12 | resolved "https://registry.yarnpkg.com/@types/react-mdl/-/react-mdl-1.7.27.tgz#9acc535480e6810b8913a8547f4c06d4605b24a3"
13 | integrity sha512-sdv7MAj+cT6s1Lg+vjgTV1Vfawfr3ijbdAmWnBbr2VZGAz/feiBbRhUiAmQystuVCGfup7wZf35INDnRrlCvbQ==
14 | dependencies:
15 | "@types/react" "*"
16 |
17 | "@types/react@*":
18 | version "16.9.35"
19 | resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.35.tgz#a0830d172e8aadd9bd41709ba2281a3124bbd368"
20 | integrity sha512-q0n0SsWcGc8nDqH2GJfWQWUOmZSJhXV64CjVN5SvcNti3TdEaA3AH0D8DwNmMdzjMAC/78tB8nAZIlV8yTz+zQ==
21 | dependencies:
22 | "@types/prop-types" "*"
23 | csstype "^2.2.0"
24 |
25 | csstype@^2.2.0:
26 | version "2.6.10"
27 | resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.10.tgz#e63af50e66d7c266edb6b32909cfd0aabe03928b"
28 | integrity sha512-D34BqZU4cIlMCY93rZHbrq9pjTAQJ3U8S8rfBqjwHxkGPThWFjzZDQpgMJY0QViLxth6ZKYiwFBo14RdN44U/w==
29 |
--------------------------------------------------------------------------------
/azure-pipelines.yml:
--------------------------------------------------------------------------------
1 | variables:
2 | YARN_CACHE_FOLDER: $(Pipeline.Workspace)/.yarn
3 |
4 | strategy:
5 | matrix:
6 | linux:
7 | imageName: 'ubuntu-16.04'
8 | nodeVersion: '13.x'
9 | mac:
10 | imageName: 'macos-10.14'
11 | nodeVersion: '13.x'
12 | windows:
13 | imageName: 'windows-2019'
14 | nodeVersion: '13.x'
15 |
16 | pool:
17 | vmImage: $(imageName)
18 |
19 | steps:
20 | # Set node version
21 | - task: NodeTool@0
22 | inputs:
23 | versionSpec: $(nodeVersion)
24 | # Cache yarn deps
25 | - task: Cache@2
26 | inputs:
27 | key: 'yarn | "$(Agent.OS)" | yarn.lock'
28 | restoreKeys: |
29 | yarn | "$(Agent.OS)"
30 | yarn
31 | path: $(YARN_CACHE_FOLDER)
32 | displayName: Cache Yarn packages
33 | # Start virtual framebuffer server
34 | - bash: |
35 | /usr/bin/Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &
36 | echo ">>> Started xvfb"
37 | displayName: Start xvfb
38 | condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'))
39 | # Install deps with yarn and run tests
40 | - script: yarn --frozen-lockfile && yarn test-all
41 | env:
42 | DISPLAY: ':99.0'
43 | # Generate coverage report
44 | - script: yarn test --coverage --coverageReporters=cobertura
45 | # Publish coverage report
46 | - task: PublishCodeCoverageResults@1
47 | inputs:
48 | codeCoverageTool: Cobertura
49 | summaryFileLocation: $(System.DefaultWorkingDirectory)/coverage/cobertura-coverage.xml
50 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | /* eslint global-require: off, import/no-extraneous-dependencies: off */
2 |
3 | const developmentEnvironments = ['development', 'test'];
4 |
5 | const developmentPlugins = [require('react-hot-loader/babel')];
6 |
7 | const productionPlugins = [
8 | require('babel-plugin-dev-expression'),
9 |
10 | // babel-preset-react-optimize
11 | require('@babel/plugin-transform-react-constant-elements'),
12 | require('@babel/plugin-transform-react-inline-elements'),
13 | require('babel-plugin-transform-react-remove-prop-types')
14 | ];
15 |
16 | module.exports = api => {
17 | // See docs about api at https://babeljs.io/docs/en/config-files#apicache
18 |
19 | const development = api.env(developmentEnvironments);
20 |
21 | return {
22 | presets: [
23 | // @babel/preset-env will automatically target our browserslist targets
24 | require('@babel/preset-env'),
25 | require('@babel/preset-typescript'),
26 | [require('@babel/preset-react'), { development }]
27 | ],
28 | plugins: [
29 | // Stage 0
30 | require('@babel/plugin-proposal-function-bind'),
31 |
32 | // Stage 1
33 | require('@babel/plugin-proposal-export-default-from'),
34 | require('@babel/plugin-proposal-logical-assignment-operators'),
35 | [require('@babel/plugin-proposal-optional-chaining'), { loose: false }],
36 | [
37 | require('@babel/plugin-proposal-pipeline-operator'),
38 | { proposal: 'minimal' }
39 | ],
40 | [
41 | require('@babel/plugin-proposal-nullish-coalescing-operator'),
42 | { loose: false }
43 | ],
44 | require('@babel/plugin-proposal-do-expressions'),
45 |
46 | // Stage 2
47 | [require('@babel/plugin-proposal-decorators'), { legacy: true }],
48 | require('@babel/plugin-proposal-function-sent'),
49 | require('@babel/plugin-proposal-export-namespace-from'),
50 | require('@babel/plugin-proposal-numeric-separator'),
51 | require('@babel/plugin-proposal-throw-expressions'),
52 |
53 | // Stage 3
54 | require('@babel/plugin-syntax-dynamic-import'),
55 | require('@babel/plugin-syntax-import-meta'),
56 | [require('@babel/plugin-proposal-class-properties'), { loose: true }],
57 | require('@babel/plugin-proposal-json-strings'),
58 |
59 | ...(development ? developmentPlugins : productionPlugins)
60 | ]
61 | };
62 | };
63 |
--------------------------------------------------------------------------------
/code_of_conduct.md:
--------------------------------------------------------------------------------
1 |
2 | # Contributor Covenant Code of Conduct
3 |
4 | ## Our Pledge
5 |
6 | In the interest of fostering an open and welcoming environment, we as
7 | contributors and maintainers pledge to make participation in our project and
8 | our community a harassment-free experience for everyone, regardless of age, body
9 | size, disability, ethnicity, sex characteristics, gender identity and expression,
10 | level of experience, education, socio-economic status, nationality, personal
11 | appearance, race, religion, or sexual identity and orientation.
12 |
13 | ## Our Standards
14 |
15 | Examples of behavior that contributes to creating a positive environment
16 | include:
17 |
18 | * Using welcoming and inclusive language
19 | * Being respectful of differing viewpoints and experiences
20 | * Gracefully accepting constructive criticism
21 | * Focusing on what is best for the community
22 | * Showing empathy towards other community members
23 |
24 | Examples of unacceptable behavior by participants include:
25 |
26 | * The use of sexualized language or imagery and unwelcome sexual attention or
27 | advances
28 | * Trolling, insulting/derogatory comments, and personal or political attacks
29 | * Public or private harassment
30 | * Publishing others' private information, such as a physical or electronic
31 | address, without explicit permission
32 | * Other conduct which could reasonably be considered inappropriate in a
33 | professional setting
34 |
35 | ## Our Responsibilities
36 |
37 | Project maintainers are responsible for clarifying the standards of acceptable
38 | behavior and are expected to take appropriate and fair corrective action in
39 | response to any instances of unacceptable behavior.
40 |
41 | Project maintainers have the right and responsibility to remove, edit, or
42 | reject comments, commits, code, wiki edits, issues, and other contributions
43 | that are not aligned to this Code of Conduct, or to ban temporarily or
44 | permanently any contributor for other behaviors that they deem inappropriate,
45 | threatening, offensive, or harmful.
46 |
47 | ## Scope
48 |
49 | This Code of Conduct applies within all project spaces, and it also applies when
50 | an individual is representing the project or its community in public spaces.
51 | Examples of representing a project or community include using an official
52 | project e-mail address, posting via an official social media account, or acting
53 | as an appointed representative at an online or offline event. Representation of
54 | a project may be further defined and clarified by project maintainers.
55 |
56 | ## Enforcement
57 |
58 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
59 | reported by contacting the project team at [INSERT EMAIL ADDRESS]. All
60 | complaints will be reviewed and investigated and will result in a response that
61 | is deemed necessary and appropriate to the circumstances. The project team is
62 | obligated to maintain confidentiality with regard to the reporter of an incident.
63 | Further details of specific enforcement policies may be posted separately.
64 |
65 | Project maintainers who do not follow or enforce the Code of Conduct in good
66 | faith may face temporary or permanent repercussions as determined by other
67 | members of the project's leadership.
68 |
69 | ## Attribution
70 |
71 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
72 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
73 |
74 | [homepage]: https://www.contributor-covenant.org
75 |
76 | For answers to common questions about this code of conduct, see
77 | https://www.contributor-covenant.org/faq
78 |
79 |
--------------------------------------------------------------------------------
/configs/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "no-console": "off",
4 | "global-require": "off",
5 | "import/no-dynamic-require": "off"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/configs/webpack.config.base.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Base webpack config used across other specific configs
3 | */
4 |
5 | import path from 'path';
6 | import webpack from 'webpack';
7 | import { dependencies as externals } from '../app/package.json';
8 |
9 | export default {
10 | externals: [...Object.keys(externals || {})],
11 |
12 | module: {
13 | rules: [
14 | {
15 | test: /\.tsx?$/,
16 | exclude: /node_modules/,
17 | use: {
18 | loader: 'babel-loader',
19 | options: {
20 | cacheDirectory: true
21 | }
22 | }
23 | }
24 | ]
25 | },
26 |
27 | output: {
28 | path: path.join(__dirname, '..', 'app'),
29 | // https://github.com/webpack/webpack/issues/1114
30 | libraryTarget: 'commonjs2'
31 | },
32 |
33 | /**
34 | * Determine the array of extensions that should be used to resolve modules.
35 | */
36 | resolve: {
37 | extensions: ['.js', '.jsx', '.json', '.ts', '.tsx'],
38 | modules: [path.join(__dirname, '..', 'app'), 'node_modules']
39 | },
40 |
41 | plugins: [
42 | new webpack.EnvironmentPlugin({
43 | NODE_ENV: 'production'
44 | }),
45 |
46 | new webpack.NamedModulesPlugin()
47 | ]
48 | };
49 |
--------------------------------------------------------------------------------
/configs/webpack.config.eslint.js:
--------------------------------------------------------------------------------
1 | /* eslint import/no-unresolved: off, import/no-self-import: off */
2 | require('@babel/register');
3 |
4 | module.exports = require('./webpack.config.renderer.dev.babel').default;
5 |
--------------------------------------------------------------------------------
/configs/webpack.config.main.prod.babel.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Webpack config for production electron main process
3 | */
4 |
5 | import path from 'path';
6 | import webpack from 'webpack';
7 | import merge from 'webpack-merge';
8 | import TerserPlugin from 'terser-webpack-plugin';
9 | import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
10 | import baseConfig from './webpack.config.base';
11 | import CheckNodeEnv from '../internals/scripts/CheckNodeEnv';
12 | import DeleteSourceMaps from '../internals/scripts/DeleteSourceMaps';
13 |
14 | CheckNodeEnv('production');
15 | DeleteSourceMaps();
16 |
17 | export default merge.smart(baseConfig, {
18 | devtool: process.env.DEBUG_PROD === 'true' ? 'source-map' : 'none',
19 |
20 | mode: 'production',
21 |
22 | target: 'electron-main',
23 |
24 | entry: './app/main.dev.ts',
25 |
26 | output: {
27 | path: path.join(__dirname, '..'),
28 | filename: './app/main.prod.js'
29 | },
30 |
31 | optimization: {
32 | minimizer: process.env.E2E_BUILD
33 | ? []
34 | : [
35 | new TerserPlugin({
36 | parallel: true,
37 | sourceMap: true,
38 | cache: true
39 | })
40 | ]
41 | },
42 |
43 | plugins: [
44 | new BundleAnalyzerPlugin({
45 | analyzerMode:
46 | process.env.OPEN_ANALYZER === 'true' ? 'server' : 'disabled',
47 | openAnalyzer: process.env.OPEN_ANALYZER === 'true'
48 | }),
49 |
50 | /**
51 | * Create global constants which can be configured at compile time.
52 | *
53 | * Useful for allowing different behaviour between development builds and
54 | * release builds
55 | *
56 | * NODE_ENV should be production so that modules do not perform certain
57 | * development checks
58 | */
59 | new webpack.EnvironmentPlugin({
60 | NODE_ENV: 'production',
61 | DEBUG_PROD: false,
62 | START_MINIMIZED: false,
63 | E2E_BUILD: false
64 | })
65 | ],
66 |
67 | /**
68 | * Disables webpack processing of __dirname and __filename.
69 | * If you run the bundle in node.js it falls back to these values of node.js.
70 | * https://github.com/webpack/webpack/issues/2010
71 | */
72 | node: {
73 | __dirname: false,
74 | __filename: false
75 | }
76 | });
77 |
--------------------------------------------------------------------------------
/configs/webpack.config.renderer.dev.babel.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Build config for development electron renderer process that uses
3 | * Hot-Module-Replacement
4 | *
5 | * https://webpack.js.org/concepts/hot-module-replacement/
6 | */
7 |
8 | import path from 'path';
9 | import fs from 'fs';
10 | import webpack from 'webpack';
11 | import chalk from 'chalk';
12 | import merge from 'webpack-merge';
13 | import { spawn, execSync } from 'child_process';
14 | import { TypedCssModulesPlugin } from 'typed-css-modules-webpack-plugin';
15 | import baseConfig from './webpack.config.base';
16 | import CheckNodeEnv from '../internals/scripts/CheckNodeEnv';
17 |
18 | // When an ESLint server is running, we can't set the NODE_ENV so we'll check if it's
19 | // at the dev webpack config is not accidentally run in a production environment
20 | if (process.env.NODE_ENV === 'production') {
21 | CheckNodeEnv('development');
22 | }
23 |
24 | const port = process.env.PORT || 1212;
25 | const publicPath = `http://localhost:${port}/dist`;
26 | const dll = path.join(__dirname, '..', 'dll');
27 | const manifest = path.resolve(dll, 'renderer.json');
28 | const requiredByDLLConfig = module.parent.filename.includes(
29 | 'webpack.config.renderer.dev.dll'
30 | );
31 |
32 | /**
33 | * Warn if the DLL is not built
34 | */
35 | if (!requiredByDLLConfig && !(fs.existsSync(dll) && fs.existsSync(manifest))) {
36 | console.log(
37 | chalk.black.bgYellow.bold(
38 | 'The DLL files are missing. Sit back while we build them for you with "yarn build-dll"'
39 | )
40 | );
41 | execSync('yarn build-dll');
42 | }
43 |
44 | export default merge.smart(baseConfig, {
45 | devtool: 'inline-source-map',
46 |
47 | mode: 'development',
48 |
49 | target: 'electron-renderer',
50 |
51 | entry: [
52 | ...(process.env.PLAIN_HMR ? [] : ['react-hot-loader/patch']),
53 | `webpack-dev-server/client?http://localhost:${port}/`,
54 | 'webpack/hot/only-dev-server',
55 | require.resolve('../app/index.tsx')
56 | ],
57 |
58 | output: {
59 | publicPath: `http://localhost:${port}/dist/`,
60 | filename: 'renderer.dev.js'
61 | },
62 |
63 | module: {
64 | rules: [
65 | {
66 | test: /\.global\.css$/,
67 | use: [
68 | {
69 | loader: 'style-loader'
70 | },
71 | {
72 | loader: 'css-loader',
73 | options: {
74 | sourceMap: true
75 | }
76 | }
77 | ]
78 | },
79 | {
80 | test: /^((?!\.global).)*\.css$/,
81 | use: [
82 | {
83 | loader: 'style-loader'
84 | },
85 | {
86 | loader: 'css-loader',
87 | options: {
88 | modules: {
89 | localIdentName: '[name]__[local]__[hash:base64:5]'
90 | },
91 | sourceMap: true,
92 | importLoaders: 1
93 | }
94 | }
95 | ]
96 | },
97 | // SASS support - compile all .global.scss files and pipe it to style.css
98 | {
99 | test: /\.global\.(scss|sass)$/,
100 | use: [
101 | {
102 | loader: 'style-loader'
103 | },
104 | {
105 | loader: 'css-loader',
106 | options: {
107 | sourceMap: true
108 | }
109 | },
110 | {
111 | loader: 'sass-loader'
112 | }
113 | ]
114 | },
115 | // SASS support - compile all other .scss files and pipe it to style.css
116 | {
117 | test: /^((?!\.global).)*\.(scss|sass)$/,
118 | use: [
119 | {
120 | loader: 'style-loader'
121 | },
122 | {
123 | loader: 'css-loader',
124 | options: {
125 | modules: {
126 | localIdentName: '[name]__[local]__[hash:base64:5]'
127 | },
128 | sourceMap: true,
129 | importLoaders: 1
130 | }
131 | },
132 | {
133 | loader: 'sass-loader'
134 | }
135 | ]
136 | },
137 | // WOFF Font
138 | {
139 | test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
140 | use: {
141 | loader: 'url-loader',
142 | options: {
143 | limit: 10000,
144 | mimetype: 'application/font-woff'
145 | }
146 | }
147 | },
148 | // WOFF2 Font
149 | {
150 | test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
151 | use: {
152 | loader: 'url-loader',
153 | options: {
154 | limit: 10000,
155 | mimetype: 'application/font-woff'
156 | }
157 | }
158 | },
159 | // TTF Font
160 | {
161 | test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
162 | use: {
163 | loader: 'url-loader',
164 | options: {
165 | limit: 10000,
166 | mimetype: 'application/octet-stream'
167 | }
168 | }
169 | },
170 | // EOT Font
171 | {
172 | test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
173 | use: 'file-loader'
174 | },
175 | // SVG Font
176 | {
177 | test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
178 | use: {
179 | loader: 'url-loader',
180 | options: {
181 | limit: 10000,
182 | mimetype: 'image/svg+xml'
183 | }
184 | }
185 | },
186 | // Common Image Formats
187 | {
188 | test: /\.(?:ico|gif|png|jpg|jpeg|webp)$/,
189 | use: 'url-loader'
190 | }
191 | ]
192 | },
193 | resolve: {
194 | alias: {
195 | 'react-dom': '@hot-loader/react-dom'
196 | }
197 | },
198 | plugins: [
199 | requiredByDLLConfig
200 | ? null
201 | : new webpack.DllReferencePlugin({
202 | context: path.join(__dirname, '..', 'dll'),
203 | manifest: require(manifest),
204 | sourceType: 'var'
205 | }),
206 |
207 | new webpack.HotModuleReplacementPlugin({
208 | multiStep: true
209 | }),
210 |
211 | new TypedCssModulesPlugin({
212 | globPattern: 'app/**/*.{css,scss,sass}'
213 | }),
214 |
215 | new webpack.NoEmitOnErrorsPlugin(),
216 |
217 | /**
218 | * Create global constants which can be configured at compile time.
219 | *
220 | * Useful for allowing different behaviour between development builds and
221 | * release builds
222 | *
223 | * NODE_ENV should be production so that modules do not perform certain
224 | * development checks
225 | *
226 | * By default, use 'development' as NODE_ENV. This can be overriden with
227 | * 'staging', for example, by changing the ENV variables in the npm scripts
228 | */
229 | new webpack.EnvironmentPlugin({
230 | NODE_ENV: 'development'
231 | }),
232 |
233 | new webpack.LoaderOptionsPlugin({
234 | debug: true
235 | })
236 | ],
237 |
238 | node: {
239 | __dirname: false,
240 | __filename: false
241 | },
242 |
243 | devServer: {
244 | port,
245 | publicPath,
246 | compress: true,
247 | noInfo: true,
248 | stats: 'errors-only',
249 | inline: true,
250 | lazy: false,
251 | hot: true,
252 | headers: { 'Access-Control-Allow-Origin': '*' },
253 | contentBase: path.join(__dirname, 'dist'),
254 | watchOptions: {
255 | aggregateTimeout: 300,
256 | ignored: /node_modules/,
257 | poll: 100
258 | },
259 | historyApiFallback: {
260 | verbose: true,
261 | disableDotRule: false
262 | },
263 | before() {
264 | if (process.env.START_HOT) {
265 | console.log('Starting Main Process...');
266 | spawn('npm', ['run', 'start-main-dev'], {
267 | shell: true,
268 | env: process.env,
269 | stdio: 'inherit'
270 | })
271 | .on('close', code => process.exit(code))
272 | .on('error', spawnError => console.error(spawnError));
273 | }
274 | }
275 | }
276 | });
277 |
--------------------------------------------------------------------------------
/configs/webpack.config.renderer.dev.dll.babel.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Builds the DLL for development electron renderer process
3 | */
4 |
5 | import webpack from 'webpack';
6 | import path from 'path';
7 | import merge from 'webpack-merge';
8 | import baseConfig from './webpack.config.base';
9 | import { dependencies } from '../package.json';
10 | import CheckNodeEnv from '../internals/scripts/CheckNodeEnv';
11 |
12 | CheckNodeEnv('development');
13 |
14 | const dist = path.join(__dirname, '..', 'dll');
15 |
16 | export default merge.smart(baseConfig, {
17 | context: path.join(__dirname, '..'),
18 |
19 | devtool: 'eval',
20 |
21 | mode: 'development',
22 |
23 | target: 'electron-renderer',
24 |
25 | externals: ['fsevents', 'crypto-browserify'],
26 |
27 | /**
28 | * Use `module` from `webpack.config.renderer.dev.js`
29 | */
30 | module: require('./webpack.config.renderer.dev.babel').default.module,
31 |
32 | entry: {
33 | renderer: Object.keys(dependencies || {})
34 | },
35 |
36 | output: {
37 | library: 'renderer',
38 | path: dist,
39 | filename: '[name].dev.dll.js',
40 | libraryTarget: 'var'
41 | },
42 |
43 | plugins: [
44 | new webpack.DllPlugin({
45 | path: path.join(dist, '[name].json'),
46 | name: '[name]'
47 | }),
48 |
49 | /**
50 | * Create global constants which can be configured at compile time.
51 | *
52 | * Useful for allowing different behaviour between development builds and
53 | * release builds
54 | *
55 | * NODE_ENV should be production so that modules do not perform certain
56 | * development checks
57 | */
58 | new webpack.EnvironmentPlugin({
59 | NODE_ENV: 'development'
60 | }),
61 |
62 | new webpack.LoaderOptionsPlugin({
63 | debug: true,
64 | options: {
65 | context: path.join(__dirname, '..', 'app'),
66 | output: {
67 | path: path.join(__dirname, '..', 'dll')
68 | }
69 | }
70 | })
71 | ]
72 | });
73 |
--------------------------------------------------------------------------------
/configs/webpack.config.renderer.prod.babel.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Build config for electron renderer process
3 | */
4 |
5 | import path from 'path';
6 | import webpack from 'webpack';
7 | import MiniCssExtractPlugin from 'mini-css-extract-plugin';
8 | import OptimizeCSSAssetsPlugin from 'optimize-css-assets-webpack-plugin';
9 | import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
10 | import merge from 'webpack-merge';
11 | import TerserPlugin from 'terser-webpack-plugin';
12 | import baseConfig from './webpack.config.base';
13 | import CheckNodeEnv from '../internals/scripts/CheckNodeEnv';
14 | import DeleteSourceMaps from '../internals/scripts/DeleteSourceMaps';
15 |
16 | CheckNodeEnv('production');
17 | DeleteSourceMaps();
18 |
19 | export default merge.smart(baseConfig, {
20 | devtool: process.env.DEBUG_PROD === 'true' ? 'source-map' : 'none',
21 |
22 | mode: 'production',
23 |
24 | target: 'electron-preload',
25 |
26 | entry: path.join(__dirname, '..', 'app/index.tsx'),
27 |
28 | output: {
29 | path: path.join(__dirname, '..', 'app/dist'),
30 | publicPath: './dist/',
31 | filename: 'renderer.prod.js'
32 | },
33 |
34 | module: {
35 | rules: [
36 | // Extract all .global.css to style.css as is
37 | {
38 | test: /\.global\.css$/,
39 | use: [
40 | {
41 | loader: MiniCssExtractPlugin.loader,
42 | options: {
43 | publicPath: './'
44 | }
45 | },
46 | {
47 | loader: 'css-loader',
48 | options: {
49 | sourceMap: true
50 | }
51 | }
52 | ]
53 | },
54 | // Pipe other styles through css modules and append to style.css
55 | {
56 | test: /^((?!\.global).)*\.css$/,
57 | use: [
58 | {
59 | loader: MiniCssExtractPlugin.loader
60 | },
61 | {
62 | loader: 'css-loader',
63 | options: {
64 | modules: {
65 | localIdentName: '[name]__[local]__[hash:base64:5]'
66 | },
67 | sourceMap: true
68 | }
69 | }
70 | ]
71 | },
72 | // Add SASS support - compile all .global.scss files and pipe it to style.css
73 | {
74 | test: /\.global\.(scss|sass)$/,
75 | use: [
76 | {
77 | loader: MiniCssExtractPlugin.loader
78 | },
79 | {
80 | loader: 'css-loader',
81 | options: {
82 | sourceMap: true,
83 | importLoaders: 1
84 | }
85 | },
86 | {
87 | loader: 'sass-loader',
88 | options: {
89 | sourceMap: true
90 | }
91 | }
92 | ]
93 | },
94 | // Add SASS support - compile all other .scss files and pipe it to style.css
95 | {
96 | test: /^((?!\.global).)*\.(scss|sass)$/,
97 | use: [
98 | {
99 | loader: MiniCssExtractPlugin.loader
100 | },
101 | {
102 | loader: 'css-loader',
103 | options: {
104 | modules: {
105 | localIdentName: '[name]__[local]__[hash:base64:5]'
106 | },
107 | importLoaders: 1,
108 | sourceMap: true
109 | }
110 | },
111 | {
112 | loader: 'sass-loader',
113 | options: {
114 | sourceMap: true
115 | }
116 | }
117 | ]
118 | },
119 | // WOFF Font
120 | {
121 | test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
122 | use: {
123 | loader: 'url-loader',
124 | options: {
125 | limit: 10000,
126 | mimetype: 'application/font-woff'
127 | }
128 | }
129 | },
130 | // WOFF2 Font
131 | {
132 | test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
133 | use: {
134 | loader: 'url-loader',
135 | options: {
136 | limit: 10000,
137 | mimetype: 'application/font-woff'
138 | }
139 | }
140 | },
141 | // TTF Font
142 | {
143 | test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
144 | use: {
145 | loader: 'url-loader',
146 | options: {
147 | limit: 10000,
148 | mimetype: 'application/octet-stream'
149 | }
150 | }
151 | },
152 | // EOT Font
153 | {
154 | test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
155 | use: 'file-loader'
156 | },
157 | // SVG Font
158 | {
159 | test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
160 | use: {
161 | loader: 'url-loader',
162 | options: {
163 | limit: 10000,
164 | mimetype: 'image/svg+xml'
165 | }
166 | }
167 | },
168 | // Common Image Formats
169 | {
170 | test: /\.(?:ico|gif|png|jpg|jpeg|webp)$/,
171 | use: 'url-loader'
172 | }
173 | ]
174 | },
175 |
176 | optimization: {
177 | minimizer: process.env.E2E_BUILD
178 | ? []
179 | : [
180 | new TerserPlugin({
181 | parallel: true,
182 | sourceMap: true,
183 | cache: true
184 | }),
185 | new OptimizeCSSAssetsPlugin({
186 | cssProcessorOptions: {
187 | map: {
188 | inline: false,
189 | annotation: true
190 | }
191 | }
192 | })
193 | ]
194 | },
195 |
196 | plugins: [
197 | /**
198 | * Create global constants which can be configured at compile time.
199 | *
200 | * Useful for allowing different behaviour between development builds and
201 | * release builds
202 | *
203 | * NODE_ENV should be production so that modules do not perform certain
204 | * development checks
205 | */
206 | new webpack.EnvironmentPlugin({
207 | NODE_ENV: 'production',
208 | DEBUG_PROD: false,
209 | E2E_BUILD: false
210 | }),
211 |
212 | new MiniCssExtractPlugin({
213 | filename: 'style.css'
214 | }),
215 |
216 | new BundleAnalyzerPlugin({
217 | analyzerMode:
218 | process.env.OPEN_ANALYZER === 'true' ? 'server' : 'disabled',
219 | openAnalyzer: process.env.OPEN_ANALYZER === 'true'
220 | })
221 | ]
222 | });
223 |
--------------------------------------------------------------------------------
/internals/mocks/fileMock.js:
--------------------------------------------------------------------------------
1 | export default 'test-file-stub';
2 |
--------------------------------------------------------------------------------
/internals/scripts/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "no-console": "off",
4 | "global-require": "off",
5 | "import/no-dynamic-require": "off",
6 | "import/no-extraneous-dependencies": "off"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/internals/scripts/BabelRegister.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | require('@babel/register')({
4 | extensions: ['.es6', '.es', '.jsx', '.js', '.mjs', '.ts', '.tsx'],
5 | cwd: path.join(__dirname, '..', '..')
6 | });
7 |
--------------------------------------------------------------------------------
/internals/scripts/CheckBuildsExist.js:
--------------------------------------------------------------------------------
1 | // Check if the renderer and main bundles are built
2 | import path from 'path';
3 | import chalk from 'chalk';
4 | import fs from 'fs';
5 |
6 | const mainPath = path.join(__dirname, '..', '..', 'app', 'main.prod.js');
7 | const rendererPath = path.join(
8 | __dirname,
9 | '..',
10 | '..',
11 | 'app',
12 | 'dist',
13 | 'renderer.prod.js'
14 | );
15 |
16 | if (!fs.existsSync(mainPath)) {
17 | throw new Error(
18 | chalk.whiteBright.bgRed.bold(
19 | 'The main process is not built yet. Build it by running "yarn build-main"'
20 | )
21 | );
22 | }
23 |
24 | if (!fs.existsSync(rendererPath)) {
25 | throw new Error(
26 | chalk.whiteBright.bgRed.bold(
27 | 'The renderer process is not built yet. Build it by running "yarn build-renderer"'
28 | )
29 | );
30 | }
31 |
--------------------------------------------------------------------------------
/internals/scripts/CheckNativeDep.js:
--------------------------------------------------------------------------------
1 | import fs from 'fs';
2 | import chalk from 'chalk';
3 | import { execSync } from 'child_process';
4 | import { dependencies } from '../../package.json';
5 |
6 | if (dependencies) {
7 | const dependenciesKeys = Object.keys(dependencies);
8 | const nativeDeps = fs
9 | .readdirSync('node_modules')
10 | .filter(folder => fs.existsSync(`node_modules/${folder}/binding.gyp`));
11 | try {
12 | // Find the reason for why the dependency is installed. If it is installed
13 | // because of a devDependency then that is okay. Warn when it is installed
14 | // because of a dependency
15 | const { dependencies: dependenciesObject } = JSON.parse(
16 | execSync(`npm ls ${nativeDeps.join(' ')} --json`).toString()
17 | );
18 | const rootDependencies = Object.keys(dependenciesObject);
19 | const filteredRootDependencies = rootDependencies.filter(rootDependency =>
20 | dependenciesKeys.includes(rootDependency)
21 | );
22 | if (filteredRootDependencies.length > 0) {
23 | const plural = filteredRootDependencies.length > 1;
24 | console.log(`
25 | ${chalk.whiteBright.bgYellow.bold(
26 | 'Webpack does not work with native dependencies.'
27 | )}
28 | ${chalk.bold(filteredRootDependencies.join(', '))} ${
29 | plural ? 'are native dependencies' : 'is a native dependency'
30 | } and should be installed inside of the "./app" folder.
31 | First uninstall the packages from "./package.json":
32 | ${chalk.whiteBright.bgGreen.bold('yarn remove your-package')}
33 | ${chalk.bold(
34 | 'Then, instead of installing the package to the root "./package.json":'
35 | )}
36 | ${chalk.whiteBright.bgRed.bold('yarn add your-package')}
37 | ${chalk.bold('Install the package to "./app/package.json"')}
38 | ${chalk.whiteBright.bgGreen.bold('cd ./app && yarn add your-package')}
39 | Read more about native dependencies at:
40 | ${chalk.bold(
41 | 'https://github.com/electron-react-boilerplate/electron-react-boilerplate/wiki/Module-Structure----Two-package.json-Structure'
42 | )}
43 | `);
44 | process.exit(1);
45 | }
46 | } catch (e) {
47 | console.log('Native dependencies could not be checked');
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/internals/scripts/CheckNodeEnv.js:
--------------------------------------------------------------------------------
1 | import chalk from 'chalk';
2 |
3 | export default function CheckNodeEnv(expectedEnv) {
4 | if (!expectedEnv) {
5 | throw new Error('"expectedEnv" not set');
6 | }
7 |
8 | if (process.env.NODE_ENV !== expectedEnv) {
9 | console.log(
10 | chalk.whiteBright.bgRed.bold(
11 | `"process.env.NODE_ENV" must be "${expectedEnv}" to use this webpack config`
12 | )
13 | );
14 | process.exit(2);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/internals/scripts/CheckPortInUse.js:
--------------------------------------------------------------------------------
1 | import chalk from 'chalk';
2 | import detectPort from 'detect-port';
3 |
4 | const port = process.env.PORT || '1212';
5 |
6 | detectPort(port, (err, availablePort) => {
7 | if (port !== String(availablePort)) {
8 | throw new Error(
9 | chalk.whiteBright.bgRed.bold(
10 | `Port "${port}" on "localhost" is already in use. Please use another port. ex: PORT=4343 yarn dev`
11 | )
12 | );
13 | } else {
14 | process.exit(0);
15 | }
16 | });
17 |
--------------------------------------------------------------------------------
/internals/scripts/CheckYarn.js:
--------------------------------------------------------------------------------
1 | if (!/yarn\.js$/.test(process.env.npm_execpath || '')) {
2 | console.warn(
3 | "\u001b[33mYou don't seem to be using yarn. This could produce unexpected results.\u001b[39m"
4 | );
5 | }
6 |
--------------------------------------------------------------------------------
/internals/scripts/DeleteSourceMaps.js:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 | import rimraf from 'rimraf';
3 |
4 | export default function deleteSourceMaps() {
5 | rimraf.sync(path.join(__dirname, '../../app/dist/*.js.map'));
6 | rimraf.sync(path.join(__dirname, '../../app/*.js.map'));
7 | }
8 |
--------------------------------------------------------------------------------
/internals/scripts/ElectronRebuild.js:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 | import { execSync } from 'child_process';
3 | import fs from 'fs';
4 | import { dependencies } from '../../app/package.json';
5 |
6 | const nodeModulesPath = path.join(__dirname, '..', '..', 'app', 'node_modules');
7 |
8 | if (
9 | Object.keys(dependencies || {}).length > 0 &&
10 | fs.existsSync(nodeModulesPath)
11 | ) {
12 | const electronRebuildCmd =
13 | '../node_modules/.bin/electron-rebuild --parallel --force --types prod,dev,optional --module-dir .';
14 | const cmd =
15 | process.platform === 'win32'
16 | ? electronRebuildCmd.replace(/\//g, '\\')
17 | : electronRebuildCmd;
18 | execSync(cmd, {
19 | cwd: path.join(__dirname, '..', '..', 'app'),
20 | stdio: 'inherit'
21 | });
22 | }
23 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "reactiontime",
3 | "productName": "ReactionTime",
4 | "version": "1.1.0",
5 | "description": "Electron application boilerplate based on React, React Router, Webpack, React Hot Loader for rapid application development",
6 | "scripts": {
7 | "build": "concurrently \"yarn build-main\" \"yarn build-renderer\"",
8 | "build-dll": "cross-env NODE_ENV=development webpack --config ./configs/webpack.config.renderer.dev.dll.babel.js --colors",
9 | "build-e2e": "cross-env E2E_BUILD=true yarn build",
10 | "build-main": "cross-env NODE_ENV=production webpack --config ./configs/webpack.config.main.prod.babel.js --colors",
11 | "build-renderer": "cross-env NODE_ENV=production webpack --config ./configs/webpack.config.renderer.prod.babel.js --colors",
12 | "dev": "cross-env START_HOT=1 node -r @babel/register ./internals/scripts/CheckPortInUse.js && cross-env START_HOT=1 yarn start-renderer-dev",
13 | "electron-rebuild": "electron-rebuild --parallel --force --types prod,dev,optional --module-dir app",
14 | "ts": "tsc",
15 | "lint": "cross-env NODE_ENV=development eslint . --cache --ext .js,.jsx,.ts,.tsx",
16 | "lint-fix": "yarn --silent lint --fix; exit 0",
17 | "lint-styles": "stylelint --ignore-path .eslintignore '**/*.*(css|scss)' --syntax scss",
18 | "lint-styles-fix": "yarn --silent lint-styles --fix; exit 0",
19 | "package": "yarn build && electron-builder build --publish never",
20 | "package-all": "yarn build && electron-builder build -mwl",
21 | "package-ci": "yarn postinstall && yarn build && electron-builder --publish always",
22 | "package-mac": "yarn build && electron-builder build --mac",
23 | "package-linux": "yarn build && electron-builder build --linux",
24 | "package-win": "yarn build && electron-builder build --win --x64",
25 | "postinstall": "node -r @babel/register internals/scripts/CheckNativeDep.js && electron-builder install-app-deps && yarn build-dll && opencollective-postinstall",
26 | "postlint-fix": "prettier --ignore-path .eslintignore --single-quote --write '**/*.{js,jsx,json,html,css,less,scss,yml}'",
27 | "postlint-styles-fix": "prettier --ignore-path .eslintignore --single-quote --write '**/*.{css,scss}'",
28 | "preinstall": "node ./internals/scripts/CheckYarn.js",
29 | "prestart": "yarn build",
30 | "start": "cross-env NODE_ENV=production electron ./app/main.prod.js",
31 | "start-main-dev": "cross-env START_HOT=1 NODE_ENV=development electron -r ./internals/scripts/BabelRegister ./app/main.dev.ts",
32 | "start-renderer-dev": "cross-env NODE_ENV=development webpack-dev-server --config configs/webpack.config.renderer.dev.babel.js",
33 | "test": "cross-env NODE_ENV=test BABEL_DISABLE_CACHE=1 jest --coverage",
34 | "test-all": "yarn lint && yarn ts && yarn build && yarn test && yarn build-e2e && yarn test-e2e",
35 | "test-e2e": "node -r @babel/register ./internals/scripts/CheckBuildsExist.js && cross-env NODE_ENV=test testcafe electron:./app ./test/e2e/HomePage.e2e.ts",
36 | "test-e2e-live": "node -r @babel/register ./internals/scripts/CheckBuildsExist.js && cross-env NODE_ENV=test testcafe --live electron:./app ./test/e2e/HomePage.e2e.ts",
37 | "test-watch": "yarn test --watch"
38 | },
39 | "lint-staged": {
40 | "*.{js,jsx,ts,tsx}": [
41 | "cross-env NODE_ENV=development eslint --cache"
42 | ],
43 | "{*.json,.{babelrc,eslintrc,prettierrc,stylelintrc}}": [
44 | "prettier --ignore-path .eslintignore --parser json --write"
45 | ],
46 | "*.{css,scss}": [
47 | "stylelint --ignore-path .eslintignore --syntax scss --fix",
48 | "prettier --ignore-path .eslintignore --single-quote --write"
49 | ],
50 | "*.{html,md,yml}": [
51 | "prettier --ignore-path .eslintignore --single-quote --write"
52 | ]
53 | },
54 | "build": {
55 | "productName": "ReactionTime",
56 | "appId": "org.develar.ElectronReact",
57 | "files": [
58 | "dist/",
59 | "node_modules/",
60 | "app.html",
61 | "main.prod.js",
62 | "main.prod.js.map",
63 | "package.json"
64 | ],
65 | "dmg": {
66 | "contents": [
67 | {
68 | "x": 130,
69 | "y": 220
70 | },
71 | {
72 | "x": 410,
73 | "y": 220,
74 | "type": "link",
75 | "path": "/Applications"
76 | }
77 | ]
78 | },
79 | "win": {
80 | "target": [
81 | "nsis",
82 | "msi"
83 | ]
84 | },
85 | "linux": {
86 | "target": [
87 | "deb",
88 | "rpm",
89 | "AppImage"
90 | ],
91 | "category": "Development"
92 | },
93 | "directories": {
94 | "buildResources": "resources",
95 | "output": "release"
96 | },
97 | "publish": {
98 | "provider": "github",
99 | "owner": "electron-react-boilerplate",
100 | "repo": "electron-react-boilerplate",
101 | "private": false
102 | }
103 | },
104 | "repository": {
105 | "type": "git",
106 | "url": "git+https://github.com/electron-react-boilerplate/electron-react-boilerplate.git"
107 | },
108 | "author": {
109 | "name": "Electron React Boilerplate Maintainers",
110 | "email": "electronreactboilerplate@gmail.com",
111 | "url": "https://electron-react-boilerplate.js.org"
112 | },
113 | "contributors": [
114 | {
115 | "name": "Vikram Rangaraj",
116 | "email": "vikr01@icloud.com",
117 | "url": "https://github.com/vikr01"
118 | },
119 | {
120 | "name": "Amila Welihinda",
121 | "email": "amilajack@gmail.com",
122 | "url": "https://github.com/amilajack"
123 | }
124 | ],
125 | "license": "MIT",
126 | "bugs": {
127 | "url": "https://github.com/electron-react-boilerplate/electron-react-boilerplate/issues"
128 | },
129 | "keywords": [
130 | "electron",
131 | "boilerplate",
132 | "react",
133 | "typescript",
134 | "ts",
135 | "sass",
136 | "webpack",
137 | "hot",
138 | "reload"
139 | ],
140 | "homepage": "https://github.com/electron-react-boilerplate/electron-react-boilerplate#readme",
141 | "jest": {
142 | "testURL": "http://localhost/",
143 | "moduleNameMapper": {
144 | "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "
/internals/mocks/fileMock.js",
145 | "\\.(css|less|sass|scss)$": "identity-obj-proxy"
146 | },
147 | "moduleFileExtensions": [
148 | "js",
149 | "jsx",
150 | "ts",
151 | "tsx",
152 | "json"
153 | ],
154 | "moduleDirectories": [
155 | "node_modules",
156 | "app/node_modules"
157 | ],
158 | "setupFiles": [
159 | "./internals/scripts/CheckBuildsExist.js"
160 | ]
161 | },
162 | "devDependencies": {
163 | "@babel/core": "^7.9.6",
164 | "@babel/plugin-proposal-class-properties": "^7.8.3",
165 | "@babel/plugin-proposal-decorators": "^7.8.3",
166 | "@babel/plugin-proposal-do-expressions": "^7.8.3",
167 | "@babel/plugin-proposal-export-default-from": "^7.8.3",
168 | "@babel/plugin-proposal-export-namespace-from": "^7.8.3",
169 | "@babel/plugin-proposal-function-bind": "^7.8.3",
170 | "@babel/plugin-proposal-function-sent": "^7.8.3",
171 | "@babel/plugin-proposal-json-strings": "^7.8.3",
172 | "@babel/plugin-proposal-logical-assignment-operators": "^7.8.3",
173 | "@babel/plugin-proposal-nullish-coalescing-operator": "^7.8.3",
174 | "@babel/plugin-proposal-numeric-separator": "^7.8.3",
175 | "@babel/plugin-proposal-optional-chaining": "^7.9.0",
176 | "@babel/plugin-proposal-pipeline-operator": "^7.8.3",
177 | "@babel/plugin-proposal-throw-expressions": "^7.8.3",
178 | "@babel/plugin-syntax-dynamic-import": "^7.8.3",
179 | "@babel/plugin-syntax-import-meta": "^7.8.3",
180 | "@babel/plugin-transform-react-constant-elements": "^7.9.0",
181 | "@babel/plugin-transform-react-inline-elements": "^7.9.0",
182 | "@babel/preset-env": "^7.9.6",
183 | "@babel/preset-react": "^7.9.4",
184 | "@babel/preset-typescript": "^7.9.0",
185 | "@babel/register": "^7.9.0",
186 | "@types/enzyme": "^3.10.5",
187 | "@types/enzyme-adapter-react-16": "^1.0.6",
188 | "@types/history": "^4.7.5",
189 | "@types/jest": "^25.2.3",
190 | "@types/node": "^14.0.4",
191 | "@types/react": "^16.9.35",
192 | "@types/react-dom": "^16.9.8",
193 | "@types/react-redux": "^7.1.6",
194 | "@types/react-router": "^5.1.7",
195 | "@types/react-router-dom": "^5.1.5",
196 | "@types/react-test-renderer": "^16.9.2",
197 | "@types/redux-logger": "^3.0.7",
198 | "@types/sinon": "^7.5.2",
199 | "@types/tapable": "^1.0.5",
200 | "@types/vfile-message": "^2.0.0",
201 | "@types/webpack": "^4.41.3",
202 | "@typescript-eslint/eslint-plugin": "^2.17.0",
203 | "@typescript-eslint/parser": "^2.17.0",
204 | "babel-core": "7.0.0-bridge.0",
205 | "babel-eslint": "^10.1.0",
206 | "babel-jest": "^25.1.0",
207 | "babel-loader": "^8.1.0",
208 | "babel-plugin-dev-expression": "^0.2.2",
209 | "babel-plugin-transform-react-remove-prop-types": "^0.4.24",
210 | "browserslist-config-erb": "^0.0.1",
211 | "chalk": "^3.0.0",
212 | "concurrently": "^5.2.0",
213 | "cross-env": "^7.0.0",
214 | "cross-spawn": "^7.0.1",
215 | "css-loader": "^3.4.2",
216 | "detect-port": "^1.3.0",
217 | "electron": "7.1.13",
218 | "electron-builder": "^22.3.6",
219 | "electron-devtools-installer": "^2.2.4",
220 | "electron-rebuild": "^1.10.0",
221 | "enzyme": "^3.11.0",
222 | "enzyme-adapter-react-16": "^1.15.2",
223 | "enzyme-to-json": "^3.4.4",
224 | "eslint": "^7.0.0",
225 | "eslint-config-airbnb-typescript": "^6.3.1",
226 | "eslint-config-erb": "^0.3.0",
227 | "eslint-config-prettier": "^6.9.0",
228 | "eslint-import-resolver-webpack": "^0.12.1",
229 | "eslint-plugin-compat": "^3.5.1",
230 | "eslint-plugin-import": "^2.20.0",
231 | "eslint-plugin-jest": "^23.6.0",
232 | "eslint-plugin-jsx-a11y": "6.2.3",
233 | "eslint-plugin-prettier": "^3.1.2",
234 | "eslint-plugin-promise": "^4.2.1",
235 | "eslint-plugin-react": "^7.18.0",
236 | "eslint-plugin-react-hooks": "^2.3.0",
237 | "eslint-plugin-testcafe": "^0.2.1",
238 | "fbjs-scripts": "^1.2.0",
239 | "file-loader": "^5.0.2",
240 | "identity-obj-proxy": "^3.0.0",
241 | "jest": "^25.1.0",
242 | "lint-staged": "^10.0.2",
243 | "mini-css-extract-plugin": "^0.9.0",
244 | "node-sass": "^4.13.1",
245 | "opencollective-postinstall": "^2.0.2",
246 | "optimize-css-assets-webpack-plugin": "^5.0.3",
247 | "prettier": "^1.19.1",
248 | "react-test-renderer": "^16.12.0",
249 | "redux-logger": "^3.0.6",
250 | "rimraf": "^3.0.0",
251 | "sass-loader": "^8.0.2",
252 | "sinon": "^8.1.1",
253 | "spectron": "^10.0.0",
254 | "style-loader": "^1.1.3",
255 | "stylelint": "^13.0.0",
256 | "stylelint-config-prettier": "^8.0.1",
257 | "stylelint-config-standard": "^19.0.0",
258 | "terser-webpack-plugin": "^2.3.2",
259 | "testcafe": "^1.8.0",
260 | "testcafe-browser-provider-electron": "^0.0.14",
261 | "testcafe-react-selectors": "^4.0.0",
262 | "typed-css-modules-webpack-plugin": "^0.1.2",
263 | "typescript": "^3.9.3",
264 | "url-loader": "^3.0.0",
265 | "webpack": "^4.41.5",
266 | "webpack-bundle-analyzer": "^3.6.0",
267 | "webpack-cli": "^3.3.10",
268 | "webpack-dev-server": "^3.10.1",
269 | "webpack-merge": "^4.2.2",
270 | "yarn": "^1.21.1"
271 | },
272 | "dependencies": {
273 | "@fortawesome/fontawesome-free": "^5.13.0",
274 | "@hot-loader/react-dom": "^16.13.0",
275 | "@material-ui/core": "^4.9.14",
276 | "@material-ui/icons": "^4.9.1",
277 | "@material-ui/styles": "^4.10.0",
278 | "connected-react-router": "^6.8.0",
279 | "core-js": "^3.6.5",
280 | "devtron": "^1.4.0",
281 | "electron-debug": "^3.0.1",
282 | "electron-log": "^4.0.6",
283 | "electron-updater": "^4.2.0",
284 | "history": "^4.10.1",
285 | "react": "^16.12.0",
286 | "react-dom": "^16.12.0",
287 | "react-hot-loader": "^4.12.19",
288 | "react-router": "^5.1.2",
289 | "react-router-dom": "^5.2.0",
290 | "source-map-support": "^0.5.16"
291 | },
292 | "devEngines": {
293 | "node": ">=7.x",
294 | "npm": ">=4.x",
295 | "yarn": ">=0.21.3"
296 | },
297 | "collective": {
298 | "url": "https://opencollective.com/electron-react-boilerplate-594"
299 | },
300 | "browserslist": [
301 | "extends browserslist-config-erb"
302 | ],
303 | "prettier": {
304 | "overrides": [
305 | {
306 | "files": [
307 | ".prettierrc",
308 | ".babelrc",
309 | ".eslintrc",
310 | ".stylelintrc"
311 | ],
312 | "options": {
313 | "parser": "json"
314 | }
315 | }
316 | ],
317 | "singleQuote": true
318 | },
319 | "stylelint": {
320 | "extends": [
321 | "stylelint-config-standard",
322 | "stylelint-config-prettier"
323 | ]
324 | },
325 | "renovate": {
326 | "extends": [
327 | "bliss"
328 | ]
329 | }
330 | }
331 |
--------------------------------------------------------------------------------
/resources/download_gif.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/ReactionTime/4ad16b791876ee4136c8f5e584cf6a1108b26d75/resources/download_gif.gif
--------------------------------------------------------------------------------
/resources/generate_test_ gif.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/ReactionTime/4ad16b791876ee4136c8f5e584cf6a1108b26d75/resources/generate_test_ gif.gif
--------------------------------------------------------------------------------
/resources/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/ReactionTime/4ad16b791876ee4136c8f5e584cf6a1108b26d75/resources/icon.ico
--------------------------------------------------------------------------------
/resources/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/ReactionTime/4ad16b791876ee4136c8f5e584cf6a1108b26d75/resources/icon.png
--------------------------------------------------------------------------------
/resources/icons/logo_transparent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/ReactionTime/4ad16b791876ee4136c8f5e584cf6a1108b26d75/resources/icons/logo_transparent.png
--------------------------------------------------------------------------------
/resources/icons/logo_transparent@0,25x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/ReactionTime/4ad16b791876ee4136c8f5e584cf6a1108b26d75/resources/icons/logo_transparent@0,25x.png
--------------------------------------------------------------------------------
/resources/icons/logo_transparent@0,33x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/ReactionTime/4ad16b791876ee4136c8f5e584cf6a1108b26d75/resources/icons/logo_transparent@0,33x.png
--------------------------------------------------------------------------------
/resources/icons/logo_transparent@0,5x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/ReactionTime/4ad16b791876ee4136c8f5e584cf6a1108b26d75/resources/icons/logo_transparent@0,5x.png
--------------------------------------------------------------------------------
/resources/icons/logo_transparent@0,75x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/ReactionTime/4ad16b791876ee4136c8f5e584cf6a1108b26d75/resources/icons/logo_transparent@0,75x.png
--------------------------------------------------------------------------------
/resources/icons/logo_transparent@1,5x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/ReactionTime/4ad16b791876ee4136c8f5e584cf6a1108b26d75/resources/icons/logo_transparent@1,5x.png
--------------------------------------------------------------------------------
/resources/icons/logo_transparent@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/ReactionTime/4ad16b791876ee4136c8f5e584cf6a1108b26d75/resources/icons/logo_transparent@2x.png
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2018",
4 | "module": "CommonJS",
5 | "lib": ["dom", "esnext"],
6 | "declaration": true,
7 | "declarationMap": true,
8 | "noEmit": true,
9 | "jsx": "react",
10 | "strict": true,
11 | "pretty": true,
12 | "sourceMap": true,
13 | /* Additional Checks */
14 | "noUnusedLocals": true,
15 | "noUnusedParameters": true,
16 | "noImplicitReturns": true,
17 | "noFallthroughCasesInSwitch": true,
18 | /* Module Resolution Options */
19 | "moduleResolution": "node",
20 | "esModuleInterop": true,
21 | "allowSyntheticDefaultImports": true,
22 | "resolveJsonModule": true,
23 | "allowJs": true
24 | },
25 | "exclude": [
26 | "test",
27 | "release",
28 | "app/main.prod.js",
29 | "app/main.prod.js.map",
30 | "app/renderer.prod.js",
31 | "app/renderer.prod.js.map",
32 | "app/style.css",
33 | "app/style.css.map",
34 | "app/dist",
35 | "dll",
36 | "app/main.js",
37 | "app/main.js.map"
38 | ]
39 | }
40 |
--------------------------------------------------------------------------------