Skip to content
This repository was archived by the owner on Jun 22, 2025. It is now read-only.

Commit d657a86

Browse files
committed
Add: full Eel-CRA demo
1 parent 126963a commit d657a86

File tree

8 files changed

+167
-15
lines changed

8 files changed

+167
-15
lines changed

examples/07 - CreateReactApp/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,5 @@
2121
npm-debug.log*
2222
yarn-debug.log*
2323
yarn-error.log*
24+
25+
*.spec
522 KB
Loading
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# README
2+
3+
Eello World example Create-React-App (CRA) with Eel. This particular project was bootstrapped with `npx create-react-app 07_CreateReactApp --typescript` (Typescript enabled), but the below modifications can be implemented in any CRA configuration or CRA version.
4+
5+
If you run into any issues with this example, open a [new issue](https://github.com/ChrisKnott/Eel/issues/new) and tag @KyleKing
6+
7+
## Quick Start
8+
9+
1. In the app's directory, run `npm install` and `pip install bottle bottle-websocket future whichcraft pyinstaller`
10+
2. Build the application with `npm run build`
11+
3. Run the built version with `python eel_CRA.py`. A Chrome window should open running the code from `build/`
12+
4. Build a binary distribution with PyInstaller using `python -m eel eel_CRA.py build --onefile` (See more detailed instructions at bottom of [the main README](https://github.com/ChrisKnott/Eel))
13+
5. For development, open two prompts. In one, run `python eel_CRA.py true` and the other, `npm start`. A browser window should open in your default web browser at: [http://localhost:3000/](http://localhost:3000/). As you make changes to the JavaScript in `src/` the browser will reload. Any changes to `eel_CRA.py` will require a restart to take effect. You may need to refresh the browser window if it gets out of sync with eel.
14+
15+
![Demo.png](Demo.png)
16+
17+
## About
18+
19+
These are the changes needed to convert the basic CRA application for Eel support.
20+
21+
### Use `window.eel.expose(func, 'func')` with `npm run build`
22+
23+
> TLDR: CRA's default code mangling in `npm run build` will rename variables and functions. To handle these changes, convert all `eel.expose(funcName)` to `window.eel(funcName, 'funcName')`. This workaround guarantees that 'funcName' will be available to call from Python
24+
25+
When you run `npm run build`, CRA generates a mangled and minified JavaScript file. The mangling will change `eel.expose(funcName)` to something like `D.expose(J)`. The modified code won't be recognized by the Eel static JS-code analyzer, which uses a regular expression to look for `eel.expose(*)` and the function name expected in python, `funcName`, is now mangled as `J`.
26+
27+
The easy workaround is just to refactor `eel.expose(funcName)` to `window.eel(funcName, 'func_name')` where `window.eel` prevents `eel` from being mangled. Then `eel.func_name()` can be called from Python
28+
29+
### src/App.tsx
30+
31+
Modified to demonstrate exposing a function from JavaScript and how to use callbacks from Python to update React GUI.
32+
33+
### eel_CRA.py
34+
35+
Basic eel file that exposes two Python functions to JavaScript. If a second argument (i.e. `true`) is provided, the app uses a development mode for a server already alive on port 3000; otherwise, the script will load `index.html` from the build/ directory, which is what you want for building from a binary.
36+
37+
### public/index.html
38+
39+
Added location of `eel.js` file based on options set in eel_CRA.py.
40+
41+
```html
42+
<!-- Load eel.js from the port specified in the eel.start options -->
43+
<script type="text/javascript" src="http://localhost:8080/eel.js"></script>
44+
```
45+
46+
### src/react-app-env.d.ts
47+
48+
This file declares window.eel as a valid type for tslint. Note: capitalization of `window`
49+
50+
51+
### src/App.css
52+
53+
Added some basic button styling :)
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import sys
2+
sys.path.insert(1, '../../')
3+
# Use latest version of Eel from parent directory
4+
5+
import os
6+
import random
7+
8+
import eel
9+
10+
11+
@eel.expose # Expose this function to JavaScript
12+
def say_hello_py(x):
13+
# Print to Python console
14+
print('Hello from %s' % x)
15+
# Call a JavaScript function
16+
eel.say_hello_js('Python {from within say_hello_py()}!')
17+
18+
19+
@eel.expose
20+
def pick_file(folder):
21+
folder = os.path.expanduser(folder)
22+
if os.path.isdir(folder):
23+
return random.choice(os.listdir(folder))
24+
else:
25+
return '{} is not a valid folder'.format(folder)
26+
27+
28+
def start_eel(develop):
29+
"""Start Eel with either production or development configuration"""
30+
if develop:
31+
directory = 'src'
32+
app = None
33+
page = {'port': 3000}
34+
flags = ['--auto-open-devtools-for-tabs']
35+
else:
36+
directory = 'build'
37+
app = 'chrome-app'
38+
page = 'index.html'
39+
flags = []
40+
41+
eel.init(directory, ['.tsx', '.ts', '.jsx', '.js', '.html'])
42+
43+
# These will be queued until the first connection is made, but won't be repeated on a page reload
44+
say_hello_py('Python World!')
45+
eel.say_hello_js('Python World!') # Call a JavaScript function (must be after `eel.init()`)
46+
47+
eel.start(page, size=(1280, 800), options={
48+
'mode': app,
49+
'port': 8080,
50+
'host': 'localhost',
51+
'chromeFlags': flags
52+
})
53+
54+
if __name__ == '__main__':
55+
import sys
56+
57+
# Pass any second argument to enable debugging. Production distribution can't receive arguments
58+
start_eel(develop=len(sys.argv) == 2)

examples/07 - CreateReactApp/public/index.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@
2323
Learn how to configure a non-root public URL by running `npm run build`.
2424
-->
2525
<title>React App</title>
26+
27+
<!-- Load eel.js from the port specified in the eel.start options -->
28+
<script type="text/javascript" src="http://localhost:8080/eel.js"></script>
29+
2630
</head>
2731
<body>
2832
<noscript>You need to enable JavaScript to run this app.</noscript>

examples/07 - CreateReactApp/src/App.css

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,18 @@
1818
color: white;
1919
}
2020

21-
.App-link {
22-
color: #61dafb;
21+
.App-button {
22+
background-color: #61dafb;
23+
border-radius: 2vmin;
24+
color: #282c34;
25+
font-size: calc(10px + 2vmin);
26+
padding: 2vmin;
27+
}
28+
29+
30+
.App-button:hover {
31+
background-color: #7ce3ff;
32+
cursor: pointer;
2333
}
2434

2535
@keyframes App-logo-spin {

examples/07 - CreateReactApp/src/App.tsx

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,42 @@ import React, { Component } from 'react';
22
import logo from './logo.svg';
33
import './App.css';
44

5-
class App extends Component {
6-
render() {
5+
// Point Eel web socket to the instance
6+
export const eel = window.eel
7+
eel.set_host( 'ws://localhost:8080' )
8+
9+
// Expose the `sayHelloJS` function to Python as `say_hello_js`
10+
function sayHelloJS( x: any ) {
11+
console.log( 'Hello from ' + x )
12+
}
13+
// WARN: must use window.eel to keep parse-able eel.expose{...}
14+
window.eel.expose( sayHelloJS, 'say_hello_js' )
15+
16+
// Test calling sayHelloJS, then call the corresponding Python function
17+
sayHelloJS( 'Javascript World!' )
18+
eel.say_hello_py( 'Javascript World!' )
19+
20+
21+
interface IAppState {
22+
message: string
23+
}
24+
25+
export class App extends Component<{}, {}> {
26+
public state: IAppState = {
27+
message: `Click button to choose a random file from the user's sustem`
28+
}
29+
30+
public pickFile = () => {
31+
eel.pick_file('~')(( message: string ) => this.setState( { message } ) )
32+
}
33+
34+
public render() {
735
return (
836
<div className="App">
937
<header className="App-header">
1038
<img src={logo} className="App-logo" alt="logo" />
11-
<p>
12-
Edit <code>src/App.tsx</code> and save to reload.
13-
</p>
14-
<a
15-
className="App-link"
16-
href="https://reactjs.org"
17-
target="_blank"
18-
rel="noopener noreferrer"
19-
>
20-
Learn React
21-
</a>
39+
<p>{this.state.message}</p>
40+
<button className='App-button' onClick={this.pickFile}>Pick Random File From `~/*`</button>
2241
</header>
2342
</div>
2443
);
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,7 @@
11
/// <reference types="react-scripts" />
2+
3+
interface Window {
4+
eel: any;
5+
}
6+
7+
declare var window: Window;

0 commit comments

Comments
 (0)