├── src ├── assets │ ├── tray.png │ ├── ico │ │ ├── icon.ico │ │ └── icon.png │ └── logo.svg ├── index.js ├── App.test.js ├── index.html ├── index.css ├── App.css ├── App.js └── MySql.js ├── .babelrc ├── .gitignore ├── main.js ├── LICENSE ├── gulpfile.js ├── main-tray.js ├── main-tray-two-windows.js ├── package.json ├── package-cert.json └── README.md /src/assets/tray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natancabral/react-js-electron-database/HEAD/src/assets/tray.png -------------------------------------------------------------------------------- /src/assets/ico/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natancabral/react-js-electron-database/HEAD/src/assets/ico/icon.ico -------------------------------------------------------------------------------- /src/assets/ico/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natancabral/react-js-electron-database/HEAD/src/assets/ico/icon.png -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env", "@babel/preset-react"], 3 | "plugins": ["@babel/plugin-proposal-class-properties"] 4 | } -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | //import './index.css'; 4 | import App from './App'; 5 | 6 | ReactDOM.render( 7 | , 8 | document.getElementById('root') 9 | ); -------------------------------------------------------------------------------- /src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | React-js + Electron + Sqlite3 9 | 10 | 11 |
12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | /dist 14 | /dist-certificate-win 15 | /release-builds 16 | /app/* 17 | 18 | # misc 19 | .DS_Store 20 | .env.local 21 | .env.development.local 22 | .env.test.local 23 | .env.production.local 24 | 25 | npm-debug.log* 26 | yarn-debug.log* 27 | yarn-error.log* 28 | 29 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React, {useEffect, useState} from 'react' 2 | //import logo from './logo.svg'; 3 | import MySql from './MySql'; 4 | import { ipcRenderer } from 'electron'; 5 | 6 | function App() { 7 | 8 | const [version, setVersion] = useState(''); 9 | 10 | const getVersion = () => { 11 | ipcRenderer.send('app_version'); 12 | ipcRenderer.on('app_version', (event, arg) => { 13 | ipcRenderer.removeAllListeners('app_version'); 14 | setVersion(arg.version); 15 | }); 16 | } 17 | 18 | useEffect(() => { 19 | getVersion(); 20 | },[]); 21 | 22 | return ( 23 |
24 |
25 | logo 26 |

React-js + Electron + Database

27 |
{version}
28 | 29 |
30 |
31 | ); 32 | } 33 | 34 | export default App; 35 | -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | const { app, ipcMain, BrowserWindow } = require('electron') 2 | const path = require('path') 3 | //const url = require('url') 4 | 5 | function createWindow () { 6 | const win = new BrowserWindow({ 7 | width: 800, 8 | height: 600, 9 | webPreferences: { 10 | // webSecurity: false, 11 | // allowRunningInsecureContent: true, 12 | // preload: path.join(__dirname, 'preload.js') 13 | nativeWindowOpen: true, 14 | nodeIntegration: true, 15 | } 16 | }) 17 | 18 | win.loadFile('app/index.html') 19 | //win.loadURL('http://127.0.0.1:3000') 20 | //win.webContents.openDevTools() 21 | } 22 | 23 | app.whenReady().then(createWindow) 24 | 25 | app.on('window-all-closed', () => { 26 | if (process.platform !== 'darwin') { 27 | app.quit() 28 | } 29 | }) 30 | 31 | app.on('activate', () => { 32 | if (BrowserWindow.getAllWindows().length === 0) { 33 | createWindow() 34 | } 35 | }) 36 | 37 | ipcMain.on('app_version', (event) => { 38 | event.sender.send('app_version', { version: app.getVersion() }); 39 | console.log('Version', app.getVersion()); 40 | }); 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Natan Cabral 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | const exec = require('child_process').exec; 2 | const gulp = require('gulp'); 3 | const babel = require('gulp-babel'); 4 | const css = require('gulp-clean-css'); 5 | const livereload = require('gulp-livereload'); 6 | //1. Compile HTML file and move them to the app folder 7 | gulp.task('html', () => { 8 | return gulp.src('src/index.html') 9 | .pipe(gulp.dest('app/')) 10 | .pipe(livereload()); 11 | }); 12 | 13 | //2. Compile CSS file and move them to the app folder 14 | gulp.task('css', () => { 15 | return gulp.src('src/**/*.css') 16 | .pipe(css()) 17 | .pipe(gulp.dest('app/')) 18 | .pipe(livereload()); 19 | }); 20 | 21 | //3. Compile JS and JSX files and move them to the app folder 22 | gulp.task('js*', () => { 23 | return gulp.src(['main*.js', 'src/**/*.js*']) 24 | .pipe(babel()) 25 | .pipe(gulp.dest('app/')) 26 | .pipe(livereload()); 27 | }); 28 | 29 | //4. Compile IMAGES file and move them to the app folder 30 | // ------------------------------------------------------------------------------------ All images inside ./assets/ 31 | gulp.task('images', () => { 32 | return gulp.src('src/assets/**/*') 33 | .pipe(gulp.dest('app/assets')) 34 | .pipe(livereload()); 35 | }) 36 | 37 | //5. Watch files 38 | gulp.task('watch', async function() { 39 | livereload.listen(); 40 | gulp.watch('src/**/*.html', gulp.series('html')); 41 | gulp.watch('src/**/*.css', gulp.series('css')); 42 | gulp.watch('src/**/*.js*', gulp.series('js*')); 43 | gulp.watch('src/assets/**/*', gulp.series('images')); 44 | }); 45 | 46 | //6. Send to app folder 47 | gulp.task('build', gulp.series('html', 'css', 'js*', 'images')); 48 | 49 | //7. Start the electron process. 50 | gulp.task('start', gulp.series('build', () => { 51 | return exec( 52 | __dirname+'/node_modules/.bin/electron .' 53 | ).on('close', () => process.exit()); 54 | })); 55 | 56 | //0. Default process. 57 | gulp.task('default', gulp.parallel('start', 'watch')); -------------------------------------------------------------------------------- /src/assets/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/MySql.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import mysql from "mysql"; 3 | 4 | function MySql() { 5 | 6 | // https://github.com/mysqljs/mysql 7 | 8 | // set connection variable 9 | const [conn, setConn] = React.useState(undefined); 10 | const dataConnection = { 11 | //host : '888.88.88.88', //:3306 12 | host: "127.0.0.1", 13 | user: "root", 14 | password: "", 15 | database: "databasename", 16 | } 17 | const [list,setList] = React.useState([]); 18 | const {host, user, password, database} = dataConnection; 19 | 20 | // function connection mysql remote 21 | const connection = () => { 22 | let c = mysql.createConnection(dataConnection); 23 | c.connect((err) => { 24 | // in case of error 25 | if (err) { 26 | alert(err.code); 27 | return console.log(err.code, err.fatal, err.stack); 28 | } 29 | return console.log("Connection successfully established"); 30 | }); 31 | setConn(c); 32 | }; 33 | 34 | // function query/search 35 | const query = () => { 36 | let sql = "SELECT `name`,`id` FROM `tablename` where id > ? limit 0,50 "; 37 | //let value = connection.escape(value); 38 | //let id = connection.escapeId(id); 39 | conn.query( 40 | { 41 | sql: sql, 42 | timeout: 40 * 1000, // 40s 43 | }, 44 | [0], // values to replace ? 45 | function (err, results, fields) { 46 | if (err) { 47 | alert(err.code); 48 | console.log(err.code); 49 | } else { 50 | alert(results); 51 | console.log(results); 52 | if (results.length) { 53 | setList(results); 54 | alert(results[0].id + results[0].name); 55 | } 56 | } 57 | }); 58 | 59 | // Close the connection 60 | conn.end(function () { 61 | // The connection has been closed 62 | }); 63 | }; 64 | 65 | const queryPost = () => { 66 | var post = {id: 1, title: 'Hello MySQL'}; 67 | var query = conn.query('INSERT INTO posts SET ?', post, function (error, results, fields) { 68 | if (error) throw error; 69 | // Neat! 70 | }); 71 | console.log(query.sql); // INSERT INTO posts SET `id` = 1, `title` = 'Hello MySQL' 72 | } 73 | 74 | return ( 75 | 76 |

Click to connect database

77 | 78 | 79 | 80 |
81 |
    82 |
  • Host: {host}
  • 83 |
  • User: {user}
  • 84 |
  • Password: {password}
  • 85 |
  • Database: {database}
  • 86 |
87 |
88 |
89 |
    90 | {list.map((dat,idx) => { 91 | return ( 92 |
  • {dat.id} {dat.name}
  • 93 | ) 94 | })} 95 |
96 |
97 |
98 | ); 99 | } 100 | 101 | export default MySql; 102 | -------------------------------------------------------------------------------- /main-tray.js: -------------------------------------------------------------------------------- 1 | const {app, BrowserWindow, Tray, nativeImage, screen } = require('electron') 2 | const path = require('path') 3 | 4 | let mainWindow = undefined;; 5 | let tray = undefined; 6 | //app.dock.hide(); 7 | 8 | function createWindow () { 9 | // Create the browser window. 10 | mainWindow = new BrowserWindow({ 11 | width: 300, 12 | height: 600, 13 | //-----tray----- start 14 | show: true, 15 | frame: false, 16 | fullscreen: false, 17 | resizable: false, 18 | transparent: false, 19 | //-----tray----- end 20 | webPreferences: { 21 | backgroundThrottling: false 22 | } 23 | }) 24 | 25 | // mainWindow.loadFile('index.html') 26 | mainWindow.loadFile(path.join(__dirname, 'app', 'index.html')) 27 | // Open the DevTools. 28 | // mainWindow.webContents.openDevTools() 29 | 30 | //-----tray----- start 31 | mainWindow.on('closed',()=>mainWindow = null) 32 | // Hide the window when it loses focus 33 | mainWindow.on('blur', () => { 34 | // if (!mainWindow.webContents.isDevToolsOpened()) { 35 | // mainWindow.hide(); 36 | // } 37 | }); 38 | //-----tray----- end 39 | } 40 | 41 | //-----tray----- start 42 | const createTray = () => { 43 | const icon = path.join(__dirname, 'assets', 'tray.png') 44 | const nimage = nativeImage.createFromPath(icon) 45 | //tray is a app variable 46 | tray = new Tray(nimage) 47 | tray.on('click', (event)=>toggleWindow()) 48 | } 49 | 50 | const toggleWindow = () => { 51 | mainWindow.isVisible() ? mainWindow.hide() : showWindow(); 52 | } 53 | 54 | const showWindow = () => { 55 | const position = getWindowPosition(); 56 | mainWindow.setPosition(position.x,position.y, false); 57 | mainWindow.show(); 58 | } 59 | 60 | const getWindowPosition = () => { 61 | 62 | //console.log(process.platform); 63 | //'aix' 64 | //'darwin' 65 | //'freebsd' 66 | //'linux' 67 | //'openbsd' 68 | //'sunos' 69 | //'win32' 70 | 71 | const { screenWidth, screenHeight } = screen.getPrimaryDisplay().workAreaSize; 72 | const windowBounds = mainWindow.getBounds(); 73 | const trayBounds = tray.getBounds(); 74 | // Center window horizontally below the tray icon 75 | const x = Math.round(trayBounds.x + (trayBounds.width / 2) - (windowBounds.width / 2)); 76 | let y = undefined; 77 | // Position window 4 pixels vertically below the tray icon 78 | if(process.platform == 'win32') 79 | y = Math.round(trayBounds.y - windowBounds.height); 80 | else 81 | y = Math.round(trayBounds.y + trayBounds.height + 4); 82 | 83 | return {x,y} 84 | } 85 | //-----tray----- end 86 | 87 | // This method will be called when Electron has finished 88 | // initialization and is ready to create browser windows. 89 | // Some APIs can only be used after this event occurs. 90 | app.whenReady().then(() => { 91 | //-----tray----- start 92 | createTray() 93 | //-----tray----- end 94 | createWindow() 95 | 96 | app.on('activate', function () { 97 | // On macOS it's common to re-create a window in the app when the 98 | // dock icon is clicked and there are no other windows open. 99 | if (BrowserWindow.getAllWindows().length === 0) createWindow() 100 | }) 101 | }) 102 | 103 | // Quit when all windows are closed, except on macOS. There, it's common 104 | // for applications and their menu bar to stay active until the user quits 105 | // explicitly with Cmd + Q. 106 | app.on('window-all-closed', function () { 107 | if (process.platform !== 'darwin') app.quit() 108 | }) 109 | 110 | // In this file you can include the rest of your app's specific main process 111 | // code. You can also put them in separate files and require them here. -------------------------------------------------------------------------------- /main-tray-two-windows.js: -------------------------------------------------------------------------------- 1 | const {app, BrowserWindow, Tray, nativeImage, screen } = require('electron') 2 | const path = require('path') 3 | 4 | let mainWindow = undefined;; 5 | let tray = undefined; 6 | //app.dock.hide(); 7 | 8 | function createWindow () { 9 | // Create the browser window. 10 | mainWindow = new BrowserWindow({ 11 | width: 700, 12 | height: 500, 13 | //-----tray----- end 14 | webPreferences: { 15 | } 16 | }) 17 | 18 | // mainWindow.loadFile('index.html') 19 | mainWindow.loadFile(path.join(__dirname, 'app', 'index.html')) 20 | // Open the DevTools. 21 | // mainWindow.webContents.openDevTools() 22 | 23 | //-----tray----- start 24 | mainWindow.on('closed',()=>mainWindow = null) 25 | // Hide the window when it loses focus 26 | mainWindow.on('blur', () => { 27 | // if (!mainWindow.webContents.isDevToolsOpened()) { 28 | // mainWindow.hide(); 29 | // } 30 | }); 31 | //-----tray----- end 32 | } 33 | 34 | let w = undefined; 35 | function createWindowTray () { 36 | // Create the browser window. 37 | w = new BrowserWindow({ 38 | width: 300, 39 | height: 600, 40 | //-----tray----- start 41 | show: false, 42 | frame: false, 43 | fullscreen: false, 44 | resizable: false, 45 | transparent: false, 46 | //-----tray----- end 47 | webPreferences: { 48 | backgroundThrottling: false 49 | } 50 | }) 51 | 52 | // w.loadFile('index.html') 53 | w.loadFile(path.join(__dirname, 'app', 'index.html')) 54 | // Open the DevTools. 55 | // w.webContents.openDevTools() 56 | 57 | //-----tray----- start 58 | w.on('closed',()=>w = null) 59 | // Hide the window when it loses focus 60 | w.on('blur', () => { 61 | // if (!w.webContents.isDevToolsOpened()) { 62 | // w.hide(); 63 | // } 64 | }); 65 | //-----tray----- end 66 | } 67 | 68 | //-----tray----- start 69 | const createTray = () => { 70 | const icon = path.join(__dirname, 'assets', 'tray.png') 71 | const nimage = nativeImage.createFromPath(icon) 72 | //tray is a app variable 73 | tray = new Tray(nimage) 74 | tray.on('click', (event)=>toggleWindow()) 75 | } 76 | 77 | const toggleWindow = () => { 78 | // mainWindow.loadFile('index.html') 79 | w.loadFile(path.join(__dirname, 'app', 'index.html')) 80 | //w.show(); 81 | w.isVisible() ? w.hide() : showWindow(); 82 | } 83 | 84 | const showWindow = () => { 85 | const position = getWindowPosition(); 86 | w.setPosition(position.x,position.y, false); 87 | w.show(); 88 | } 89 | 90 | const getWindowPosition = () => { 91 | 92 | //console.log(process.platform); 93 | //'aix' 94 | //'darwin' 95 | //'freebsd' 96 | //'linux' 97 | //'openbsd' 98 | //'sunos' 99 | //'win32' 100 | 101 | const { screenWidth, screenHeight } = screen.getPrimaryDisplay().workAreaSize; 102 | const windowBounds = w.getBounds(); 103 | const trayBounds = tray.getBounds(); 104 | // Center window horizontally below the tray icon 105 | const x = Math.round(trayBounds.x + (trayBounds.width / 2) - (windowBounds.width / 2)); 106 | let y = undefined; 107 | // Position window 4 pixels vertically below the tray icon 108 | if(process.platform == 'win32') 109 | y = Math.round(trayBounds.y - windowBounds.height); 110 | else 111 | y = Math.round(trayBounds.y + trayBounds.height + 4); 112 | 113 | return {x,y} 114 | } 115 | //-----tray----- end 116 | 117 | // This method will be called when Electron has finished 118 | // initialization and is ready to create browser windows. 119 | // Some APIs can only be used after this event occurs. 120 | app.whenReady().then(() => { 121 | //-----tray----- start 122 | createTray() 123 | createWindowTray() 124 | //-----tray----- end 125 | createWindow() 126 | 127 | 128 | app.on('activate', function () { 129 | // On macOS it's common to re-create a window in the app when the 130 | // dock icon is clicked and there are no other windows open. 131 | if (BrowserWindow.getAllWindows().length === 0) createWindow() 132 | }) 133 | }) 134 | 135 | // Quit when all windows are closed, except on macOS. There, it's common 136 | // for applications and their menu bar to stay active until the user quits 137 | // explicitly with Cmd + Q. 138 | app.on('window-all-closed', function () { 139 | if (process.platform !== 'darwin') app.quit() 140 | }) 141 | 142 | // In this file you can include the rest of your app's specific main process 143 | // code. You can also put them in separate files and require them here. 144 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-js-electron-database", 3 | "description": "...", 4 | "version": "0.1.0", 5 | "private": true, 6 | "repository": "https://github.com/natancabral/react-js-electron-database.git", 7 | "author": { 8 | "name": "Natan Cabral", 9 | "email": "natancabral@hotmail.com" 10 | }, 11 | "dependencies": { 12 | "@babel/plugin-proposal-class-properties": "^7.12.1", 13 | "@testing-library/jest-dom": "^5.11.6", 14 | "@testing-library/react": "^11.2.2", 15 | "@testing-library/user-event": "^12.2.2", 16 | "babel": "^6.23.0", 17 | "fs": "^0.0.1-security", 18 | "gulp-cli": "^1.4.0", 19 | "gulp-livereload": "^4.0.2", 20 | "mysql": "^2.18.1", 21 | "react": "^17.0.1", 22 | "react-dom": "^17.0.1", 23 | "react-script": "^2.0.5", 24 | "react-scripts": "^4.0.3", 25 | "vinyl-fs": "^2.4.1", 26 | "web-vitals": "^0.2.4", 27 | "webpack": "^5.52.1", 28 | "webpack-manifest-plugin": "^4.0.2" 29 | }, 30 | "main": "app/main.js", 31 | "scripts": { 32 | "packager:win:1": "electron-packager . --overwrite --platform=win32 --arch=ia32 --out=release-builds", 33 | "packager:win:2": "electron-packager . --overwrite --platform=win32 --arch=ia32 --out=release-builds --icon=./app/assets/icons/win/app.ico", 34 | "packager:win:3": "electron-packager . --overwrite --platform=win32 --arch=ia32 --out=release-builds --icon=./app/assets/icons/win/icon.ico --prune=true --version-string.CompanyName=CE --version-string.FileDescription=CE --version-string.ProductName=\"React Electron Sqlite\"", 35 | "build:dist:1": "electron-builder", 36 | "build:dist:2": "electron-builder --dir", 37 | "build:postinstall": "electron-builder install-app-deps", 38 | "electron": "electron .", 39 | "start": "gulp", 40 | "delete:all": "rm -r ./app", 41 | "postinstall": "install-app-deps", 42 | "build": "gulp build", 43 | "test": "gulp test", 44 | "release": "gulp release" 45 | }, 46 | "eslintConfig": { 47 | "extends": [ 48 | "react-app", 49 | "react-app/jest" 50 | ] 51 | }, 52 | "browserslist": { 53 | "production": [ 54 | ">0.2%", 55 | "not dead", 56 | "not op_mini all" 57 | ], 58 | "development": [ 59 | "last 1 chrome version", 60 | "last 1 firefox version", 61 | "last 1 safari version" 62 | ] 63 | }, 64 | "devDependencies": { 65 | "@babel/core": "^7.12.9", 66 | "@babel/preset-env": "^7.12.7", 67 | "@babel/preset-react": "^7.12.7", 68 | "electron": "^11.0.3", 69 | "electron-builder": "^22.9.1", 70 | "electron-packager": "^15.1.0", 71 | "gulp": "^4.0.2", 72 | "gulp-babel": "^8.0.0", 73 | "gulp-clean-css": "^4.3.0", 74 | "gulp-concat": "^2.6.1" 75 | }, 76 | "build": { 77 | "asar": true, 78 | "extends": null, 79 | "publish": null, 80 | "appId": "com.natancabral.package", 81 | "compression": "maximum", 82 | "productName": "Package Name", 83 | "win": { 84 | "target": [ 85 | "nsis", 86 | "msi" 87 | ], 88 | "icon": "./app/assets/ico/icon.ico" 89 | }, 90 | "nsis": { 91 | "shortcutName": "Package Shortcut Name", 92 | "artifactName": "Setup ${productName} v${version}.${ext}", 93 | "installerIcon": "./app/assets/ico/icon.ico", 94 | "oneClick": true, 95 | "perMachine": true, 96 | "allowElevation": true, 97 | "runAfterFinish": true, 98 | "createDesktopShortcut": true, 99 | "createStartMenuShortcut": true, 100 | "deleteAppDataOnUninstall": true, 101 | "allowToChangeInstallationDirectory": false 102 | }, 103 | "mac": { 104 | "target": [ 105 | "dmg" 106 | ], 107 | "icon": "./app/assets/ico/mac512.icns", 108 | "category": "public.app-category.graphics-design" 109 | }, 110 | "dmg": { 111 | "contents": [ 112 | { 113 | "x": 110, 114 | "y": 150 115 | }, 116 | { 117 | "x": 240, 118 | "y": 150, 119 | "type": "link", 120 | "path": "/Applications" 121 | } 122 | ], 123 | "title": "MAC ${productName} ${version}", 124 | "icon": "./app/assets/ico/mac512.icns" 125 | }, 126 | "linux": { 127 | "target": [ 128 | "deb", 129 | "AppImage" 130 | ], 131 | "category": "Development" 132 | }, 133 | "deb": {}, 134 | "directories": { 135 | "buildResources": "./app", 136 | "output": "dist-certificate-win" 137 | }, 138 | "files": [ 139 | "package.json", 140 | "app/**/*" 141 | ] 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /package-cert.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-js-electron-sqlite3", 3 | "description": "...", 4 | "version": "0.1.0", 5 | "private": true, 6 | "repository": "https://github.com/natancabral/react-js-electron-database.git", 7 | "author": { 8 | "name": "Natan Cabral", 9 | "email": "natancabral@hotmail.com" 10 | }, 11 | "homepage": "https://www.gnnc.com.br", 12 | "dependencies": { 13 | "@babel/plugin-proposal-class-properties": "^7.12.1", 14 | "@testing-library/jest-dom": "^5.11.6", 15 | "@testing-library/react": "^11.2.2", 16 | "@testing-library/user-event": "^12.2.2", 17 | "gulp-cli": "^2.3.0", 18 | "gulp-livereload": "^4.0.2", 19 | "react": "^17.0.1", 20 | "react-dom": "^17.0.1", 21 | "react-scripts": "4.0.1", 22 | "web-vitals": "^0.2.4", 23 | "mysql": "^2.18.1" 24 | }, 25 | "main": "app/main.js", 26 | "scripts": { 27 | "packager:win:1": "electron-packager . --overwrite --platform=win32 --arch=ia32 --out=release-builds", 28 | "packager:win:2": "electron-packager . --overwrite --platform=win32 --arch=ia32 --out=release-builds --icon=./app/assets/ico/icon48.png", 29 | "packager:win:3": "electron-packager . --overwrite --platform=win32 --arch=ia32 --out=release-builds --icon=./app/assets/ico/icon48.png --prune=true --version-string.CompanyName=CE --version-string.FileDescription=CE --version-string.ProductName=\"Cat�logo Valpec\"", 30 | "build:dist:1": "electron-builder", 31 | "build:dist:win": "electron-builder --win", 32 | "build:dist:2": "electron-builder --dir", 33 | "build:dist:all": "electron-builder -mwl", 34 | "build:postinstall": "electron-builder install-app-deps", 35 | "electron": "electron .", 36 | "r": "react-scripts start", 37 | "start": "gulp", 38 | "delete:app": "rm -rf ./app", 39 | "delete:dist": "rm -rf ./dist", 40 | "delete:all": "rm -rf ./app && rm -rf ./dist", 41 | "postinstall": "install-app-deps", 42 | "build": "gulp build", 43 | "test": "gulp test", 44 | "release": "gulp release" 45 | }, 46 | "eslintConfig": { 47 | "extends": [ 48 | "react-app", 49 | "react-app/jest" 50 | ] 51 | }, 52 | "browserslist": { 53 | "production": [ 54 | ">0.2%", 55 | "not dead", 56 | "not op_mini all" 57 | ], 58 | "development": [ 59 | "last 1 chrome version", 60 | "last 1 firefox version", 61 | "last 1 safari version" 62 | ] 63 | }, 64 | "devDependencies": { 65 | "@babel/core": "^7.12.9", 66 | "@babel/preset-env": "^7.12.7", 67 | "@babel/preset-react": "^7.12.7", 68 | "electron": "^11.0.3", 69 | "electron-builder": "^22.9.1", 70 | "electron-packager": "^15.1.0", 71 | "gulp": "^4.0.2", 72 | "gulp-babel": "^8.0.0", 73 | "gulp-clean-css": "^4.3.0", 74 | "gulp-concat": "^2.6.1" 75 | }, 76 | "build-no-used": { 77 | "asarUnpack": "**/assets/*" 78 | }, 79 | "build": { 80 | "asar": true, 81 | "extends": null, 82 | "publish": null, 83 | "appId": "com.natancabral.package", 84 | "compression": "maximum", 85 | "productName": "Package Name", 86 | "win": { 87 | "target": [ 88 | "nsis", 89 | "msi" 90 | ], 91 | "icon": "./app/assets/ico/icon48.ico", 92 | "certificateFile": "./../file.pfx", 93 | "certificatePassword": "password", 94 | "legalTrademarks": "(c) 2020 gnnc.com.br" 95 | }, 96 | "nsis": { 97 | "shortcutName": "Package Shortcut Name", 98 | "artifactName": "Setup ${productName} v${version}.${ext}", 99 | "installerIcon": "./app/assets/ico/icon48.ico", 100 | "oneClick": true, 101 | "perMachine": true, 102 | "allowElevation": true, 103 | "runAfterFinish": true, 104 | "createDesktopShortcut": true, 105 | "createStartMenuShortcut": true, 106 | "deleteAppDataOnUninstall": true, 107 | "allowToChangeInstallationDirectory": false 108 | }, 109 | "mac": { 110 | "target": [ 111 | "dmg" 112 | ], 113 | "icon": "./app/assets/ico/mac512.icns", 114 | "category": "public.app-category.graphics-design" 115 | }, 116 | "dmg": { 117 | "contents": [ 118 | { 119 | "x": 110, 120 | "y": 150 121 | }, 122 | { 123 | "x": 240, 124 | "y": 150, 125 | "type": "link", 126 | "path": "/Applications" 127 | } 128 | ], 129 | "title": "MAC ${productName} ${version}", 130 | "icon": "./app/assets/ico/mac512.icns" 131 | }, 132 | "linux": { 133 | "target": [ 134 | "deb", 135 | "AppImage" 136 | ], 137 | "category": "Development" 138 | }, 139 | "deb": {}, 140 | "directories": { 141 | "buildResources": "./app", 142 | "output": "dist-certificate-win" 143 | }, 144 | "files": [ 145 | "package.json", 146 | "app/**/*" 147 | ] 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React-js + Electron + Database 2 | #### Clone this project 3 | ```bash 4 | git clone https://github.com/natancabral/react-js-electron-database.git react-js-electron-database 5 | cd react-js-electron-database 6 | npm install 7 | npm audit fix 8 | npm run start 9 | ``` 10 | #### Make yourself 11 | * Create project 12 | * Begin with: [React](#begin-with-react) 13 | * Begin with: [Electron](#begin-with-electron) 14 | * Run React 15 | * Working with: [Babel](#working-with-babel) | read: [css-error](#css-error) 16 | * Working with: [Concurrently + Wait-on](#working-with-wait-on-and-concurrently) (need nodejs installed to run) 17 | * Database 18 | * [MySql](#mysql) 19 | * Sqlite3 (todo) 20 | * [AppTray Window](#apptray-window) 21 | * Tray + NativeImage (todo) 22 | * Packaging App 23 | * [Electron Builder](#electron-builder) 24 | * [Electron Packager](#electron-packager) 25 | * Update (npm audit fix, npm update) 26 | * [Kill Process](#kill-process-port3000) 27 | * [Test](#test) 28 | * [Error](#error) 29 | 30 | ---- 31 | # Create Project 32 | ## Begin with: React 33 | 38 | First option begin with React 39 | #### Create project and install React 40 | ```bash 41 | # you need node.js 42 | $ npx create-react-app react-js-electron-sqlite 43 | $ cd react-js-electron-sqlite 44 | ``` 45 | #### Install Electron 46 | ```bash 47 | # need sudo 48 | $ npm install electron --save-dev 49 | ``` 50 | #### Update package.json file 51 | * en: Open **package.json** file add insert above "scripts" 52 | > "main": "main.js", 53 | * en: Insert inside "scripts" 54 | > "electron": "electron .", 55 | 56 | #### Create main.js file 57 | * en: Copy this script: 58 | ```js 59 | const { app, BrowserWindow } = require('electron') 60 | const path = require('path') 61 | //const url = require('url') 62 | 63 | function createWindow () { 64 | const win = new BrowserWindow({ 65 | width: 800, 66 | height: 600, 67 | webPreferences: { 68 | //webSecurity: false, 69 | //allowRunningInsecureContent: true, 70 | //preload: path.join(__dirname, 'preload.js') 71 | nodeIntegration: true 72 | } 73 | }) 74 | 75 | win.loadFile('src/index.html') 76 | //win.loadURL('http://127.0.0.1:3000') 77 | //win.webContents.openDevTools() 78 | } 79 | 80 | app.whenReady().then(createWindow) 81 | 82 | app.on('window-all-closed', () => { 83 | if (process.platform !== 'darwin') { 84 | app.quit() 85 | } 86 | }) 87 | 88 | app.on('activate', () => { 89 | if (BrowserWindow.getAllWindows().length === 0) { 90 | createWindow() 91 | } 92 | }) 93 | ``` 94 | 95 | #### /src/index.html file 96 | I will create a **src/** folder and **index.html** file: 97 | ```html 98 | 99 | 100 | 101 | 102 | 103 | React-js + Electron + Sqlite3 104 | 105 | 106 |

React-js + Electron + Sqlite3

107 | 108 |
109 |
110 | 111 | 112 | 113 | ``` 114 | #### Install react react-dom 115 | ```bash 116 | # need sudo 117 | $ npm install react react-dom 118 | ``` 119 | #### Done! 120 | ```bash 121 | $ npm run electron 122 | ``` 123 | ## Begin with: Electron 124 | Second option begin with Electron 125 | #### Clone electron-quick-start project 126 | ```bash 127 | # you need node.js 128 | $ git clone https://github.com/electron/electron-quick-start react-js-electron-sqlite 129 | $ cd react-js-electron-sqlite 130 | $ npm install 131 | $ npm start 132 | ``` 133 | #### Install react react-dom 134 | ```bash 135 | $ npm install react react-dom 136 | ``` 137 | #### Files 138 | * I will create a **src/** folder 139 | * and move to inside **index.html** and **renderer.js**, 140 | * renamed as **renderer.js** to **index.js**. 141 | * I will create an **index.css** and link it to the html. Finally, add an **app** container div. 142 | * Replace **index.html** file: 143 | ```html 144 | 145 | 146 | 147 | 148 | 149 | React-js + Electron + Sqlite3 150 | 151 | 152 |

React-js + Electron + Sqlite3

153 | 154 |
155 |
156 | 157 | 158 | 159 | ``` 160 | #### Change main.js file 161 | With a small change to **main.js** so that it points to the correct file: 162 | ```js 163 | .loadFile(path.join(__dirname, 'src', 'index.html')) 164 | ``` 165 | and **preload.js** to **index.js** 166 | ```js 167 | webPreferences: { 168 | preload: path.join(__dirname, 'src', 'index.js') 169 | } 170 | ``` 171 | #### index.js 172 | ```js 173 | import React from 'react'; 174 | import ReactDOM from 'react-dom'; 175 | //import App from './App.js'; // <-- App / begin React 176 | import App from './app.js'; // <-- app / begin Electron 177 | 178 | window.onload = () => { 179 | ReactDOM.render(, document.getElementById('app')); 180 | }; 181 | ``` 182 | ---- 183 | # Run React 184 | 185 | ## Working with: Babel 186 | Transpiling ES6 with Babel 7. 187 | #### Install Babel + Preset 188 | ```bash 189 | $ npm i @babel/core --save-dev # this will install babel 7.0 190 | $ npm i @babel/preset-env @babel/preset-react --save-dev 191 | $ npm i @babel/plugin-proposal-class-properties 192 | ``` 193 | #### Create .babelrc file 194 | When it runs, it looks for its configuration in a file named .babelrc, so create in on the root and add: 195 | ```json 196 | { 197 | "presets": ["@babel/preset-env", "@babel/preset-react"], 198 | "plugins": ["@babel/plugin-proposal-class-properties"] 199 | } 200 | ``` 201 | #### Install Gulp 202 | Babel needs to run before any code executes and the best way schedule that is through a build tool 203 | ```bash 204 | $ npm i gulp gulp-babel --save-dev # basic gulp 205 | $ npm i gulp-concat gulp-clean-css --save-dev # plugins 206 | $ npm i gulp-livereload 207 | # need root/admin 208 | $ npm i -g gulp-cli # best sudo 209 | ``` 210 | #### Create gulpfile.js file 211 | Create a gulpfile.js at the root of your project and add the tasks 212 | ```js 213 | const exec = require('child_process').exec; 214 | const gulp = require('gulp'); 215 | const babel = require('gulp-babel'); 216 | const css = require('gulp-clean-css'); 217 | const livereload = require('gulp-livereload'); 218 | //1. Compile HTML file and move them to the app folder 219 | gulp.task('html', () => { 220 | return gulp.src('src/index.html') 221 | .pipe(gulp.dest('app/')) 222 | .pipe(livereload()); 223 | }); 224 | 225 | //2. Compile CSS file and move them to the app folder 226 | gulp.task('css', () => { 227 | return gulp.src('src/**/*.css') 228 | .pipe(css()) 229 | .pipe(gulp.dest('app/')) 230 | .pipe(livereload()); 231 | }); 232 | 233 | //3. Compile JS and JSX files and move them to the app folder 234 | gulp.task('js*', () => { 235 | return gulp.src(['main*.js', 'src/**/*.js*']) 236 | .pipe(babel()) 237 | .pipe(gulp.dest('app/')) 238 | .pipe(livereload()); 239 | }); 240 | 241 | //4. Compile IMAGES file and move them to the app folder 242 | // ------------------------------------------------------------------------------------ All images inside ./assets/ 243 | gulp.task('images', () => { 244 | return gulp.src('src/assets/**/*') 245 | .pipe(gulp.dest('app/assets')) 246 | .pipe(livereload()); 247 | }) 248 | 249 | //5. Watch files 250 | gulp.task('watch', async function() { 251 | livereload.listen(); 252 | gulp.watch('src/**/*.html', gulp.series('html')); 253 | gulp.watch('src/**/*.css', gulp.series('css')); 254 | gulp.watch('src/**/*.js*', gulp.series('js*')); 255 | gulp.watch('src/assets/**/*', gulp.series('images')); 256 | }); 257 | 258 | //6. Send to app folder 259 | gulp.task('build', gulp.series('html', 'css', 'js*', 'images')); 260 | 261 | //7. Start the electron process. 262 | gulp.task('start', gulp.series('build', () => { 263 | return exec( 264 | __dirname+'/node_modules/.bin/electron .' 265 | ).on('close', () => process.exit()); 266 | })); 267 | 268 | //0. Default process. 269 | gulp.task('default', gulp.parallel('start', 'watch')); 270 | 271 | ``` 272 | #### Edit package.json file 273 | Insert/change this: 274 | ```json 275 | "main": "app/main.js", 276 | ``` 277 | And this: 278 | ```json 279 | "scripts": { 280 | "electron": "electron .", 281 | "dev": "react-scripts start", 282 | "start": "gulp", 283 | "delete:all": "rm -r ./app", 284 | "postinstall": "install-app-deps", 285 | "build": "gulp build", 286 | "test": "gulp test", 287 | "release": "gulp release" 288 | } 289 | ``` 290 | #### Edit main.js file 291 | Insert/change this: 292 | ```js 293 | // find .loadFile( 294 | // change to 295 | .loadFile(path.join(__dirname, 'app', 'index.html')) 296 | // or 297 | .loadFile('app/index.html') 298 | ``` 299 | 300 | #### CSS error 301 | Babel cant import css files in js or jsx. 302 | > **import './style.css'** show error 303 | 304 | You need load css files inside react-context or index.html file. 305 | 306 | #### Run 307 | ```bash 308 | $ npm run-script start 309 | # or 310 | $ npm run start 311 | ``` 312 | 313 | ---- 314 | ## Working with: Wait-on and Concurrently 315 | 316 | #### Install Wait-on 317 | * en: [Wait-on](https://www.npmjs.com/package/wait-on) is a cross-platform command line utility which will wait for files, ports, sockets, and http(s) resources to become available (or not available using reverse mode). Functionality is also available via a Node.js API. Cross-platform - runs everywhere Node.js runs (linux, unix, mac OS X, windows) 318 | ```node 319 | $ npm install wait-on 320 | ``` 321 | #### Install Concurrently 322 | * en: Run multiple commands [concurrently](https://www.npmjs.com/package/concurrently) 323 | ```bash 324 | $ npm install concurrently 325 | ``` 326 | #### Run Wait-on + Concurrently 327 | * en: Insert inside "scripts" 328 | ```json 329 | "electron-react": "concurrently \"BROWSER=none npm start\" \"wait-on http://localhost:3000 && electron .\"", 330 | ``` 331 | ---- 332 | #### main.js 333 | * en: Remember change this: (file) 334 | > .loadFile('index.html') 335 | * en: To this: (url) 336 | > .loadURL('http://127.0.0.1:3000') 337 | 338 | #### Run app 339 | ```bash 340 | $ npm run-script electron-react 341 | ``` 342 | #### Done! 343 | Welcome React-Electron project! 344 | 345 | ---- 346 | # Database 347 | 348 | ## MySql 349 | 350 | Install package mysql 351 | ```bash 352 | $ npm install mysql 353 | ``` 354 | 355 | Import package mysql on component file: 356 | ```js 357 | import mysql from 'mysql'; 358 | ``` 359 | 360 | inside same component file: 361 | ```js 362 | 363 | // set connection variable 364 | const [conn,setConn] = React.useState(undefined); 365 | 366 | // function connection mysql remote 367 | const connection = () => { 368 | let c = mysql.createConnection({ 369 | //host : '888.88.88.88', //:3306 370 | host : 'localhost', 371 | user : 'root', 372 | password : '', 373 | database : 'databasename' 374 | }); 375 | c.connect((err) => { 376 | // in case of error 377 | if(err){ 378 | alert( err.code ); 379 | return console.log(err.code, err.fatal, err.stack); 380 | } 381 | return console.log('Connection successfully established'); 382 | }); 383 | setConn(c); 384 | } 385 | 386 | // function query/search 387 | const query = () => { 388 | let sql = 'SELECT `name`,`id` FROM `tablename` where id > 0 limit 0,50 '; 389 | conn.query(sql, function (err, results, fields) { 390 | if (err) { 391 | alert(err.code); 392 | console.log(err.code); 393 | } 394 | else { 395 | alert(results); 396 | console.log(results); 397 | if(results.length) 398 | alert(results[0].id + results[0].name); 399 | } 400 | }); 401 | 402 | // Close the connection 403 | conn.end(function(){ 404 | // The connection has been closed 405 | console.log('Connection successfully closed'); 406 | }); 407 | } 408 | ``` 409 | 410 | Insert call buttons HTML/React/JSX: 411 | ```html 412 | 413 | 414 | ``` 415 | 416 | 417 | 418 | ## Sqlite3 419 | 420 | 423 | 487 | 488 | ---- 489 | # AppTray Window 490 | 491 | ## Tray + NativeImage 492 | * en: I will create a **main-tray.js** file: 493 | ```js 494 | const {app, BrowserWindow, Tray, nativeImage, screen } = require('electron') 495 | const path = require('path') 496 | 497 | let mainWindow = undefined;; 498 | let tray = undefined; 499 | //app.dock.hide(); 500 | 501 | function createWindow () { 502 | // Create the browser window. 503 | mainWindow = new BrowserWindow({ 504 | width: 300, 505 | height: 600, 506 | //-----tray----- start 507 | show: true, //set this false 508 | frame: false, 509 | fullscreen: false, 510 | resizable: false, 511 | transparent: false, 512 | //-----tray----- end 513 | webPreferences: { 514 | backgroundThrottling: false 515 | } 516 | }) 517 | 518 | // mainWindow.loadFile('index.html') 519 | mainWindow.loadFile(path.join(__dirname, 'index.html')) 520 | // Open the DevTools. 521 | // mainWindow.webContents.openDevTools() 522 | 523 | //-----tray----- start 524 | mainWindow.on('closed',()=>mainWindow = null) 525 | // Hide the window when it loses focus 526 | mainWindow.on('blur', () => { 527 | // if (!mainWindow.webContents.isDevToolsOpened()) { 528 | // mainWindow.hide(); 529 | // } 530 | }); 531 | //-----tray----- end 532 | } 533 | 534 | //-----tray----- start 535 | const createTray = () => { 536 | const icon = path.join(__dirname, 'app', 'assets', 'tray.png') 537 | const nimage = nativeImage.createFromPath(icon) 538 | //tray is a app variable 539 | tray = new Tray(nimage) 540 | tray.on('click', (event)=>toggleWindow()) 541 | } 542 | 543 | const toggleWindow = () => { 544 | mainWindow.isVisible() ? mainWindow.hide() : showWindow(); 545 | } 546 | 547 | const showWindow = () => { 548 | const position = getWindowPosition(); 549 | mainWindow.setPosition(position.x,position.y, false); 550 | mainWindow.show(); 551 | } 552 | 553 | const getWindowPosition = () => { 554 | 555 | //console.log(process.platform); 556 | //'aix' 557 | //'darwin' 558 | //'freebsd' 559 | //'linux' 560 | //'openbsd' 561 | //'sunos' 562 | //'win32' 563 | 564 | const { screenWidth, screenHeight } = screen.getPrimaryDisplay().workAreaSize; 565 | const windowBounds = mainWindow.getBounds(); 566 | const trayBounds = tray.getBounds(); 567 | // Center window horizontally below the tray icon 568 | const x = Math.round(trayBounds.x + (trayBounds.width / 2) - (windowBounds.width / 2)); 569 | let y = undefined; 570 | // Position window 4 pixels vertically below the tray icon 571 | if(process.platform == 'win32') 572 | y = Math.round(trayBounds.y - windowBounds.height); 573 | else 574 | y = Math.round(trayBounds.y + trayBounds.height + 4); 575 | 576 | return {x,y} 577 | } 578 | //-----tray----- end 579 | 580 | // This method will be called when Electron has finished 581 | // initialization and is ready to create browser windows. 582 | // Some APIs can only be used after this event occurs. 583 | app.whenReady().then(() => { 584 | //-----tray----- start 585 | createTray() 586 | //-----tray----- end 587 | createWindow() 588 | 589 | app.on('activate', function () { 590 | // On macOS it's common to re-create a window in the app when the 591 | // dock icon is clicked and there are no other windows open. 592 | if (BrowserWindow.getAllWindows().length === 0) createWindow() 593 | }) 594 | }) 595 | 596 | // Quit when all windows are closed, except on macOS. There, it's common 597 | // for applications and their menu bar to stay active until the user quits 598 | // explicitly with Cmd + Q. 599 | app.on('window-all-closed', function () { 600 | if (process.platform !== 'darwin') app.quit() 601 | }) 602 | 603 | // In this file you can include the rest of your app's specific main process 604 | // code. You can also put them in separate files and require them here. 605 | ``` 606 | #### Edit package.json file 607 | Insert/change this: 608 | ```json 609 | "main": "app/main-tray.js", 610 | ``` 611 | * [sample1](main-tray.js) 612 | * [sample2](main-tray-two-windows.js) 613 | ---- 614 | # Packaging App 615 | 616 | ## Electron Builder 617 | * en: There are mainly two options for packaging an Electron app and we will go with the second, [Electron Builder](https://www.npmjs.com/package/electron-builder/) (the other being Electron Packager). 618 | ```bash 619 | $ npm i electron-builder --save-dev 620 | ``` 621 | We need to point the tool to the folder with the code to be compiled through the **package.json** by adding: 622 | ```json 623 | "build": { 624 | "asar": true, 625 | "extends": null, 626 | "publish": null, 627 | "appId": "com.natancabral.react-js-electron-sqlite3", 628 | "compression": "maximum", 629 | "productName": "File Name App", 630 | "nsis": { 631 | "shortcutName": "App Name Shortcut", 632 | "installerIcon": "./app/assets/ico/icon48.ico", 633 | "oneClick": true, 634 | "perMachine": true, 635 | "allowElevation": true, 636 | "runAfterFinish": true, 637 | "createDesktopShortcut": true, 638 | "createStartMenuShortcut": true, 639 | "allowToChangeInstallationDirectory": false 640 | }, 641 | "win": { 642 | "target": "nsis", 643 | "icon": "./app/assets/ico/icon48.ico" 644 | }, 645 | "directories": { 646 | "buildResources": "./app", 647 | "output": "dist" 648 | }, 649 | "files": [ 650 | "package.json", 651 | "app/**/*" 652 | ] 653 | } 654 | ``` 655 | And inside scritps. 656 | ```json 657 | "scripts": { 658 | ... 659 | "build:dist:1": "electron-builder", 660 | "build:dist:2": "electron-builder --dir", 661 | "build:postinstall": "electron-builder install-app-deps", 662 | } 663 | ``` 664 | Plus info. 665 | ```json 666 | "version": "1.0.0" 667 | "author": "", 668 | "description": "", 669 | "license": "", 670 | "private": true, 671 | ``` 672 | 673 | ## Electron Packager 674 | * en: Install [electron-packager](https://github.com/electron/electron-packager/) 675 | ```bash 676 | $ npm install electron-packager --save-dev 677 | ``` 678 | #### Shotcut to create App 679 | * en: Open **package.json** and insert inside on scripts: 680 | ```json 681 | "scripts": { 682 | ... 683 | "packager:win:1": "electron-packager . --overwrite --platform=win32 --arch=ia32 --out=release-builds", 684 | "packager:win:2": "electron-packager . --overwrite --platform=win32 --arch=ia32 --out=release-builds --icon=./app/assets/icons/win/app.ico", 685 | "packager:win:3": "electron-packager . --overwrite --platform=win32 --arch=ia32 --out=release-builds --icon=./app/assets/icons/win/icon.ico --prune=true --version-string.CompanyName=CE --version-string.FileDescription=CE --version-string.ProductName=\"React Electron Sqlite\"", 686 | 687 | "packager:mac:1": "electron-packager . --overwrite --platform=darwin --arch=x64 --out=release-builds", 688 | "packager:mac:2": "electron-packager . --overwrite --platform=darwin --arch=x64 --out=release-builds --icon=./app/assets/icons/mac/icon.icns --prune=true", 689 | "packager:mac:3": "electron-packager . --overwrite --platform=darwin --arch=x64 --out=release-builds --icon=./app/assets/icons/mac/app.icns --osx-sign.identity='React Electron Sqlite' --extend-info=assets/mac/info.plist", 690 | 691 | "packager:linux:1": "electron-packager . --overwrite --platform=linux --arch=x64 --out=release-builds", 692 | "packager:linux:2": "electron-packager . --overwrite --platform=linux --arch=x64 --out=release-builds --icon=./app/assets/icons/png/1024x1024.png --prune=true", 693 | 694 | "packager:sign-exe": "signcode './release-builds/Electron API Demos-win32-ia32/Electron API Demos.exe' --cert ~/electron-api-demos.p12 --prompt --name 'React Electron Sqlite' --url 'http://electron.atom.io'", 695 | "packager:installer": "node ./script/installer.js", 696 | "packager:sign-installer": "signcode './release-builds/windows-installer/ElectronAPIDemosSetup.exe' --cert ~/electron-api-demos.p12 --prompt --name 'React Electron Sqlite' --url 'http://electron.atom.io'", 697 | ... 698 | } 699 | ``` 700 | #### Create binary app 701 | ```bash 702 | $ npm run packager:win:1 703 | $ npm run packager:mac:1 704 | $ npm run packager:linux:1 705 | ``` 706 | ---- 707 | # Others 708 | 709 | ## Kill Process port:3000 710 | #### Install find-process to close server x.x.x.x:3000 711 | * en: Install find-process 712 | ```bash 713 | $ npm install find-process 714 | ``` 715 | * en: main.js 716 | ```js 717 | const find = require('find-process'); 718 | 719 | app.on('before-quit', (e) => { 720 | find('port', 3000) 721 | .then(function (list) { 722 | if (list[0] != null) { 723 | console.log('---kill---:', list[0].pid); 724 | process.kill(list[0].pid, 'SIGHUP'); 725 | } 726 | }) 727 | .catch((e) => { 728 | console.log('---error---',e.stack || e); 729 | }); 730 | }); 731 | ``` 732 | ## Test 733 | #### Jest test 734 | ```bash 735 | $ npm i jest 736 | $ npm i babel-jest 737 | ``` 738 | #### React test renderer 739 | ```bash 740 | $ npm i react-test-renderer 741 | ``` 742 | ## Error 743 | * Error: EACCES: permission denied, mkdir '/usr/local/lib/node_modules/electron/.electron' [issues](https://github.com/npm/npm/issues/17268) 744 | ```bash 745 | $ sudo npm install -g electron --unsafe-perm=true --allow-root 746 | ``` 747 | * Cant remove or update global create-react-app version. 748 | ```bash 749 | $ sudo rm -rf /usr/local/bin/create-react-app 750 | ``` 751 | * Update babel 752 | ```bash 753 | $ sudo npm install --save-dev @babel/core @babel/cli 754 | $ sudo npx babel-upgrade --write --install # --install optional 755 | ``` 756 | * Danger: Permission denied 757 | ```bash 758 | $ sudo npm install ... --unsafe-perm=true --allow-root # danger 759 | ``` 760 | * Gtk-Message: hh:mm:ss.mls: Failed to load module "canberra-gtk-module" 761 | ```bash 762 | $ sudo apt-get install libcanberra-gtk-module 763 | ``` 764 | 765 |