Does anyone know how to get this working with Create-React-App ?
I've been struggling all day and I am still nowhere forward :(
It works if I build the CRA itself BUT I have to keep doing this every time I change something. Create-REact-App comes with it's own Dev server that hot reloads and I wanted to be able to plug into it but when I do a console.log(eel) it always prints undefined.
How about something like this to reload that app: https://github.com/AoiKuiyuyou/AoikLiveReload
I have not tried it... but I plan to.
@AnthoniG this is something I want to get working, but I don't have time until next month. If you get it working in the meantime I please post here
I played around with this for just a few minutes. I did it using VueJS instead, but the concept should be the same. It is not yet an elegant solution, but it works without making any modifications to Eel.
Here is my file structure.
.project
βββ app.py
βββ start.sh
βββ web
βββ build
βββ config
βββ index.html
βββ node_modules
βββ package.json
βββ README.md
βββ src
βββ static
βββ yarn.lock
Here is start.sh:
#!/bin/bash
cd web
yarn run dev
And, here is app.py
import eel
import threading
from subprocess import call
from time import sleep
def start_web():
call(['./start.sh'])
def start_eel():
sleep(4)
eel.init('web')
eel.start('', options={
'port': 8080,
'host': 'localhost',
})
if __name__ == '__main__':
t1 = threading.Thread(target=start_web)
t2 = threading.Thread(target=start_eel)
t1.start()
t2.start()
As you can see, the idea is simple: start both the eel webserver, and whatever other webserver you want. Then, tell the eel browser to open your other webbrowser instead of a static file.
I hacked this together in just a few minutes as a proof of concept. Clearly we can improve upon this, and looks like something that we could and should be able to bake into eel itself.
As you can see, I needed to throw a sleep in there just to make sure the webpack server was up and running first. This needs to be fixed.
Maybe also there is a better solution to using Threading
This may not be the best solution, but it does work. I was able to startup the servers, and make changes to my Vue app and have it live reload inside of the eel browser.
Kudos to @ChrisKnott for an awesomely simple and elegant implementation.
I have been playing around with this, and I think I have an idea on how to set this up with an API sort of like this:
eel.init('web')
eel.start(
{
'port': 8888,
'host': 'localhost',
βpathβ: ββ
},
services=[
{
βdirβ: βsome/working/pathβ,
βexecβ: βmy_executable_command.shβ
}
]
)
The thought would be to block the run_lambda function if services is present. In that case, Eel would go out and startup whatever services it could, and once they were up and running, continue on with run_lambda.
The second change would be to make the first parameter in start to be either a string or an object. If it is an object, then it would be used for setting the location of the browser so that the options keyword argument could still be used for gevent.
@ChrisKnott If you agree with this approach, Iβd be happy to put together a PR for you. Am I on the right track?
I created a PR #33. This allows users to set any arbitrary location inside eel.start.
The effect of this would be to serve (for example) an application running from npm run dev.
HOWEVER, this does not cover the second half of launching services. I am hoping to get some feedback on @ChrisKnott about my strategy if it is a worthwhile endeavor or not.
This could (as shown above) be something entirely handled by app.py and not be bundled inside of eel. I just happen to think it would be a nicer API if eel could manage spinning up the other services as well.
Of course, in the react or vue instance, this would be in development only. When packaged up, this would be bundled into static files that COULD be served by eel.
Here is an example of how this is running using Threading outside of eel.
@ahopkins Loving the idea and going to play around with your git
Also going to have a play around with React and see what that thinks of this. Like I mentioned I got it to partially work, but this looks to be a cleaner solution.
BTW: How did you get it to not complain about address in use ?
Also, what do you do for a build? Have seperate app.py or conditional checks to see if in production etc ?
@AnthoniG
BTW: How did you get it to not complain about address in use ?
The options parameter is used to tell gevent which port to hook up to. So, I tried to separate the location of the browser from the binding of gevent. The way I have it running actually is to let my webpack service run on 8080, and I changed gevent to 8888. As long as they are running on different ports, all is fine.
page = {
'port': 8080,
}
eel.start(page, options={
'port': 8888,
})
Right now, I am just launching webpack in a separate terminal session waiting to head back from @ChrisKnott. I think the best route would be to create a services parameter that can spawn new processes in an identical manner as used already, and then initiate the process, also as currently done for launching the browser.
Also, what do you do for a build?
I have not tested it out yet. But, conceptually, there would be at least a different operation to run. Once there is a build of the Javascript app, that could be handled statically by gevent and served without needing to get another process in there. I have not tried it yet, but it would be no different conceptually from what is on the README.
Have seperate app.py or conditional checks to see if in production etc ?
Perhaps. Or, rather than building the conditionals into it, just replace the script with a build version. I suppose it depends how much abstraction gets introduced.
@ahopkins Thanks for that. I won't be able to fully test it until this weekend. My idea then is to use your code as a base and re-factor it for my Create-React-App version of it.
Before this, I was thinking of going the way of using React in the browser and compile in-memory like JSBin / JSFiddle et al. do
Awesome. Can you post your code here? Curious to see how your solution may differ
@ahopkins Yep can do, although it won't change much. Will just use Create-React-App itself rather than VueJS.
The other method of having it compile in-memory I never got around to testing, but was going to be doing it all over the weekend.
Here's my code. Like I said it's based on your VueJS code :smiley_cat:
https://github.com/AnthoniG/eel_react
Need to play around with it and work how to do a build / deploy scenario but other than that it works. Guess just need main Eel distro to be altered with your pull request.
Also included a requirements.txt BUT it's listing Eel as the one from Pypi. However I did a pip install git+ from @ahopkins REPO :smile:
I've hit a problem on the Python call to Javascript side of things.
No matter what I do, I can not get Python to call a Javascript function.
It keeps throwing an AttributeError and crashes (I wrapped it in a try..except to prevent that, but it still happens)
I will amend my repo with the code I have and hopefully some one can figure it out.
@ahopkins Your code works fine (I only put the JavaScript function in index.html, did not try it further down the pipeline because I don't understand Vue that much)
I was planning to try and get eel to be exposed inside webpack tonight. Iβll post any code changes I have. Push what you have to your repo and I will be happy to take a look.
@ahopkins Code updated.
You will see in App.tsx (my main app entry) that I have several comments in there that explain how I was trying to setup the functions.
Files changed :-
eel_react.py
App.tsx
Files Added :-
src/classes/eel.tsx
_(this is because Typescript requires a definition file and this will allow me to call eel functions from anywhere in my code by simply importing this file.)_
[Will work on a proper .d.ts file later, once I've got everything working lol]
@AnthoniG I figured out the problem. Actually, there were a couple.
eel is "exposing" methods in JS is by crawling the source files looking for eel.expose. In order to get it to look for methods in a tsx file, I needed to add it to __init__.py in the eel package: allowed_extensions = '.js .html .txt .htm .xhtml .tsx'.split()
eel.tsx, it worked fine.I think this sort of underscores a potential flaw in the setup of Eel. No offense to @ChrisKnott, but this method I think is not scalable for an app built on (for example) React, and may potentially be flawed. The startup time is delayed quite a bit because of the size of node_modules directory. Granted, once built, this would not be a problem.
I would rather see eel.expose in the JS be a call to the Websocket that pushes the name of the method. This would make it a little more transparent what eel.expose is doing, and would allow for dynamic changes to the exposed functions, rather than everything being declared up front at initialization.
@ahopkins Do I need to re-pull Eel from your git then in order to make this work ?
Also agree on the once built part all of this work around and hiccups go away. However during building it's a pain.
I have been looking around for alternatives and exploring them.
(IE: Using jquery and some other plugins etc, look for a book by Michael S Mikowski)
Github link to Single Page Web Application
You would need to stash a local copy of the eel repo, and make the change. I have not committed it.
git clone https://github.com/ahopkins/Eel.git
Then, install that.
pip install -e /path/to/Eel
Go into Eel/eel/__init__.py and add .tsx into allowed_extensions as shown above. That will get it working for now until there is a solution. Your alternative would be to define all of your eel methods in a file with a .js extension.
@ahopkins I am not familiar with React at all (my background is in games dev and C++ mainly!) do you mind if I add you as a collaborator to the project, then I can stand back and let you integrate the React things?
I honestly wouldn't even know how to go about testing it!
Awesome. I would love very to help out. Not sure I'd call myself a React guru, although my main background is as a full stack web developer. I am happy to help and provide my input.
@ahopkins Not sure if anyone is still working on this issue. If so, maybe it would be nice to open it as a separate branch so everyone can check the latest progress and potentially contribute.
I do agree that eel should have a way to build with popular framework such as React, Angular or Vue. Especially for the complied files of those front-end frameworks, I wondering if there is an elegant way for eel to detect those "exposures". :/
Yes, I am working on it. I have not committed code because it still needs some more tests and (quite honestly) the last couple weeks were simply too busy for me. Hopefully I will have a chance to push soon.
Most helpful comment
I played around with this for just a few minutes. I did it using VueJS instead, but the concept should be the same. It is not yet an elegant solution, but it works without making any modifications to Eel.
Files
Here is my file structure.
Here is
start.sh:And, here is
app.pyPlan
As you can see, the idea is simple: start both the eel webserver, and whatever other webserver you want. Then, tell the eel browser to open your other webbrowser instead of a static file.
Pitfalls
I hacked this together in just a few minutes as a proof of concept. Clearly we can improve upon this, and looks like something that we could and should be able to bake into eel itself.
As you can see, I needed to throw a
sleepin there just to make sure the webpack server was up and running first. This needs to be fixed.Maybe also there is a better solution to using
ThreadingThis may not be the best solution, but it does work. I was able to startup the servers, and make changes to my Vue app and have it live reload inside of the eel browser.
Kudos to @ChrisKnott for an awesomely simple and elegant implementation.