# PlutoPages.jl in Windows

**URL:** https://discourse.julialang.org/t/plutopages-jl-in-windows/129710
**Category:** Pluto
**Tags:** question, pluto
**Created:** [June 6, 2025, 6:26pm UTC](https://discourse.julialang.org/t/plutopages-jl-in-windows/129710 "2025-06-06T18:26:57Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![eduardovrs](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/eduardovrs/32/20041_2.png) [@eduardovrs](https://discourse.julialang.org/u/eduardovrs)
#### Post date: [June 6, 2025, 6:26pm UTC](https://discourse.julialang.org/t/plutopages-jl-in-windows/129710/1 "2025-06-06T18:26:57Z")

</div>

Hello there,

I’m trying to make a some interactive notebooks with Pluto, and I want an index similar to [Computational Thinking Course](https://computationalthinking.mit.edu/Fall24/), and have found [PlutoPages.jl](https://github.com/JuliaPluto/PlutoPages.jl) but it doesn’t work on Windows locally.

```julia
julia> output_dir = PlutoPages.generate(my_site_source)
[ Info: PlutoPages: Starting Pluto notebook...
[ Info: Pluto app: waiting for notebook to finish...
[ Info: Notebook: 0/97 done...
[ Info: Notebook: 1/97 done...
[ Info: Notebook: 2/97 done...
[ Info: Notebook: 3/97 done...
[ Info: Notebook: 4/97 done...
[ Info: Notebook: 5/97 done...
[ Info: Notebook: 7/97 done...
[ Info: Notebook: 14/97 done...
[ Info: Notebook: 17/97 done...
[ Info: Notebook: 20/97 done...
[ Info: Notebook: 26/97 done...
[ Info: Notebook: 28/97 done...
[ Info: Notebook: 41/97 done...
[ Info: Notebook: 44/97 done...
[ Info: Notebook: 45/97 done...
[ Info: Notebook: 61/97 done...
[ Info: Notebook: 78/97 done...
[ Info: Notebook: 80/97 done...
[ Info: Notebook: 96/97 done...
[ Info: Pluto app: notebook finished!
┌ Error: Cell errored
│ c.code = "template_results = let\n\tif isdir(joinpath(output_dir, \"generated_assets\"))\n\t\trm(joinpath(output_dir, \"generated_assets\"); recursive=true)\n\tend\n\t\n\t# let's go! running all the template handlers\n\tprogressmap_async(allfiles; ntasks=NUM_PARALLEL_WORKERS) do f\n\t\tabsolute_path = joinpath(input_dir, f)\n\t\t\n\t\tinput = TemplateInput(;\n\t\t\tcontents=read(absolute_path),\n\t\t\tabsolute_path,\n\t\t\trelative_path=f,\n\t\t\tfrontmatter=FrontMatter(\n\t\t\t\t\"root_url\" => root_url,\n\t\t\t),\n\t\t)\n\t\t\n\t\toutput = try\n\t\t\ttemplate_handler(Val(Symbol(splitext(f)[2])), input)\n\t\tcatch e\n\t\t\t@error \"Template handler failed\" f exception=(e,catch_backtrace())\n\t\t\trethrow()\n\t\tend\n\n\t\tinput, output\n\tend\nend"
│ c.cell_id = Base.UUID("079a6399-50eb-4dee-a36d-b3dcb81c8456")
│ Text(c.output.body) = Dict{Symbol, Any}(:msg => "AssertionError: PlutoSliderServer does not work on Windows yet! Feel free to open a PR to add support.\nStacktrace:\n [1] 
# ...

```

Is there any other alternative to do something similar? nothing complicated.

Thanks,  
Eduardo

---

<div class="post-metadata">

### Author: ![digital\_carver](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/digital_carver/32/33818_2.png) [@digital\_carver](https://discourse.julialang.org/u/digital_carver)
#### Post date: [June 6, 2025, 9:52pm UTC](https://discourse.julialang.org/t/plutopages-jl-in-windows/129710/2 "2025-06-06T21:52:59Z")

</div>

The reason given for Windows not working ([`/` vs `\` in paths](https://github.com/JuliaPluto/PlutoSliderServer.jl/issues/102)) seems a pretty simple thing, so maybe you can take a look and see how much work it would be to fix it. Even if not a “proper” fix that solves the issue, maybe just `dev`ing the package locally and doing a hacky fix or workaround might be enough to get your `generate` done.

Another option is WSL, maybe with just a tiny Linux distro that’s quick to install and get going, if you don’t plan to use WSL long term.

Another thing worth trying (although I don’t know how well this will actually work) is using Google Colab for this. Colab has Julia support now, and runs on Linux afaik, so uploading your notebooks and running the `generate` there will be a no-frills hack if it works.

---

<div class="post-metadata">

### Author: ![fonsp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fonsp/32/222349_2.png) [@fonsp](https://discourse.julialang.org/u/fonsp)
#### Post date: [June 7, 2025, 12:53pm UTC](https://discourse.julialang.org/t/plutopages-jl-in-windows/129710/3 "2025-06-07T12:53:20Z")

</div>

Hi! The issue is that PlutoSliderServer.jl (a dependency of PlutoPages) does not yet work on Windows, only on MacOS and Linux. @digital_carver gave some good options for getting a Linux development setup.

It shouldn’t be too hard to add Windows support to PlutoSliderServer and PlutoPages – there are a couple of places where `/` from URIs are directly mapped to `/` for paths, and this needs special handling in Windows. Make a fork, try fixing it, and just keep running `test PlutoSliderServer` while working on a fix.

---

<div class="post-metadata">

### Author: ![fonsp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fonsp/32/222349_2.png) [@fonsp](https://discourse.julialang.org/u/fonsp)
#### Post date: [June 7, 2025, 4:49pm UTC](https://discourse.julialang.org/t/plutopages-jl-in-windows/129710/4 "2025-06-07T16:49:59Z")

</div>

I wrote a bit more info in the issue [PlutoSliderServer on Windows · Issue #102 · JuliaPluto/PlutoSliderServer.jl · GitHub](https://github.com/JuliaPluto/PlutoSliderServer.jl/issues/102), this is a good first issue to get started if people are interested in contributing to open source Pluto/Julia!

---

<div class="post-metadata">

### Author: ![eduardovrs](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/eduardovrs/32/20041_2.png) [@eduardovrs](https://discourse.julialang.org/u/eduardovrs)
#### Post date: [June 9, 2025, 4:11pm UTC](https://discourse.julialang.org/t/plutopages-jl-in-windows/129710/5 "2025-06-09T16:11:46Z")

</div>

Thanks for the help to both @digital_carver and @fonsp, I understand the issue now, not sure how to make it work yet, and but will give it a try to make it work I have to start somewhere.

@fonsp great work with Pluto, it’s awesome to use it when ever I can.

Thanks,  
Eduardo

---

<div class="post-metadata">

### Author: ![eduardovrs](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/eduardovrs/32/20041_2.png) [@eduardovrs](https://discourse.julialang.org/u/eduardovrs)
#### Post date: [July 4, 2025, 2:01am UTC](https://discourse.julialang.org/t/plutopages-jl-in-windows/129710/6 "2025-07-04T02:01:34Z")

</div>

Finally got some time to work in this 🙂 and here is a little update about this.

As @fonsp said, I have been trying to fix it and running `test PlutoSliderServer`. Mainly I have adding `joinpath(...)` in the run tests so they are compatible with Windows.

Right now I am stuck in some errors of the `test`s.

The first one is in `static_export.jl`: “static - Index HTML and JSON - fancy=false” , it looks for the a notebook path in the JSON file `pluto_export.json`. I believe is about escaping the `\` when JSON file is made.

Test Failed:

```julia
static - Index HTML and JSON – fancy=false: Test Failed at C:\Users\EV\.julia\dev\PlutoSliderServer\test\static export.jl:252
  Expression: occursin(p, jsonstr)
   Evaluated: occursin("subdir\\c.plutojl", "{\"notebooks\":{\"b.pluto.jl\":{\"id\":\"b.pluto.jl\",\"hash\":\"xuMH18BT9LlXOVZa1gKokIr65kzVGewh5bWfCAfL90I\",\"html_path\":\"b.html\",\"statefile_path\":\"b.plutostate\",\"notebookfile_path\":null,\"current_hash\":\"xuMH18BT9LlXOVZa1gKokIr65kzVGewh5bWfCAfL90I\",\"desired_hash\":\"xuMH18BT9LlXOVZa1gKokIr65kzVGewh5bWfCAfL90I\",\"frontmatter\":{\"title\":\"b\"}},\"a.jl\":{\"id\":\"a.jl\",\"hash\":\"_huF1Zv0MKEBI3H0EnYIe0jbxZKzsWarNzg-JL4zt9k\",\"html_path\":\"a.html\",\"statefile_path\":\"a.plutostate\",\"notebookfile_path\":null,\"current_hash\":\"_huF1Zv0MKEBI3H0EnYIe0jbxZKzsWarNzg-JL4zt9k\",\"desired_hash\":\"_huF1Zv0MKEBI3H0EnYIe0jbxZKzsWarNzg-JL4zt9k\",\"frontmatter\":{\"author_url\":\"https://github.com/JuliaPluto\",\"image\":\"https://upload.wikimedia.org/wikipedia/commons/9/99/Unofficial_JavaScript_logo_2.svg\",\"title\":\"My<Title\",\"tags\":[\"aaa\",\"bbb\"],\"author_name\":\"Pluto.jl\",\"description\":\"ccc\",\"license\":\"Unlicense\"}},\"subdir\\\\c.plutojl\":{\"id\":\"subdir\\\\c.plutojl\",\"hash\":\"xuMH18BT9LlXOVZa1gKokIr65kzVGewh5bWfCAfL90I\",\"html_path\":\"subdir\\\\c.html\",\"statefile_path\":\"subdir\\\\c.plutostate\",\"notebookfile_path\":null,\"current_hash\":\"xuMH18BT9LlXOVZa1gKokIr65kzVGewh5bWfCAfL90I\",\"desired_hash\":\"xuMH18BT9LlXOVZa1gKokIr65kzVGewh5bWfCAfL90I\",\"frontmatter\":{\"title\":\"c\"}}},\"pluto_version\":\"0.20.8\",\"julia_version\":\"1.11.5\",\"format_version\":\"1\",\"title\":null,\"description\":null,\"collections\":null,\"binder_url\":\"https://mybinder.org/v2/gh/fonsp/pluto-on-binder/v0.20.8\",\"slider_server_url\":\"krat\"}")

```

`pluto_export.json`:

```json
{
	"notebooks":{
		"b.pluto.jl":{
			"id":"b.pluto.jl",
			"hash":"xuMH18BT9LlXOVZa1gKokIr65kzVGewh5bWfCAfL90I",
			"html_path":"b.html","statefile_path":"b.plutostate",
			"notebookfile_path":null,
			"current_hash":"xuMH18BT9LlXOVZa1gKokIr65kzVGewh5bWfCAfL90I",
			"desired_hash":"xuMH18BT9LlXOVZa1gKokIr65kzVGewh5bWfCAfL90I",
			"frontmatter":{"title":"b"}
		},
		
		"a.jl":{
			"id":"a.jl",
			"hash":"_huF1Zv0MKEBI3H0EnYIe0jbxZKzsWarNzg-JL4zt9k",
			"html_path":"a.html",
			"statefile_path":"a.plutostate",
			"notebookfile_path":null,
			"current_hash":"_huF1Zv0MKEBI3H0EnYIe0jbxZKzsWarNzg-JL4zt9k",
			"desired_hash":"_huF1Zv0MKEBI3H0EnYIe0jbxZKzsWarNzg-JL4zt9k",
			"frontmatter":{
				"author_url":"https://github.com/JuliaPluto",
				"image":"https://upload.wikimedia.org/wikipedia/commons/9/99/Unofficial_JavaScript_logo_2.svg",
				"title":"My<Title",
				"tags":["aaa","bbb"],
				"author_name":"Pluto.jl",
				"description":"ccc",
				"license":"Unlicense"
			}
		},
		
		"subdir\\c.plutojl":{
			"id":"subdir\\c.plutojl",
			"hash":"xuMH18BT9LlXOVZa1gKokIr65kzVGewh5bWfCAfL90I",
			"html_path":"subdir\\c.html",
			"statefile_path":"subdir\\c.plutostate",
			"notebookfile_path":null,
			"current_hash":"xuMH18BT9LlXOVZa1gKokIr65kzVGewh5bWfCAfL90I",
			"desired_hash":"xuMH18BT9LlXOVZa1gKokIr65kzVGewh5bWfCAfL90I",
			"frontmatter":{"title":"c"}
		}
	},
	
	"pluto_version":"0.20.8",
	"julia_version":"1.11.5",
	"format_version":"1",
	"title":null,
	"description":null,
	"collections":null,
	"binder_url":"https://mybinder.org/v2/gh/fonsp/pluto-on-binder/v0.20.8",
	"slider_server_url":"krat"
}

```

Another error in `/HTTP requests.jl`: “HTTP requests: static”.

```julia
HTTP requests: static: Error During Test at C:\Users\EV\.julia\dev\PlutoSliderServer\test\HTTP requests.jl:190
  Test threw exception
  Expression: s_export_only.run isa PlutoSliderServer.var"../Types.jl".FinishedNotebook
  UndefVarError: `../Types.jl` not defined in `PlutoSliderServer`
  Suggestion: check for spelling errors or missing imports.
  Stacktrace:
   [1] getproperty(x::Module, f::Symbol)
     @ Base .\Base.jl:42
   [2] macro expansion
     @ C:\Users\EV\.julia\juliaup\julia-1.11.5+0.x64.w64.mingw32\share\julia\stdlib\v1.11\Test\src\Test.jl:676 [inlined]
   [3] macro expansion
     @ C:\Users\EV\.julia\dev\PlutoSliderServer\test\HTTP requests.jl:190 [inlined]
   [4] macro expansion
     @ C:\Users\EV\.julia\juliaup\julia-1.11.5+0.x64.w64.mingw32\share\julia\stdlib\v1.11\Test\src\Test.jl:1704 [inlined]
   [5] top-level scope
     @ C:\Users\EV\.julia\dev\PlutoSliderServer\test\HTTP requests.jl:136
┌ Info: Request hash not found. See error hint in my source code.
└ notebook_hash = "ungWv48Bz-pBQUDeXa4iI7ADYaOWF3qctBD_YfIAFa0"
response.headers = Pair{SubString{String}, SubString{String}}["Content-Type" => "text/html; charset=utf-8", "Content-Length" => "574", "Access-Control-Allow-Origin" => "*", "Cache-Control" => "no-store, no-cache", "Referrer-Policy" => "origin-when-cross-origin"]
response.headers = Pair{SubString{String}, SubString{String}}["Content-Type" => "application/json; charset=utf-8", "Access-Control-Allow-Origin" => "*", "Cache-Control" => "no-store, no-cache", "Referrer-Policy" => "origin-when-cross-origin", "Transfer-Encoding" => "chunked"]
response.headers = Pair{SubString{String}, SubString{String}}["Content-Type" => "text/html; charset=utf-8", "Content-Length" => "5246", "Access-Control-Allow-Origin" => "*", "Referrer-Policy" => "origin-when-cross-origin"]
response.headers = Pair{SubString{String}, SubString{String}}["Content-Type" => "text/julia; charset=utf-8", "Content-Length" => "518", "Access-Control-Allow-Origin" => "*", "Referrer-Policy" => "origin-when-cross-origin"]
response.headers = Pair{SubString{String}, SubString{String}}["Content-Type" => "application/octet-stream", "Content-Length" => "1993", "Access-Control-Allow-Origin" => "*", "Referrer-Policy" => "origin-when-cross-origin"]
response.headers = Pair{SubString{String}, SubString{String}}["Content-Type" => "text/html; charset=utf-8", "Content-Length" => "4873", "Access-Control-Allow-Origin" => "*", "Referrer-Policy" => "origin-when-cross-origin"]
response.headers = Pair{SubString{String}, SubString{String}}["Content-Type" => "text/julia; charset=utf-8", "Content-Length" => "218", "Access-Control-Allow-Origin" => "*", "Referrer-Policy" => "origin-when-cross-origin"]
response.headers = Pair{SubString{String}, SubString{String}}["Content-Type" => "application/octet-stream", "Content-Length" => "1780", "Access-Control-Allow-Origin" => "*", "Referrer-Policy" => "origin-when-cross-origin"]
response.headers = Pair{SubString{String}, SubString{String}}["Content-Type" => "text/html; charset=utf-8", "Content-Length" => "4873", "Access-Control-Allow-Origin" => "*", "Referrer-Policy" => "origin-when-cross-origin"]
response.headers = Pair{SubString{String}, SubString{String}}["Content-Type" => "application/octet-stream", "Content-Length" => "218", "Access-Control-Allow-Origin" => "*", "Referrer-Policy" => "origin-when-cross-origin"]
response.headers = Pair{SubString{String}, SubString{String}}["Content-Type" => "application/octet-stream", "Content-Length" => "1780", "Access-Control-Allow-Origin" => "*", "Referrer-Policy" => "origin-when-cross-origin"]
[ Info: Server on 127.0.0.1:23664 closing
[ Info: DONEZO
Test Summary: | Pass Error Total Time
HTTP requests: static | 48 1 49 11.8s
  Static asset - | 3 3 0.4s
  Static asset - pluto_export.json | 3 3 0.0s
  Static asset - a.html | 5 5 0.0s
  Static asset - a.jl | 4 4 0.0s
  Static asset - a.plutostate | 4 4 0.0s
  Static asset - b.html | 5 5 0.0s
  Static asset - b.pluto.jl | 4 4 0.0s
  Static asset - b.plutostate | 4 4 0.0s
  Static asset - subdir\c.html | 5 5 0.0s
  Static asset - subdir\c.plutojl | 4 4 0.0s
  Static asset - subdir\c.plutostate | 4 4 0.0s
ERROR: LoadError: Some tests did not pass: 48 passed, 0 failed, 1 errored, 0 broken.
in expression starting at C:\Users\EV\.julia\dev\PlutoSliderServer\test\HTTP requests.jl:135
in expression starting at C:\Users\EV\.julia\dev\PlutoSliderServer\test\runtests.jl:14
ERROR: Package PlutoSliderServer errored during testing

```

It would be really helpful some guidance on how I can fix it. I am trying to understand how the package `PlutoSliderServer.jl` works.

Thanks a lot for the help.

---

<div class="post-metadata">

### Author: ![disberd](https://avatars.discourse-cdn.com/v4/letter/d/8edcca/32.png) [@disberd](https://discourse.julialang.org/u/disberd)
#### Post date: [July 4, 2025, 5:36pm UTC](https://discourse.julialang.org/t/plutopages-jl-in-windows/129710/7 "2025-07-04T17:36:38Z")

</div>

Hey @eduardovrs, nice that you started looking into this issue!

I would suggest opening a PR directly, or at least create your own fork of PlutoSliderServer and push your tested changes to a branch there so that people can see better the code you worked on to give you advices more easily.
