Skip to content

Commit 897dcb5

Browse files
authored
refactor: Avoid creating unnecessary theme objects for precompiled checks (#1162)
* chore: use hashes, delayed eval and caching for faster precompiled checks * chore: use `withr::local_options()` for `local_disable_cache()` * chore: make `.precompiled_css_versions()` a function for runtime checks * chore: rewrite comment for clarity * chore: rename variable * chore: ensure version is character
1 parent 7594d67 commit 897dcb5

File tree

2 files changed

+43
-28
lines changed

2 files changed

+43
-28
lines changed

R/precompiled.R

+40-24
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,30 @@
1-
2-
# This figures out which precompiled CSS files are available.
3-
# This is memoized - it runs once per R session.
4-
precompiled_css <- local({
5-
themes <- NULL
6-
1+
# List which precompiled CSS files are available.
2+
.precompiled_css_versions <- local({
3+
versions <- NULL
74
function() {
8-
if (is.null(themes)) {
9-
versions <- dir(system.file("css-precompiled", package = "bslib"))
10-
themes <<- lapply(versions, function(version) {
11-
list(
12-
version = version,
13-
theme = bs_theme(version, brand = FALSE)
14-
)
15-
})
5+
if (is.null(versions)) {
6+
versions <<- dir(system.file("css-precompiled", package = "bslib"))
167
}
17-
themes
8+
versions
189
}
1910
})
2011

12+
.precompiled_css_themes <- new.env(parent = emptyenv())
2113

22-
precompiled_css_version <- function(theme) {
23-
for (precompiled in precompiled_css()) {
24-
if (identical(theme, precompiled$theme)) {
25-
return(theme_version(theme))
26-
}
14+
# Precompiled themes are created for base `bs_theme()`, changing only the
15+
# Bootstrap version number. To decide if we can use the precompiled theme, we
16+
# hash `bs_theme(version)`, which we'll compare with a hash of the user's theme.
17+
precompiled_bs_theme_hash <- function(version) {
18+
theme_hash <- get0(as.character(version), .precompiled_css_themes)
19+
20+
if (is.null(theme_hash)) {
21+
theme_hash <- rlang::hash(bs_theme(version = version, brand = FALSE))
22+
assign(version, theme_hash, envir = .precompiled_css_themes)
2723
}
2824

29-
return(NULL)
25+
return(theme_hash)
3026
}
3127

32-
3328
#' Get the path to a precompiled CSS file
3429
#'
3530
#' This function is meant for development and debugging purposes. It can be used
@@ -42,10 +37,31 @@ precompiled_css_version <- function(theme) {
4237
#' @keywords internal
4338
#' @export
4439
precompiled_css_path <- function(theme = bs_theme()) {
45-
version <- precompiled_css_version(theme)
40+
version <- theme_version(theme)
41+
theme_hash <- rlang::hash(theme)
42+
version_precompiled <- NULL
43+
4644
if (is.null(version)) {
45+
for (v in .precompiled_css_versions()) {
46+
if (identical(theme_hash, precompiled_bs_theme_hash(v))) {
47+
version_precompiled <- v
48+
break
49+
}
50+
}
51+
} else if (version %in% .precompiled_css_versions()) {
52+
if (identical(theme_hash, precompiled_bs_theme_hash(version))) {
53+
version_precompiled <- version
54+
}
55+
}
56+
57+
if (is.null(version_precompiled)) {
4758
return(NULL)
4859
}
4960

50-
system_file(package = "bslib", "css-precompiled", version, "bootstrap.min.css")
61+
system_file(
62+
package = "bslib",
63+
"css-precompiled",
64+
version_precompiled,
65+
"bootstrap.min.css"
66+
)
5167
}

tests/testthat/helper-cache.R

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
# Turn off the default cache until the calling function exits; when that
22
# happens, the previous default cache will be restored.
33
local_disable_cache <- function(env = parent.frame()) {
4-
old_opts <- options(sass.cache = FALSE)
5-
withr::defer(
6-
options(old_opts),
7-
envir = env
4+
withr::local_options(
5+
list(sass.cache = FALSE),
6+
.local_envir = env
87
)
98
}

0 commit comments

Comments
 (0)