GenieFramework / Genie.jl

🧞The highly productive Julia web framework
https://genieframework.com
MIT License
2.26k stars 190 forks source link

Remove includet #717

Open PingoLee opened 2 months ago

PingoLee commented 2 months ago

I'm trying to use PrecompileTools in my Genie application and because of this, I replaced the Revise.includet. However, I got this message when I tried to precompile: ERROR: Evaluation into the closed module `Loader` breaks incremental compilation because the side effects will not be permanent. This is likely due to some other module mutating `Loader` with `eval` during precompilation - don't do this

Is there any way to replace eval calls in Genie?

I'm try do this in https://github.com/PingoLee/LinkSUS

essenciary commented 2 months ago

@PingoLee I've also started to get the error and I tried everything to get rid of it - I'm also curious on how to fix it. What does the PR solve?

PingoLee commented 2 months ago

@essenciary, The PR solves one eval. With this PR # Genie.Configuration.isdev() && Core.eval(context, :(__revise_mode__ = :eval)) can be removed. Besides this, abspath allows starting the app this way (that is important to precompile all apps):

module LinkSUS

using PrecompileTools: @setup_workload, @compile_workload, verbose

using Genie

const up = Genie.up
export up

Genie.genie(; context = @__MODULE__)

...

And for last, autoload may include a *.jl file.

I have some ideas to replace the others eval, however, I don't have much experience in app development. If you accept this PR or give me some feedback, if you get into any trouble, I can spend some time to solve this

PingoLee commented 2 months ago

@essenciary I did a lot of modifications in Genie in https://github.com/PingoLee/Genie.jl. However, I don't overcome the problem to compilating this function:

function get_template(path::String; partial::Bool = true, context::Module = @__MODULE__, vars...) :: Function
  path, extension = Genie.Renderer.view_file_info(path, SUPPORTED_HTML_OUTPUT_FILE_FORMATS)

  f_name = Genie.Renderer.function_name(string(path, partial)) |> Symbol
  mod_name = Genie.Renderer.m_name(string(path, partial)) * HTML_FILE_EXT
  f_path = joinpath(Genie.config.path_build, Genie.Renderer.BUILD_NAME, mod_name)
  f_stale = Genie.Renderer.build_is_stale(path, f_path)

  if f_stale || ! isdefined(context, f_name)
    if extension in MARKDOWN_FILE_EXT
      path = MdHtml.md_to_html(path, context = context)
    end

    parsingfunction = (extension == HTML_FILE_EXT ? julia_to_julia : html_to_julia)

    f_stale && Genie.Renderer.build_module(parsingfunction(path, partial = partial, extension = extension), path, mod_name)

    # that return a erro when i try compile, and i don't know why    
    return Base.include(context, joinpath(Genie.config.path_build, Genie.Renderer.BUILD_NAME, mod_name))
  end

  println("Returning: ", getfield(context, f_name))

  getfield(context, f_name)
end

So, create other functions to create a template based in string, my results are:

ENV["PRECOMPILE"] = false
ENV["GENIE_ENV"] = "prod"

using Pkg
Pkg.activate(".")
using LinkSUS
LinkSUS.main()
LinkSUS.Genie.isrunning() || up(port=8001)

# first run (new function without precompilation)
@time LinkSUS.Genie.Renderer.Html.raw_html(LinkSUS.Genie.Renderer.filepath("layouts\\templates\\linkage.jl.html"), layout = LinkSUS.Genie.Renderer.filepath("layouts\\app.jl.html"), scripts="<script src='/js/cust/linksus.js'></script>")
  0.319638 seconds (258.72 k allocations: 17.696 MiB, 3.04% gc time, 99.76% compilation time)

# second run (new function without precompilation)
@time LinkSUS.Genie.Renderer.Html.raw_html(LinkSUS.Genie.Renderer.filepath("layouts\\templates\\linkage.jl.html"), layout = LinkSUS.Genie.Renderer.filepath("layouts\\app.jl.html"), scripts="<script src='/js/cust/linksus.js'></script>")
  0.000404 seconds (105 allocations: 73.008 KiB)

# first run (standard function without precompilation)
@time LinkSUS.Genie.Renderer.Html.html(LinkSUS.Genie.Renderer.filepath("layouts\\templates\\linkage.jl.html"), layout = LinkSUS.Genie.Renderer.filepath("layouts\\app.jl.html"), scripts="<script src='/js/cust/linksus.js'></script>")
  8.589951 seconds (9.32 M allocations: 640.676 MiB, 1.74% gc time, 98.85% compilation time: <1% of which was recompilation)

# second run (standard function without precompilation)
@time LinkSUS.Genie.Renderer.Html.html(LinkSUS.Genie.Renderer.filepath("layouts\\templates\\linkage.jl.html"), layout = LinkSUS.Genie.Renderer.filepath("layouts\\app.jl.html"), scripts="<script src='/js/cust/linksus.js'></script>")
  0.060727 seconds (37.40 k allocations: 2.830 MiB, 77.73% compilation time)

# third run (standard function without precompilation)
@time LinkSUS.Genie.Renderer.Html.html(LinkSUS.Genie.Renderer.filepath("layouts\\templates\\linkage.jl.html"), layout = LinkSUS.Genie.Renderer.filepath("layouts\\app.jl.html"), scripts="<script src='/js/cust/linksus.js'></script>")
  0.012596 seconds (9.68 k allocations: 895.406 KiB)

When I precompile the application:

ENV["PRECOMPILE"] = true
ENV["GENIE_ENV"] = "prod"
using Pkg
Pkg.activate(".")
using LinkSUS
LinkSUS.main()
LinkSUS.Genie.isrunning() || up(port=8001)

# first run (new function without precompilation)
@time LinkSUS.Genie.Renderer.Html.raw_html(LinkSUS.Genie.Renderer.filepath("layouts\\templates\\linkage.jl.html"), layout = LinkSUS.Genie.Renderer.filepath("layouts\\app.jl.html"), scripts="<script src='/js/cust/linksus.js'></script>")
  0.075482 seconds (7.89 k allocations: 354.867 KiB, 98.90% compilation time)

# second run (new function without precompilation)
@time LinkSUS.Genie.Renderer.Html.raw_html(LinkSUS.Genie.Renderer.filepath("layouts\\templates\\linkage.jl.html"), layout = LinkSUS.Genie.Renderer.filepath("layouts\\app.jl.html"), scripts="<script src='/js/cust/linksus.js'></script>")
  0.000363 seconds (105 allocations: 73.008 KiB)

The application: https://github.com/PingoLee/LinkSUS