Genie.jl
Genie.jl copied to clipboard
Genie template system cannot render custom elements (Web Components)
Describe the bug
Genie throws an error when it encounters autonomous custom elements in a .jl.html
template.
(Autonomous custom elements are basically just HTML elements with custom, hyphenated tag names, e.g. <my-element></my-element>
. They are used to implement Web Components, a WHATWG standard for building reusable UI components.)
Error stacktrace
β Error: 2022-07-29 05:33:49 UndefVarError: prte__navigation not defined
β Stacktrace:
β [1] (::Genie.Renderer.Html.var"#1086#1088"{ProvocaWWWAppTier.TheoryTypes.CoverPage})()
β @ Genie.Renderer.Html /tmp/jl_genie_build_YOIAHv/GenieViews/0b3d20051a772f4ace7e3c5f511d2c37da9a4a57.jl:7
β [2] #invokelatest#2
β @ ./essentials.jl:716 [inlined]
β [3] invokelatest
β @ ./essentials.jl:714 [inlined]
β [4] normal_element(f::Function, elem::String, args::Vector{Any}, attrs::Vector{Pair{Symbol, Any}})
β @ Genie.Renderer.Html ~/.julia/packages/Genie/3nusr/src/renderers/Html.jl:137
β [5] #div#184
β @ ./none:2 [inlined]
β [6] func_0b3d20051a772f4ace7e3c5f511d2c37da9a4a57(; context::Module, coverpage::ProvocaWWWAppTier.TheoryTypes.CoverPage)
β @ Genie.Renderer.Html /tmp/jl_genie_build_YOIAHv/GenieViews/0b3d20051a772f4ace7e3c5f511d2c37da9a4a57.jl:5
β [7] func_0b3d20051a772f4ace7e3c5f511d2c37da9a4a57()
β @ Genie.Renderer.Html /tmp/jl_genie_build_YOIAHv/GenieViews/0b3d20051a772f4ace7e3c5f511d2c37da9a4a57.jl:5
β [8] (::Genie.Renderer.Html.var"#1080#1084")()
β @ Genie.Renderer.Html /tmp/jl_genie_build_YOIAHv/GenieViews/3d028e305c5b9c16a676c61917530fcc0f1b3866.jl:31
β [9] #invokelatest#2
β @ ./essentials.jl:716 [inlined]
β [10] invokelatest
β @ ./essentials.jl:714 [inlined]
β [11] normal_element(f::Function, elem::String, args::Vector{Any}, attrs::Vector{Pair{Symbol, Any}})
β @ Genie.Renderer.Html ~/.julia/packages/Genie/3nusr/src/renderers/Html.jl:137
β [12] #body#76
β @ ./none:2 [inlined]
β [13] (::Genie.Renderer.Html.var"#1077#1081"{ProvocaWWWAppTier.TheoryTypes.CoverPage})()
β @ Genie.Renderer.Html /tmp/jl_genie_build_YOIAHv/GenieViews/3d028e305c5b9c16a676c61917530fcc0f1b3866.jl:9
β [14] #invokelatest#2
β @ ./essentials.jl:716 [inlined]
β [15] invokelatest
β @ ./essentials.jl:714 [inlined]
β [16] normal_element(f::Function, elem::String, args::Vector{Any}, attrs::Vector{Pair{Symbol, Any}})
β @ Genie.Renderer.Html ~/.julia/packages/Genie/3nusr/src/renderers/Html.jl:137
β [17] html(::Function; attrs::Base.Pairs{Symbol, String, NTuple{4, Symbol}, NamedTuple{(:htmlsourceindent, :lang, :xmlns, Symbol("xml:lang")), NTuple{4, String}}})
β @ Genie.Renderer.Html ./none:2
β [18] func_3d028e305c5b9c16a676c61917530fcc0f1b3866(; context::Module, coverpage::ProvocaWWWAppTier.TheoryTypes.CoverPage)
β @ Genie.Renderer.Html /tmp/jl_genie_build_YOIAHv/GenieViews/3d028e305c5b9c16a676c61917530fcc0f1b3866.jl:5
β [19] func_3d028e305c5b9c16a676c61917530fcc0f1b3866()
β @ Genie.Renderer.Html /tmp/jl_genie_build_YOIAHv/GenieViews/3d028e305c5b9c16a676c61917530fcc0f1b3866.jl:5
β [20] #invokelatest#2
β @ ./essentials.jl:716 [inlined]
β [21] invokelatest
β @ ./essentials.jl:714 [inlined]
β [22] Genie.Renderer.WebRenderable(::Function)
β @ Genie.Renderer ~/.julia/packages/Genie/3nusr/src/Renderer.jl:158
β [23] |>
β @ ./operators.jl:966 [inlined]
β [24] render(::Type{MIME{Symbol("text/html")}}, viewfile::FilePathsBase.PosixPath; layout::FilePathsBase.PosixPath, context::Module, vars::Base.Pairs{Symbol, ProvocaWWWAppTier.TheoryTypes.CoverPage, Tuple{Symbol}, NamedTuple{(:coverpage,), Tuple{ProvocaWWWAppTier.TheoryTypes.CoverPage}}})
β @ Genie.Renderer.Html ~/.julia/packages/Genie/3nusr/src/renderers/Html.jl:475
β [25] #html#30
β @ ~/.julia/packages/Genie/3nusr/src/renderers/Html.jl:574 [inlined]
β [26] html(resource::Symbol, action::Symbol; layout::Symbol, context::Module, status::Int64, headers::Dict{String, String}, vars::Base.Pairs{Symbol, ProvocaWWWAppTier.TheoryTypes.CoverPage, Tuple{Symbol}, NamedTuple{(:coverpage,), Tuple{ProvocaWWWAppTier.TheoryTypes.CoverPage}}})
β @ Genie.Renderer.Html ~/.julia/packages/Genie/3nusr/src/renderers/Html.jl:486
β [27] render_coverpage
β @ ~/active/ProvocaTeach/ProvocaWWW/ProvocaWWW_App_Tier/app/resources/pieces/PiecesController.jl:119 [inlined]
β [28] render_coverpage(slug::SubString{String}, db_uri::ProvocaWWWAppTier.FantasyLoader.SparqlEndpoint)
β @ ProvocaWWWAppTier.PiecesController ~/active/ProvocaTeach/ProvocaWWW/ProvocaWWW_App_Tier/app/resources/pieces/PiecesController.jl:129
β [29] (::ProvocaWWWAppTier.var"#9#10")()
β @ ProvocaWWWAppTier ~/active/ProvocaTeach/ProvocaWWW/ProvocaWWW_App_Tier/routes.jl:14
β [30] run_route(r::Genie.Router.Route)
β @ Genie.Router ~/.julia/packages/Genie/3nusr/src/Router.jl:527
β [31] route_request(req::HTTP.Messages.Request, res::HTTP.Messages.Response)
β @ Genie.Router ~/.julia/packages/Genie/3nusr/src/Router.jl:169
β [32] handle_request(req::HTTP.Messages.Request, res::HTTP.Messages.Response)
β @ Genie.Server ~/.julia/packages/Genie/3nusr/src/Server.jl:269
β [33] #29
β @ ~/packages/julias/julia-1.7/share/julia/stdlib/v1.7/Distributed/src/macros.jl:123 [inlined]
β [34] run_work_thunk(thunk::Genie.Server.var"#29#30"{HTTP.Messages.Request, HTTP.Messages.Response}, print_error::Bool)
β @ Distributed ~/packages/julias/julia-1.7/share/julia/stdlib/v1.7/Distributed/src/process_messages.jl:63
β [35] #remotecall_fetch#158
β @ ~/packages/julias/julia-1.7/share/julia/stdlib/v1.7/Distributed/src/remotecall.jl:454 [inlined]
β [36] remotecall_fetch
β @ ~/packages/julias/julia-1.7/share/julia/stdlib/v1.7/Distributed/src/remotecall.jl:454 [inlined]
β [37] #remotecall_fetch#162
β @ ~/packages/julias/julia-1.7/share/julia/stdlib/v1.7/Distributed/src/remotecall.jl:496 [inlined]
β [38] remotecall_fetch
β @ ~/packages/julias/julia-1.7/share/julia/stdlib/v1.7/Distributed/src/remotecall.jl:496 [inlined]
β [39] setup_http_listener(req::HTTP.Messages.Request, res::HTTP.Messages.Response)
β @ Genie.Server ~/.julia/packages/Genie/3nusr/src/Server.jl:296
β [40] setup_http_listener
β @ ~/.julia/packages/Genie/3nusr/src/Server.jl:295 [inlined]
β [41] handle
β @ ~/.julia/packages/HTTP/aTjcj/src/Handlers.jl:254 [inlined]
β [42] handle(::HTTP.Handlers.RequestHandlerFunction{typeof(Genie.Server.setup_http_listener)}, ::HTTP.Streams.Stream{HTTP.Messages.Request, HTTP.ConnectionPool.Transaction{Sockets.TCPSocket}})
β @ HTTP.Handlers ~/.julia/packages/HTTP/aTjcj/src/Handlers.jl:277
β [43] setup_http_streamer(http::HTTP.Streams.Stream{HTTP.Messages.Request, HTTP.ConnectionPool.Transaction{Sockets.TCPSocket}})
β @ Genie.Server ~/.julia/packages/Genie/3nusr/src/Server.jl:285
β [44] (::Genie.Server.var"#7#14"{Int64})(http::HTTP.Streams.Stream{HTTP.Messages.Request, HTTP.ConnectionPool.Transaction{Sockets.TCPSocket}})
β @ Genie.Server ~/.julia/packages/Genie/3nusr/src/Server.jl:117
β [45] macro expansion
β @ ~/.julia/packages/HTTP/aTjcj/src/Servers.jl:415 [inlined]
β [46] (::HTTP.Servers.var"#13#14"{Genie.Server.var"#7#14"{Int64}, HTTP.ConnectionPool.Transaction{Sockets.TCPSocket}, HTTP.Servers.Server{Nothing, Sockets.TCPServer}, HTTP.Streams.Stream{HTTP.Messages.Request, HTTP.ConnectionPool.Transaction{Sockets.TCPSocket}}})()
β @ HTTP.Servers ./task.jl:429
β
β @ Genie.Server ~/.julia/packages/Genie/3nusr/src/Server.jl:308
To reproduce
Add any custom element tag, e.g. <my-element></my-element>
(or in my case, <prte-navigation></prte-navigation>
), to a .jl.html
template and have Genie try to render it.
Expected behavior
Donβt throw an error; just treat <my-element></my-element>
as the valid HTML that it is.
Note Because Web Components are completely handled by the browser and client-side JavaScript, all Genie needs to do is not throw an error when it encounters them. There is no need to treat them in a special way.
Additional context
julia> versioninfo()
Julia Version 1.7.3
Commit 742b9abb4d (2022-05-06 12:58 UTC)
Platform Info:
OS: Linux (x86_64-pc-linux-gnu)
CPU: AMD Ryzen 5 2600 Six-Core Processor
WORD_SIZE: 64
LIBM: libopenlibm
LLVM: libLLVM-12.0.1 (ORCJIT, znver1)
(ProvocaWWWAppTier) pkg> st
Project ProvocaWWWAppTier v0.1.0
Status `~/active/ProvocaTeach/ProvocaWWW/ProvocaWWW_App_Tier/Project.toml`
[e30172f5] Documenter v0.27.22
[c43c736e] Genie v5.0.0
[cd3eb016] HTTP v0.9.17
[6d011eab] Inflector v1.0.1
[0f8b85d8] JSON3 v1.9.5
[e6f89c97] LoggingExtras v0.4.9
[739be429] MbedTLS v1.1.1
[295af30f] Revise v3.3.4
[5c2747f8] URIs v1.4.0
[2a0f44e3] Base64
[ade2ca70] Dates
[56ddb016] Logging
Yes, because Genie's rendering layer maps HTML tags to Julia functions. And it doesn't know how to render this one as it doesn't have the corresponding function.
Adding Genie.Renderer.Html.register_normal_element("my__element", context = @__MODULE__)
in the Controller (or in scope) will register the rendering function.
Hm, even with that code in my controller, I still seem to be getting a 500 error:
β Error: 2022-08-01 16:47:32 UndefVarError: prte__navigation not defined
β Stacktrace:
β [1] (::Genie.Renderer.Html.var"#1054#1056"{ProvocaWWWAppTier.TheoryTypes.CoverPage})()
β @ Genie.Renderer.Html /tmp/jl_genie_build_YOIAHv/GenieViews/0b3d20051a772f4ace7e3c5f511d2c37da9a4a57.jl:9
β [2] #invokelatest#2
β @ ./essentials.jl:716 [inlined]
β [3] invokelatest
β @ ./essentials.jl:714 [inlined]
β [4] normal_element(f::Function, elem::String, args::Vector{Any}, attrs::Vector{Pair{Symbol, Any}})
β @ Genie.Renderer.Html ~/.julia/packages/Genie/3nusr/src/renderers/Html.jl:137
β [5] #div#184
β @ ./none:2 [inlined]
β [6] func_0b3d20051a772f4ace7e3c5f511d2c37da9a4a57(; context::Module, coverpage::ProvocaWWWAppTier.TheoryTypes.CoverPage)
β @ Genie.Renderer.Html /tmp/jl_genie_build_YOIAHv/GenieViews/0b3d20051a772f4ace7e3c5f511d2c37da9a4a57.jl:5
β [7] func_0b3d20051a772f4ace7e3c5f511d2c37da9a4a57()
β @ Genie.Renderer.Html /tmp/jl_genie_build_YOIAHv/GenieViews/0b3d20051a772f4ace7e3c5f511d2c37da9a4a57.jl:5
β [8] (::Genie.Renderer.Html.var"#1062#1066")()
β @ Genie.Renderer.Html /tmp/jl_genie_build_YOIAHv/GenieViews/3d028e305c5b9c16a676c61917530fcc0f1b3866.jl:53
β [9] #invokelatest#2
β @ ./essentials.jl:716 [inlined]
β [10] invokelatest
β @ ./essentials.jl:714 [inlined]
β [11] normal_element(f::Function, elem::String, args::Vector{Any}, attrs::Vector{Pair{Symbol, Any}})
β @ Genie.Renderer.Html ~/.julia/packages/Genie/3nusr/src/renderers/Html.jl:137
β [12] #body#76
β @ ./none:2 [inlined]
β [13] (::Genie.Renderer.Html.var"#1059#1063"{ProvocaWWWAppTier.TheoryTypes.CoverPage})()
β @ Genie.Renderer.Html /tmp/jl_genie_build_YOIAHv/GenieViews/3d028e305c5b9c16a676c61917530fcc0f1b3866.jl:9
β [14] #invokelatest#2
β @ ./essentials.jl:716 [inlined]
β [15] invokelatest
β @ ./essentials.jl:714 [inlined]
β [16] normal_element(f::Function, elem::String, args::Vector{Any}, attrs::Vector{Pair{Symbol, Any}})
β @ Genie.Renderer.Html ~/.julia/packages/Genie/3nusr/src/renderers/Html.jl:137
β [17] html(::Function; attrs::Base.Pairs{Symbol, String, NTuple{4, Symbol}, NamedTuple{(:htmlsourceindent, :lang, :xmlns, Symbol("xml:lang")), NTuple{4, String}}})
β @ Genie.Renderer.Html ./none:2
β [18] func_3d028e305c5b9c16a676c61917530fcc0f1b3866(; context::Module, coverpage::ProvocaWWWAppTier.TheoryTypes.CoverPage)
β @ Genie.Renderer.Html /tmp/jl_genie_build_YOIAHv/GenieViews/3d028e305c5b9c16a676c61917530fcc0f1b3866.jl:5
β [19] func_3d028e305c5b9c16a676c61917530fcc0f1b3866()
β @ Genie.Renderer.Html /tmp/jl_genie_build_YOIAHv/GenieViews/3d028e305c5b9c16a676c61917530fcc0f1b3866.jl:5
β [20] #invokelatest#2
β @ ./essentials.jl:716 [inlined]
β [21] invokelatest
β @ ./essentials.jl:714 [inlined]
β [22] Genie.Renderer.WebRenderable(::Function)
β @ Genie.Renderer ~/.julia/packages/Genie/3nusr/src/Renderer.jl:158
β [23] |>
β @ ./operators.jl:966 [inlined]
β [24] render(::Type{MIME{Symbol("text/html")}}, viewfile::FilePathsBase.PosixPath; layout::FilePathsBase.PosixPath, context::Module, vars::Base.Pairs{Symbol, ProvocaWWWAppTier.TheoryTypes.CoverPage, Tuple{Symbol}, NamedTuple{(:coverpage,), Tuple{ProvocaWWWAppTier.TheoryTypes.CoverPage}}})
β @ Genie.Renderer.Html ~/.julia/packages/Genie/3nusr/src/renderers/Html.jl:475
β [25] #html#30
β @ ~/.julia/packages/Genie/3nusr/src/renderers/Html.jl:574 [inlined]
β [26] html(resource::Symbol, action::Symbol; layout::Symbol, context::Module, status::Int64, headers::Dict{String, String}, vars::Base.Pairs{Symbol, ProvocaWWWAppTier.TheoryTypes.CoverPage, Tuple{Symbol}, NamedTuple{(:coverpage,), Tuple{ProvocaWWWAppTier.TheoryTypes.CoverPage}}})
β @ Genie.Renderer.Html ~/.julia/packages/Genie/3nusr/src/renderers/Html.jl:486
β [27] render_coverpage
β @ ~/active/ProvocaTeach/ProvocaWWW/ProvocaWWW_App_Tier/app/resources/pieces/PiecesController.jl:128 [inlined]
β [28] render_coverpage(slug::SubString{String}, db_uri::ProvocaWWWAppTier.FantasyLoader.SparqlEndpoint)
β @ ProvocaWWWAppTier.PiecesController ~/active/ProvocaTeach/ProvocaWWW/ProvocaWWW_App_Tier/app/resources/pieces/PiecesController.jl:138
β [29] (::ProvocaWWWAppTier.var"#9#10")()
β @ ProvocaWWWAppTier ~/active/ProvocaTeach/ProvocaWWW/ProvocaWWW_App_Tier/routes.jl:14
β [30] run_route(r::Genie.Router.Route)
β @ Genie.Router ~/.julia/packages/Genie/3nusr/src/Router.jl:527
β [31] route_request(req::HTTP.Messages.Request, res::HTTP.Messages.Response)
β @ Genie.Router ~/.julia/packages/Genie/3nusr/src/Router.jl:169
β [32] handle_request(req::HTTP.Messages.Request, res::HTTP.Messages.Response)
β @ Genie.Server ~/.julia/packages/Genie/3nusr/src/Server.jl:269
β [33] #29
β @ ~/packages/julias/julia-1.7/share/julia/stdlib/v1.7/Distributed/src/macros.jl:123 [inlined]
β [34] run_work_thunk(thunk::Genie.Server.var"#29#30"{HTTP.Messages.Request, HTTP.Messages.Response}, print_error::Bool)
β @ Distributed ~/packages/julias/julia-1.7/share/julia/stdlib/v1.7/Distributed/src/process_messages.jl:63
β [35] #remotecall_fetch#158
β @ ~/packages/julias/julia-1.7/share/julia/stdlib/v1.7/Distributed/src/remotecall.jl:454 [inlined]
β [36] remotecall_fetch
β @ ~/packages/julias/julia-1.7/share/julia/stdlib/v1.7/Distributed/src/remotecall.jl:454 [inlined]
β [37] #remotecall_fetch#162
β @ ~/packages/julias/julia-1.7/share/julia/stdlib/v1.7/Distributed/src/remotecall.jl:496 [inlined]
β [38] remotecall_fetch
β @ ~/packages/julias/julia-1.7/share/julia/stdlib/v1.7/Distributed/src/remotecall.jl:496 [inlined]
β [39] setup_http_listener(req::HTTP.Messages.Request, res::HTTP.Messages.Response)
β @ Genie.Server ~/.julia/packages/Genie/3nusr/src/Server.jl:296
β [40] setup_http_listener
β @ ~/.julia/packages/Genie/3nusr/src/Server.jl:295 [inlined]
β [41] handle
β @ ~/.julia/packages/HTTP/aTjcj/src/Handlers.jl:254 [inlined]
β [42] handle(::HTTP.Handlers.RequestHandlerFunction{typeof(Genie.Server.setup_http_listener)}, ::HTTP.Streams.Stream{HTTP.Messages.Request, HTTP.ConnectionPool.Transaction{Sockets.TCPSocket}})
β @ HTTP.Handlers ~/.julia/packages/HTTP/aTjcj/src/Handlers.jl:277
β [43] setup_http_streamer(http::HTTP.Streams.Stream{HTTP.Messages.Request, HTTP.ConnectionPool.Transaction{Sockets.TCPSocket}})
β @ Genie.Server ~/.julia/packages/Genie/3nusr/src/Server.jl:285
β [44] (::Genie.Server.var"#7#14"{Int64})(http::HTTP.Streams.Stream{HTTP.Messages.Request, HTTP.ConnectionPool.Transaction{Sockets.TCPSocket}})
β @ Genie.Server ~/.julia/packages/Genie/3nusr/src/Server.jl:117
β [45] macro expansion
β @ ~/.julia/packages/HTTP/aTjcj/src/Servers.jl:415 [inlined]
β [46] (::HTTP.Servers.var"#13#14"{Genie.Server.var"#7#14"{Int64}, HTTP.ConnectionPool.Transaction{Sockets.TCPSocket}, HTTP.Servers.Server{Nothing, Sockets.TCPServer}, HTTP.Streams.Stream{HTTP.Messages.Request, HTTP.ConnectionPool.Transaction{Sockets.TCPSocket}}})()
β @ HTTP.Servers ./task.jl:429
Can you try Genie.Renderer.Html.register_normal_element("my__element")
instead? The context
matters and that's dependent on how you set up the context
for the view rendering (that defines the scope where this function is registered). Basically, it needs to be in the same context
as the rendering of the view.
Same error. Only workaround I could find was using a JavaScript document.createElement()
on page load. (Very bad for SEO due to the cumulative layout shift.)
Is there no way to specify the tag name in Genie? Because I donβt think it has any way of knowing that "my__element"
(with an underscore) corresponds to <my-element>
(with a hyphen).
So have you tried it and hasn't worked?
Is there no way to specify the tag name in Genie? Because I donβt think it has any way of knowing that "my__element" (with an underscore) corresponds to
(with a hyphen).
It's how it works by design and that's how you specify the tag name in Genie.
You can see it here (and in many other places): https://github.com/GenieFramework/StippleUI.jl/blob/2135b6522d9f4c77c992c0507af3c034b0bbea99/src/FormInputs.jl#L8