extremeheat / JSPyBridge

🌉. Bridge to interoperate Node.js and Python
MIT License
672 stars 48 forks source link

Is it possiable to use an other js runtime(like a browser) #20

Open ODtian opened 3 years ago

ODtian commented 3 years ago

I would like to conbine this and an other repo pywebview for a better js bridge in webview.

extremeheat commented 3 years ago

In theory, yes. With Python as the parent process, this would involve several changes internally, particularly relating to the communication protocol. It would require a JS server that would be able to handling the bridging. At the moment we use stdio for simple cross-platform communication.

With respect to a WebView, it may be easier and more natural to use the bridge from the JS side to call Python. For example, you can use fully featured Electron to start the window and the GUI. Then in the JS startup code, call Python and pass in the relevant references like the window object so that the Python side can control the window and interactions.

ODtian commented 3 years ago

Thanks for your reply. Actually pywebview is different from electron, it calls .net api on windows to create a webview form in winform (or other webview providers), neither of them run on node.js which means they act like a browser and can't call python natively, the only way could communicate between python and webview is eval js, which is sometimes not so stable, this could be difficult.

extremeheat commented 3 years ago

Yes, I understand that. I was referring to using the pythonia bridge instead.

As of right now, with electron, you can do the following:

npm install electron@alpha pythonia

write to index.js:

const { app, BrowserWindow } = require('electron')
const { python } = require('pythonia')

let mainWindow;

// Quit when all windows are closed.
app.on('window-all-closed', function() {
  if (process.platform != 'darwin')
    app.quit();
});

// This method will be called when Electron has done everything
// initialization and ready for creating browser windows.
app.on('ready', async () => {
    const index = await python("./index.py")
    await index.init(app, BrowserWindow)
});

to index.py:

import sys, os

sys.stdout = sys.stderr # Looks like Electron breaks stdout through the bridge, until this is fixed you can use stderr instead

def init(app, BrowserWindow):
    print("I was inited")
    main_window = BrowserWindow.new({ 'width': 800, 'height': 600, 'webPreferences': { 'nodeIntegration': True } })
    main_window.loadURL('https://www.google.com')

then run it with npx electron . and use anything out of the electron ecosystem (packaging, etc.)

image

You can also loadURL on any local file also, where the JS scripts on the page have access to the Electron window. In Electron, there are two processes that can communicate with each other, the main and the render process. The render processes can be given access to run node.js via nodeIntegration, which means you can also call into Python and have it manage the window. (The example above is Python started on the main process.)

With respect to Python as the parent process, that's something that can be looked into indeed, but would likely require further thought on the best way to go about it. The current javascript bridge on pip is very much designed around Node.js, with features such as dependency management. A solution for this should not be tool specific if possible.

ODtian commented 3 years ago

Wow, that's cool👍. In some way, I think your method mentioned above is available. If python can run without node.js, maybe we just need start webview in python process and call native webview python api to load the page, then call python on js side after page is loaded to expose the api for each side. Only a few code is needed in such way. Anyway, that helps me a lot.

Update: It seems like that node.js is needed for ipc channel, which can be insteaded by python subprocess or just use a smaller ipc based on webview jsbridge.