I might . But this solution doesn’t generalize because there are other packages with precompile times that are too long to wait through daily or multiple times a day which do not have ready alternatives in other languages (e.g. Zygote/Flux)
I’ve added the following to my .julia/config/startup.jl
file so that I can call _add("Plots")
, wait for the precompilation, and then have a quick using Plots
in any environment. Unlike adding Plots
to my global environment, Plots
will not reprecompile when it or any of its dependencies is updated unless I explicitly invoke _add("Plots")
or _up("Plots")
. When I switch Julia versions, it will reprecompile, but only once per julia version per call to _add
or _up
. Unlike the PackageCompiler route, with this approach the reprecompilation time on julia updates is lower and requires no manual intervention whatsoever. Normal Pkg usage should be entirely unaffected by this patch.
The implementation is mostly untested and the UX is terrible:
# https://discourse.julialang.org/t/10-15-minute-ttfp-with-plots-jl-please-help/92636/23?u=lilith
if isinteractive()
import Pkg
function _add(pkg::AbstractString)
project = dirname(Base.active_project())
Pkg.activate(pkg, shared=true)
Pkg.add(pkg)
Pkg.activate(project)
pkg ∈ KNOWN_PACKAGES && return
push!(KNOWN_PACKAGES, Symbol(pkg))
open(joinpath(@__DIR__, "known_packages"), "a") do io
println(io, pkg)
end
end
function _up(pkg::AbstractString)
project = dirname(Base.active_project())
Pkg.activate(pkg, shared=true)
Pkg.update()
Pkg.activate(project)
end
function _rm(pkg::AbstractString)
filter!(≠(pkg), KNOWN_PACKAGES)
open(joinpath(@__DIR__, "known_packages"), "w") do io
for pkg in KNOWN_PACKAGES
println(io, pkg)
end
end
end
isfile(joinpath(@__DIR__, "known_packages")) || touch(joinpath(@__DIR__, "known_packages"))
const KNOWN_PACKAGES = Symbol.(readlines(joinpath(@__DIR__, "known_packages")))
pushfirst!(Pkg.REPL.install_packages_hooks, symbols -> begin
isdisjoint(symbols, KNOWN_PACKAGES) && return false
if symbols ⊆ KNOWN_PACKAGES
project = dirname(Base.active_project())
for s in symbols # Install known packages
Pkg.activate(string(s), shared=true)
@eval using $s
end
Pkg.activate(project)
@info "Successfully loaded $(join(symbols, ", ")). Please ignore the following error message:"
true
else
@warn "$(intersection(symbols, KNOWN_PACKAGES)) are special packages that cannot be installed at the same time as ordinary packages $(setdiff(symbols, KNOWN_PACKAGES))."
false
end
end)
end
The tradeoff is that I may, in theory, be exposed to known package version incompatibilities between the plotting stack and whatever else I may be working with. OTOH I think I get the same risk with PackageCompiler and updating the sysimg is harder than a call to _up("Plots")
Lovely! That was the problem. In 1.8 I got a sysimg made in 385 seconds which is in line with the ratio I’ve been seeing in this thread w.r.t. my timings vs other folks’. I’m still going to try the idea in this post first for the aforementioned reasons, though)