diff --git a/importing local JS modules 2.jl b/importing local JS modules 2.jl new file mode 100644 index 00000000..54773eb3 --- /dev/null +++ b/importing local JS modules 2.jl @@ -0,0 +1,382 @@ +### A Pluto.jl notebook ### +# v0.19.38 + +using Markdown +using InteractiveUtils + +# This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error). +macro bind(def, element) + quote + local iv = try Base.loaded_modules[Base.PkgId(Base.UUID("6e696c72-6542-2067-7265-42206c756150"), "AbstractPlutoDingetjes")].Bonds.initial_value catch; b -> missing; end + local el = $(esc(element)) + global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : iv(el) + el + end +end + +# ╔═╡ 2b517038-9a33-4aa7-b33e-9835b68b68e2 +using HypertextLiteral + +# ╔═╡ ce9d33f2-ca7b-11ee-3907-c534f702f4c1 +import AbstractPlutoDingetjes + +# ╔═╡ 4d08d092-2caf-47b7-8423-b94bb07d78bf +md""" +# Loading the dependency + +This should be done once, during package init. +""" + +# ╔═╡ d6eb8b85-6d41-40da-8072-0198aed0e787 +# this would be better if it was from an artifact +js_dep_path = download("https://esm.sh/v135/plotly.js-dist-min@2.29.1/es2022/plotly.js-dist-min.bundle.mjs") + +# ╔═╡ 31859a35-9779-4165-a926-9abe574c0658 +js_dep_contents = read(js_dep_path, String) + +# ╔═╡ a02834ab-5a6a-4516-a2d8-9e12a8cbe176 +Text("$(length(js_dep_contents) / 1e6) MB") + +# ╔═╡ bb536569-d8bb-4049-9ec8-5ce32af6e27c +md""" +# Magic + +We use [`AbstractPlutoDingetjes.Display.published_to_js`](https://plutojl.org/en/docs/abstractplutodingetjes/#published_to_js) to make the string available to JS running in the cell output. Inside the JS, we turn the string into a blob URL and call `import()` on that. + +We create a `Map`, called `window.created_imports`, to keep track of strings that we already imported. When you re-import the same string a second time, the original import result is retured. +""" + +# ╔═╡ 47873b9e-e4d3-4fd2-b5c1-912b4710c825 +begin + struct _ImportedLocalJS + published + end + + function Base.show(io, m::MIME"text/javascript", i::_ImportedLocalJS) + write(io, + """ + await (() => { + window.created_imports = window.created_imports ?? new Map(); + let code = """ + ) + Base.show(io, m, i.published) + + write(io, + """; + if(created_imports.has(code)){ + return created_imports.get(code); + } else { + let blob_promise = new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = async () => { + try { + resolve(await import(reader.result)); + } catch(e) { + reject(); + } + } + reader.onerror = () => reject(); + reader.onabort = () => reject(); + reader.readAsDataURL( + new Blob([code], {type : "text/javascript"})) + }); + created_imports.set(code, blob_promise); + return blob_promise; + } + })() + """ + ) + end + + + """ + ```julia + import_local_js(js_module_code::AbstractString) + ``` + + Make the contents of an ES6 module available to JavaScript. This function uses fancy Pluto data transfer and caching to make sure that the actual module code is only downloaded and loaded once by the browser, when the same data is used (multiple times) by multiple cells. + + Use it like so: + + ```julia + HypertextLiteral.@htl(""\" + const themodule = \$(import_local_js(js_dep_contents)) + "\"") + ``` + + # What is an ES6 module? + This function is for ES6 modules, which you would typically load with + ```js + import {something} from "https://esm.sh/somepackage@1.2.3" + + // or in Pluto cells: + const {something} = await import + ``` + + If your library is loaded in the old-school way, then it cannot be loaded (yet) with `import_local_js`: + + ```html + + + ``` + + If this is your case, consider using [esm.sh](esm.sh) to turn the package into an ES6 module. + + # Why? + Using this function in your package (instead of just `await import("https://esm.sh/...")` in JavaScript), in combination with Artifacts.toml ensures that the module is available when viewing a Pluto notebook offline. The same is true for exported HTML documents. + + + # Bundled + This only works well if your ES6 module is bundled: it contains no further `import`s. + + If you are working with a local JS codebase, then you could use `deno bundle` or other bundling tools to get a single JS file. If you use a package from a CDN, then see if your CDN has the option to bundle it for you. In esm, this means adding `.bundle.js` to the URL. + + + # Example + + ```julia + js_dep_path = download("https://esm.sh/v135/plotly.js-dist-min@2.29.1/es2022/plotly.js-dist-min.bundle.mjs") + + js_dep_contents = read(js_dep_path, String) + + @htl("\"" + + + "\"") + ``` + + """ + function import_local_js(code::AbstractString) + + code_js = + try + AbstractPlutoDingetjes.Display.published_to_js(code) + catch e + @warn "published_to_js did not work" exception=(e,catch_backtrace()) maxlog=1 + repr(code) + end + + _ImportedLocalJS(code_js) + end +end + +# ╔═╡ 6da1183a-cc84-41f1-8e7c-b5d20e76563d + + +# ╔═╡ 5b01c9bd-bd44-4650-91ba-a492686b522d +@bind x html"" + +# ╔═╡ 1a4a8409-6613-4507-9d36-e93a776db19b +function my_widget(x) + @htl(""" + + + + """) +end + +# ╔═╡ 2328495c-b4fb-4dfd-916e-1bdefc0212ea +my_widget(x) + +# ╔═╡ 00000000-0000-0000-0000-000000000001 +PLUTO_PROJECT_TOML_CONTENTS = """ +[deps] +AbstractPlutoDingetjes = "6e696c72-6542-2067-7265-42206c756150" +HypertextLiteral = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2" + +[compat] +AbstractPlutoDingetjes = "~1.2.3" +HypertextLiteral = "~0.9.5" +""" + +# ╔═╡ 00000000-0000-0000-0000-000000000002 +PLUTO_MANIFEST_TOML_CONTENTS = """ +# This file is machine-generated - editing it directly is not advised + +julia_version = "1.10.0" +manifest_format = "2.0" +project_hash = "70be3486f293846b1ddc7c639dfbf884afc3561e" + +[[deps.AbstractPlutoDingetjes]] +deps = ["Pkg"] +git-tree-sha1 = "c278dfab760520b8bb7e9511b968bf4ba38b7acc" +uuid = "6e696c72-6542-2067-7265-42206c756150" +version = "1.2.3" + +[[deps.ArgTools]] +uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" +version = "1.1.1" + +[[deps.Artifacts]] +uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" + +[[deps.Base64]] +uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" + +[[deps.Dates]] +deps = ["Printf"] +uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" + +[[deps.Downloads]] +deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"] +uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" +version = "1.6.0" + +[[deps.FileWatching]] +uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" + +[[deps.HypertextLiteral]] +deps = ["Tricks"] +git-tree-sha1 = "7134810b1afce04bbc1045ca1985fbe81ce17653" +uuid = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2" +version = "0.9.5" + +[[deps.InteractiveUtils]] +deps = ["Markdown"] +uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" + +[[deps.LibCURL]] +deps = ["LibCURL_jll", "MozillaCACerts_jll"] +uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" +version = "0.6.4" + +[[deps.LibCURL_jll]] +deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] +uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" +version = "8.4.0+0" + +[[deps.LibGit2]] +deps = ["Base64", "LibGit2_jll", "NetworkOptions", "Printf", "SHA"] +uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" + +[[deps.LibGit2_jll]] +deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll"] +uuid = "e37daf67-58a4-590a-8e99-b0245dd2ffc5" +version = "1.6.4+0" + +[[deps.LibSSH2_jll]] +deps = ["Artifacts", "Libdl", "MbedTLS_jll"] +uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" +version = "1.11.0+1" + +[[deps.Libdl]] +uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" + +[[deps.Logging]] +uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" + +[[deps.Markdown]] +deps = ["Base64"] +uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" + +[[deps.MbedTLS_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" +version = "2.28.2+1" + +[[deps.MozillaCACerts_jll]] +uuid = "14a3606d-f60d-562e-9121-12d972cd8159" +version = "2023.1.10" + +[[deps.NetworkOptions]] +uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" +version = "1.2.0" + +[[deps.Pkg]] +deps = ["Artifacts", "Dates", "Downloads", "FileWatching", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] +uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" +version = "1.10.0" + +[[deps.Printf]] +deps = ["Unicode"] +uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" + +[[deps.REPL]] +deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] +uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" + +[[deps.Random]] +deps = ["SHA"] +uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" + +[[deps.SHA]] +uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" +version = "0.7.0" + +[[deps.Serialization]] +uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" + +[[deps.Sockets]] +uuid = "6462fe0b-24de-5631-8697-dd941f90decc" + +[[deps.TOML]] +deps = ["Dates"] +uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" +version = "1.0.3" + +[[deps.Tar]] +deps = ["ArgTools", "SHA"] +uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" +version = "1.10.0" + +[[deps.Tricks]] +git-tree-sha1 = "eae1bb484cd63b36999ee58be2de6c178105112f" +uuid = "410a4b4d-49e4-4fbc-ab6d-cb71b17b3775" +version = "0.1.8" + +[[deps.UUIDs]] +deps = ["Random", "SHA"] +uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" + +[[deps.Unicode]] +uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" + +[[deps.Zlib_jll]] +deps = ["Libdl"] +uuid = "83775a58-1f1d-513f-b197-d71354ab007a" +version = "1.2.13+1" + +[[deps.nghttp2_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" +version = "1.52.0+1" + +[[deps.p7zip_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" +version = "17.4.0+2" +""" + +# ╔═╡ Cell order: +# ╠═ce9d33f2-ca7b-11ee-3907-c534f702f4c1 +# ╠═2b517038-9a33-4aa7-b33e-9835b68b68e2 +# ╟─4d08d092-2caf-47b7-8423-b94bb07d78bf +# ╠═d6eb8b85-6d41-40da-8072-0198aed0e787 +# ╠═31859a35-9779-4165-a926-9abe574c0658 +# ╟─a02834ab-5a6a-4516-a2d8-9e12a8cbe176 +# ╟─bb536569-d8bb-4049-9ec8-5ce32af6e27c +# ╟─47873b9e-e4d3-4fd2-b5c1-912b4710c825 +# ╠═6da1183a-cc84-41f1-8e7c-b5d20e76563d +# ╠═5b01c9bd-bd44-4650-91ba-a492686b522d +# ╠═2328495c-b4fb-4dfd-916e-1bdefc0212ea +# ╠═1a4a8409-6613-4507-9d36-e93a776db19b +# ╟─00000000-0000-0000-0000-000000000001 +# ╟─00000000-0000-0000-0000-000000000002