Skip to content

Commit fee663a

Browse files
fpligerntoll
authored andcommitted
add running offline page adapting content directly from GH issue 581
1 parent 4afe14b commit fee663a

File tree

1 file changed

+223
-0
lines changed

1 file changed

+223
-0
lines changed

docs/user-guide/running-offline.md

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
# Running PyScript offline
2+
3+
Althought users will want to create and share PyScript apps on the internet, there are cases when user want to run PyScript applications offline, in an airgapped fashion. This means that both PyScript core and the interpreter used to run code need to be served with the application itself. In short, the 2 main explicit tasks needed to create an offline PyScript application are:
4+
5+
* download and include PyScript core (`core.js`)
6+
* download and include the [Python] interpreters you want to use in your Application
7+
8+
## Downloading and Including PyScript's `core.js`
9+
10+
There are at least 2 ways to use PyScript offline:
11+
12+
* by **cloning the repository**, then building and installing dependencies and then run and then reach the `./dist/` folder
13+
* by **grabbing the npm package** which for simplicity sake will be the method used here at least until we find a better place to *pin* our *dist* folder via our CDN and make the procedure even easier than it is now
14+
15+
In the examples below, we'll assume we are creating a PyScript Application folder called `pyscript-offline` and we'll add all the necessary files to the folder.
16+
17+
First of all, we are going to create a `pyscript-offline` folder as reference.
18+
19+
```sh
20+
mkdir -p pyscript-offline
21+
cd pyscript-offline
22+
```
23+
24+
### Adding ore by Cloning the Repository
25+
26+
...
27+
28+
### Adding core by Installing `@pyscript/core` Locally
29+
30+
First of all, ensure you are in the folder you would like to test PyScirpt locally. In this case, the `pyscript-offline` folder we created earlier.
31+
32+
Once within the folder, be sure there is a `package.json` file. Even an empty one with just `{}` as content would work.
33+
This is needed to be sure the folder will include locally the `npm_modules` folder instead of placing the package in the parent folder, if any.
34+
35+
```sh
36+
# only if there is no package.json, create one
37+
echo '{}' > ./package.json
38+
39+
# install @pyscript/core
40+
npm i @pyscript/core
41+
```
42+
43+
At this point the folder should contain a `node_module` in it and we can actually copy its `dist` folder wherever we like.
44+
45+
```sh
46+
# create a public folder to serve locally
47+
mkdir -p public
48+
49+
# move @pyscript/core dist into such folder
50+
cp -R ./node_modules/@pyscript/core/dist ./public/pyscript
51+
```
52+
53+
## Setting up your application
54+
55+
Once you've added PyScript code following one of the methods above, that's almost it! We are half way through our goal but we can already create a `./public/index.html` file that loads the project:
56+
57+
```html
58+
<!DOCTYPE html>
59+
<html lang="en">
60+
<head>
61+
<meta charset="UTF-8">
62+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
63+
<title>PyScript Offline</title>
64+
<script type="module" src="/pyscript/core.js"></script>
65+
<link rel="stylesheet" href="/pyscript/core.css">
66+
</head>
67+
<body>
68+
<script type="mpy">
69+
from pyscript import document
70+
71+
document.body.append("Hello from PyScript")
72+
</script>
73+
</body>
74+
</html>
75+
```
76+
77+
To run this project directly, after being sure that `index.html` file is saved into the `public` folder, you can try:
78+
79+
```sh
80+
python3 -m http.server -d ./public/
81+
```
82+
83+
Alternatively, if you would like to test also `worker` features, you can try instead:
84+
85+
```sh
86+
npx static-handler --coi ./public/
87+
```
88+
89+
**Please note this page still needs the network to load** so that both *MicroPython* or *Pyodide* will be fetched from related CDN ... we are getting close though!
90+
91+
### Install MicroPython locally
92+
93+
Similarly to what we did for `@pyscript/core`, we can also install *MicroPython* from *npm*:
94+
95+
```sh
96+
npm i @micropython/micropython-webassembly-pyscript
97+
```
98+
99+
Our `node_modules` folder now should contain a `@micropython` one and from there we can move relevant files into our `public` folder, but let's be sure we have a target for that:
100+
101+
```sh
102+
# create a folder in our public space
103+
mkdir -p ./public/micropython
104+
105+
# copy related files into such folder
106+
cp ./node_modules/@micropython/micropython-webassembly-pyscript/micropython.* ./public/micropython/
107+
```
108+
109+
That folder should contain at least both `micropython.mjs` and `micropython.wasm` files and these are the files we are going to use locally via our dedicated config.
110+
111+
```html
112+
<!DOCTYPE html>
113+
<html lang="en">
114+
<head>
115+
<meta charset="UTF-8">
116+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
117+
<title>PyScript Offline</title>
118+
<script type="module" src="/pyscript/core.js"></script>
119+
<link rel="stylesheet" href="/pyscript/core.css">
120+
</head>
121+
<body>
122+
<mpy-config>
123+
interpreter = "/micropython/micropython.mjs"
124+
</mpy-config>
125+
<script type="mpy">
126+
from pyscript import document
127+
128+
document.body.append("Hello from PyScript")
129+
</script>
130+
</body>
131+
</html>
132+
```
133+
134+
We are basically done: if we try to disconnect from the internet but we still run our local server, the page will still show that very same *Hello from PyScript* message :partying_face:
135+
136+
### Install Pyodide locally
137+
138+
Currently there is a difference between MicroPython and Pyodide: the former does not have (*yet*) a package manager while the latest does, it's called *micropip*.
139+
140+
This is important to remember because while the procedure to have *pyodide* offline is very similar to the one we've just seen, if we want to use also 3rd party packages we also need to have these running locally ... but let's start simple:
141+
142+
```sh
143+
# install locally the pyodide module
144+
npm i pyodide
145+
146+
# create a folder in our public space
147+
mkdir -p ./public/pyodide
148+
149+
# move all necessary files into that folder
150+
cp ./node_modules/pyodide/pyodide* ./public/pyodide/
151+
cp ./node_modules/pyodide/python_stdlib.zip ./public/pyodide/
152+
```
153+
154+
Please **note** that also `pyodide-lock.json` file is needed so please don't change that `cp` operation as all `pyodide*` files need to be moved.
155+
156+
At this point, all we need to do is to change our *HTML* page to use *pyodide* instead:
157+
158+
```html
159+
<!DOCTYPE html>
160+
<html lang="en">
161+
<head>
162+
<meta charset="UTF-8">
163+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
164+
<title>PyScript Offline</title>
165+
<script type="module" src="/pyscript/core.js"></script>
166+
<link rel="stylesheet" href="/pyscript/core.css">
167+
</head>
168+
<body>
169+
<py-config>
170+
interpreter = "/pyodide/pyodide.mjs"
171+
</py-config>
172+
<script type="py">
173+
from pyscript import document
174+
175+
document.body.append("Hello from PyScript")
176+
</script>
177+
</body>
178+
</html>
179+
```
180+
181+
We can now drop internet, still keeping the local server running, and everything should be fine :partying_face:
182+
183+
### Local Pyodide Packages
184+
185+
In order to have also 3rd party packages available, we can use the bundle from [pyodide releases](https://github.com/pyodide/pyodide/releases/tag/0.24.1) that contains also packages.
186+
187+
Please note this bundle is more than 200MB: it not downloaded all at once, it contains each package that is required and it loads only related packages when needed.
188+
189+
Once downloaded and extracted, where in this case I am using `0.24.1` as reference bundle, we can literally copy and paste, or even move, all those files and folders inside the `pyodide-0.24.1/pyodide/*` directory into our `./public/pyodide/*` folder.
190+
191+
As the bundle contains files already present, feel free to either skip or replace the content, or even directly move that *pyodide* folder inside our `./public/` one.
192+
193+
Once it's done, we can now use any package we like that is available in *pyodide*. Let's see an example:
194+
195+
```html
196+
<!DOCTYPE html>
197+
<html lang="en">
198+
<head>
199+
<meta charset="UTF-8">
200+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
201+
<title>PyScript Offline</title>
202+
<script type="module" src="/pyscript/core.js"></script>
203+
<link rel="stylesheet" href="/pyscript/core.css">
204+
</head>
205+
<body>
206+
<py-config>
207+
interpreter = "/pyodide/pyodide.mjs"
208+
packages = ["pandas"]
209+
</py-config>
210+
<script type="py">
211+
import pandas as pd
212+
x = pd.Series([1,2,3,4,5,6,7,8,9,10])
213+
214+
from pyscript import document
215+
document.body.append(str([i**2 for i in x]))
216+
</script>
217+
</body>
218+
</html>
219+
```
220+
221+
If everything went fine, we should now be able to read `[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]` on the page *even* if we disconnect from the Internet.
222+
223+
And **that's all folks** :wave:

0 commit comments

Comments
 (0)