plotly/leaflet的 htmlwidgets在自包含的 `bookdown::html_document2` HTML中渲染为空白

前端开发 2026-07-08

当我用默认的 self_contained: true 编织一个 bookdown::html_document2 文档时,每一个 plotlyleaflet 小部件都显示为空白区域。容器存在,尺寸也正确,但从未出现任何图形或地图。编织过程没有报错,HTML的其他部分也没问题。

设置 self_contained: false,使这两个小部件都能正确渲染,但这会生成一个我宁愿不随报告一起发布的 _files/ 依赖文件夹。删除并重新安装 plotlyleaflethtmlwidgetsbookdownhtmltools 都没有改变。

Reprex:

---
title: "htmlwidget self_contained reprex"
output:
  bookdown::html_document2:
    self_contained: true
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE, message = FALSE, warning = FALSE)
library(plotly)
plot_ly(mtcars, x = ~wt, y = ~mpg, type = "scatter", mode = "markers")
library(leaflet)
leaflet() |>
  addTiles() |>
  setView(lng = -93.42, lat = 44.71, zoom = 11) |>
  addMarkers(lng = -93.42, lat = 44.71, popup = "marker")

[渲染后的 HTML 文件可在 RPubs 上查看](http://rpubs.com/aomop/1443157)

渲染后的文档应该包含一个互动散点图和一个互动地图,但实际只看到两个具有正确尺寸的空白区域,并没有任何内容渲染出来。设置 `self_contained: false` 可行,但我真的不喜欢那个方案。HTML 文件包含正确渲染所需的一切:

* 两个小部件容器,尺寸正确,例如 `<div class="plotly html-widget html-fill-item" id="htmlwidget-..." style="width:672px;height:480px;">` 和相应的 `leaflet html-widget` div;
* 两个 `<script type="application/json" data-for="htmlwidget-...">` 数据负载(图表/地图的规格);
* 嵌入的库本身(`Plotly.newPlot(...)` 和 Leaflet 的 `L.map(...)` 都存在);
* 以及包含 `HTMLWidgets.staticRender` 的 `HTMLWidgets` 运行时也都存在。

在浏览器中,使用开发者工具会出现以下错误:

widget_selfcontained_reprex.html:2097 Uncaught SyntaxError: missing ) after argument list widget_selfcontained_reprex.html:1299 Uncaught ReferenceError: Plotly is not defined at Object.renderValue (widget_selfcontained_reprex.html:1299:18) at widget_selfcontained_reprex.html:887:19 at Array.forEach () at forEach (widget_selfcontained_reprex.html:290:14) at widget_selfcontained_reprex.html:809:7 at Array.forEach () at forEach (widget_selfcontained_reprex.html:290:14) at window.HTMLWidgets.staticRender (widget_selfcontained_reprex.html:807:5) at maybeStaticRenderLater (widget_selfcontained_reprex.html:932:26) at HTMLDocument. (widget_selfcontained_reprex.html:939:7) widget_selfcontained_reprex.html:1 Unsafe attempt to load URL file:///C:/Users/User/Downloads/widget_selfcontained_reprex.html from frame with URL file:///C:/Users/User/Downloads/widget_selfcontained_reprex.html. 'file:' URLs are treated as unique security origins.


### Environment

R version 4.6.0 (2026-04-24 ucrt) Platform: x86_64-w64-mingw32/x64 Running under: Windows 11 x64 (build 26100)

Pandoc version: 3.8.3 Sys.which("pandoc") -> ""
rmarkdown::pandoc_version() -> 3.8.3

bookdown_0.47 rmarkdown_2.31 knitr_1.51 xfun_0.58 htmlwidgets_1.6.4 htmltools_0.5.9 crosstalk_1.2.2 jsonlite_2.0.0 plotly_4.12.0 leaflet_2.2.3 leaflet.providers_3.0.0 bslib_0.11.0 jquerylib_0.1.4 evaluate_1.0.5 ggplot2_4.0.3


Has anyone experienced anything like this? Is there a way to keep `self_contained: true` and get the widgets to render? I'm not very familiar with HTML or anything outside R for that matter, so let me know if there is more context I can give here.

## 解决方案

我把问题中链接的上传文件与我在 Mac 上生成的正确版本进行了对比。正确版本中的 JavaScript 代码的一部分差异首先出现在如下所示:

o=n("<89>PNG\r\n^Z\n"),s=n("IHDR"); ```

在该文件中,"<89>" 是一个单独的0x89字符,而 "^Z" 是一个单独的0x1a字符,即Ctrl-Z。

在错误下载的版本中,跳过了 "^Z" 及其后面的一大段代码,这正是导致所有的语法错误的原因。

正确的字符串就是用作PNG文件签名的字符串。它使用一个 "^Z" 字符来在MSDOS中停止显示该文件,根据 文档 的说明。这大概解释了为什么错误在Windows上出现而不是在Mac上:生产过程中的某个环节以文本模式复制文件,在Windows下把 "^Z" 当作EOF标志。

也许这能帮助开发者修复这个bug。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章