|
@@ -0,0 +1,259 @@
|
|
|
+from nicegui import ui
|
|
|
+
|
|
|
+from ...demo import bash_window, python_window
|
|
|
+from ...model import SectionDocumentation
|
|
|
+from ...more.run_documentation import RunDocumentation
|
|
|
+
|
|
|
+
|
|
|
+class ConfigurationDeploymentDocumentation(SectionDocumentation, title='Configuration & Deployment', name='configuration_deployment'):
|
|
|
+
|
|
|
+ def content(self) -> None:
|
|
|
+ @self.demo('URLs', '''
|
|
|
+ You can access the list of all URLs on which the NiceGUI app is available via `app.urls`.
|
|
|
+ The URLs are not available in `app.on_startup` because the server is not yet running.
|
|
|
+ Instead, you can access them in a page function or register a callback with `app.urls.on_change`.
|
|
|
+ ''')
|
|
|
+ def urls_demo():
|
|
|
+ from nicegui import app
|
|
|
+
|
|
|
+ # @ui.page('/')
|
|
|
+ # def index():
|
|
|
+ # for url in app.urls:
|
|
|
+ # ui.link(url, target=url)
|
|
|
+ # END OF DEMO
|
|
|
+ ui.link('https://nicegui.io', target='https://nicegui.io')
|
|
|
+
|
|
|
+ self.intro(RunDocumentation())
|
|
|
+
|
|
|
+ @self.demo('Native Mode', '''
|
|
|
+ You can enable native mode for NiceGUI by specifying `native=True` in the `ui.run` function.
|
|
|
+ To customize the initial window size and display mode, use the `window_size` and `fullscreen` parameters respectively.
|
|
|
+ Additionally, you can provide extra keyword arguments via `app.native.window_args` and `app.native.start_args`.
|
|
|
+ Pick any parameter as it is defined by the internally used [pywebview module](https://pywebview.flowrl.com/guide/api.html)
|
|
|
+ for the `webview.create_window` and `webview.start` functions.
|
|
|
+ Note that these keyword arguments will take precedence over the parameters defined in `ui.run`.
|
|
|
+
|
|
|
+ In native mode the `app.native.main_window` object allows you to access the underlying window.
|
|
|
+ It is an async version of [`Window` from pywebview](https://pywebview.flowrl.com/guide/api.html#window-object).
|
|
|
+ ''') # TODO: tab=lambda: ui.label('NiceGUI')
|
|
|
+ def native_mode_demo():
|
|
|
+ from nicegui import app
|
|
|
+
|
|
|
+ app.native.window_args['resizable'] = False
|
|
|
+ app.native.start_args['debug'] = True
|
|
|
+
|
|
|
+ ui.label('app running in native mode')
|
|
|
+ # ui.button('enlarge', on_click=lambda: app.native.main_window.resize(1000, 700))
|
|
|
+ #
|
|
|
+ # ui.run(native=True, window_size=(400, 300), fullscreen=False)
|
|
|
+ # END OF DEMO
|
|
|
+ ui.button('enlarge', on_click=lambda: ui.notify('window will be set to 1000x700 in native mode'))
|
|
|
+
|
|
|
+ # Show a helpful workaround until issue is fixed upstream.
|
|
|
+ # For more info see: https://github.com/r0x0r/pywebview/issues/1078
|
|
|
+ ui.markdown('''
|
|
|
+ If webview has trouble finding required libraries, you may get an error relating to "WebView2Loader.dll".
|
|
|
+ To work around this issue, try moving the DLL file up a directory, e.g.:
|
|
|
+
|
|
|
+ * from `.venv/Lib/site-packages/webview/lib/x64/WebView2Loader.dll`
|
|
|
+ * to `.venv/Lib/site-packages/webview/lib/WebView2Loader.dll`
|
|
|
+ ''')
|
|
|
+
|
|
|
+ @self.demo('Environment Variables', '''
|
|
|
+ You can set the following environment variables to configure NiceGUI:
|
|
|
+
|
|
|
+ - `MATPLOTLIB` (default: true) can be set to `false` to avoid the potentially costly import of Matplotlib.
|
|
|
+ This will make `ui.pyplot` and `ui.line_plot` unavailable.
|
|
|
+ - `NICEGUI_STORAGE_PATH` (default: local ".nicegui") can be set to change the location of the storage files.
|
|
|
+ - `MARKDOWN_CONTENT_CACHE_SIZE` (default: 1000): The maximum number of Markdown content snippets that are cached in memory.
|
|
|
+ ''')
|
|
|
+ def env_var_demo():
|
|
|
+ from nicegui.elements import markdown
|
|
|
+
|
|
|
+ ui.label(f'Markdown content cache size is {markdown.prepare_content.cache_info().maxsize}')
|
|
|
+
|
|
|
+ self.text('Server Hosting', '''
|
|
|
+ To deploy your NiceGUI app on a server, you will need to execute your `main.py` (or whichever file contains your `ui.run(...)`) on your cloud infrastructure.
|
|
|
+ You can, for example, just install the [NiceGUI python package via pip](https://pypi.org/project/nicegui/) and use systemd or similar service to start the main script.
|
|
|
+ In most cases, you will set the port to 80 (or 443 if you want to use HTTPS) with the `ui.run` command to make it easily accessible from the outside.
|
|
|
+
|
|
|
+ A convenient alternative is the use of our [pre-built multi-arch Docker image](https://hub.docker.com/r/zauberzeug/nicegui) which contains all necessary dependencies.
|
|
|
+ With this command you can launch the script `main.py` in the current directory on the public port 80:
|
|
|
+ ''')
|
|
|
+
|
|
|
+ @self.ui
|
|
|
+ def docker_run():
|
|
|
+ with bash_window(classes='max-w-lg w-full h-44'):
|
|
|
+ ui.markdown('''
|
|
|
+ ```bash
|
|
|
+ docker run -it --restart always \\
|
|
|
+ -p 80:8080 \\
|
|
|
+ -e PUID=$(id -u) \\
|
|
|
+ -e PGID=$(id -g) \\
|
|
|
+ -v $(pwd)/:/app/ \\
|
|
|
+ zauberzeug/nicegui:latest
|
|
|
+ ```
|
|
|
+ ''')
|
|
|
+
|
|
|
+ self.text('', '''
|
|
|
+ The demo assumes `main.py` uses the port 8080 in the `ui.run` command (which is the default).
|
|
|
+ The `-d` tells docker to run in background and `--restart always` makes sure the container is restarted if the app crashes or the server reboots.
|
|
|
+ Of course this can also be written in a Docker compose file:
|
|
|
+ ''')
|
|
|
+
|
|
|
+ @self.ui
|
|
|
+ def docker_compose():
|
|
|
+ with python_window('docker-compose.yml', classes='max-w-lg w-full h-60'):
|
|
|
+ ui.markdown('''
|
|
|
+ ```yaml
|
|
|
+ app:
|
|
|
+ image: zauberzeug/nicegui:latest
|
|
|
+ restart: always
|
|
|
+ ports:
|
|
|
+ - 80:8080
|
|
|
+ environment:
|
|
|
+ - PUID=1000 # change this to your user id
|
|
|
+ - PGID=1000 # change this to your group id
|
|
|
+ volumes:
|
|
|
+ - ./:/app/
|
|
|
+ ```
|
|
|
+ ''')
|
|
|
+
|
|
|
+ self.text('', '''
|
|
|
+ There are other handy features in the Docker image like non-root user execution and signal pass-through.
|
|
|
+ For more details we recommend to have a look at our [Docker example](https://github.com/zauberzeug/nicegui/tree/main/examples/docker_image).
|
|
|
+
|
|
|
+ You can provide SSL certificates directly using [FastAPI](https://fastapi.tiangolo.com/deployment/https/).
|
|
|
+ In production we also like using reverse proxies like [Traefik](https://doc.traefik.io/traefik/) or [NGINX](https://www.nginx.com/) to handle these details for us.
|
|
|
+ See our development [docker-compose.yml](https://github.com/zauberzeug/nicegui/blob/main/docker-compose.yml) as an example.
|
|
|
+
|
|
|
+ You may also have a look at [our demo for using a custom FastAPI app](https://github.com/zauberzeug/nicegui/tree/main/examples/fastapi).
|
|
|
+ This will allow you to do very flexible deployments as described in the [FastAPI documentation](https://fastapi.tiangolo.com/deployment/).
|
|
|
+ Note that there are additional steps required to allow multiple workers.
|
|
|
+ ''')
|
|
|
+
|
|
|
+ self.text('Package for Installation', '''
|
|
|
+ NiceGUI apps can also be bundled into an executable with [PyInstaller](https://www.pyinstaller.org/).
|
|
|
+ This allows you to distribute your app as a single file that can be executed on any computer.
|
|
|
+
|
|
|
+ Just take care your `ui.run` command does not use the `reload` argument.
|
|
|
+ Running the `build.py` below will create an executable `myapp` in the `dist` folder:
|
|
|
+ ''')
|
|
|
+
|
|
|
+ @self.ui
|
|
|
+ def pyinstaller():
|
|
|
+ with ui.row().classes('w-full items-stretch'):
|
|
|
+ with python_window(classes='max-w-lg w-full'):
|
|
|
+ ui.markdown('''
|
|
|
+ ```python
|
|
|
+ from nicegui import native, ui
|
|
|
+
|
|
|
+ ui.label('Hello from PyInstaller')
|
|
|
+
|
|
|
+ ui.run(reload=False, port=native.find_open_port())
|
|
|
+ ```
|
|
|
+ ''')
|
|
|
+ with python_window('build.py', classes='max-w-lg w-full'):
|
|
|
+ ui.markdown('''
|
|
|
+ ```python
|
|
|
+ import os
|
|
|
+ import subprocess
|
|
|
+ from pathlib import Path
|
|
|
+ import nicegui
|
|
|
+
|
|
|
+ cmd = [
|
|
|
+ 'python',
|
|
|
+ '-m', 'PyInstaller',
|
|
|
+ 'main.py', # your main file with ui.run()
|
|
|
+ '--name', 'myapp', # name of your app
|
|
|
+ '--onefile',
|
|
|
+ #'--windowed', # prevent console appearing, only use with ui.run(native=True, ...)
|
|
|
+ '--add-data', f'{Path(nicegui.__file__).parent}{os.pathsep}nicegui'
|
|
|
+ ]
|
|
|
+ subprocess.call(cmd)
|
|
|
+ ```
|
|
|
+ ''')
|
|
|
+
|
|
|
+ self.text('', '''
|
|
|
+ **Packaging Tips:**
|
|
|
+
|
|
|
+ - When building a PyInstaller app, your main script can use a native window (rather than a browser window) by
|
|
|
+ using `ui.run(reload=False, native=True)`.
|
|
|
+ The `native` parameter can be `True` or `False` depending on whether you want a native window or to launch a
|
|
|
+ page in the user's browser - either will work in the PyInstaller generated app.
|
|
|
+
|
|
|
+ - Specifying `--windowed` to PyInstaller will prevent a terminal console from appearing.
|
|
|
+ However you should only use this option if you have also specified `native=True` in your `ui.run` command.
|
|
|
+ Without a terminal console the user won't be able to exit the app by pressing Ctrl-C.
|
|
|
+ With the `native=True` option, the app will automatically close when the window is closed, as expected.
|
|
|
+
|
|
|
+ - Specifying `--windowed` to PyInstaller will create an `.app` file on Mac which may be more convenient to distribute.
|
|
|
+ When you double-click the app to run it, it will not show any console output.
|
|
|
+ You can also run the app from the command line with `./myapp.app/Contents/MacOS/myapp` to see the console output.
|
|
|
+
|
|
|
+ - Specifying `--onefile` to PyInstaller will create a single executable file.
|
|
|
+ Whilst convenient for distribution, it will be slower to start up.
|
|
|
+ This is not NiceGUI's fault but just the way Pyinstaller zips things into a single file, then unzips everything
|
|
|
+ into a temporary directory before running.
|
|
|
+ You can mitigate this by removing `--onefile` from the PyInstaller command,
|
|
|
+ and zip up the generated `dist` directory yourself, distribute it,
|
|
|
+ and your end users can unzip once and be good to go,
|
|
|
+ without the constant expansion of files due to the `--onefile` flag.
|
|
|
+
|
|
|
+ - Summary of user experience for different options:
|
|
|
+
|
|
|
+ | PyInstaller | `ui.run(...)` | Explanation |
|
|
|
+ | :--- | :--- | :--- |
|
|
|
+ | `onefile` | `native=False` | Single executable generated in `dist/`, runs in browser |
|
|
|
+ | `onefile` | `native=True` | Single executable generated in `dist/`, runs in popup window |
|
|
|
+ | `onefile` and `windowed` | `native=True` | Single executable generated in `dist/` (on Mac a proper `dist/myapp.app` generated incl. icon), runs in popup window, no console appears |
|
|
|
+ | `onefile` and `windowed` | `native=False` | Avoid (no way to exit the app) |
|
|
|
+ | Specify neither | | A `dist/myapp` directory created which can be zipped manually and distributed; run with `dist/myapp/myapp` |
|
|
|
+
|
|
|
+ - If you are using a Python virtual environment, ensure you `pip install pyinstaller` within your virtual environment
|
|
|
+ so that the correct PyInstaller is used, or you may get broken apps due to the wrong version of PyInstaller being picked up.
|
|
|
+ That is why the build script invokes PyInstaller using `python -m PyInstaller` rather than just `pyinstaller`.
|
|
|
+ ''')
|
|
|
+
|
|
|
+ @self.ui
|
|
|
+ def install_pyinstaller():
|
|
|
+ with bash_window(classes='max-w-lg w-full h-42 self-center'):
|
|
|
+ ui.markdown('''
|
|
|
+ ```bash
|
|
|
+ python -m venv venv
|
|
|
+ source venv/bin/activate
|
|
|
+ pip install nicegui
|
|
|
+ pip install pyinstaller
|
|
|
+ ```
|
|
|
+ ''')
|
|
|
+
|
|
|
+ self.text('', '''
|
|
|
+ **Note:**
|
|
|
+ If you're getting an error "TypeError: a bytes-like object is required, not 'str'", try adding the following lines to the top of your `main.py` file:
|
|
|
+ ```py
|
|
|
+ import sys
|
|
|
+ sys.stdout = open('logs.txt', 'w')
|
|
|
+ ```
|
|
|
+ See <https://github.com/zauberzeug/nicegui/issues/681> for more information.
|
|
|
+ ''')
|
|
|
+
|
|
|
+ self.text('NiceGUI On Air', '''
|
|
|
+ By using `ui.run(on_air=True)` you can share your local app with others over the internet 🧞.
|
|
|
+
|
|
|
+ When accessing the on-air URL, all libraries (like Vue, Quasar, ...) are loaded from our CDN.
|
|
|
+ Thereby only the raw content and events need to be transmitted by your local app.
|
|
|
+ This makes it blazing fast even if your app only has a poor internet connection (e.g. a mobile robot in the field).
|
|
|
+
|
|
|
+ By setting `on_air=True` you will get a random URL which is valid for 1 hour.
|
|
|
+ If you sign-up at <https://on-air.nicegui.io> you get a token which could be used to identify your device: `ui.run(on_air='<your token>'`).
|
|
|
+ This will give you a fixed URL and the possibility to protect remote access with a passphrase.
|
|
|
+
|
|
|
+ Currently On Air is available as a tech preview and can be used free of charge (for now).
|
|
|
+ We will gradually improve stability, introduce payment options and extend the service with multi-device management, remote terminal access and more.
|
|
|
+ Please let us know your feedback on [GitHub](https://github.com/zauberzeug/nicegui/discussions),
|
|
|
+ [Reddit](https://www.reddit.com/r/nicegui/), or [Discord](https://discord.gg/TEpFeAaF4f).
|
|
|
+
|
|
|
+ **Data Privacy:**
|
|
|
+ We take your privacy very serious.
|
|
|
+ NiceGUI On Air does not log or store any content of the relayed data.
|
|
|
+ ''')
|