Skip to content

Commit

Permalink
Merge pull request #293 from GenieFramework/hh-precompile3
Browse files Browse the repository at this point in the history
add `@stipple_precompile` for easier precompilation of user apps
  • Loading branch information
hhaensel authored Oct 12, 2024
2 parents 60ac830 + 9d05e53 commit 83a1125
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 43 deletions.
61 changes: 19 additions & 42 deletions src/Stipple.jl
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ function init_storage end

include("Tools.jl")
include("ReactiveTools.jl")
export @stipple_precompile

#===#

Expand Down Expand Up @@ -1252,50 +1253,26 @@ include("Layout.jl")
# precompilation ...

using Stipple.ReactiveTools
@setup_workload begin
# Putting some things in `setup` can reduce the size of the
# precompile file and potentially make loading faster.
using Genie.HTTPUtils.HTTP
PRECOMPILE[] = true
@compile_workload begin
# all calls in this block will be precompiled, regardless of whether
# they belong to your package or not (on Julia 1.8 and higher)
# set secret in order to avoid automatic generation of a new one,
# which would invalidate the precompiled file
Genie.Secrets.secret_token!(repeat("f", 64))
ui() = [cell("hello"), row("world"), htmldiv("Hello World")]

@app PrecompileApp begin
@in demo_i = 1
@out demo_s = "Hi"

@onchange demo_i begin
println(demo_i)
end
end
@stipple_precompile begin
ui() = [cell("hello"), row("world"), htmldiv("Hello World")]

route("/") do
model = Stipple.ReactiveTools.@init PrecompileApp
page(model, ui) |> html
end
port = tryparse(Int, get(ENV, "STIPPLE_PRECOMPILE_PORT", ""))
port === nothing && (port = rand(8081:8999))

Logging.with_logger(Logging.SimpleLogger(stdout, Logging.Error)) do
up(port)

precompile_get = tryparse(Bool, get(ENV, "STIPPLE_PRECOMPILE_GET", "1"))
precompile_get === true && HTTP.get("http://localhost:$port")
# The following lines (still) produce an error although
# they pass at the repl. Not very important though.
# HTTP.get("http://localhost:$port$(Genie.Assets.asset_path(Genie.assets_config, :js, file = "channels"))")
# HTTP.get("http://localhost:$port$(Genie.Assets.asset_path(assets_config, :js, file = "stipplecore"))")
down()
end
# reset secret back to empty string
Genie.Secrets.secret_token!("")
@app PrecompileApp begin
@in demo_i = 1
@out demo_s = "Hi"

@onchange demo_i begin
println(demo_i)
end
end

route("/") do
model = Stipple.ReactiveTools.@init PrecompileApp
page(model, ui) |> html
end
PRECOMPILE[] = false

precompile_get("/")
deps_routes(core_theme = true)
precompile_get(Genie.Assets.asset_path(assets_config, :js, file = "stipplecore"))
end

end
106 changes: 105 additions & 1 deletion src/Tools.jl
Original file line number Diff line number Diff line change
Expand Up @@ -106,4 +106,108 @@ function delete_kwargs!(expressions, kwargs::Vector{Symbol})
end

delete_kwarg(expressions, kwarg::Symbol) = delete_kwarg!(Any[copy(x) for x in expressions], kwarg)
delete_kwargs(expressions, kwarg::Vector{Symbol}) = delete_kwargs!(Any[copy(x) for x in expressions], kwarg)
delete_kwargs(expressions, kwarg::Vector{Symbol}) = delete_kwargs!(Any[copy(x) for x in expressions], kwarg)

"""
@stipple_precompile(setup, workload)
A macro that facilitates the precompilation process for Stipple-related code.
# Arguments
- `setup`: An optional setup configuration that is required for the precompilation.
- `workload`: The workload or tasks that need to be precompiled.
The macro defines three local routines: `precompile_get`, `precompile_post`, and `precompile_request`.
These routines can be used to send requests to the local server that is started during the
precompilation process.
The envrionment variable ENV["STIPPLE_PRECOMPILE_REQUESTS"] can be set to "false" to disable the
precompilation of HTTP.requests. The default value is "true".
# Example (see also end of Stipple.jl)
```
module MyApp
using Stipple, Stipple.ReactiveTools
@app PrecompileApp begin
@in demo_i = 1
@out demo_s = "Hi"
@onchange demo_i begin
println(demo_i)
end
end
ui() = [cell("hello"), row("world"), htmldiv("Hello World")]
function __init__()
@page("/", ui)
end
@stipple_precompile begin
# the @page macro cannot be called here, as it reilies on writing some cache files to disk
# hence, we use a manual route definition for precompilation
route("/") do
model = @init PrecompileApp
page(model, ui) |> html
end
precompile_get("/")
end
end
```
"""
macro stipple_precompile(setup, workload)
quote
@setup_workload begin
# Putting some things in `setup` can reduce the size of the
# precompile file and potentially make loading faster.
using Genie.HTTPUtils.HTTP
PRECOMPILE[] = true

esc($setup)

@compile_workload begin
# all calls in this block will be precompiled, regardless of whether
# they belong to your package or not (on Julia 1.8 and higher)
# set secret in order to avoid automatic generation of a new one,
# which would invalidate the precompiled file
Genie.Secrets.secret_token!(repeat("f", 64))

port = tryparse(Int, get(ENV, "STIPPLE_PRECOMPILE_PORT", ""))
port === nothing && (port = rand(8081:8999))
precompile_requests = tryparse(Bool, get(ENV, "STIPPLE_PRECOMPILE_REQUESTS", "true"))
# for compatibility with older versions
precompile_requests |= tryparse(Bool, get(ENV, "STIPPLE_PRECOMPILE_GET", "true"))

function precompile_request(method, location, args...; kwargs...)
precompile_requests && HTTP.request(method, "http://localhost:$port/$(lstrip(location, '/'))", args...; kwargs...)
end

precompile_get(location::String, args...; kwargs...) = precompile_request(:GET, location, args...; kwargs...)
precompile_post(location::String, args...; kwargs...) = precompile_request(:POST, location, args...; kwargs...)

Logging.with_logger(Logging.SimpleLogger(stdout, Logging.Error)) do
up(port)

esc($workload)

down()
end
# reset secret back to empty string
Genie.Secrets.secret_token!("")
end
PRECOMPILE[] = false
end
end
end

macro stipple_precompile(workload)
quote
@stipple_precompile begin end begin
$workload
end
end
end

0 comments on commit 83a1125

Please sign in to comment.