├── .gitignore ├── README.md ├── app ├── .testcafe-electron-rc ├── app.html ├── app.icns ├── components │ ├── Beaker.tsx │ ├── CreateRootTest.tsx │ ├── FallbackTest.tsx │ ├── HomePage │ │ ├── homePage.css │ │ ├── homePage.css.d.ts │ │ ├── homePage.tsx │ │ └── resources │ │ │ ├── logo.png │ │ │ ├── logo_transparent.png │ │ │ └── logo_transparent_blue.png │ ├── PackageTest.tsx │ ├── SearchGlass.tsx │ ├── SetUp.tsx │ ├── SuspenseTest.tsx │ └── __tests__ │ │ ├── CreateRootTest.test.js │ │ ├── FallbackTest.test.js │ │ ├── Home.test.js │ │ ├── PackageTest.test.js │ │ └── SuspenseTest.test.js ├── dist │ ├── 0cb5a5c0d251c109458c85c6afeffbaa.svg │ ├── 13685372945d816a2b474fc082fd9aaa.ttf │ ├── 1ab236ed440ee51810c56bd16628aef0.ttf │ ├── 261d666b0147c6c5cda07265f98b8f8c.eot │ ├── 89ffa3aba80d30ee0a9371b25c968bbb.svg │ ├── a0369ea57eb6d3843d6474c035111f29.eot │ ├── a06da7f0950f9dd366fc9db9d56d618a.woff2 │ ├── b15db15f746f29ffa02638cb455b8ec0.woff2 │ ├── bea989e82b07e9687c26fc58a4805021.woff │ ├── c1868c9545d2de1cf8488f1dadd8c9d0.eot │ ├── c20b5b7362d8d7bb7eddf94344ace33e.woff2 │ ├── db78b9359171f24936b16d84f63af378.ttf │ ├── ec3cfddedb8bebd2d7a3fdf511f7c1cc.woff │ ├── ec763292e583294612f124c0b0def500.svg │ ├── f89ea91ecd1ca2db7e09baa2c4b156d1.woff │ ├── renderer.prod.js │ ├── renderer.prod.js.LICENSE │ ├── renderer.prod.js.LICENSE.txt │ ├── style.css │ ├── style.css.d.ts │ └── style.css.map ├── index.tsx ├── main.dev.ts ├── main.prod.js ├── main.prod.js.LICENSE ├── main.prod.js.LICENSE.txt ├── menu.ts ├── package.json ├── utils │ └── .gitkeep └── yarn.lock ├── azure-pipelines.yml ├── babel.config.js ├── code_of_conduct.md ├── configs ├── .eslintrc ├── webpack.config.base.js ├── webpack.config.eslint.js ├── webpack.config.main.prod.babel.js ├── webpack.config.renderer.dev.babel.js ├── webpack.config.renderer.dev.dll.babel.js └── webpack.config.renderer.prod.babel.js ├── dll ├── renderer.dev.dll.js └── renderer.json ├── internals ├── mocks │ └── fileMock.js └── scripts │ ├── .eslintrc │ ├── BabelRegister.js │ ├── CheckBuildsExist.js │ ├── CheckNativeDep.js │ ├── CheckNodeEnv.js │ ├── CheckPortInUse.js │ ├── CheckYarn.js │ ├── DeleteSourceMaps.js │ └── ElectronRebuild.js ├── package-lock.json ├── package.json ├── resources ├── download_gif.gif ├── generate_test_ gif.gif ├── icon.ico ├── icon.png └── icons │ ├── logo_transparent.png │ ├── logo_transparent@0,25x.png │ ├── logo_transparent@0,33x.png │ ├── logo_transparent@0,5x.png │ ├── logo_transparent@0,75x.png │ ├── logo_transparent@1,5x.png │ └── logo_transparent@2x.png ├── tsconfig.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | .DS_Store 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | *.lcov 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # TypeScript cache 43 | *.tsbuildinfo 44 | 45 | # Optional npm cache directory 46 | .npm 47 | 48 | # Optional eslint cache 49 | .eslintcache 50 | 51 | # Optional REPL history 52 | .node_repl_history 53 | 54 | # Output of 'npm pack' 55 | *.tgz 56 | 57 | # Yarn Integrity file 58 | .yarn-integrity 59 | 60 | # dotenv environment variables file 61 | .env 62 | .env.test 63 | 64 | # parcel-bundler cache (https://parceljs.org/) 65 | .cache 66 | 67 | # next.js build output 68 | .next 69 | 70 | # nuxt.js build output 71 | .nuxt 72 | 73 | # vuepress build output 74 | .vuepress/dist 75 | 76 | # Serverless directories 77 | .serverless/ 78 | 79 | # FuseBox cache 80 | .fusebox/ 81 | 82 | # DynamoDB Local files 83 | .dynamodb/ 84 | 85 | # Webpack 86 | .webpack/ 87 | 88 | # Electron-Forge 89 | out/ 90 | 91 | # Custom Git Ignore for Electron App 92 | app/dist/renderer.prod.js 93 | app/dist/renderer.prod.js.LICENSE 94 | app/dist/style.css 95 | app/dist/style.css.d.ts 96 | app/dist/style.css.map 97 | app/main.prod.js 98 | app/main.prod.js.LICENSE 99 | dll/renderer.dev.dll.js -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # ReactionTime 3 | ![Preview](https://i.ibb.co/S7jmPqK/Reaction-Time.png#center) 4 | 5 | ## What is ReactionTime 6 | ReactionTime is an application to help users build tests for the newest features of React Concurrent mode. 7 | 8 | ## How to install 9 | Looking for the application? Navigate to reactiontimeapp.com to install it on windows or mac! 10 | 11 | ![ReactionTime Download](https://media.giphy.com/media/ckBYRVbOiyC8iQk3RS/giphy.gif) 12 | 13 | ## Quick Start 14 | 1. Install Jest and React-Testing-Library into your application 15 | 2. Create a new file (should end in .test.js) 16 | 3. Import Jest and React-Testing-Library at the top of that file 17 | 4. Import React and Components that you plan on testing at the top of that file 18 | 5. Generate tests using ReactionTime and the names of those components: 19 | 20 | ![ReactionTime Download](https://media.giphy.com/media/SrzQQM4KgsOyMVsF11/giphy.gif) 21 | 22 | 6. Paste those tests into your .test.js file 23 | 7. Enjoy all the green checks ✔️✔️✔️✔️ 24 | 25 | ## Team 26 | Christian Hubbard [@christianhubbard](https://github.com/christianhubbard "Christian's Github"), Jimmy Phong [@jayacados](https://github.com/jayacados "Jimmy's Github"), Jae Myung [@jhm304](https://github.com/jhm304 "Jae's Github"), Tony Shen [@tshen815](https://github.com/tshen815 "Tony's Github") 27 | -------------------------------------------------------------------------------- /app/.testcafe-electron-rc: -------------------------------------------------------------------------------- 1 | { 2 | "mainWindowUrl": "./app.html", 3 | "appPath": "." 4 | } 5 | -------------------------------------------------------------------------------- /app/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ReactionTime 6 | 7 | 21 | 22 | 23 | 24 |
25 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /app/app.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/ReactionTime/4ad16b791876ee4136c8f5e584cf6a1108b26d75/app/app.icns -------------------------------------------------------------------------------- /app/components/Beaker.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | // Import Material UI Card Component 4 | import Card from "@material-ui/core/Card"; 5 | import CardContent from "@material-ui/core/CardContent"; 6 | import Typography from "@material-ui/core/Typography"; 7 | import { createMuiTheme, ThemeProvider } from '@material-ui/core/styles'; 8 | 9 | import {Link} from "react-router-dom" 10 | 11 | fontFamily: "Raleway, sans-serif" 12 | const theme = createMuiTheme({ 13 | typography: { 14 | fontFamily: [ 15 | 'Raleway', 16 | 'sans-serif', 17 | ].join(','), 18 | }, 19 | }); 20 | 21 | export default function SimpleCard() { 22 | 23 | 24 | return ( 25 | // Begin 2x2 26 | // 27 |
28 | {/* Begin Card 1 */} 29 |
30 |
31 | 32 | 33 | 34 | 35 | Concurrent Setup Test 36 | 37 | 38 | Tests if Concurrent Mode is enabled 39 | 40 | 41 | {`Replaces ReactDOM.render(, rootNode) and enables Concurrent Mode`} 42 | 43 | 44 | 45 | 46 |
47 |
48 | 49 | 50 | 51 | 52 | React Experimental Test 53 | 54 | 55 | Tests for React's experimental version 56 | 57 | 58 | {`Concurrent Mode is only available in the experimental builds of React`} 59 | 60 | 61 | 62 | 63 |
64 |
65 |
66 |
67 | 68 | 69 | 70 | 71 | Component Fallback Test 72 | 73 | 74 | Tests if fallback component is present and defined 75 | 76 | 77 | {`Concurrent Mode is only available in the experimental builds of React`} 78 | 79 | 80 | 81 | 82 |
83 |
84 | 85 | 86 | 87 | 88 | Component Suspense Test 89 | 90 | 91 | Mock test to determine fallback renders in the DOM. 92 | 93 | 94 | {'This will take one argument, a child component that the user expects to suspend. As of now, the suspended component must act as a standalone component'} 95 | 96 | 97 | 98 | 99 |
100 |
101 |
102 | ); 103 | } 104 | -------------------------------------------------------------------------------- /app/components/CreateRootTest.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 CreateRootTest = () => { 7 | const [name, setName] = useState(""); 8 | 9 | let result: string; 10 | 11 | const handleSubmit = (evt: FormEvent) => { 12 | evt.preventDefault(); 13 | result = ` 14 | let file = fs.readFileSync(path.resolve(__dirname, ${name})).toString("utf-8"); 15 | 16 | test('index to contain createRoot', () => { 17 | \u00A0\u00A0return expect(file).toMatch(/createRoot/); 18 | }) 19 | `; 20 | 21 | document.getElementById('test')!.innerText = result; 22 | } 23 | 24 | const darkTheme = createMuiTheme({ 25 | palette: { 26 | type: 'dark', 27 | }, 28 | }); 29 | 30 | return ( 31 |
32 |
33 | 34 |
35 | 36 | {/*
*/} 37 | 38 | Please enter the file path of your index.jsx from the root: 39 | 40 |
41 |
42 |
43 | 44 | setName(e.target.value)} color="primary" style={{color:"#ebebeb"}}/> 46 | 47 | {/*
*/} 48 | 49 |
50 |
51 | 52 |
53 |
54 |
55 |
56 |
57 |
58 | ); 59 | }; 60 | -------------------------------------------------------------------------------- /app/components/FallbackTest.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 FallbackTest = () => { 7 | const [name, setName] = useState(""); 8 | const [fallback, setFallback] = useState(""); 9 | 10 | let result: string; 11 | const handleSubmit = (evt: FormEvent) => { 12 | evt.preventDefault(); 13 | result = ` 14 | if (typeof ${name} === 'undefined') { 15 | \u00A0\u00A0test('renders fallback component', () => { 16 | \u00A0\u00A0\u00A0\u00A0return expect(${name}); 17 | }) 18 | 19 | if (!${fallback}) { 20 | \u00A0\u00A0test('renders fallback component', () => { 21 | \u00A0\u00A0\u00A0\u00A0return expect(${fallback}); 22 | \u00A0\u00A0}) 23 | } else { 24 | \u00A0\u00A0let textFallback = ${fallback}.toString('utf-8'); 25 | \u00A0\u00A0let renderedFallback = testingLibrary.render(${fallback}); 26 | 27 | \u00A0\u00A0if (typeof ${fallback} === "string") { 28 | \u00A0\u00A0\u00A0\u00A0test('renders fallback string instead of component', () => { 29 | \u00A0\u00A0\u00A0\u00A0\u00A0\u00A0const { getByText } = testingLibrary.render(${name}); 30 | \u00A0\u00A0\u00A0\u00A0\u00A0\u00A0return expect(getByText(textFallback)).toBeInTheDocument(); 31 | \u00A0\u00A0\u00A0\u00A0}) 32 | \u00A0\u00A0} else { 33 | \u00A0\u00A0\u00A0\u00A0test('renders fallback inside of suspense component', () => { 34 | \u00A0\u00A0\u00A0\u00A0\u00A0\u00A0const wrapper = testingLibrary.render(${name}); 35 | \u00A0\u00A0\u00A0\u00A0\u00A0\u00A0return expect(wrapper.baseElement).toEqual(renderedFallback.baseElement); 36 | \u00A0\u00A0\u00A0\u00A0}) 37 | \u00A0\u00A0} 38 | } 39 | `; 40 | 41 | document.getElementById('test')!.innerText = result; 42 | 43 | } 44 | const darkTheme = createMuiTheme({ 45 | palette: { 46 | type: 'dark', 47 | }, 48 | }); 49 | 50 | return ( 51 |
52 |
53 | 54 |
55 | 56 | 57 | Please enter the name of your suspenseful component: 58 | 59 | setName(e.target.value)} color="primary" style={{color:"#ebebeb"}}/> 61 |
62 |
63 |
64 |
65 | 66 | Please enter the name of your fallback component: 67 | 68 | setFallback(e.target.value)} color="primary" style={{color:"#ebebeb"}}/> 70 |
71 |
72 |
73 |
74 | 75 |
76 | 77 |
78 |
79 | 80 |
81 |
82 |
83 |
84 |
85 |
86 | ); 87 | }; 88 | 89 | -------------------------------------------------------------------------------- /app/components/HomePage/homePage.css: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | -webkit-background-size: cover; 3 | -moz-background-size: cover; 4 | -o-background-size: cover; 5 | background-size: cover; 6 | height: 2000px; 7 | overflow: hidden; 8 | } 9 | 10 | .logo { 11 | width: 15px; 12 | height: 15px; 13 | } 14 | 15 | .title { 16 | text-align: center; 17 | padding-top: 12px; 18 | font-weight: 800; 19 | font-style: italic; 20 | text-align: center; 21 | } 22 | 23 | .subtitle { 24 | text-align: center; 25 | font-style: italic; 26 | font-weight: 800; 27 | padding-top: 3px; 28 | } 29 | 30 | .text { 31 | padding: 2px; 32 | color: #eeeeee; 33 | font-weight: 600; 34 | margin-left: 40%; 35 | margin-right: 40%; 36 | text-align: center; 37 | } -------------------------------------------------------------------------------- /app/components/HomePage/homePage.css.d.ts: -------------------------------------------------------------------------------- 1 | declare const styles: { 2 | readonly "wrapper": string; 3 | readonly "logo": string; 4 | readonly "title": string; 5 | readonly "subtitle": string; 6 | readonly "text": string; 7 | }; 8 | export = styles; 9 | 10 | -------------------------------------------------------------------------------- /app/components/HomePage/homePage.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Component } from 'react'; 3 | import './homePage.css'; 4 | 5 | import logo from "./resources/logo_transparent_blue.png"; 6 | 7 | 8 | class HomePage extends Component { 9 | render() { 10 | return ( 11 |
12 |
13 |

Welcome to ReactionTime

14 |

A Simpler Way to Write Tests for React's Experimental Concurrent Mode

15 |
16 |
17 |
18 |
19 | ReactionTime Logo 22 | 23 |
24 |
25 |
26 |
27 |
28 |
29 |

30 | Version 1.0 31 |

32 |

33 | ReactionTime is an open source project associated with OSLabs. 34 |

35 |

36 | To learn more, please checkout our GitHub. 37 |

38 |
39 |
40 | ) 41 | } 42 | } 43 | 44 | // class HomePage extends Component { 45 | // render() { 46 | // return ( 47 | //
48 | //
49 | //

Welcome to ReactionTime

50 | //

A SIMPLER WAY TO WRITE TESTS FOR REACT'S EXPERIMENTAL CONCURRENT MODE

51 | //
52 | //
53 | // ReactionTime Logo 56 | // 57 | //
58 | //
59 | //

60 | // Version 1.0 61 | //

62 | //

63 | // ReactionTime is an open source project associated with OSLabs. 64 | //

65 | //

66 | // To learn more, please checkout our GitHub. 67 | //

68 | //
69 | //
70 | // ) 71 | // } 72 | // } 73 | 74 | export default HomePage; 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /app/components/HomePage/resources/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/ReactionTime/4ad16b791876ee4136c8f5e584cf6a1108b26d75/app/components/HomePage/resources/logo.png -------------------------------------------------------------------------------- /app/components/HomePage/resources/logo_transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/ReactionTime/4ad16b791876ee4136c8f5e584cf6a1108b26d75/app/components/HomePage/resources/logo_transparent.png -------------------------------------------------------------------------------- /app/components/HomePage/resources/logo_transparent_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/ReactionTime/4ad16b791876ee4136c8f5e584cf6a1108b26d75/app/components/HomePage/resources/logo_transparent_blue.png -------------------------------------------------------------------------------- /app/components/PackageTest.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 PackageTest = () => { 7 | const [name, setName] = useState(""); 8 | 9 | let result: string; 10 | const handleSubmit = (evt: FormEvent) => { 11 | evt.preventDefault(); 12 | result = ` 13 | let packageFile = fs.readFileSync(path.resolve(__dirname, ${name})).toString("utf-8"); 14 | 15 | test('package.json to contain react experimental', () => { 16 | \u00A0\u00A0return expect(packageFile).toMatch(/\"react\": \"\^?0.0.0-experimental/); 17 | }) 18 | `; 19 | 20 | document.getElementById('test')!.innerText = result; 21 | 22 | 23 | } 24 | 25 | const darkTheme = createMuiTheme({ 26 | palette: { 27 | type: 'dark', 28 | }, 29 | }); 30 | 31 | return ( 32 |
33 |
34 | 35 |
36 | 37 | {/*
*/} 38 | 39 | Please enter the file path of your package.json from the root: 40 | 41 |
42 |
43 |
44 | 45 | setName(e.target.value)} color="primary" style={{color:"#ebebeb"}}/> 47 | 48 | {/*
*/} 49 | 50 |
51 |
52 | 53 |
54 |
55 |
56 |
57 |
58 |
59 | ); 60 | }; 61 | -------------------------------------------------------------------------------- /app/components/SearchGlass.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Card from "@material-ui/core/Card"; 3 | import CardContent from "@material-ui/core/CardContent"; 4 | 5 | export const SearchGlass = () => { 6 | return ( 7 | 8 |
9 |

Further Reading

10 | 11 | 12 | 13 |

What is Concurrency?

14 |
15 |

In Concurrent Mode, rendering is not blocking. It is interruptible.

16 | Learn More About Concurrency 17 |
18 |
19 |
20 |
21 | 22 | 23 |

Setting Up Concurrent Mode

24 |
25 |

Install the experimental builds of React and Enable Concurrent Mode

26 | Set Up Concurrent Mode 27 |
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 |
45 |

Ready for Concurrent Mode?

46 | See What is Possible 47 |
48 |
49 |
50 | 51 | {/* export const SearchGlass = () => { 52 | return ( 53 | 54 |
55 |
56 | 57 |
58 |

Further Reading

59 | 60 |

What is Concurrency?

61 |
62 |

In Concurrent Mode, rendering is not blocking. It is interruptible.

63 | Learn More About Concurrency 64 |
65 | 66 |

Setting Up Concurrent Mode

67 |
68 |

Install the experimental builds of React and Enable Concurrent Mode

69 | Set Up Concurrent Mode 70 |
71 | 72 |

What Can You Do with Concurrent Mode?

73 |
74 |

Suspense for Data Fetching is a new feature that lets you use Suspense to declaratively “wait” for anything else, including data.

75 | Learn More About Suspense for Data Fetching 76 |
77 | 78 |

More on Concurrent Mode

79 |
80 |

Ready for Concurrent Mode?

81 | See What is Possible 82 |
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 |
42 | 43 | {/*
*/} 44 | 45 | Please enter the name of your Suspenseful Component: 46 | 47 |
48 |
49 |
50 | 51 | setName(e.target.value)} color="primary" style={{color:"#ebebeb"}}/> 53 | 54 | {/*
*/} 55 | 56 |
57 |
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 | --------------------------------------------------------------------------------