feat: complete boilerplate overhaul. main/renderer processes split, scripts updated, i18n, pre-commit, locales, tests, webpack configs, hot, store updated, configs redesigned
16
.editorconfig
Executable file
@@ -0,0 +1,16 @@
|
||||
# http://editorconfig.org/
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[*.{json,yml,js,ts,tsx,css,scss,graphql,gql,html}]
|
||||
indent_size = 2
|
||||
3
.env
@@ -1,3 +0,0 @@
|
||||
AWS_ACCESS_KEY_ID=AKIAJJ66DJJUOB5YDCTQ
|
||||
AWS_SECRET_ACCESS_KEY=xZCLgrQj5QBZNsqslV5WLzmJb2WaeTTBASsS5vsI
|
||||
BUCKET_NAME=pure-app-develop
|
||||
@@ -1,3 +0,0 @@
|
||||
AWS_ACCESS_KEY_ID=
|
||||
AWS_SECRET_ACCESS_KEY=
|
||||
BUCKET_NAME=
|
||||
17
.github/pull_request_template.md
vendored
@@ -1,17 +0,0 @@
|
||||
Jira: [YY-XXX]
|
||||
|
||||
**Description**
|
||||
|
||||
<details>
|
||||
<summary><b>Screenshots</b></summary>
|
||||
// put images here
|
||||
</details>
|
||||
|
||||
**PR Status**
|
||||
|
||||
- [ ] Code Review
|
||||
- [ ] Quality Assurance
|
||||
|
||||
**Blockers**
|
||||
|
||||
**Deploy Notes**
|
||||
24
.github/workflows/lint.yml
vendored
@@ -1,24 +0,0 @@
|
||||
name: Linting
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [12.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: npm install, build, and test
|
||||
run: |
|
||||
npm install
|
||||
npm run lint
|
||||
env:
|
||||
CI: true
|
||||
24
.github/workflows/test.yml
vendored
@@ -1,24 +0,0 @@
|
||||
name: Unit Tests
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [12.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: npm install, build, and test
|
||||
run: |
|
||||
npm install
|
||||
npm test
|
||||
env:
|
||||
CI: true
|
||||
24
.github/workflows/type-check.yml
vendored
@@ -1,24 +0,0 @@
|
||||
name: Type Checking
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [12.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: npm install, build, and test
|
||||
run: |
|
||||
npm install
|
||||
npm run type-check
|
||||
env:
|
||||
CI: true
|
||||
14
.gitignore
vendored
@@ -25,19 +25,19 @@ build/Release
|
||||
# Dependency directory
|
||||
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
|
||||
node_modules
|
||||
app/node_modules
|
||||
src/node_modules
|
||||
|
||||
# OSX
|
||||
.DS_Store
|
||||
|
||||
# App packaged
|
||||
release
|
||||
app/main.js
|
||||
app/main.js.map
|
||||
app/bundle.js
|
||||
app/bundle.js.map
|
||||
app/style.css
|
||||
app/style.css.map
|
||||
src/main.js
|
||||
src/main.js.map
|
||||
src/bundle.js
|
||||
src/bundle.js.map
|
||||
src/style.css
|
||||
src/style.css.map
|
||||
dist
|
||||
main.js
|
||||
main.js.map
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { configure, addDecorator } from "@storybook/react"
|
||||
import { action } from "@storybook/addon-actions"
|
||||
import GlobalStyle from "../app/theming/global-style.component"
|
||||
import { Normalize } from "styled-normalize"
|
||||
import React from "react"
|
||||
import { ThemeProvider } from "styled-components"
|
||||
import theme from "../app/theming/theme"
|
||||
import { Normalize } from "styled-normalize"
|
||||
import { configure, addDecorator } from "@storybook/react"
|
||||
import { action } from "@storybook/addon-actions"
|
||||
|
||||
const req = require.context("../app", true, /\.stories\.tsx$/)
|
||||
import GlobalStyle from "Renderer/styles/global-style.component"
|
||||
import theme from "Renderer/styles/theming/theme"
|
||||
|
||||
const req = require.context("../src", true, /\.stories\.tsx$/)
|
||||
function loadStories() {
|
||||
req.keys().forEach(filename => req(filename))
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
const { resolve } = require('../webpack/resolve');
|
||||
|
||||
module.exports = ({ config }) => {
|
||||
// use installed babel-loader which is v8.0-beta (which is meant to work with @babel/core@7)
|
||||
config.module.rules[0].use[0].loader = require.resolve("babel-loader")
|
||||
@@ -27,7 +29,7 @@ module.exports = ({ config }) => {
|
||||
],
|
||||
},
|
||||
})
|
||||
config.resolve.extensions.push(".ts", ".tsx")
|
||||
config.resolve = resolve
|
||||
return config
|
||||
}
|
||||
|
||||
|
||||
51
.travis.yml
@@ -1,51 +0,0 @@
|
||||
sudo: false
|
||||
|
||||
language: node_js
|
||||
|
||||
node_js:
|
||||
- 8
|
||||
- 7
|
||||
|
||||
cache:
|
||||
yarn: true
|
||||
directories:
|
||||
- node_modules
|
||||
- app/node_modules
|
||||
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-4.8
|
||||
- icnsutils
|
||||
- graphicsmagick
|
||||
- xz-utils
|
||||
- xorriso
|
||||
|
||||
before_install: yarn global add greenkeeper-lockfile@1
|
||||
|
||||
install:
|
||||
- export CXX="g++-4.8"
|
||||
- yarn
|
||||
- cd app && yarn && cd ..
|
||||
- /sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile
|
||||
--background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x16
|
||||
|
||||
before_script:
|
||||
- greenkeeper-lockfile-update
|
||||
- export DISPLAY=:99.0
|
||||
- sh -e /etc/init.d/xvfb start &
|
||||
- sleep 3
|
||||
|
||||
script:
|
||||
- node --version
|
||||
- yarn package
|
||||
- yarn test
|
||||
- yarn test-e2e
|
||||
|
||||
after_script: greenkeeper-lockfile-upload
|
||||
|
||||
env:
|
||||
global:
|
||||
secure: hH+MmHE3WhyyBflZoOZLqqr501OOnvA1VtaqF3WU9rJCpjnKb4fZvHejYtVw65Ho2C40G2a34oBGxnT6INF1BfClYz4IMijL689xuR8dgStQzvcpMTwEQkrLsaCTSqXJR6nzqbRRGmaRfjSLdF6vhd3bGmtVNMEtoEky5EsXeBVjn8D5WMrme17m4F4D/qjHty6Xr5PjZL6eInVKlPZEbALYBhnIWqE5Xw6LcGa8JkqsWw80sLNtz4yWQSwkjrZ1lzCNd/GSUDN5K/BFK6kUZB5HpJZUzUoIQyXmEft+ALZFE4p4tX/H044JguPN9sKsP4SNkz2+3tOMevz/x5of3ssLMqB7gFtd5SGKwjdn6sWYNHKeM0MALyXAARhilyzY0v+xf226ZLRb++8Ih/vAZNymvQjn0idBfwC8ffUSXEx786Zysot1AqWrxaktKFHkBHkiQ4BGkAXVT4FLCgLtdMta+NLYYmuNrmXoU2iEhSzwvZmw94wcBxZie+TvuXE76TgrOiopRPbGXw/0iDm8J1MVWpoPmqSLUG5Vbq9fSNZnR/6j89j7Ws83fdnfZby+qOcV5WMJetQs/EHTxfWJu/AM6bxCYSSmXEJUb8dHpk8el8T+MGLI9pCTiiyy1ozOeo1WKpcOdmF6GU64EOxRWn2837+a9W0kXXAj6tPCW6A=
|
||||
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018-present R. Franken
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
211
README.md
@@ -1,213 +1,42 @@
|
||||
# electron-react-typescript-boilerplate
|
||||
# PDA: Mudita's Pure Desktop App
|
||||
|
||||
[![Build Status][travis-image]][travis-url]
|
||||
[](https://greenkeeper.io/)
|
||||
|
||||
This is a slight modificiation of the great [electron-react-boilerplate](https://github.com/chentsulin/electron-react-boilerplate) by chentsulin.
|
||||
Instead of [Babel](https://babeljs.io) and [flow](https://flowtype.org) this version uses [TypeScript](https://www.typescriptlang.org). Support for [Sass](http://sass-lang.com) has also been added.
|
||||
|
||||
# electron-react-boilerplate
|
||||
|
||||

|
||||
|
||||
> Live editing development on desktop app
|
||||
|
||||
[Electron](http://electron.atom.io/) application boilerplate based on [React](https://facebook.github.io/react/), [Redux](https://github.com/reactjs/redux), [React Router](https://github.com/reactjs/react-router), [Webpack](http://webpack.github.io/docs/), [React Transform HMR](https://github.com/gaearon/react-transform-hmr) for rapid application development
|
||||
|
||||
## Screenshot
|
||||
|
||||

|
||||
### A Boilerplate for an Easy Start with TypeScript, React, and Electron.
|
||||
|
||||
## Install
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
* **Note: requires a node version >= 6 and an npm version >= 3.**
|
||||
* **If you have installation or compilation issues with this project, please see [our debugging guide](https://github.com/chentsulin/electron-react-boilerplate/issues/400)**
|
||||
|
||||
First, clone the repo via git:
|
||||
## Usage
|
||||
Both processes have to be started **simultaneously** in different console tabs:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/iRath96/electron-react-typescript-boilerplate.git your-project-name
|
||||
npm run start-renderer-dev
|
||||
npm run start-main-dev
|
||||
```
|
||||
|
||||
And then install dependencies.
|
||||
**ProTip**: Install with [yarn](https://github.com/yarnpkg/yarn) for faster and safer installation
|
||||
This will start the application with hot-reload so you can instantly start developing your application.
|
||||
|
||||
You can also run do the following to start both in a single process:
|
||||
|
||||
```bash
|
||||
$ cd your-project-name && npm install
|
||||
npm run start-dev
|
||||
```
|
||||
|
||||
:bulb: *In order to remove boilerplate sample code, simply run `npm run cleanup`. After this is run, the initial sample boilerplate code will be removed in order for a clean project for starting custom dev*
|
||||
|
||||
## Run
|
||||
|
||||
Run these two commands __simultaneously__ in different console tabs.
|
||||
|
||||
```bash
|
||||
$ npm run hot-server
|
||||
$ npm run start-hot
|
||||
```
|
||||
|
||||
or run two servers with one command
|
||||
|
||||
```bash
|
||||
$ npm run dev
|
||||
```
|
||||
|
||||
## Editor Configuration
|
||||
**Atom**
|
||||
```bash
|
||||
apm install editorconfig es6-javascript atom-ternjs javascript-snippets linter linter-eslint language-babel autocomplete-modules
|
||||
```
|
||||
|
||||
**Sublime**
|
||||
* https://github.com/sindresorhus/editorconfig-sublime#readme
|
||||
* https://github.com/SublimeLinter/SublimeLinter3
|
||||
* https://github.com/roadhump/SublimeLinter-eslint
|
||||
* https://github.com/babel/babel-sublime
|
||||
|
||||
**Others**
|
||||
* [Editorconfig](http://editorconfig.org/#download)
|
||||
* [ESLint](http://eslint.org/docs/user-guide/integrations#editors)
|
||||
* Babel Syntax Plugin
|
||||
|
||||
## DevTools
|
||||
|
||||
#### Toggle Chrome DevTools
|
||||
|
||||
- OS X: <kbd>Cmd</kbd> <kbd>Alt</kbd> <kbd>I</kbd> or <kbd>F12</kbd>
|
||||
- Linux: <kbd>Ctrl</kbd> <kbd>Shift</kbd> <kbd>I</kbd> or <kbd>F12</kbd>
|
||||
- Windows: <kbd>Ctrl</kbd> <kbd>Shift</kbd> <kbd>I</kbd> or <kbd>F12</kbd>
|
||||
|
||||
*See [electron-debug](https://github.com/sindresorhus/electron-debug) for more information.*
|
||||
|
||||
#### DevTools extension
|
||||
|
||||
This boilerplate is included following DevTools extensions:
|
||||
|
||||
* [Devtron](https://github.com/electron/devtron) - Install via [electron-debug](https://github.com/sindresorhus/electron-debug).
|
||||
* [React Developer Tools](https://github.com/facebook/react-devtools) - Install via [electron-devtools-installer](https://github.com/GPMDP/electron-devtools-installer).
|
||||
* [Redux DevTools](https://github.com/zalmoxisus/redux-devtools-extension) - Install via [electron-devtools-installer](https://github.com/GPMDP/electron-devtools-installer).
|
||||
|
||||
You can find the tabs on Chrome DevTools.
|
||||
|
||||
If you want to update extensions version, please set `UPGRADE_EXTENSIONS` env, just run:
|
||||
|
||||
```bash
|
||||
$ UPGRADE_EXTENSIONS=1 npm run dev
|
||||
|
||||
# For Windows
|
||||
$ set UPGRADE_EXTENSIONS=1 && npm run dev
|
||||
```
|
||||
|
||||
|
||||
|
||||
## CSS Modules
|
||||
|
||||
This boilerplate out of the box is configured to use [css-modules](https://github.com/css-modules/css-modules).
|
||||
|
||||
All `.css` file extensions will use css-modules unless it has `.global.css`.
|
||||
|
||||
If you need global styles, stylesheets with `.global.css` will not go through the
|
||||
css-modules loader. e.g. `app.global.css`
|
||||
|
||||
If you want to import global css libraries (like `bootstrap`), you can just write the following code in `.global.css`:
|
||||
|
||||
```css
|
||||
@import "~bootstrap/dist/css/bootstrap.css";
|
||||
```
|
||||
|
||||
|
||||
## Packaging
|
||||
|
||||
To package apps for the local platform:
|
||||
We use [Electron builder](https://www.electron.build/) to build and package the application. By default you can run the following to package for your current platform:
|
||||
|
||||
```bash
|
||||
$ npm run package
|
||||
npm run dist
|
||||
```
|
||||
|
||||
To package apps for all platforms:
|
||||
This will create a installer for your platform in the `releases` folder.
|
||||
|
||||
First, refer to [Multi Platform Build](https://github.com/electron-userland/electron-builder/wiki/Multi-Platform-Build) for dependencies.
|
||||
|
||||
Then,
|
||||
```bash
|
||||
$ npm run package-all
|
||||
```
|
||||
|
||||
To package apps with options:
|
||||
You can make builds for specific platforms (or multiple platforms) by using the options found [here](https://www.electron.build/cli). E.g. building for all platforms (Windows, Mac, Linux):
|
||||
|
||||
```bash
|
||||
$ npm run package -- --[option]
|
||||
npm run dist -- -mwl
|
||||
```
|
||||
|
||||
## Further commands
|
||||
|
||||
To run the application without packaging run
|
||||
|
||||
```bash
|
||||
$ npm run build
|
||||
$ npm start
|
||||
```
|
||||
|
||||
To run End-to-End Test
|
||||
|
||||
```bash
|
||||
$ npm run build
|
||||
$ npm run test-e2e
|
||||
```
|
||||
|
||||
#### Options
|
||||
|
||||
See [electron-builder CLI Usage](https://github.com/electron-userland/electron-builder#cli-usage)
|
||||
|
||||
#### Module Structure
|
||||
|
||||
This boilerplate uses a [two package.json structure](https://github.com/electron-userland/electron-builder#two-packagejson-structure).
|
||||
|
||||
1. If the module is native to a platform or otherwise should be included with the published package (i.e. bcrypt, openbci), it should be listed under `dependencies` in `./app/package.json`.
|
||||
2. If a module is `import`ed by another module, include it in `dependencies` in `./package.json`. See [this ESLint rule](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-extraneous-dependencies.md).
|
||||
3. Otherwise, modules used for building, testing and debugging should be included in `devDependencies` in `./package.json`.
|
||||
|
||||
## Static Type Checking
|
||||
This project comes with Flow support out of the box! You can annotate your code with types, [get Flow errors as ESLint errors](https://github.com/amilajack/eslint-plugin-flowtype-errors), and get [type errors during runtime](https://github.com/gcanti/babel-plugin-tcomb-boilerplate) during development. Types are completely optional.
|
||||
|
||||
## Native-like UI
|
||||
|
||||
If you want to have native-like User Interface (OS X El Capitan and Windows 10), [react-desktop](https://github.com/gabrielbull/react-desktop) may perfect suit for you.
|
||||
|
||||
## Dispatching redux actions from main process
|
||||
|
||||
see discusses in [#118](https://github.com/chentsulin/electron-react-boilerplate/issues/118) and [#108](https://github.com/chentsulin/electron-react-boilerplate/issues/108)
|
||||
|
||||
## How to keep the boilerplate updated
|
||||
|
||||
If your application is a fork from this repo, you can add this repo to another git remote:
|
||||
|
||||
```sh
|
||||
git remote add upstream https://github.com/chentsulin/electron-react-boilerplate.git
|
||||
```
|
||||
|
||||
Then, use git to merge some latest commits:
|
||||
|
||||
```sh
|
||||
git pull upstream master
|
||||
```
|
||||
|
||||
## Maintainers
|
||||
|
||||
- [C. T. Lin](https://github.com/chentsulin)
|
||||
- [Jhen-Jie Hong](https://github.com/jhen0409)
|
||||
- [Amila Welihinda](https://github.com/amilajack)
|
||||
|
||||
|
||||
## License
|
||||
MIT © [C. T. Lin](https://github.com/chentsulin)
|
||||
|
||||
[npm-image]: https://img.shields.io/npm/v/electron-react-boilerplate.svg?style=flat-square
|
||||
[npm-url]: https://npmjs.org/package/electron-react-boilerplate
|
||||
[travis-image]: https://travis-ci.org/iRath96/electron-react-typescript-boilerplate.svg?branch=master
|
||||
[travis-url]: https://travis-ci.org/iRath96/electron-react-typescript-boilerplate
|
||||
[appveyor-image]: https://ci.appveyor.com/api/projects/status/github/chentsulin/electron-react-boilerplate?svg=true
|
||||
[appveyor-url]: https://ci.appveyor.com/project/chentsulin/electron-react-boilerplate/branch/master
|
||||
[david_img]: https://img.shields.io/david/chentsulin/electron-react-boilerplate.svg
|
||||
[david_site]: https://david-dm.org/chentsulin/electron-react-boilerplate
|
||||
## Precommit and Prettier
|
||||
This project comes with both Precommit and Prettier setup to ensure a consistent code style.
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
module.exports = "test-file-stub"
|
||||
46
app/app.html
@@ -1,46 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Hello Electron React!</title>
|
||||
<script>
|
||||
(function() {
|
||||
if (!process.env.HOT) {
|
||||
const link = document.createElement('link');
|
||||
link.rel = 'stylesheet';
|
||||
link.href = './dist/style.css';
|
||||
document.getElementsByTagName('head')[0].appendChild(link);
|
||||
}
|
||||
}());
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<!--Current version: <span id="version">vX.Y.Z</span>-->
|
||||
<!--<div id="messages"></div>-->
|
||||
<div id="root"></div>
|
||||
<script>
|
||||
{
|
||||
const script = document.createElement('script');
|
||||
const port = process.env.PORT || 3000;
|
||||
script.src = (process.env.HOT)
|
||||
? 'http://localhost:' + port + '/dist/bundle.js'
|
||||
: './dist/bundle.js';
|
||||
// HACK: Writing the script path should be done with webpack
|
||||
document.body.appendChild(script);
|
||||
|
||||
// let version = window.location.hash.substring(1);
|
||||
// document.getElementById('version').innerText = version;
|
||||
// // Listen for messages
|
||||
// const {ipcRenderer} = require('electron');
|
||||
//
|
||||
// ipcRenderer.on('message', function(event, text) {
|
||||
// var container = document.getElementById('messages');
|
||||
// var message = document.createElement('div');
|
||||
// message.innerHTML = text;
|
||||
// container.appendChild(message);
|
||||
// })
|
||||
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
BIN
app/app.icns
@@ -1,11 +0,0 @@
|
||||
import * as React from "react"
|
||||
import styled from "styled-components"
|
||||
import FunctionComponent from "../types/function-component.interface"
|
||||
|
||||
const AppWrapper = styled.div``
|
||||
|
||||
const AppContainer: FunctionComponent = ({ children }) => {
|
||||
return <AppWrapper>{children}</AppWrapper>
|
||||
}
|
||||
|
||||
export default AppContainer
|
||||
@@ -1,4 +0,0 @@
|
||||
import { combineEpics } from "redux-observable"
|
||||
import { setFilesEffect } from "../files/effects/files.effects"
|
||||
|
||||
export const rootEpic = combineEpics(setFilesEffect)
|
||||
@@ -1,44 +0,0 @@
|
||||
export const SET_FILES = "SET FILES"
|
||||
export type SET_FILES = typeof SET_FILES
|
||||
|
||||
export const SET_CURRENT_PATH = "SET_CURRENT_PATH"
|
||||
export type SET_CURRENT_PATH = typeof SET_CURRENT_PATH
|
||||
|
||||
export const SET_FILES_WITH_TYPES = "SET FILES WITH TYPES"
|
||||
export type SET_FILES_WITH_TYPES = typeof SET_FILES_WITH_TYPES
|
||||
|
||||
export interface SetFilesAction {
|
||||
readonly type: SET_FILES
|
||||
payload: string[]
|
||||
}
|
||||
|
||||
export interface SetCurrentPathAction {
|
||||
readonly type: SET_CURRENT_PATH
|
||||
payload: string
|
||||
}
|
||||
|
||||
export interface FileType {
|
||||
type: string
|
||||
name: string
|
||||
}
|
||||
|
||||
interface SetFilesWithTypes {
|
||||
readonly type: SET_FILES_WITH_TYPES
|
||||
payload: FileType[]
|
||||
}
|
||||
|
||||
export function setFiles(files: string[]): SetFilesAction {
|
||||
return {
|
||||
type: SET_FILES,
|
||||
payload: files,
|
||||
}
|
||||
}
|
||||
|
||||
export function setCurrentPath(path: string): SetCurrentPathAction {
|
||||
return {
|
||||
type: SET_CURRENT_PATH,
|
||||
payload: path,
|
||||
}
|
||||
}
|
||||
|
||||
export type Actions = SetFilesAction | SetCurrentPathAction | SetFilesWithTypes
|
||||
@@ -1,26 +0,0 @@
|
||||
import * as React from "react"
|
||||
import styled from "styled-components"
|
||||
import FunctionComponent from "../../../types/function-component.interface"
|
||||
|
||||
interface FileListElementProps {
|
||||
el?: string
|
||||
onClick: (element: string | undefined) => void
|
||||
}
|
||||
|
||||
const FileListElementWrapper = styled.li`
|
||||
border-bottom: 1px solid #ddd;
|
||||
`
|
||||
|
||||
const FileListElement: FunctionComponent<FileListElementProps> = ({
|
||||
el,
|
||||
onClick,
|
||||
}) => {
|
||||
const handleWrapperClick = () => onClick(el)
|
||||
return (
|
||||
<FileListElementWrapper onClick={handleWrapperClick}>
|
||||
{el}
|
||||
</FileListElementWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
export default FileListElement
|
||||
@@ -1,96 +0,0 @@
|
||||
import { useEffect } from "react"
|
||||
import * as React from "react"
|
||||
import { connect } from "react-redux"
|
||||
import styled from "styled-components"
|
||||
import RootState from "../../../reducers/state"
|
||||
import FunctionComponent from "../../../types/function-component.interface"
|
||||
import { setCurrentPath, setFiles } from "../../actions/files.actions"
|
||||
import { State as FileState } from "../../reducers/files.reducer"
|
||||
import { currentPath, selectFiles } from "../../selectors/file.selector"
|
||||
import FileListElementComponent from "../file-list-element/file-list-element.component"
|
||||
|
||||
const { remote } = require("electron")
|
||||
const mainRef = remote.require("./main.js")
|
||||
|
||||
const fileUtils = mainRef.electronUtils.fileUtils
|
||||
|
||||
interface FileProps {
|
||||
link?: string
|
||||
}
|
||||
|
||||
interface DispatchProps {
|
||||
setCurrentPath: (path: string) => void
|
||||
setFiles: (files: string[]) => void
|
||||
}
|
||||
|
||||
const FilesWrapper = styled.div`
|
||||
background-color: #222;
|
||||
padding: 1rem;
|
||||
color: white;
|
||||
`
|
||||
|
||||
export const FilesIntro = styled.p`
|
||||
font-size: large;
|
||||
code {
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
`
|
||||
|
||||
export const FilesTitle = styled.h1`
|
||||
font-weight: 900;
|
||||
`
|
||||
|
||||
const FileListWrapper = styled.ul`
|
||||
background: #00c2;
|
||||
padding: 20px;
|
||||
margin: 0;
|
||||
padding: 0.5rem 1rem;
|
||||
border: 1px solid #ddd;
|
||||
border-left: 0.4rem solid red;
|
||||
`
|
||||
|
||||
const Files: FunctionComponent<FileProps & FileState & DispatchProps> = ({
|
||||
currentFolder,
|
||||
filePaths,
|
||||
setCurrentPath: setCurrentPathAction,
|
||||
setFiles: setFilesAction,
|
||||
}) => {
|
||||
useEffect(() => {
|
||||
fileUtils.listFiles().then(setFilesAction)
|
||||
}, [])
|
||||
const onElementClick = (element: string | undefined) => {
|
||||
if (element) {
|
||||
setCurrentPathAction(element)
|
||||
}
|
||||
}
|
||||
return (
|
||||
<FilesWrapper>
|
||||
<FilesTitle>{currentFolder}</FilesTitle>
|
||||
<FilesIntro>File list below</FilesIntro>
|
||||
<FileListWrapper>
|
||||
{filePaths.map((el, key) => (
|
||||
<FileListElementComponent
|
||||
onClick={onElementClick}
|
||||
key={key}
|
||||
el={el.name}
|
||||
/>
|
||||
))}
|
||||
</FileListWrapper>
|
||||
</FilesWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: RootState): FileState => ({
|
||||
currentFolder: currentPath(state),
|
||||
filePaths: selectFiles(state),
|
||||
})
|
||||
|
||||
const mapDispatchToProps = (dispatch: any): DispatchProps => ({
|
||||
setCurrentPath: (path: string) => dispatch(setCurrentPath(path)),
|
||||
setFiles: (path: string[]) => dispatch(setFiles(path)),
|
||||
})
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(Files)
|
||||
@@ -1,34 +0,0 @@
|
||||
import { ofType } from "redux-observable"
|
||||
import { flatMap, map, tap } from "rxjs/operators"
|
||||
import {
|
||||
SET_FILES,
|
||||
SET_FILES_WITH_TYPES,
|
||||
SetFilesAction,
|
||||
} from "../actions/files.actions"
|
||||
|
||||
const { remote } = require("electron")
|
||||
const mainRef = remote.require("./main.js")
|
||||
|
||||
const fileUtils = mainRef.electronUtils.fileUtils
|
||||
|
||||
export const setFilesEffect = (action$: any) =>
|
||||
action$.pipe(
|
||||
ofType(SET_FILES),
|
||||
tap(() => console.log("Setting path type")), // debugging
|
||||
flatMap((action: SetFilesAction) => {
|
||||
return Promise.all(
|
||||
action.payload.map(async (el: string) => {
|
||||
return {
|
||||
name: el,
|
||||
type: await fileUtils.checkType(el),
|
||||
}
|
||||
})
|
||||
)
|
||||
}),
|
||||
map(data => {
|
||||
return {
|
||||
type: SET_FILES_WITH_TYPES,
|
||||
payload: data,
|
||||
}
|
||||
})
|
||||
)
|
||||
@@ -1,23 +0,0 @@
|
||||
import * as React from "react"
|
||||
import styled from "styled-components"
|
||||
import Navigation from "../../../shared/components/navigation/navigation.component"
|
||||
import FunctionComponent from "../../../types/function-component.interface"
|
||||
import Files from "../../components/file/files.component"
|
||||
|
||||
const FilePageWrapper = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: 1px #ccc dotted;
|
||||
padding: 10px;
|
||||
`
|
||||
|
||||
const FilesPage: FunctionComponent = () => {
|
||||
return (
|
||||
<FilePageWrapper>
|
||||
<Navigation />
|
||||
<Files />
|
||||
</FilePageWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
export default FilesPage
|
||||
@@ -1,22 +0,0 @@
|
||||
import { expect } from "chai"
|
||||
import { setCurrentPath } from "../actions/files.actions"
|
||||
import { getInitialState, reducer } from "./files.reducer"
|
||||
|
||||
test("starts with empty path", () => {
|
||||
expect(getInitialState().currentFolder).eq("")
|
||||
})
|
||||
|
||||
test("starts with empty file paths", () => {
|
||||
expect(getInitialState().filePaths).deep.eq([])
|
||||
})
|
||||
|
||||
test("returns the state on unrecognized actions", () => {
|
||||
const state = getInitialState()
|
||||
expect(reducer(state, { type: "SOME_RANDOM_UNKNOWN" } as any)).eq(state)
|
||||
})
|
||||
|
||||
test("sets current path to given", () => {
|
||||
const state = getInitialState()
|
||||
const expectedState = { ...getInitialState(), currentFolder: "currentPath" }
|
||||
expect(reducer(state, setCurrentPath("currentPath"))).deep.eq(expectedState)
|
||||
})
|
||||
@@ -1,32 +0,0 @@
|
||||
import * as filesAction from "../actions/files.actions"
|
||||
import { FileType } from "../actions/files.actions"
|
||||
|
||||
export interface State {
|
||||
readonly currentFolder: string
|
||||
readonly filePaths: FileType[]
|
||||
}
|
||||
|
||||
export const getInitialState = (): State =>
|
||||
({
|
||||
currentFolder: "",
|
||||
filePaths: [],
|
||||
} as State)
|
||||
|
||||
const initState = getInitialState()
|
||||
|
||||
export function reducer(state: State = initState, action: filesAction.Actions) {
|
||||
switch (action.type) {
|
||||
case filesAction.SET_CURRENT_PATH:
|
||||
return {
|
||||
...state,
|
||||
currentFolder: action.payload,
|
||||
}
|
||||
case filesAction.SET_FILES_WITH_TYPES:
|
||||
return {
|
||||
...state,
|
||||
filePaths: [...action.payload],
|
||||
}
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import { expect } from "chai"
|
||||
import { currentPath, selectFiles, selectFilesState } from "./file.selector"
|
||||
|
||||
test("selects the files state", () => {
|
||||
expect(selectFilesState({ files: "files state" } as any)).deep.eq(
|
||||
"files state"
|
||||
)
|
||||
})
|
||||
|
||||
describe("when filePaths exists", () => {
|
||||
test("selects the filePaths", () => {
|
||||
expect(selectFiles({ files: { filePaths: [] } } as any)).deep.eq([])
|
||||
})
|
||||
})
|
||||
|
||||
describe("when currentPath exists", () => {
|
||||
test("selects the should select currentFolder", () => {
|
||||
expect(currentPath({ files: { currentFolder: "./" } } as any)).deep.eq("./")
|
||||
})
|
||||
})
|
||||
@@ -1,7 +0,0 @@
|
||||
import RootState from "../../reducers/state"
|
||||
|
||||
export const selectFilesState = (state: RootState) => state.files
|
||||
export const selectFiles = (state: RootState) =>
|
||||
selectFilesState(state).filePaths
|
||||
export const currentPath = (state: RootState) =>
|
||||
selectFilesState(state).currentFolder
|
||||
@@ -1,61 +0,0 @@
|
||||
import * as React from "react"
|
||||
import { useEffect, useState } from "react"
|
||||
import styled from "styled-components"
|
||||
import FunctionComponent from "../../../types/function-component.interface"
|
||||
|
||||
const { remote } = require("electron")
|
||||
const mainRef = remote.require("./main.js")
|
||||
|
||||
const fileUtils = mainRef.electronUtils.fileUtils
|
||||
const basePath = require("electron").remote.app.getPath("documents")
|
||||
|
||||
const FilesHookWrapper = styled.div`
|
||||
flex: 1;
|
||||
`
|
||||
|
||||
const UlStyle = styled.ul`
|
||||
padding: 0;
|
||||
`
|
||||
|
||||
const LiStyle = styled.li`
|
||||
padding-left: 16px;
|
||||
content: "*";
|
||||
padding-right: 8px;
|
||||
`
|
||||
|
||||
const FilesHook: FunctionComponent = () => {
|
||||
const [currentPath, setCurrentPath] = useState(`${basePath}`)
|
||||
const [paths, setPaths] = useState([] as any[])
|
||||
|
||||
useEffect(() => {
|
||||
fileUtils.listFiles(currentPath).then((result: any[]) => {
|
||||
const structuredPaths = result.map(el => {
|
||||
return {
|
||||
type: fileUtils.checkType(el),
|
||||
path: el,
|
||||
}
|
||||
})
|
||||
console.log(structuredPaths)
|
||||
setPaths(structuredPaths)
|
||||
// setCurrentPath('.')
|
||||
})
|
||||
}, [currentPath])
|
||||
|
||||
const linkedPaths = paths.map((el, index) => {
|
||||
const handleElementClick = () =>
|
||||
setCurrentPath(`${currentPath}.\\${el.path}`)
|
||||
return (
|
||||
<LiStyle onClick={handleElementClick} key={index}>
|
||||
{el.path}
|
||||
</LiStyle>
|
||||
)
|
||||
})
|
||||
|
||||
return (
|
||||
<FilesHookWrapper>
|
||||
<UlStyle>{linkedPaths}</UlStyle>
|
||||
</FilesHookWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
export default FilesHook
|
||||
@@ -1,22 +0,0 @@
|
||||
import * as React from "react"
|
||||
import styled from "styled-components"
|
||||
import Navigation from "../../../shared/components/navigation/navigation.component"
|
||||
import FilesHook from "../../components/files-hook/files-hook.component"
|
||||
|
||||
const FilePageWrapper = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: 1px #ccc dotted;
|
||||
padding: 10px;
|
||||
`
|
||||
|
||||
const FilesPageHook = () => {
|
||||
return (
|
||||
<FilePageWrapper>
|
||||
<Navigation />
|
||||
<FilesHook />
|
||||
</FilePageWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
export default FilesPageHook
|
||||
@@ -1,32 +0,0 @@
|
||||
import * as React from "react"
|
||||
import { render } from "react-dom"
|
||||
import { AppContainer } from "react-hot-loader"
|
||||
import RootContainer from "./containers/root.container"
|
||||
import { rootEpic } from "./effects/root.effects"
|
||||
const {
|
||||
configureStore,
|
||||
history,
|
||||
epicMiddleware,
|
||||
} = require("./store/configureStore")
|
||||
const store = configureStore()
|
||||
|
||||
epicMiddleware.run(rootEpic)
|
||||
|
||||
render(
|
||||
<AppContainer>
|
||||
<RootContainer store={store} history={history} />
|
||||
</AppContainer>,
|
||||
document.getElementById("root")
|
||||
)
|
||||
|
||||
if ((module as any).hot) {
|
||||
;(module as any).hot.accept("./containers/root.container", () => {
|
||||
const NextRoot = require("./containers/root.container").default
|
||||
render(
|
||||
<AppContainer>
|
||||
<NextRoot store={store} history={history} />
|
||||
</AppContainer>,
|
||||
document.getElementById("root") as HTMLElement
|
||||
)
|
||||
})
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
const {darwinWindow, windowsWindow} = require("./electron/window");
|
||||
const {app, BrowserWindow, Menu} = require('electron');
|
||||
const {autoUpdater} = require("electron-updater");
|
||||
const log = require('electron-log');
|
||||
|
||||
log.transports.file.level = "debug";
|
||||
autoUpdater.logger = log;
|
||||
|
||||
let menu;
|
||||
let template;
|
||||
let mainWindow = null;
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
const sourceMapSupport = require('source-map-support'); // eslint-disable-line
|
||||
sourceMapSupport.install();
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
require('electron-debug')(); // eslint-disable-line global-require
|
||||
const path = require('path'); // eslint-disable-line
|
||||
const p = path.join(__dirname, '..', 'app', 'node_modules'); // eslint-disable-line
|
||||
require('module').globalPaths.push(p); // eslint-disable-line
|
||||
}
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') app.quit();
|
||||
});
|
||||
|
||||
//`fsPromises.readdir`
|
||||
//
|
||||
// mainWindow.webContents.send('ping', value)
|
||||
|
||||
function sendStatusToWindow(text) {
|
||||
log.info(text);
|
||||
mainWindow.webContents.send('message', text);
|
||||
}
|
||||
|
||||
const installExtensions = () => {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
const installer = require('electron-devtools-installer'); // eslint-disable-line global-require
|
||||
require('devtron').install();
|
||||
|
||||
const extensions = [
|
||||
'REACT_DEVELOPER_TOOLS',
|
||||
'REDUX_DEVTOOLS'
|
||||
];
|
||||
const forceDownload = !!process.env.UPGRADE_EXTENSIONS;
|
||||
return Promise.all(extensions.map(name => installer.default(installer[name], forceDownload)));
|
||||
}
|
||||
|
||||
return Promise.resolve([]);
|
||||
};
|
||||
|
||||
app.on('ready', async () => {
|
||||
await installExtensions();
|
||||
|
||||
// const appVersion = require('./package.json').version;
|
||||
// log.info(`app.getVersion ${app.getVersion()}`);
|
||||
// log.info(`package.json-require.version ${appVersion}`);
|
||||
|
||||
mainWindow = new BrowserWindow({
|
||||
show: false,
|
||||
width: 1024,
|
||||
height: 728,
|
||||
webPreferences: {
|
||||
// Warning! https://github.com/electron/electron/issues/18139#issuecomment-489137050
|
||||
// Leaving it for now as the current app requires access to the process.
|
||||
nodeIntegration: true
|
||||
}
|
||||
});
|
||||
|
||||
mainWindow.loadURL(`file://${__dirname}/app.html`);
|
||||
|
||||
mainWindow.webContents.on('did-finish-load', async () => {
|
||||
mainWindow.show();
|
||||
mainWindow.focus();
|
||||
await autoUpdater.checkForUpdatesAndNotify();
|
||||
});
|
||||
|
||||
mainWindow.on('closed', () => {
|
||||
mainWindow = null;
|
||||
});
|
||||
|
||||
autoUpdater.on('checking-for-update', () => {
|
||||
sendStatusToWindow('Checking for update...');
|
||||
});
|
||||
|
||||
autoUpdater.on('update-available', (info) => {
|
||||
sendStatusToWindow('Update available.');
|
||||
});
|
||||
|
||||
autoUpdater.on('update-not-available', (info) => {
|
||||
sendStatusToWindow('Update not available.');
|
||||
});
|
||||
|
||||
autoUpdater.on('error', (err) => {
|
||||
sendStatusToWindow('Error in auto-updater. ' + err);
|
||||
});
|
||||
|
||||
autoUpdater.on('download-progress', (progressObj) => {
|
||||
let log_message = "Download speed: " + progressObj.bytesPerSecond;
|
||||
log_message = log_message + ' - Downloaded ' + progressObj.percent + '%';
|
||||
log_message = log_message + ' (' + progressObj.transferred + "/" + progressObj.total + ')';
|
||||
sendStatusToWindow(log_message);
|
||||
});
|
||||
|
||||
autoUpdater.on('update-downloaded', (info) => {
|
||||
sendStatusToWindow('Update downloaded');
|
||||
});
|
||||
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
mainWindow.openDevTools();
|
||||
mainWindow.webContents.on('context-menu', (e, props) => {
|
||||
const {x, y} = props;
|
||||
|
||||
Menu.buildFromTemplate([{
|
||||
label: 'Inspect element',
|
||||
click() {
|
||||
mainWindow.inspectElement(x, y);
|
||||
}
|
||||
}]).popup(mainWindow);
|
||||
});
|
||||
}
|
||||
|
||||
if (process.platform === 'darwin') {
|
||||
template = darwinWindow(app, mainWindow);
|
||||
menu = Menu.buildFromTemplate(template);
|
||||
Menu.setApplicationMenu(menu);
|
||||
} else {
|
||||
template = windowsWindow(app, mainWindow);
|
||||
menu = Menu.buildFromTemplate(template);
|
||||
mainWindow.setMenu(menu)
|
||||
}
|
||||
});
|
||||
|
||||
exports.electronUtils = require('./utils/file.utils');
|
||||
5
app/package-lock.json
generated
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"name": "pure-desktop-app",
|
||||
"version": "0.15.0",
|
||||
"lockfileVersion": 1
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"name": "pure-desktop-app",
|
||||
"productName": "Pure desktop app",
|
||||
"version": "0.15.0",
|
||||
"description": "Electron pure desktop",
|
||||
"main": "./main.js",
|
||||
"scripts": {
|
||||
"postinstall": "npm rebuild --runtime=electron --target=1.6.6 --disturl=https://atom.io/download/atom-shell --build-from-source"
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {},
|
||||
"author": {
|
||||
"name": "Appnroll",
|
||||
"email": "dota@appnroll.com",
|
||||
"url": "https://github.com/Appnroll"
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
import { connectRouter } from "connected-react-router"
|
||||
import { History } from "history"
|
||||
import { combineReducers } from "redux"
|
||||
import { reducer as fileReducer } from "../files/reducers/files.reducer"
|
||||
import RootState from "./state"
|
||||
|
||||
const createRootReducer = (history: History) =>
|
||||
combineReducers<RootState>({
|
||||
router: connectRouter(history),
|
||||
files: fileReducer,
|
||||
})
|
||||
|
||||
export default createRootReducer
|
||||
@@ -1,16 +0,0 @@
|
||||
import * as React from "react"
|
||||
import { Route, Switch } from "react-router"
|
||||
import AppContainer from "./containers/app.container"
|
||||
import FilesPage from "./files/pages/files/files.page"
|
||||
import FilesPageHook from "./fileshook/pages/files-hook/files-hook.page"
|
||||
import HomePage from "./home/pages/home/home.page"
|
||||
|
||||
export default () => (
|
||||
<AppContainer>
|
||||
<Switch>
|
||||
<Route path="/filesHooks" component={FilesPageHook} />
|
||||
<Route path="/files" component={FilesPage} />
|
||||
<Route path="/" component={HomePage} />
|
||||
</Switch>
|
||||
</AppContainer>
|
||||
)
|
||||
@@ -1,56 +0,0 @@
|
||||
import { push, routerMiddleware } from "connected-react-router"
|
||||
import { createHashHistory } from "history"
|
||||
import { applyMiddleware, compose, createStore } from "redux"
|
||||
import { createLogger } from "redux-logger"
|
||||
import { createEpicMiddleware } from "redux-observable"
|
||||
import thunk from "redux-thunk"
|
||||
import * as filesAction from "../files/actions/files.actions"
|
||||
import createRootReducer from "../reducers"
|
||||
|
||||
const epicMiddleware = createEpicMiddleware()
|
||||
|
||||
declare const window: Window & {
|
||||
__REDUX_DEVTOOLS_EXTENSION_COMPOSE__?(a: any): void
|
||||
}
|
||||
|
||||
declare const module: NodeModule & {
|
||||
hot?: {
|
||||
accept(...args: any[]): any
|
||||
}
|
||||
}
|
||||
|
||||
const actionCreators = Object.assign({}, filesAction, { push })
|
||||
|
||||
const logger = (createLogger as any)({
|
||||
level: "info",
|
||||
collapsed: true,
|
||||
})
|
||||
|
||||
const history = createHashHistory() // must be hash, do not change
|
||||
|
||||
const composeEnhancers: typeof compose = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
|
||||
? (window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
|
||||
// Options: http://zalmoxisus.github.io/redux-devtools-extension/API/Arguments.html
|
||||
actionCreators,
|
||||
}) as any)
|
||||
: compose
|
||||
|
||||
const enhancer = composeEnhancers(
|
||||
applyMiddleware(thunk, logger, routerMiddleware(history), epicMiddleware)
|
||||
)
|
||||
|
||||
export = {
|
||||
epicMiddleware,
|
||||
history,
|
||||
configureStore() {
|
||||
const store = createStore(createRootReducer(history), {}, enhancer)
|
||||
|
||||
if (module.hot) {
|
||||
module.hot.accept(
|
||||
"../reducers",
|
||||
() => store.replaceReducer(require("../reducers")) // eslint-disable-line global-require
|
||||
)
|
||||
}
|
||||
return store
|
||||
},
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import { createBrowserHistory } from "history"
|
||||
import { routerMiddleware } from "react-router-redux"
|
||||
import { applyMiddleware, createStore } from "redux"
|
||||
import thunk from "redux-thunk"
|
||||
import createRootReducer from "../reducers"
|
||||
|
||||
const history = createBrowserHistory()
|
||||
const router = routerMiddleware(history)
|
||||
const enhancer = applyMiddleware(thunk, router)
|
||||
|
||||
export = {
|
||||
history,
|
||||
configureStore() {
|
||||
return createStore(createRootReducer(history), {}, enhancer)
|
||||
},
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
let configureStore: any
|
||||
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
configureStore = require("./configureStore.production")
|
||||
} else {
|
||||
configureStore = require("./configureStore.development")
|
||||
}
|
||||
|
||||
export = configureStore
|
||||
@@ -1,52 +0,0 @@
|
||||
const fsPromises = require("fs").promises
|
||||
const fs = require("fs")
|
||||
|
||||
const FileType = {
|
||||
file: "file",
|
||||
directory: "directory",
|
||||
unknown: "unknown",
|
||||
}
|
||||
|
||||
const listFiles = async (path = "./") => {
|
||||
return await fsPromises.readdir(path)
|
||||
}
|
||||
|
||||
const isElementFile = async path => {
|
||||
try {
|
||||
const file = await fsPromises.lstat(path)
|
||||
return file.isFile()
|
||||
} catch (err) {
|
||||
throw new Error("is element file error")
|
||||
}
|
||||
}
|
||||
|
||||
const isElementDirectory = async path => {
|
||||
try {
|
||||
const file = await fsPromises.lstat(path)
|
||||
return file.isDirectory()
|
||||
} catch (err) {
|
||||
throw new Error("is element file error")
|
||||
}
|
||||
}
|
||||
|
||||
const checkType = path => {
|
||||
const isFile = fs.lstatSync(path).isFile()
|
||||
const isDirectory = fs.lstatSync(path).isDirectory()
|
||||
|
||||
if (isFile) {
|
||||
return FileType.file
|
||||
}
|
||||
|
||||
if (isDirectory) {
|
||||
return FileType.directory
|
||||
}
|
||||
|
||||
return FileType.unknown
|
||||
}
|
||||
|
||||
exports.fileUtils = {
|
||||
checkType,
|
||||
listFiles,
|
||||
isElementFile,
|
||||
isElementDirectory,
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
AWS_ACCESS_KEY_ID=AKIAJJ66DJJUOB5YDCTQ
|
||||
AWS_SECRET_ACCESS_KEY=xZCLgrQj5QBZNsqslV5WLzmJb2WaeTTBASsS5vsI
|
||||
BIN
erb-logo.png
|
Before Width: | Height: | Size: 21 KiB |
@@ -1 +0,0 @@
|
||||
export default 'test-file-stub';
|
||||
@@ -8,7 +8,7 @@ module.exports = {
|
||||
".+\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$":
|
||||
"<rootDir>/__mocks__/file-mock.js",
|
||||
},
|
||||
rootDir: "../",
|
||||
rootDir: "./",
|
||||
moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"],
|
||||
testPathIgnorePatterns: ["node_modules", ".cache", "public", "cypress"],
|
||||
globals: {
|
||||
15688
package-lock.json
generated
224
package.json
@@ -1,111 +1,99 @@
|
||||
{
|
||||
"name": "electron-pure-desktop-app",
|
||||
"productName": "Pure desktop app",
|
||||
"version": "1.0.0",
|
||||
"description": "Electron pure desktop",
|
||||
"main": "main.js",
|
||||
"name": "pure-desktop-app",
|
||||
"version": "0.0.1",
|
||||
"description": "",
|
||||
"main": "./dist/main.js",
|
||||
"scripts": {
|
||||
"test": "jest --config=./.jest/config.js",
|
||||
"test-all": "npm run test && npm run build && npm run test-e2e",
|
||||
"build-main": "cross-env NODE_ENV=production webpack --config webpack.main.prod.config.js",
|
||||
"build-renderer": "cross-env NODE_ENV=production webpack --config webpack.renderer.prod.config.js",
|
||||
"build": "npm run build-main && npm run build-renderer",
|
||||
"start-renderer-dev": "webpack-dev-server --config webpack.renderer.dev.config.js",
|
||||
"start-main-dev": "webpack --config webpack.main.config.js && electron ./dist/main.js",
|
||||
"start-dev": "cross-env START_HOT=1 npm run start-renderer-dev",
|
||||
"prestart": "npm run build",
|
||||
"start": "electron .",
|
||||
"lint": "tslint '{src,test,mocks}/**/*.{ts,tsx}' --project ./tsconfig.json",
|
||||
"test": "jest",
|
||||
"test-all": "npm run test && npm run build",
|
||||
"test:watch": "tsc && cross-env NODE_ENV=test cross-env TEST_DIALECT=sqlite mocha -w --recursive --compilers ts:ts-node/register --bail \"test/**/*.spec.ts\"",
|
||||
"test-watch": "npm test -- --watch",
|
||||
"test-e2e": "cross-env NODE_ENV=test node --trace-warnings ./test/runTests.js e2e",
|
||||
"lint": "tslint --project .",
|
||||
"type-check": "tsc --noEmit",
|
||||
"hot-server": "cross-env NODE_ENV=development node --max_old_space_size=2096 server.js",
|
||||
"build-main": "cross-env NODE_ENV=production node ./node_modules/webpack/bin/webpack --config webpack.config.electron.js --progress --profile --colors",
|
||||
"build-renderer": "cross-env NODE_ENV=production node ./node_modules/webpack/bin/webpack --config webpack.config.production.js --progress --profile --colors",
|
||||
"build": "npm run build-main && npm run build-renderer",
|
||||
"start": "cross-env NODE_ENV=production electron ./app/",
|
||||
"start-hot": "cross-env HOT=1 NODE_ENV=development electron ./app/main.development",
|
||||
"postinstall": "npm run build",
|
||||
"develop": "npm run hot-server -- --start-hot",
|
||||
"format": "prettier --write app/**/*.{js,jsx,ts,tsx}",
|
||||
"package": "npm run build && build --publish never",
|
||||
"package-win": "npm run build && build --win --x64",
|
||||
"package-linux": "npm run build && build --linux",
|
||||
"package-all": "npm run build && build -mwl",
|
||||
"cleanup": "mop -v",
|
||||
"pack": "electron-builder --dir",
|
||||
"dist": "electron-builder",
|
||||
"publish_s3": "npm run build && electron-builder --publish always",
|
||||
"pretest:e2e": "npm run build",
|
||||
"test:e2e": "jest '(\\/test\\/e2e/).*'",
|
||||
"pack": "npm run build && electron-builder --dir",
|
||||
"dist": "npm run build && electron-builder",
|
||||
"postinstall": "electron-builder install-app-deps",
|
||||
"beforecommit": "lint-staged && npm test && npm run check:translations",
|
||||
"check:translations": "ts-node -r esm ./scripts/translationCheck",
|
||||
"generate:translations": "ts-node -r esm ./scripts/translationRunner.js",
|
||||
"storybook:serve": "start-storybook -p 6006",
|
||||
"storybook:build": "build-storybook"
|
||||
},
|
||||
"pre-commit": "beforecommit",
|
||||
"lint-staged": {
|
||||
"{src,test,mocks}/**/*.{js,ts,tsx,json,css,scss,md}": [
|
||||
"tslint --fix",
|
||||
"git add"
|
||||
]
|
||||
},
|
||||
"jest": {
|
||||
"transform": {
|
||||
"^.+\\.tsx?$": "ts-jest"
|
||||
},
|
||||
"testRegex": "(/test/.+\\.spec)\\.tsx?$",
|
||||
"moduleFileExtensions": [
|
||||
"ts",
|
||||
"tsx",
|
||||
"js",
|
||||
"json",
|
||||
"node"
|
||||
],
|
||||
"moduleNameMapper": {
|
||||
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/mocks/fileMock.js",
|
||||
"\\.(s?css|sass)$": "<rootDir>/mocks/styleMock.js"
|
||||
}
|
||||
},
|
||||
"build": {
|
||||
"productName": "Pure-desktop-app",
|
||||
"appId": "com.mudita.pure",
|
||||
"dmg": {
|
||||
"contents": [
|
||||
{
|
||||
"x": 410,
|
||||
"y": 150,
|
||||
"type": "link",
|
||||
"path": "/Applications"
|
||||
},
|
||||
{
|
||||
"x": 130,
|
||||
"y": 150,
|
||||
"type": "file"
|
||||
}
|
||||
]
|
||||
"productName": "PureDesktopApp",
|
||||
"appId": "mudita.pure.desktopApp",
|
||||
"mac": {
|
||||
"category": "your.app.category.type"
|
||||
},
|
||||
"directories": {
|
||||
"output": "release"
|
||||
},
|
||||
"files": [
|
||||
"dist/",
|
||||
"node_modules/",
|
||||
"app.html",
|
||||
"main.js",
|
||||
"main.js.map",
|
||||
"package.json"
|
||||
],
|
||||
"directories": {
|
||||
"buildResources": "resources",
|
||||
"output": "release"
|
||||
},
|
||||
"publish": {
|
||||
"provider": "s3",
|
||||
"bucket": "pure-app-develop",
|
||||
"path": "/release",
|
||||
"acl": "public-read"
|
||||
"linux": {
|
||||
"target": "deb"
|
||||
},
|
||||
"win": {
|
||||
"target": "nsis"
|
||||
},
|
||||
"linux": {
|
||||
"target": [
|
||||
"deb",
|
||||
"AppImage"
|
||||
]
|
||||
}
|
||||
},
|
||||
"bin": {
|
||||
"electron": "./node_modules/.bin/electron"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/irath96/electron-react-typescript-boilerplate.git"
|
||||
"url": "https://github.com/Appnroll/pure-desktop-app"
|
||||
},
|
||||
"author": {
|
||||
"name": "Appnroll",
|
||||
"email": "dota@appnroll.com",
|
||||
"url": "https://github.com/Appnroll"
|
||||
"name": "Mudita",
|
||||
"email": "contact@mudita.com"
|
||||
},
|
||||
"license": "MIT",
|
||||
"license": "SEE LICENSE",
|
||||
"bugs": {
|
||||
"url": "https://github.com/Appnroll/pure-desktop-app/issues"
|
||||
},
|
||||
"keywords": [
|
||||
"electron",
|
||||
"boilerplate",
|
||||
"react",
|
||||
"react-router",
|
||||
"flux",
|
||||
"webpack",
|
||||
"react-hot"
|
||||
],
|
||||
"homepage": "https://github.com/irath96/electron-react-typescript-boilerplate#readme",
|
||||
"homepage": "https://github.com/Appnroll/pure-desktop-app",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.7.2",
|
||||
"@babel/plugin-proposal-class-properties": "^7.7.0",
|
||||
"@babel/polyfill": "^7.7.0",
|
||||
"@babel/preset-env": "^7.7.1",
|
||||
"@babel/preset-react": "^7.7.0",
|
||||
"@babel/preset-typescript": "^7.7.2",
|
||||
"@hot-loader/react-dom": "^16.11.0",
|
||||
"@storybook/addon-actions": "^5.2.5",
|
||||
"@storybook/addon-knobs": "^5.2.5",
|
||||
"@storybook/addon-links": "^5.2.5",
|
||||
@@ -114,66 +102,92 @@
|
||||
"@testing-library/jest-dom": "^4.2.3",
|
||||
"@testing-library/react": "^9.3.2",
|
||||
"@types/chai": "^4.2.4",
|
||||
"@types/electron-devtools-installer": "^2.2.0",
|
||||
"@types/history": "^4.7.3",
|
||||
"@types/jest": "^24.0.22",
|
||||
"@types/jest": "^24.0.13",
|
||||
"@types/node": "^12.12.6",
|
||||
"@types/react": "16.9.11",
|
||||
"@types/react-dom": "16.9.4",
|
||||
"@types/react-hot-loader": "4.1.0",
|
||||
"@types/react-redux": "7.1.5",
|
||||
"@types/react": "^16.8.18",
|
||||
"@types/react-dom": "^16.8.4",
|
||||
"@types/react-hot-loader": "^4.1.1",
|
||||
"@types/react-redux": "^7.0.9",
|
||||
"@types/react-router": "^5.1.2",
|
||||
"@types/react-router-dom": "^5.1.2",
|
||||
"@types/react-router-redux": "^5.0.18",
|
||||
"@types/react-test-renderer": "^16.9.1",
|
||||
"@types/redux-logger": "^3.0.7",
|
||||
"@types/redux-mock-store": "^1.0.1",
|
||||
"@types/sinon": "^7.5.0",
|
||||
"@types/webdriverio": "^5.0.0",
|
||||
"@types/webpack-env": "^1.14.1",
|
||||
"asar": "^2.0.1",
|
||||
"babel-core": "7.0.0-bridge.0",
|
||||
"babel-loader": "^8.0.6",
|
||||
"babel-plugin-styled-components": "^1.10.6",
|
||||
"babel-runtime": "^6.26.0",
|
||||
"boiler-room-custodian": "^0.6.2",
|
||||
"chalk": "^3.0.0",
|
||||
"circular-dependency-plugin": "^5.2.0",
|
||||
"concurrently": "^5.0.0",
|
||||
"cross-env": "^6.0.3",
|
||||
"css-loader": "^3.2.0",
|
||||
"devtron": "^1.4.0",
|
||||
"electron": "^7.1.0",
|
||||
"electron-builder": "22.1.0",
|
||||
"electron": "^7.1.1",
|
||||
"electron-builder": "^21.2.0",
|
||||
"electron-builder-http": "^19.27.5",
|
||||
"electron-devtools-installer": "^2.2.4",
|
||||
"electron-rebuild": "^1.8.6",
|
||||
"express": "^4.17.1",
|
||||
"extract-text-webpack-plugin": "^4.0.0-beta.0",
|
||||
"extract-text-webpack-plugin": "^3.0.2",
|
||||
"file-loader": "^4.2.0",
|
||||
"html-webpack-plugin": "3.2.0",
|
||||
"fork-ts-checker-webpack-plugin": "^3.1.0",
|
||||
"fs": "0.0.1-security",
|
||||
"glob": "^7.1.6",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"identity-obj-proxy": "^3.0.0",
|
||||
"jest": "24.9.0",
|
||||
"image-webpack-loader": "^6.0.0",
|
||||
"jest": "^24.8.0",
|
||||
"jest-styled-components": "^6.3.3",
|
||||
"json-loader": "^0.5.7",
|
||||
"lint-staged": "^9.4.3",
|
||||
"mini-css-extract-plugin": "0.8.0",
|
||||
"mocha": "^6.2.2",
|
||||
"prettier": "^1.18.2",
|
||||
"react-hot-loader": "^4.12.16",
|
||||
"react-test-renderer": "^16.11.0",
|
||||
"node-sass": "^4.13.0",
|
||||
"pre-commit": "^1.2.2",
|
||||
"prettier": "^1.17.1",
|
||||
"react-hot-loader": "^4.8.8",
|
||||
"react-intl": "^3.6.0",
|
||||
"react-intl-translations-manager": "^5.0.3",
|
||||
"react-test-renderer": "^16.8.6",
|
||||
"redux-devtools-extension": "^2.13.5",
|
||||
"redux-logger": "^3.0.6",
|
||||
"redux-mock-store": "^1.5.3",
|
||||
"sass-loader": "^8.0.0",
|
||||
"sinon": "^7.5.0",
|
||||
"source-map-loader": "^0.2.4",
|
||||
"spectron": "^9.0.0",
|
||||
"style-loader": "^1.0.0",
|
||||
"ts-jest": "^24.1.0",
|
||||
"ts-jest": "^24.0.2",
|
||||
"ts-loader": "6.2.1",
|
||||
"ts-node": "^8.4.1",
|
||||
"tslint": "^5.20.1",
|
||||
"ts-node": "^8.5.2",
|
||||
"tslint": "^5.16.0",
|
||||
"tslint-config-airbnb": "^5.11.2",
|
||||
"tslint-config-prettier": "^1.18.0",
|
||||
"tslint-eslint-rules": "^5.4.0",
|
||||
"tslint-plugin-prettier": "^2.0.1",
|
||||
"typescript": "3.7.2",
|
||||
"tslint-react": "^4.0.0",
|
||||
"typescript": "^3.4.5",
|
||||
"url-loader": "2.2.0",
|
||||
"webpack": "4.41.2",
|
||||
"webpack-cli": "^3.3.10",
|
||||
"webpack": "^4.32.2",
|
||||
"webpack-cli": "^3.3.2",
|
||||
"webpack-dev-middleware": "3.7.2",
|
||||
"webpack-dev-server": "^3.9.0",
|
||||
"webpack-hot-middleware": "2.25.0",
|
||||
"webpack-merge": "4.2.2"
|
||||
"webpack-merge": "^4.2.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "^16.12.0",
|
||||
"react-dom": "^16.12.0",
|
||||
"react-redux": "^7.0.3",
|
||||
"redux": "^4.0.1",
|
||||
"@storybook/addon-info": "^5.2.5",
|
||||
"@storybook/cli": "^5.2.5",
|
||||
"@types/styled-components": "^4.1.21",
|
||||
@@ -185,16 +199,10 @@
|
||||
"electron-publisher-s3": "^20.17.2",
|
||||
"electron-updater": "^4.2.0",
|
||||
"font-awesome": "^4.7.0",
|
||||
"fork-ts-checker-webpack-plugin": "^3.0.1",
|
||||
"history": "^4.10.1",
|
||||
"react": "16.11.0",
|
||||
"react-docgen-typescript-webpack-plugin": "^1.1.0",
|
||||
"react-dom": "16.11.0",
|
||||
"react-redux": "^7.1.3",
|
||||
"react-router": "^5.1.2",
|
||||
"react-router-dom": "^5.1.2",
|
||||
"react-router-redux": "^5.0.0-alpha.6",
|
||||
"redux": "^4.0.4",
|
||||
"redux-observable": "^1.2.0",
|
||||
"redux-thunk": "^2.3.0",
|
||||
"rxjs": "^6.5.3",
|
||||
@@ -205,9 +213,5 @@
|
||||
"tslint-react": "^4.1.0",
|
||||
"update-electron-app": "^1.5.0",
|
||||
"usb": "^1.6.1"
|
||||
},
|
||||
"devEngines": {
|
||||
"node": ">=12.9",
|
||||
"npm": ">=6.10"
|
||||
}
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 361 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 156 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 954 B |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 77 KiB |
|
Before Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 12 KiB |
48
scripts/translationCheck.js
Executable file
@@ -0,0 +1,48 @@
|
||||
const { sync: globSync } = require('glob');
|
||||
const { readFileSync } = require('fs');
|
||||
const chalk = require('chalk');
|
||||
|
||||
const stringToHash = require('../src/renderer/utils/stringToHash.ts').default;
|
||||
const { LANGUAGE } = require('../src/renderer/constants/languages.ts');
|
||||
|
||||
function checkTranslations(dir) {
|
||||
let files;
|
||||
if (LANGUAGE.available.length > 1) {
|
||||
files = globSync(`${dir}{${LANGUAGE.available.join(',')}}.json`);
|
||||
} else {
|
||||
files = globSync(`${dir}${LANGUAGE.available[0]}.json`);
|
||||
}
|
||||
|
||||
if (!files.length || files.length !== LANGUAGE.available.length) {
|
||||
console.log(
|
||||
chalk.red(`${dir} directory probably does not exist or is empty or not all files present`),
|
||||
);
|
||||
process.exitCode = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
const keys = files
|
||||
.map(filename => JSON.parse(readFileSync(filename, 'utf8')))
|
||||
.map(data => Object.keys(data).sort());
|
||||
const hashes = keys.map(data => stringToHash(data.join(' ')));
|
||||
const equal = hashes.every((str, idx, arr) => str === arr[0]);
|
||||
|
||||
if (!equal) {
|
||||
console.log(chalk.red('Number of keys in translation files is not equal'));
|
||||
keys.forEach((data, idx) => {
|
||||
console.log(
|
||||
chalk.blue(`${dir}${files[idx]}.json`),
|
||||
chalk.gray('keys:'),
|
||||
chalk.yellow(data.length),
|
||||
chalk.gray('hash:'),
|
||||
chalk.yellow(hashes[idx]),
|
||||
);
|
||||
});
|
||||
process.exitCode = 2;
|
||||
} else {
|
||||
console.log(chalk.green('Number of keys in translation files is equal: '));
|
||||
files.forEach(file => console.log(chalk.gray(` ${file}`)));
|
||||
}
|
||||
}
|
||||
|
||||
checkTranslations('./src/renderer/locales/main/');
|
||||
37
scripts/translationRunner.js
Executable file
@@ -0,0 +1,37 @@
|
||||
const chalk = require('chalk');
|
||||
const manageTranslations = require('react-intl-translations-manager').default;
|
||||
const { sync: globSync } = require('glob');
|
||||
|
||||
const { LANGUAGE } = require('../src/renderer/constants/languages.ts');
|
||||
const provideExtractedMessagesCustom = require('./provideExtractedMessagesCustom');
|
||||
|
||||
const jsonOptions = { space: 2, trailingNewline: true };
|
||||
|
||||
const messagesDirectory = './tmp/extractedMessages';
|
||||
|
||||
const files = globSync('./tmp/extractedMessages/**/*.json');
|
||||
|
||||
if (!files.length) {
|
||||
console.log(
|
||||
chalk.red('./tmp directory probably does not exist or is empty'),
|
||||
chalk.yellow('Change some files and restart build (`npm run start`)'),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const commonOptions = {
|
||||
messagesDirectory,
|
||||
languages: LANGUAGE.available,
|
||||
jsonOptions,
|
||||
};
|
||||
|
||||
manageTranslations({
|
||||
...commonOptions,
|
||||
translationsDirectory: './src/locales/main',
|
||||
overrideCoreMethods: {
|
||||
beforeReporting() {
|
||||
console.log(chalk.cyan('--------------- ./src/locales/main ---------------\n'));
|
||||
},
|
||||
provideExtractedMessages: () => provideExtractedMessagesCustom(messagesDirectory),
|
||||
},
|
||||
});
|
||||
51
server.js
@@ -1,51 +0,0 @@
|
||||
/**
|
||||
* Setup and run the development server for Hot-Module-Replacement
|
||||
* https://webpack.github.io/docs/hot-module-replacement-with-webpack.html
|
||||
*/
|
||||
|
||||
const express = require('express');
|
||||
const webpack = require('webpack');
|
||||
const webpackDevMiddleware = require('webpack-dev-middleware');
|
||||
const webpackHotMiddleware = require('webpack-hot-middleware');
|
||||
const { spawn } = require('child_process');
|
||||
|
||||
const config = require('./webpack.config.development');
|
||||
|
||||
const argv = require('minimist')(process.argv.slice(2));
|
||||
|
||||
const app = express();
|
||||
const compiler = webpack(config);
|
||||
const PORT = process.env.PORT || 3000;
|
||||
|
||||
const wdm = webpackDevMiddleware(compiler, {
|
||||
publicPath: config.output.publicPath,
|
||||
stats: {
|
||||
colors: true
|
||||
}
|
||||
});
|
||||
|
||||
app.use(wdm);
|
||||
|
||||
app.use(webpackHotMiddleware(compiler));
|
||||
|
||||
const server = app.listen(PORT, 'localhost', serverError => {
|
||||
if (serverError) {
|
||||
return console.error(serverError);
|
||||
}
|
||||
|
||||
if (argv['start-hot']) {
|
||||
spawn('npm', ['run', 'start-hot'], { shell: true, env: process.env, stdio: 'inherit' })
|
||||
.on('close', code => process.exit(code))
|
||||
.on('error', spawnError => console.error(spawnError));
|
||||
}
|
||||
|
||||
console.log(`Listening at http://localhost:${PORT}`);
|
||||
});
|
||||
|
||||
process.on('SIGTERM', () => {
|
||||
console.log('Stopping dev server');
|
||||
wdm.close();
|
||||
server.close(() => {
|
||||
process.exit(0);
|
||||
});
|
||||
});
|
||||
65
setup.js
@@ -1,65 +0,0 @@
|
||||
// Note: this file is the configuration file *only* for
|
||||
// use by the boiler-room-custodian utility. the point
|
||||
// of the boiler-room-custodian is to clean sample code
|
||||
// from the boilerplate from initial state so that you
|
||||
// can start custom development on a "blank project"
|
||||
//
|
||||
// For more information or to report issues please go
|
||||
// to https://github.com/tstringer/boiler-room-custodian
|
||||
//
|
||||
// This file should remain unmodified by end users and
|
||||
// should only be invoked by running `npm run cleanup`
|
||||
module.exports = {
|
||||
// remove the following files as they are mostly
|
||||
// related to the sample counter page and functionality
|
||||
remove: [
|
||||
{ file: 'app/actions/counter.ts' },
|
||||
{ file: 'app/components/Counter.scss' },
|
||||
{ file: 'app/components/Counter.tsx' },
|
||||
{ file: 'app/containers/CounterPage.tsx' },
|
||||
{ file: 'app/reducers/counter.ts' },
|
||||
{ file: 'test/actions/counter.spec.ts' },
|
||||
{ file: 'test/components/Counter.spec.tsx' },
|
||||
{ file: 'test/containers/CounterPage.spec.tsx' },
|
||||
{ file: 'test/reducers/counter.spec.ts' },
|
||||
{ file: 'erb-logo.png' }
|
||||
],
|
||||
// clean the following files by either clearing them
|
||||
// (by specifying {clear: true}) or by removing lines
|
||||
// that match a regex pattern
|
||||
clean: [
|
||||
{
|
||||
file: 'app/reducers/index.ts',
|
||||
pattern: /counter/
|
||||
},
|
||||
{
|
||||
file: 'app/store/configureStore.development.ts',
|
||||
pattern: /counterActions/
|
||||
},
|
||||
{
|
||||
file: 'app/routes.tsx',
|
||||
pattern: /CounterPage/
|
||||
},
|
||||
{
|
||||
file: 'test/e2e.ts',
|
||||
clear: true
|
||||
},
|
||||
{
|
||||
file: 'README.md',
|
||||
clear: true
|
||||
},
|
||||
{
|
||||
file: 'app/components/Home.tsx',
|
||||
pattern: /(h2|Link)/
|
||||
}
|
||||
],
|
||||
// add the following files to the project, mostly
|
||||
// related to .gitkeep for version control
|
||||
add: [
|
||||
{ file: 'app/actions/.gitkeep' },
|
||||
{ file: 'test/actions/.gitkeep' },
|
||||
{ file: 'test/components/.gitkeep' },
|
||||
{ file: 'test/containers/.gitkeep' },
|
||||
{ file: 'test/reducers/.gitkeep' }
|
||||
]
|
||||
};
|
||||
67
src/main/main.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import { app, BrowserWindow } from "electron"
|
||||
import * as path from "path"
|
||||
import * as url from "url"
|
||||
|
||||
let win: BrowserWindow | null
|
||||
|
||||
const installExtensions = async () => {
|
||||
const installer = require("electron-devtools-installer")
|
||||
const forceDownload = !!process.env.UPGRADE_EXTENSIONS
|
||||
const extensions = ["REACT_DEVELOPER_TOOLS", "REDUX_DEVTOOLS"]
|
||||
|
||||
return Promise.all(
|
||||
extensions.map(name => installer.default(installer[name], forceDownload))
|
||||
).catch(console.log)
|
||||
}
|
||||
|
||||
const createWindow = async () => {
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
await installExtensions()
|
||||
}
|
||||
|
||||
win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
},
|
||||
})
|
||||
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = "1"
|
||||
win.loadURL(`http://localhost:2003`)
|
||||
} else {
|
||||
win.loadURL(
|
||||
url.format({
|
||||
pathname: path.join(__dirname, "index.html"),
|
||||
protocol: "file:",
|
||||
slashes: true,
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
// Open DevTools, see https://github.com/electron/electron/issues/12438 for why we wait for dom-ready
|
||||
win.webContents.once("dom-ready", () => {
|
||||
win!.webContents.openDevTools()
|
||||
})
|
||||
}
|
||||
|
||||
win.on("closed", () => {
|
||||
win = null
|
||||
})
|
||||
}
|
||||
|
||||
app.on("ready", createWindow)
|
||||
|
||||
app.on("window-all-closed", () => {
|
||||
if (process.platform !== "darwin") {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on("activate", () => {
|
||||
if (win === null) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
18
src/renderer/app.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import { AppContainer } from "react-hot-loader"
|
||||
|
||||
import history from "Renderer/routes/history"
|
||||
import store from "Renderer/store"
|
||||
import RootWrapper from "Renderer/wrappers/root.wrapper"
|
||||
|
||||
// Create main element
|
||||
const mainElement = document.createElement("div")
|
||||
document.body.appendChild(mainElement)
|
||||
|
||||
ReactDOM.render(
|
||||
<AppContainer>
|
||||
<RootWrapper store={store} history={history} />
|
||||
</AppContainer>,
|
||||
mainElement
|
||||
)
|
||||
@@ -1,6 +1,7 @@
|
||||
import * as React from "react"
|
||||
import styled from "styled-components"
|
||||
import FunctionComponent from "../../../types/function-component.interface"
|
||||
|
||||
import FunctionComponent from "Renderer/types/function-component.interface"
|
||||
|
||||
const HeaderWrapper = styled.div`
|
||||
flex: 1;
|
||||
@@ -10,7 +11,7 @@ const HeaderWrapper = styled.div`
|
||||
`
|
||||
|
||||
const Header: FunctionComponent = () => {
|
||||
return <HeaderWrapper> Header </HeaderWrapper>
|
||||
return <HeaderWrapper>Header</HeaderWrapper>
|
||||
}
|
||||
|
||||
export default Header
|
||||
0
src/renderer/config/.gitkeep
Normal file
5
src/renderer/constants/languages.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export const LANGUAGE = {
|
||||
default: "en-US",
|
||||
defaultShort: "en",
|
||||
available: ["en-US"],
|
||||
}
|
||||
5
src/renderer/constants/urls.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export const URL_MAIN = {
|
||||
root: "/",
|
||||
files: "/files",
|
||||
filesHooks: "/filesHooks",
|
||||
}
|
||||
0
src/renderer/i18n/.gitkeep
Normal file
3
src/renderer/locales/main/en-US.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"test": "test"
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as React from "react"
|
||||
import { textColor } from "Renderer/styles/theming/theme-getters"
|
||||
import FunctionComponent from "Renderer/types/function-component.interface"
|
||||
import styled from "styled-components"
|
||||
import { textColor } from "../../../theming/theme-getters"
|
||||
import FunctionComponent from "../../../types/function-component.interface"
|
||||
|
||||
const HomeWrapper = styled.div`
|
||||
color: ${textColor("primary")}
|
||||
@@ -1,9 +1,10 @@
|
||||
import * as React from "react"
|
||||
import styled from "styled-components"
|
||||
import Header from "../../../shared/components/header/header.component"
|
||||
import Navigation from "../../../shared/components/navigation/navigation.component"
|
||||
import FunctionComponent from "../../../types/function-component.interface"
|
||||
import Home from "../../components/home/home.component"
|
||||
|
||||
import Header from "Renderer/components/header/header.component"
|
||||
import Navigation from "Renderer/components/navigation/navigation.component"
|
||||
import FunctionComponent from "Renderer/types/function-component.interface"
|
||||
import Home from "./components/home/home.component"
|
||||
|
||||
const HomePageWrapper = styled.div`
|
||||
display: flex;
|
||||
12
src/renderer/reducers/index.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { connectRouter } from "connected-react-router"
|
||||
import { History } from "history"
|
||||
import { combineReducers } from "redux"
|
||||
import history from "Renderer/routes/history"
|
||||
import RootState from "./state"
|
||||
|
||||
const createRootReducer = (historyState: History) =>
|
||||
combineReducers<RootState>({
|
||||
router: connectRouter(historyState),
|
||||
})
|
||||
|
||||
export default createRootReducer(history)
|
||||
@@ -1,7 +1,5 @@
|
||||
import { RouterState } from "connected-react-router"
|
||||
import { State as FileState } from "../files/reducers/files.reducer"
|
||||
|
||||
export default interface State {
|
||||
router: RouterState
|
||||
files: FileState
|
||||
}
|
||||
15
src/renderer/routes/base-routes.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import * as React from "react"
|
||||
import { Route, Switch } from "react-router"
|
||||
|
||||
import HomePage from "Renderer/modules/home/home.page"
|
||||
import AppWrapper from "Renderer/wrappers/app.wrapper"
|
||||
|
||||
import { URL_MAIN } from "Renderer/constants/urls"
|
||||
|
||||
export default () => (
|
||||
<AppWrapper>
|
||||
<Switch>
|
||||
<Route path={URL_MAIN.root} component={HomePage} />
|
||||
</Switch>
|
||||
</AppWrapper>
|
||||
)
|
||||
3
src/renderer/routes/history.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { createHashHistory } from "history"
|
||||
|
||||
export default createHashHistory()
|
||||
21
src/renderer/store/index.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { applyMiddleware, createStore, Store } from "redux"
|
||||
import { composeWithDevTools } from "redux-devtools-extension"
|
||||
|
||||
import rootReducer from "Renderer/reducers"
|
||||
import RootState from "Renderer/reducers/state"
|
||||
|
||||
const index = (initialState?: RootState): Store<RootState | undefined> => {
|
||||
const middlewares: any[] = []
|
||||
const enhancer = composeWithDevTools(applyMiddleware(...middlewares))
|
||||
return createStore(rootReducer, initialState, enhancer)
|
||||
}
|
||||
|
||||
const store = index()
|
||||
|
||||
if (typeof module.hot !== "undefined") {
|
||||
module.hot.accept("../reducers", () =>
|
||||
store.replaceReducer(require("../reducers").rootReducer)
|
||||
)
|
||||
}
|
||||
|
||||
export default store
|
||||
@@ -1,5 +1,5 @@
|
||||
import { createGlobalStyle } from "styled-components"
|
||||
import { Theme } from "./theme"
|
||||
import { Theme } from "./theming/theme"
|
||||
|
||||
const GlobalStyle = createGlobalStyle<{ theme: Theme }>`
|
||||
html, body {
|
||||
31
src/renderer/utils/stringToHash.ts
Executable file
@@ -0,0 +1,31 @@
|
||||
/* tslint:disable no-bitwise prettier */
|
||||
|
||||
/**
|
||||
* Converts string to numeric hash
|
||||
* @param {string} str - string to be converted
|
||||
* @returns {number}
|
||||
*
|
||||
* Please note:
|
||||
* This is a JS implementation of Java's String.hashCode() method, converted to function.
|
||||
* It looks utterly ugly but it's short and it gets the job done.
|
||||
* Reference: https://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/
|
||||
*/
|
||||
|
||||
const stringToHash = (str: string) => {
|
||||
let hash = 0
|
||||
const strLength = str.length
|
||||
|
||||
if (strLength === 0) {
|
||||
return hash
|
||||
}
|
||||
|
||||
for (let i = 0; i < strLength; i++) {
|
||||
const char = str.charCodeAt(i)
|
||||
hash = ((hash << 5) - hash) + char;
|
||||
hash &= hash; // convert to 32bit integer
|
||||
}
|
||||
|
||||
return hash;
|
||||
};
|
||||
|
||||
export default stringToHash;
|
||||
12
src/renderer/wrappers/app.wrapper.tsx
Normal file
@@ -0,0 +1,12 @@
|
||||
import * as React from "react"
|
||||
import styled from "styled-components"
|
||||
|
||||
import FunctionComponent from "Renderer/types/function-component.interface"
|
||||
|
||||
const SAppWrapper = styled.div``
|
||||
|
||||
const AppWrapper: FunctionComponent = ({ children }) => {
|
||||
return <SAppWrapper>{children}</SAppWrapper>
|
||||
}
|
||||
|
||||
export default AppWrapper
|
||||
@@ -4,17 +4,18 @@ import * as React from "react"
|
||||
import { Provider } from "react-redux"
|
||||
import { ThemeProvider } from "styled-components"
|
||||
import { Normalize } from "styled-normalize"
|
||||
import Routes from "../routes"
|
||||
import GlobalStyle from "../theming/global-style.component"
|
||||
import theme from "../theming/theme"
|
||||
import FunctionComponent from "../types/function-component.interface"
|
||||
|
||||
import BaseRoutes from "Renderer/routes/base-routes"
|
||||
import GlobalStyle from "Renderer/styles/global-style.component"
|
||||
import theme from "Renderer/styles/theming/theme"
|
||||
import FunctionComponent from "Renderer/types/function-component.interface"
|
||||
|
||||
interface Props {
|
||||
store: any
|
||||
history: History
|
||||
}
|
||||
|
||||
const RootContainer: FunctionComponent<Props> = ({ store, history }) => {
|
||||
const RootWrapper: FunctionComponent<Props> = ({ store, history }) => {
|
||||
return (
|
||||
<ThemeProvider theme={theme}>
|
||||
<>
|
||||
@@ -22,7 +23,7 @@ const RootContainer: FunctionComponent<Props> = ({ store, history }) => {
|
||||
<GlobalStyle />
|
||||
<Provider store={store}>
|
||||
<ConnectedRouter history={history}>
|
||||
<Routes />
|
||||
<BaseRoutes />
|
||||
</ConnectedRouter>
|
||||
</Provider>
|
||||
</>
|
||||
@@ -30,4 +31,4 @@ const RootContainer: FunctionComponent<Props> = ({ store, history }) => {
|
||||
)
|
||||
}
|
||||
|
||||
export default RootContainer
|
||||
export default RootWrapper
|
||||
|
Before Width: | Height: | Size: 32 KiB |
118
tsconfig.json
@@ -1,30 +1,120 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
/***** Basic Options ******/
|
||||
/* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */
|
||||
"target": "es5",
|
||||
"moduleResolution": "node",
|
||||
/* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
||||
"module": "commonjs",
|
||||
"jsx": "react",
|
||||
"lib": ["dom", "es6", "dom.iterable", "scripthost", "es5", "es7", "es2017"],
|
||||
"types": ["jest", "node"],
|
||||
/* Specify library files to be included in the compilation: */
|
||||
"lib": [
|
||||
"dom",
|
||||
"es6",
|
||||
"dom.iterable",
|
||||
"scripthost",
|
||||
"es5",
|
||||
"es7",
|
||||
"es2017"
|
||||
],
|
||||
/* Allow javascript files to be compiled. */
|
||||
"allowJs": true,
|
||||
/* Report errors in .js files. */
|
||||
// "checkJs": true,
|
||||
/* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
|
||||
"jsx": "react",
|
||||
/* Generates corresponding '.d.ts' file. */
|
||||
// "declaration": true,
|
||||
/* Generates corresponding '.map' file. */
|
||||
"sourceMap": true,
|
||||
/* Concatenate and emit output to single file. */
|
||||
// "outFile": "./",
|
||||
/* Redirect output structure to the directory. */
|
||||
"outDir": "./dist",
|
||||
/* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
||||
// "rootDir": "./",
|
||||
/* Do not emit comments to output. */
|
||||
// "removeComments": true,
|
||||
/* Do not emit outputs. */
|
||||
// "noEmit": true,
|
||||
/* Import emit helpers from 'tslib'. */
|
||||
// "importHelpers": true,
|
||||
/* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
||||
// "downlevelIteration": true,
|
||||
/* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
||||
// "isolatedModules": true,
|
||||
|
||||
|
||||
/***** Strict Type-Checking Options ******/
|
||||
/* Enable all strict type-checking options. */
|
||||
"strict": true,
|
||||
"alwaysStrict": true,
|
||||
"strictNullChecks": true,
|
||||
/* Raise error on expressions and declarations with an implied 'any' type. */
|
||||
"noImplicitAny": true,
|
||||
"noImplicitReturns": true,
|
||||
/* Enable strict null checks. */
|
||||
"strictNullChecks": true,
|
||||
/* Enable strict checking of function types. */
|
||||
// "strictFunctionTypes": true,
|
||||
/* Raise error on 'this' expressions with an implied 'any' type. */
|
||||
"noImplicitThis": true,
|
||||
/* Parse in strict mode and emit "use strict" for each source file. */
|
||||
"alwaysStrict": true,
|
||||
|
||||
/***** Additional Checks *****/
|
||||
/* Report errors on unused locals. */
|
||||
"noUnusedLocals": true,
|
||||
"skipLibCheck": true,
|
||||
/* Report errors on unused parameters. */
|
||||
// "noUnusedParameters": true,
|
||||
/* Report error when not all code paths in function return a value. */
|
||||
"noImplicitReturns": true,
|
||||
/* Report errors for fallthrough cases in switch statement. */
|
||||
// "noFallthroughCasesInSwitch": true,
|
||||
|
||||
|
||||
/***** Module Resolution Options *****/
|
||||
/* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
||||
"moduleResolution": "node",
|
||||
/* Base directory to resolve non-absolute module names. */
|
||||
"baseUrl": "./",
|
||||
/* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
||||
"paths": {
|
||||
"App/*": ["src/*"],
|
||||
"Renderer/*": ["src/renderer/*"],
|
||||
"Cypress/*": ["cypress/*"],
|
||||
"Storybook/*": [".storybook/*"]
|
||||
},
|
||||
/* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||
// "rootDirs": [],
|
||||
/* List of folders to include type definitions from. */
|
||||
// "typeRoots": [],
|
||||
/* Type declaration files to be included in compilation. */
|
||||
"types": ["jest", "node"],
|
||||
/* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
||||
// "allowSyntheticDefaultImports": true,
|
||||
/* Do not resolve the real path of symlinks. */
|
||||
// "preserveSymlinks": true,
|
||||
|
||||
|
||||
/***** Source Map Options *****/
|
||||
/* Specify the location where debugger should locate TypeScript files instead of source locations. */
|
||||
// "sourceRoot": "./",
|
||||
/* Specify the location where debugger should locate map files instead of generated locations. */
|
||||
// "mapRoot": "./",
|
||||
/* Emit a single file with source maps instead of having a separate file. */
|
||||
// "inlineSourceMap": true,
|
||||
/* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
|
||||
// "inlineSources": true,
|
||||
|
||||
|
||||
/***** Experimental Options *****/
|
||||
/* Enables experimental support for ES7 decorators. */
|
||||
"experimentalDecorators": true,
|
||||
/* Enables experimental support for emitting type metadata for decorators. */
|
||||
"emitDecoratorMetadata": true,
|
||||
|
||||
"sourceMap": true,
|
||||
|
||||
"outDir": "dist"
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"files": ["app/index.tsx"],
|
||||
"include": [
|
||||
"app/**/*.ts",
|
||||
"app/**/*.tsx"
|
||||
"./src",
|
||||
"./test",
|
||||
"./mocks"
|
||||
],
|
||||
"exclude": ["dist", "node_modules"]
|
||||
}
|
||||
|
||||
36
tslint.json
@@ -1,20 +1,20 @@
|
||||
{
|
||||
"defaultSeverity": "error",
|
||||
"extends": [
|
||||
"tslint:recommended",
|
||||
"tslint-react",
|
||||
"tslint-eslint-rules",
|
||||
"tslint-config-prettier"
|
||||
],
|
||||
"jsRules": {},
|
||||
"rules": {
|
||||
"semicolon": false,
|
||||
"interface-name": false,
|
||||
"no-console": false,
|
||||
"object-literal-sort-keys": false,
|
||||
"jsx-boolean-value": false,
|
||||
"no-var-requires": false,
|
||||
"prettier": true
|
||||
},
|
||||
"rulesDirectory": ["tslint-plugin-prettier"]
|
||||
"defaultSeverity": "error",
|
||||
"extends": [
|
||||
"tslint:recommended",
|
||||
"tslint-react",
|
||||
"tslint-eslint-rules",
|
||||
"tslint-config-prettier"
|
||||
],
|
||||
"jsRules": {},
|
||||
"rules": {
|
||||
"semicolon": false,
|
||||
"interface-name": false,
|
||||
"no-console": false,
|
||||
"object-literal-sort-keys": false,
|
||||
"jsx-boolean-value": false,
|
||||
"no-var-requires": false,
|
||||
"prettier": true
|
||||
},
|
||||
"rulesDirectory": ["tslint-plugin-prettier"]
|
||||
}
|
||||
|
||||
@@ -1,25 +1,19 @@
|
||||
/**
|
||||
* Build config for electron 'Renderer Process' file
|
||||
*/
|
||||
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const ExtractTextPlugin = require('extract-text-webpack-plugin');
|
||||
const merge = require('webpack-merge');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const baseConfig = require('./webpack.config.base');
|
||||
|
||||
module.exports = merge(baseConfig, {
|
||||
devtool: 'cheap-module-source-map',
|
||||
const { resolve } = require('./webpack/resolve');
|
||||
const plugins = require('./webpack/plugins')();
|
||||
|
||||
entry: [
|
||||
'./app/index'
|
||||
],
|
||||
|
||||
output: {
|
||||
path: path.join(__dirname, 'app/dist'),
|
||||
publicPath: '../dist/'
|
||||
},
|
||||
module.exports = {
|
||||
mode: 'development',
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: '[name].js'
|
||||
},
|
||||
node: {
|
||||
__dirname: false,
|
||||
__filename: false
|
||||
},
|
||||
devtool: 'source-map',
|
||||
|
||||
module: {
|
||||
rules: [
|
||||
@@ -77,28 +71,9 @@ module.exports = merge(baseConfig, {
|
||||
test: /\.(?:ico|gif|png|jpg|jpeg|webp)$/,
|
||||
use: 'url-loader',
|
||||
}
|
||||
]
|
||||
],
|
||||
},
|
||||
|
||||
plugins: [
|
||||
// https://webpack.github.io/docs/list-of-plugins.html#occurrenceorderplugin
|
||||
// https://github.com/webpack/webpack/issues/864
|
||||
new webpack.optimize.OccurrenceOrderPlugin(),
|
||||
|
||||
// NODE_ENV should be production so that modules do not perform certain development checks
|
||||
new webpack.DefinePlugin({
|
||||
'process.env.NODE_ENV': JSON.stringify('production')
|
||||
}),
|
||||
|
||||
new ExtractTextPlugin('style.css'),
|
||||
|
||||
new HtmlWebpackPlugin({
|
||||
filename: '../app.html',
|
||||
template: 'app/app.html',
|
||||
inject: false
|
||||
})
|
||||
],
|
||||
|
||||
// https://github.com/chentsulin/webpack-target-electron-renderer#how-this-module-works
|
||||
target: 'electron-renderer'
|
||||
});
|
||||
resolve,
|
||||
plugins,
|
||||
};
|
||||
@@ -1,42 +0,0 @@
|
||||
/**
|
||||
* Base webpack config used across other specific configs
|
||||
*/
|
||||
|
||||
const path = require('path');
|
||||
const {
|
||||
dependencies: externals
|
||||
} = require('./app/package.json');
|
||||
|
||||
module.exports = {
|
||||
module: {
|
||||
rules: [{
|
||||
test: /\.tsx?$/,
|
||||
loaders: ['react-hot-loader/webpack', 'ts-loader'],
|
||||
exclude: /node_modules/
|
||||
}, {
|
||||
test: /\.json$/,
|
||||
loader: 'json-loader'
|
||||
}]
|
||||
},
|
||||
|
||||
output: {
|
||||
path: path.join(__dirname, 'app'),
|
||||
filename: 'bundle.js',
|
||||
|
||||
// https://github.com/webpack/webpack/issues/1114
|
||||
libraryTarget: 'commonjs2'
|
||||
},
|
||||
|
||||
// https://webpack.github.io/docs/configuration.html#resolve
|
||||
resolve: {
|
||||
extensions: ['.js', '.ts', '.tsx', '.json'],
|
||||
modules: [
|
||||
path.join(__dirname, 'app'),
|
||||
'node_modules',
|
||||
]
|
||||
},
|
||||
|
||||
plugins: [],
|
||||
|
||||
externals: Object.keys(externals || {})
|
||||
};
|
||||
@@ -1,110 +0,0 @@
|
||||
/* eslint-disable max-len */
|
||||
/**
|
||||
* Build config for development process that uses Hot-Module-Replacement
|
||||
* https://webpack.github.io/docs/hot-module-replacement-with-webpack.html
|
||||
*/
|
||||
|
||||
const webpack = require('webpack');
|
||||
const merge = require('webpack-merge');
|
||||
const baseConfig = require('./webpack.config.base');
|
||||
|
||||
const port = process.env.PORT || 3000;
|
||||
|
||||
module.exports = merge(baseConfig, {
|
||||
devtool: 'inline-source-map',
|
||||
mode: 'development',
|
||||
entry: [
|
||||
'react-hot-loader/patch',
|
||||
`webpack-hot-middleware/client?path=http://localhost:${port}/__webpack_hmr&reload=true`,
|
||||
'./app/index'
|
||||
],
|
||||
|
||||
output: {
|
||||
publicPath: `http://localhost:${port}/dist/`
|
||||
},
|
||||
|
||||
module: {
|
||||
// preLoaders: [
|
||||
// {
|
||||
// test: /\.js$/,
|
||||
// loader: 'eslint-loader',
|
||||
// exclude: /node_modules/
|
||||
// }
|
||||
// ],
|
||||
rules: [
|
||||
// WOFF Font
|
||||
{
|
||||
test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
|
||||
use: {
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 10000,
|
||||
mimetype: 'application/font-woff',
|
||||
}
|
||||
},
|
||||
},
|
||||
// WOFF2 Font
|
||||
{
|
||||
test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
|
||||
use: {
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 10000,
|
||||
mimetype: 'application/font-woff',
|
||||
}
|
||||
}
|
||||
},
|
||||
// TTF Font
|
||||
{
|
||||
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
|
||||
use: {
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 10000,
|
||||
mimetype: 'application/octet-stream'
|
||||
}
|
||||
}
|
||||
},
|
||||
// EOT Font
|
||||
{
|
||||
test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
|
||||
use: 'file-loader',
|
||||
},
|
||||
// SVG Font
|
||||
{
|
||||
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
|
||||
use: {
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 10000,
|
||||
mimetype: 'image/svg+xml',
|
||||
}
|
||||
}
|
||||
},
|
||||
// Common Image Formats
|
||||
{
|
||||
test: /\.(?:ico|gif|png|jpg|jpeg|webp)$/,
|
||||
use: 'url-loader',
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
plugins: [
|
||||
// https://webpack.github.io/docs/hot-module-replacement-with-webpack.html
|
||||
new webpack.HotModuleReplacementPlugin(),
|
||||
|
||||
new webpack.NoEmitOnErrorsPlugin(),
|
||||
|
||||
// NODE_ENV should be production so that modules do not perform certain development checks
|
||||
new webpack.DefinePlugin({
|
||||
'process.env.NODE_ENV': JSON.stringify('development')
|
||||
}),
|
||||
|
||||
new webpack.LoaderOptionsPlugin({
|
||||
debug: true
|
||||
}),
|
||||
],
|
||||
|
||||
// https://github.com/chentsulin/webpack-target-electron-renderer#how-this-module-works
|
||||
target: 'electron-renderer'
|
||||
});
|
||||
@@ -1,50 +0,0 @@
|
||||
/**
|
||||
* Build config for electron 'Main Process' file
|
||||
*/
|
||||
|
||||
const webpack = require('webpack');
|
||||
const merge = require('webpack-merge');
|
||||
const baseConfig = require('./webpack.config.base');
|
||||
|
||||
module.exports = merge(baseConfig, {
|
||||
devtool: 'source-map',
|
||||
mode: 'development',
|
||||
|
||||
entry: ['./app/main.development'],
|
||||
|
||||
// 'main.js' in root
|
||||
output: {
|
||||
path: __dirname,
|
||||
filename: './app/main.js'
|
||||
},
|
||||
|
||||
plugins: [
|
||||
// Add source map support for stack traces in node
|
||||
// https://github.com/evanw/node-source-map-support
|
||||
// new webpack.BannerPlugin(
|
||||
// 'require("source-map-support").install();',
|
||||
// { raw: true, entryOnly: false }
|
||||
// ),
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': {
|
||||
NODE_ENV: JSON.stringify('production')
|
||||
}
|
||||
})
|
||||
],
|
||||
|
||||
/**
|
||||
* Set target to Electron specific node.js env.
|
||||
* https://github.com/chentsulin/webpack-target-electron-renderer#how-this-module-works
|
||||
*/
|
||||
target: 'electron-main',
|
||||
|
||||
/**
|
||||
* Disables webpack processing of __dirname and __filename.
|
||||
* If you run the bundle in node.js it falls back to these values of node.js.
|
||||
* https://github.com/webpack/webpack/issues/2010
|
||||
*/
|
||||
node: {
|
||||
__dirname: false,
|
||||
__filename: false
|
||||
},
|
||||
});
|
||||