diff --git a/docs/guides/exporting.md b/docs/guides/exporting.md
index 5da57d3b89f..e6a9c8da590 100644
--- a/docs/guides/exporting.md
+++ b/docs/guides/exporting.md
@@ -163,6 +163,10 @@ python -m http.server
### Deploying to GitHub Pages
+::: tip "Template repository"
+
+ You can fork our [template repository](https://github.com/marimo-team/marimo-gh-pages-template) for deploying multiple notebooks to GitHub Pages. Once you have forked the repository, add your notebooks to the `notebooks`/`apps` directory.
+
You can deploy your WebAssembly marimo notebook to GitHub Pages using the following GitHub Actions workflow:
```yaml
@@ -201,6 +205,31 @@ jobs:
artifact_name: github-pages
```
+### Exporting multiple notebooks
+
+In order to export multiple notebooks under the same folder, you can use the following snippet:
+
+```bash
+files=("batch_and_form.py" "data_explorer.py")
+
+for file in "${files[@]}"; do
+ without_extension="${file%.*}"
+ marimo export html-wasm "$file" -o public/"$without_extension".html --mode run
+done
+```
+
+Optionally, create an `index.html` file in the public directory:
+
+```bash
+# Optionally, create an index.html file in the public directory
+echo "
" > public/index.html
+for file in "${files[@]}"; do
+ without_extension="${file%.*}"
+ echo "- $without_extension
" >> public/index.html
+done
+echo "
" >> public/index.html
+```
+
## 🏝️ Embed marimo outputs in HTML using Islands
!!! note "Preview"
diff --git a/marimo/_cli/export/commands.py b/marimo/_cli/export/commands.py
index 4a0acc49971..0b44f015f1b 100644
--- a/marimo/_cli/export/commands.py
+++ b/marimo/_cli/export/commands.py
@@ -393,30 +393,32 @@ def html_wasm(
show_code: bool,
) -> None:
"""Export a notebook as a WASM-powered standalone HTML file."""
+ out_dir = output
+ filename = "index.html"
+ ignore_index_html = False
+ # If ends with .html, get the directory
+ if output.endswith(".html"):
+ out_dir = os.path.dirname(output)
+ filename = os.path.basename(output)
+ ignore_index_html = True
def export_callback(file_path: MarimoPath) -> ExportResult:
return export_as_wasm(file_path, mode, show_code=show_code)
- # Validate output is not a file
- if os.path.isfile(output):
- raise click.UsageError(
- f"Output {output} is a file, but must be a directory."
- )
-
# Export assets first
- Exporter().export_assets(output)
+ Exporter().export_assets(out_dir, ignore_index_html=ignore_index_html)
echo(
- f"Assets copied to {green(output)}. These assets are required for the "
+ f"Assets copied to {green(out_dir)}. These assets are required for the "
"notebook to run in the browser."
)
echo(
"To run the exported notebook, use:\n"
- f" python -m http.server --directory {output}\n"
+ f" python -m http.server --directory {out_dir}\n"
"Then open the URL that is printed to your terminal."
)
- outfile = os.path.join(output, "index.html")
+ outfile = os.path.join(out_dir, filename)
return watch_and_export(MarimoPath(name), outfile, False, export_callback)
diff --git a/marimo/_server/export/exporter.py b/marimo/_server/export/exporter.py
index 8e24952d1b3..2d8dfdf834a 100644
--- a/marimo/_server/export/exporter.py
+++ b/marimo/_server/export/exporter.py
@@ -356,7 +356,9 @@ def export_as_wasm(
return html, download_filename
- def export_assets(self, directory: str) -> None:
+ def export_assets(
+ self, directory: str, ignore_index_html: bool = False
+ ) -> None:
# Copy assets to the same directory as the notebook
dirpath = Path(directory)
LOGGER.debug(f"Copying assets to {dirpath}")
@@ -365,7 +367,16 @@ def export_assets(self, directory: str) -> None:
import shutil
- shutil.copytree(root, dirpath, dirs_exist_ok=True)
+ shutil.copytree(
+ root,
+ dirpath,
+ dirs_exist_ok=True,
+ ignore=(
+ shutil.ignore_patterns("index.html")
+ if ignore_index_html
+ else None
+ ),
+ )
class AutoExporter:
diff --git a/tests/_cli/test_cli_export.py b/tests/_cli/test_cli_export.py
index eac12ad5171..b5434992e7e 100644
--- a/tests/_cli/test_cli_export.py
+++ b/tests/_cli/test_cli_export.py
@@ -84,6 +84,28 @@ def test_cli_export_html_wasm(temp_marimo_file: str) -> None:
)
assert " None:
+ out_dir = Path(temp_marimo_file).parent / "out_file"
+ p = subprocess.run(
+ [
+ "marimo",
+ "export",
+ "html-wasm",
+ temp_marimo_file,
+ "--output",
+ str(out_dir / "foo.html"),
+ ],
+ capture_output=True,
+ )
+ assert p.returncode == 0, p.stderr.decode()
+ assert Path(out_dir / "foo.html").exists()
+ assert not Path(out_dir / "index.html").exists()
+ html = Path(out_dir / "foo.html").read_text()
+ assert " None:
out_dir = Path(temp_marimo_file).parent / "out"