VUE2 + Electron + Flask -> Python not spawning on build - vue.js

I've just finished my first vue+electron+flask project and I am having quite a hard time trying to package it. Everything is workig "perfectly" when using "npm run electron:serve" but when running "npm run electron:build" I do not get any error, but Flask is not launched at all. I do not really know how to fix the problem, my guess is that when building the dist folder the path to app.py is not correct, but I tried to fix it without luck.
Here is the background.js code:
'use strict'
import { app, protocol, BrowserWindow } from 'electron'
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'
import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'
const isDevelopment = process.env.NODE_ENV !== 'production'
// Scheme must be registered before the app is ready
protocol.registerSchemesAsPrivileged([
{ scheme: 'app', privileges: { secure: true, standard: true } }
])
async function createWindow() {
// spawn flask app (https://medium.com/red-buffer/integrating-python-flask-backend-with-electron-nodejs-frontend-8ac621d13f72)
var python = require('child_process').spawn('py', ['../server/app.py']);
python.stdout.on('data', function (data) {
console.log("data: ", data.toString('utf8'));
});
python.stderr.on('data', (data) => {
console.log(`stderr: ${data}`); // when error
});
// Create the browser window.
const win = new BrowserWindow({
width: 1500,
height: 1200,
webPreferences: {
// Use pluginOptions.nodeIntegration, leave this alone
// See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION
}
})
if (process.env.WEBPACK_DEV_SERVER_URL) {
// Load the url of the dev server if in development mode
await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
if (!process.env.IS_TEST) win.webContents.openDevTools()
} else {
createProtocol('app')
// Load the index.html when not in development
win.loadURL('app://./index.html')
}
}
// Quit when all windows are closed.
app.on('window-all-closed', () => {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', async () => {
if (isDevelopment && !process.env.IS_TEST) {
// Install Vue Devtools
try {
await installExtension(VUEJS_DEVTOOLS)
} catch (e) {
console.error('Vue Devtools failed to install:', e.toString())
}
}
createWindow()
})
// Exit cleanly on request from parent process in development mode.
if (isDevelopment) {
if (process.platform === 'win32') {
process.on('message', (data) => {
if (data === 'graceful-exit') {
app.quit()
}
})
} else {
process.on('SIGTERM', () => {
app.quit()
})
}
}
The relevant part of the code calling app.py is the following:
async function createWindow() {
// spawn flask app (https://medium.com/red-buffer/integrating-python-flask-backend-with-electron-nodejs-frontend-8ac621d13f72)
var python = require('child_process').spawn('py', ['../server/app.py']);
python.stdout.on('data', function (data) {
console.log("data: ", data.toString('utf8'));
});
python.stderr.on('data', (data) => {
console.log(`stderr: ${data}`); // when error
});
// Create the browser window.
const win = new BrowserWindow({
width: 1500,
height: 1200,
webPreferences: {
// Use pluginOptions.nodeIntegration, leave this alone
// See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION
}
})
I tried to put 3 dots insted of 2 in the app.py path ['.../server/app.py] just in case when creating the dist folder I need this extra dot to find the app.py file, but this is not working either.
My folder structure is the follwing:
Vue-Electron
client
dist_electron
node_modules
public
src
assets
components
router
views
App.vue
background.js
main.js
other config files
server
data
env
app.py
requirements.txt
other python scripts imported to app.py
sqlite_portofolio.db
As this program will only be used by me in my personal pc, I did not want to bother using pyInstaller (I thought it would be easier to not package the python side, but if I am wrong please let me know). I would like to have a electron .exe file that I can just doble click to open the electron build and then spawn the Flask server.
Also, my feeling is that I am not killing the Flask server correctly when closing the app. I think Flask is still running when closing electron. What should I do to ensure Flask server is properly closed.
There is not a lot of information of those topics that I can follow. Any help will be aprreaciated.

I´m having the same problem. I followed the link to this article (https://medium.com/red-buffer/integrating-python-flask-backend-with-electron-nodejs-frontend-8ac621d13f72), and it has the answer about killing the python flask server. And if you follow everything the article says, it's supposed to run the backend when opening the electron.exe, but this is not happening here on my end.
EDIT: I found the error, you need to change the path on your spawn. I sugest you to run the electron.exe on the cmd so you can see the error on it, so you will see the path that spawn is trying to run.
it´s probably:
var python = require('child_process').spawn('py', ['../resources/app/server/app.py']);
you will need to acess the app.py through [resources/app] as spawn start at the base dir of the electron build.
PS: I used electron-packeger that´s why mine need to add resources/app, and I used pyinstaller on my backend
Hope it will help you.

Related

How to configure Detox lifecycle hooks in the latest version?

I run detox in version 17.13.2 with jest-circus as the test runner. My main problem is the app is not reset either after or before I run the tests which leads to an inconsistent state of the app.
My test file:
import { by, device, element, expect, waitFor } from "detox"
describe("Login", () => {
beforeEach(async () => {
await device.reloadReactNative()
})
it("should login with correct data", async () => {
await element(by.id("login_email_input")).typeText("ch.tietz#gmail.com")
await element(by.id("login_password_input")).typeText("12345678")
await element(by.id("login_submit_button")).tap()
await waitFor(element(by.id("workout_screen"))).toBeVisible()
// additional test steps
})
})
Now if the login actually works but the test fails at one of the subsequent steps, the state of the app user will still be "logged in".
From what I understand, it's not possible to actually alter the app state, e.g. by clearing the AsyncStorage or interacting directly with the state mgmt tool. Instead, it's recommended to just reinstall the app - but this is exactly where I am struggling.
I have tried numerous approaches and none of them worked. What makes it really hard to understand configuration is that detox completely changed how the configuration works and switched to jest-circus as the main test runner.
My setup is basically the one created by jest init -r jest. From what I understand, this already includes some defaults for detox.init() and detox.cleanup():
{
"detox": {
"behavior": {
"init": {
"reinstallApp": true,
"launchApp": true,
"exposeGlobals": true
},
"cleanup": {
"shutdownDevice": false
}
}
}
}
However, this does not seem to be sufficient to actually wipe the app state after running the tests.
I tried working with an init script as setupFilesAfterEnv, which would call cleanup() after the test suite is run. Actually that works in an older project which still uses jasmine 2 as test runner.
import { cleanup, init } from 'detox';
const adapter = require('detox/runners/jest/adapter');
const specReporter = require('detox/runners/jest/specReporter');
const config = require('../package.json').detox;
// Set the default timeout
jest.setTimeout(120000);
jasmine.getEnv().addReporter(adapter);
// This takes care of generating status logs on a per-spec basis. By default, jest only reports at file-level.
// This is strictly optional.
jasmine.getEnv().addReporter(specReporter);
beforeAll(async () => {
await init(config, { launchApp: false });
}, 300000);
beforeEach(async () => {
await adapter.beforeEach();
});
afterAll(async () => {
await adapter.afterAll();
await cleanup();
});
First off, it complains that jasmine is not defined. I guess that's because actually the adapter in this case should be a DetoxAdapterCircus which it is not, even though in my config file I specify:
{
"preset": "react-native",
"testEnvironment": "./environment.ts",
"testRunner": "jest-circus/runner",
"testTimeout": 120000,
"testRegex": "\\.e2e\\.ts$",
"reporters": ["detox/runners/jest/streamlineReporter"],
"verbose": true
}
"testRunner": "jest-circus/runner"
Another idea would be to alter the CustomDetoxEnvironment but I do not understand how I can get access to the detox lifecycle hooks.
const {
DetoxCircusEnvironment,
SpecReporter,
WorkerAssignReporter,
} = require("detox/runners/jest-circus")
class CustomDetoxEnvironment extends DetoxCircusEnvironment {
constructor(config) {
super(config)
// should I access the hooks here now?
// This takes care of generating status logs on a per-spec basis. By default, Jest only reports at file-level.
// This is strictly optional.
this.registerListeners({
SpecReporter,
WorkerAssignReporter,
})
}
}
module.exports = CustomDetoxEnvironment
Tl;dr: I don't know where to put my reusable lifecycle hooks in the latest version of Detox. Also, I wonder if these custom configurations are even needed to reinstall the app and wipe the app data before each test suite.
You can still use setupFilesAfterEnv, but you're not supposed to call the same hooks/cleanup as before (see https://github.com/wix/Detox/issues/2410#issuecomment-744387707).
here's an example of our init script:
// init.ts
// with "setupFilesAfterEnv": ["./init.ts"] in the conf
beforeAll(async () => {
// to reset the state
await device.clearKeychain();
// we are launching the app manually
await device.launchApp({
permissions: { notifications: 'YES', location: 'inuse' },
});
await device.setURLBlacklist([
// ...
]);
});

Nuxt end to end testing with jest

Hello im searching for a way to use component testing as well as end to end testing with nuxt.
we want to be able to test components (which already works) and also check if pages parse their url parameters correctly or sitemaps are correctly created and other page level features and router functions
i tried ava but we already implemented the component testing with jest which works fine now and in the nuxt docs the server rendering for testing was described with ava and i adapted that to jest now but i get timeout errors so i increased the time out to 40 seconds but still get a timeout.
did anybody get the testing to work with the nuxt builder like in the example (https://nuxtjs.org/guide/development-tools)?
this is my end to end test example file
// test.spec.js:
const { resolve } = require('path')
const { Nuxt, Builder } = require('nuxt')
// We keep the nuxt and server instance
// So we can close them at the end of the test
let nuxt = null
// Init Nuxt.js and create a server listening on localhost:4000
beforeAll(async (done) => {
jest.setTimeout(40000)
const config = {
dev: false,
rootDir: resolve(__dirname, '../..'),
telemetry: false,
}
nuxt = new Nuxt(config)
try {
await new Builder(nuxt).build()
nuxt.server.listen(4000, 'localhost')
} catch (e) {
console.log(e)
}
done()
}, 30000)
describe('testing nuxt', () => {
// Example of testing only generated html
test('Route / exits and render HTML', async (t, done) => {
const context = {}
const { html } = await nuxt.server.renderRoute('/', context)
t.true(html.includes('<h1 class="red">Hello world!</h1>'))
jest.setTimeout(30000)
done()
})
})
// Close server and ask nuxt to stop listening to file changes
afterAll((t) => {
nuxt.close()
})
my current error is :
● Test suite failed to run
Timeout - Async callback was not invoked within the 40000ms timeout specified by jest.setTimeout.Error: Timeout - Async callback was not invoked within the 40000ms timeout specified by jest.setTimeout.
any info is very appreciated as i could not resolve this issue myself

Electron with Vue disable auto reload

I install Electron with Vue using this tutorial.
I looking for answer how I can disable auto reload ?
I start my application using npm run dev, when I change somethink in code Electron run auto reload (refreshes and compiles the application again
). I would like to refresh the application myself after writing a part of the code.
I don't use Webpack.
Yes, I know I can disable auto save in Visual Studio Code, but this is not a solution.
Disable on Main and Renderer processes
Remove the call of startElectron() in dev-runner.js > startMain().
function startMain () {
return new Promise((resolve, reject) => {
mainConfig.entry.main = [path.join(__dirname, '../src/main/index.dev.js')].concat(mainConfig.entry.main)
mainConfig.mode = 'development'
const compiler = webpack(mainConfig)
compiler.hooks.watchRun.tapAsync('watch-run', (compilation, done) => {
//Remove these lines and ...
// logStats('Main', chalk.white.bold('compiling...'))
// hotMiddleware.publish({ action: 'compiling' })
done()
})
compiler.watch({}, (err, stats) => {
if (err) {
console.log(err)
return
}
//... these lines.
// logStats('Main', stats)
//
// if (electronProcess && electronProcess.kill) {
// manualRestart = true
// process.kill(electronProcess.pid)
// electronProcess = null
// startElectron()
//
// setTimeout(() => {
// manualRestart = false
// }, 5000)
// }
resolve()
})
})
}
Disable only on Renderer process
Delete import line below from src/main/index.js.
import '../renderer/store';
This line is required by vuex-electron which makes vuex to run on main process. If you are not planning to use createPersistedState() or createSharedMutations(), you can delete this.

Preload / Pre-populate PouchDB in React Native Application

Is it possible to preload / pre-populate a database in my React Native application and then the first time it is run, simply do a sync? I already have most, if not all of the database information before the app is distributed, it would be awesome if it just had to do a quick sync when the app is run. Any ideas how I would go about doing that?
I found this - https://pouchdb.com/2016/04/28/prebuilt-databases-with-pouchdb.html but it doesn't mention React Native
Using:
pouchdb-find: ^7.0.0
pouchdb-react-native: ^6.4.1
react: 16.3.1
react-moment: ^0.7.9
react-native: ~0.55.2
Thanks for any pointers.
Update Here is the code I'm using to try the loading of a dump file. This code exists in /screens/Home.js
The dump file is located in /client/dbfile/database.txt
var db = new PouchDB("cs1");
db.get("_local/initial_load_complete")
.catch(function(err) {
console.log("loading dumpfile");
if (err.status !== 404) {
// 404 means not found
throw err;
}
db.load("/client/dbfile/database.txt").then(function() {
return db.put({ _id: "_local/initial_load_complete" });
});
})
.then(function() {
// at this point, we are sure that
// initial replication is complete
console.log("loading is complete!");
return db.allDocs({ include_docs: true });
})
.then(
function(res) {
// display all docs for debugging purposes (empty)
console.log(res);
});
this.localDB = db;
When this runs my console displays this - showing there have been 0 rows added.
Object {
"offset": 0,
"rows": Array [],
"total_rows": 0,
}
Possible Unhandled Promise Rejection (id: 0):
Object {
"message": undefined,
"name": "unknown",
"status": 0,
}
In my project I have couple of db docs I distribute with app (translations JSON is the one good example).
So at app init I just try to read translations doc from db, if there is none - I import content from js module and store in db.
Then translations changes just being replicated from server to local db.
//transmob.js
const transMobFile = {
//content goes here
);
module.exports = transMobFile
//dbInit.js
import transMobFile from 'data/transMob';
..
PDB.getDoc('TransMob')
.then((doc)=> {
if (!doc) {
global.locales = transMobFile.localesMob; // locales
global.translations = transMobFile.langMob; // translations
return PDB.saveDoc('TransMob', transMobFile)
}
})
You can use react-native-fs to load a file from /android/app/src/main/assets. Just put the file into the assets folder and read it with RNFS.readFileAssets.
import PouchDB from 'pouchdb-core';
PouchDB
.plugin(require('pouchdb-find'))
.plugin(require('pouchdb-load'));
import RNFS from 'react-native-fs';
const localDB = new PouchDB("cs1", {adapter: 'asyncstorage'});
localDB.get("_local/initial_load_complete")
.catch(function(err) {
console.log("loading dumpfile");
if (err.status !== 404) {
// 404 means not found
throw err;
}
RNFS.readFileAssets('yourdb.txt', 'utf8')
.then((contents) => {
localDB.load(contents).then(function() {
return localDB.put({ _id: "_local/initial_load_complete" });
}).then(function() {
// at this point, we are sure that
// initial replication is complete
console.log("loading is complete!");
return localDB.allDocs({ include_docs: true }).then(
function(res) {
// display all docs for debugging purposes (empty)
console.log(res);
});
}, function(err) {
console.log(err);
});
})
})
You'll need to rebuild your project, reloading is not sufficient.
My project crashes when I attempt to load a 30MB file, so I probably will split it into a few smaller files. Check out https://github.com/pouchdb-community/pouchdb-load to see how this works if needed.
I found that the db.load() function from the pouchdb-load module requires a URL. I was pointing it to a file path on the device's filesystem. I placed my database.txt file on my server, changed it to use the url and it worked.
In my mind this isn't ideal because if they install the app and have slow wireless, it still has to pull the file from the server. It is still much faster than performing a full-on replicate when the app opens for the first time however.

Simple example for accessing the camera via WebRTC in react-native (Android)

I'm trying to adapt an augmented reality app I wrote in JS that only works in Firefox on Android to a react native app that can work in either Android or iOS. Since I need the camera input, I'm using react-native-webrtc (rather than importing the html and js I have been using, since I'm also trying to reduce framerate lag). I've been trying to parse out the demo here:
https://github.com/oney/RCTWebRTCDemo/blob/master/main.js
But the demo app is quite complex since it is a video chatroom (from what I can surmise). I just need to access the camera and keep it as the background of the app. This is what I have so far:
import React, { Component } from 'react';
import {
AppRegistry,
View,
} from 'react-native';
import {
RTCPeerConnection,
RTCMediaStream,
RTCIceCandidate,
RTCSessionDescription,
RTCView,
MediaStreamTrack,
getUserMedia,
} from 'react-native-webrtc';
let localStream;
function getLocalStream(isFront, callback) {
MediaStreamTrack.getSources(sourceInfos => {
let videoSourceId;
for (const i = 0; i < sourceInfos.length; i++) {
const sourceInfo = sourceInfos[i];
if(sourceInfo.kind == "video" && sourceInfo.facing == (isFront ? "front" : "back")) {
videoSourceId = sourceInfo.id;
}
}
getUserMedia({
audio: false,
video: {
mandatory: {
minWidth: 500,
minHeight: 300,
minFrameRate: 30
},
facingMode: (isFront ? "user" : "environment"),
optional: [{ sourceId: sourceInfos.id}]
}
}, function(stream) {
console.log("dddd", stream);
callback(stream);
}, logError);
});
}
function logError(error) {
console.log("logError: ", error);
}
let container;
var CanvasTest = React.createClass({
getInitialState: function() {
return {
isFront: true,
selfViewSrc: null};
},
componentDidMount: function() {
container = this;
},
render() {
return (
<View>
<RTCView streamURL={this.state.selfViewSrc} />
{console.log("this.state: ", this.state)}
{getLocalStream(true, function(stream) {
//localStream = stream;
//container.setState({selfViewSrc: stream.toURL()});
})
}
</View>
);
}
});
AppRegistry.registerComponent('CanvasTest', () => CanvasTest);
Everything is okay until I try to call the getLocalStream function. I get an "undefined is not an object" error for that line. (I've commented out the lines inside the callback to see if they are causing the problem, they are not).
This is what I get from the console in Android Studio:
E/ReactNativeJS: undefined is not an object (evaluating 'WebRTCModule.mediaStreamTrackGetSources')
E/EGL_emulation: tid 3106: eglSurfaceAttrib(1165): error 0x3009 (EGL_BAD_MATCH)
W/OpenGLRenderer: Failed to set EGL_SWAP_BEHAVIOR on surface 0xa0899300, error=EGL_BAD_MATCH
I think I'm calling the function in the wrong place. I want the view to load up the camera stream when the app starts. What am I doing wrong?
Is there a simpler example somewhere of using WebRTC in react native?
About undefined is not an object
It may because of not install it properly.
I'd suggest restart a fresh build again:
remove npm module: rm -rf $YourProject/node_modules/react-native-webrtc
clean npm cache: npm cache clean
clear gradle build intermediate files or
clear xocde project by Product -> clean
( it depends on your env )
npm install react-native-webrtc
follow the documents steps by steps carefully (Android / iOS)
be sure grant all permissions mentions on documents then try again.
Where to execute getLocalStream()
in your case, you can execute it in ComponentDidMount
otherwise, in some case, app may warn that you can't setState() in render()
(setState() will trigger render() normally, the warning is to prevent infinite loop.)
Suggestion
I would suggest you to NOT test it on simulators as possible for libraries which needs to access lots of hardware's functionalities.