Skip to content

Commit

Permalink
make embedded plotly.js as opt-in via feature flag
Browse files Browse the repository at this point in the history
Signed-off-by: Andrei Gherghescu <[email protected]>
  • Loading branch information
andrei-ng committed Sep 13, 2024
1 parent e3052a5 commit 4e7d681
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 59 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a

## [0.10.0] - 2024-xx-xx
### Added
- [[#231](https://github.com/plotly/plotly.rs/pull/231)] Added new `plotly_noembed` feature to reduce binary sizes by not embedding `plotly.min.js`.
- [[#231](https://github.com/plotly/plotly.rs/pull/231)] Added new `plotly_embed_js` feature to reduce binary sizes by not embedding `plotly.min.js` in the library unless explicitly enabled via the feature flag. Deprecates `use_local_plotly` in favor of explicit opt-in via the feature flag and introduce method `use_cdn_plotly` to allow users to use CDN version even behind the `plotly_embed_js` feature flag.

## [0.9.1] - 2024-09-06
### Added
Expand Down
15 changes: 10 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,12 @@ plot.add_trace(trace);
plot.write_html("out.html");
```

By default, the Plotly JavaScript library will be included via CDN, which results in a smaller filesize, but slightly slower first load as the JavaScript library has to be downloaded first. To instead embed the JavaScript library (several megabytes in size) directly into the HTML file, the following can be done:
By default, the Plotly JavaScript library will be included via CDN, which results in a smaller filesize, but slightly slower first load as the JavaScript library has to be downloaded first. To instead embed the JavaScript library (several megabytes in size) directly into the HTML file, the library must be compiled with the feature flag `plotly_embed_js`. Once enabled, by default the JavaScript library is directly embedded in the generated HTML file. It is still possible to use the CDN version, by using the `use_cdn_plotly` method.

```rust
// <-- Create a `Plot` -->

plot.use_local_plotly();
plot.use_cdn_plotly();
plot.write_html("out.html");
```

Expand Down Expand Up @@ -201,10 +201,15 @@ Adds trait implementations so that `image::RgbImage` and `image::RgbaImage` can

Adds support for creating plots directly using [ndarray](https://github.com/rust-ndarray/ndarray) types.

### `plotly_noembed`
### `plotly_embed_js`

This feature can be used to reduce the binary size by not embedding `plotly.min.js`. This requires the use of the CDN version,
and disables the `use_local_plotly` method.
By default, the CDN version of `plotly.js` is used in the library and in the generated HTML files. This feature can be used to opt in for embedding `plotly.min.js` in the generated HTML files. The benefit is that the plot will load faster in the browser.

However, there are two downsides of using this feature flag, one is that the resulting html will be much larger, as a copy of the `plotly.min.js` library is embedded in each HTML file. The second, more relevant, is that a copy of the `plotly.min.js` library needs to be compiled in the `plotly-rs` library itself which increases the size by approx `3.5 Mb`.

When the feature is enabled, users can still opt in for the CDN version by using the method `use_cdn_plotly`.

Note that when using `Plot::to_inline_html()`, it is assumed that the `plotly.js` library is already in scope within the HTML file, so enabling this feature flag will have no effect.

### `wasm`

Expand Down
2 changes: 1 addition & 1 deletion plotly/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ exclude = ["target/*"]
kaleido = ["plotly_kaleido"]
plotly_ndarray = ["ndarray"]
plotly_image = ["image"]
plotly_noembed = []
plotly_embed_js = []
wasm = ["getrandom", "js-sys", "wasm-bindgen", "wasm-bindgen-futures"]
with-axum = ["rinja/with-axum", "rinja_axum"]

Expand Down
71 changes: 30 additions & 41 deletions plotly/src/plot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,40 +11,20 @@ use serde::Serialize;

use crate::{Configuration, Layout};

#[cfg(not(feature = "plotly_noembed"))]
#[derive(Template)]
#[template(path = "plot.html", escape = "none")]
struct PlotTemplate<'a> {
plot: &'a Plot,
remote_plotly_js: bool,
plotly_js_source: String,
}

#[cfg(feature = "plotly_noembed")]
#[derive(Template)]
#[template(path = "plot_noembed.html", escape = "none")]
struct PlotTemplate<'a> {
plot: &'a Plot,
}

#[cfg(not(feature = "plotly_noembed"))]
#[derive(Template)]
#[template(path = "static_plot.html", escape = "none")]
#[cfg(not(target_family = "wasm"))]
struct StaticPlotTemplate<'a> {
plot: &'a Plot,
format: ImageFormat,
remote_plotly_js: bool,
width: usize,
height: usize,
}

#[cfg(feature = "plotly_noembed")]
#[derive(Template)]
#[template(path = "static_plot_noembed.html", escape = "none")]
#[cfg(not(target_family = "wasm"))]
struct StaticPlotTemplate<'a> {
plot: &'a Plot,
format: ImageFormat,
plotly_js_source: String,
width: usize,
height: usize,
}
Expand Down Expand Up @@ -202,32 +182,26 @@ pub struct Plot {
#[serde(rename = "config")]
configuration: Configuration,
#[serde(skip)]
#[cfg(not(feature = "plotly_noembed"))]
remote_plotly_js: bool,
plotly_js_source: String,
}

impl Plot {
/// Create a new `Plot`.
pub fn new() -> Plot {
Plot {
traces: Traces::new(),
#[cfg(not(feature = "plotly_noembed"))]
remote_plotly_js: true,
plotly_js_source: Self::plotly_js_source(),
..Default::default()
}
}

/// This option results in the plotly.js library being written directly in
/// the html output. The benefit is that the plot will load faster in
/// the browser and the downside is that the resulting html will be much
/// larger.
///
/// Note that when using `Plot::to_inline_html()`, it is assumed that the
/// `plotly.js` library is already in scope, so setting this attribute
/// will have no effect.
#[cfg(not(feature = "plotly_noembed"))]
pub fn use_local_plotly(&mut self) {
self.remote_plotly_js = false;
/// Switch to CDN `plotly.js` in the generated HTML instead of the default
/// local `plotly.js` version. Method is only available when the feature
/// `plotly_embed_js` is enabled since without this feature the default
/// version used is always the CDN version.
#[cfg(feature = "plotly_embed_js")]
pub fn use_cdn_plotly(&mut self) {
self.plotly_js_source = Self::cdn_plotly_js();
}

/// Add a `Trace` to the `Plot`.
Expand Down Expand Up @@ -445,8 +419,7 @@ impl Plot {
fn render(&self) -> String {
let tmpl = PlotTemplate {
plot: self,
#[cfg(not(feature = "plotly_noembed"))]
remote_plotly_js: self.remote_plotly_js,
plotly_js_source: self.plotly_js_source.clone(),
};
tmpl.render().unwrap()
}
Expand All @@ -456,8 +429,7 @@ impl Plot {
let tmpl = StaticPlotTemplate {
plot: self,
format,
#[cfg(not(feature = "plotly_noembed"))]
remote_plotly_js: self.remote_plotly_js,
plotly_js_source: self.plotly_js_source.clone(),
width,
height,
};
Expand All @@ -472,6 +444,23 @@ impl Plot {
tmpl.render().unwrap()
}

fn plotly_js_source() -> String {
if cfg!(feature = "plotly_embed_js") {
Self::local_plotly_js()
} else {
Self::cdn_plotly_js()
}
}

fn local_plotly_js() -> String {
let local_plotly = include_str!("../templates/plotly.min.js");
format!("<script type=\"text/javascript\">{}</script>", local_plotly).to_string()
}

fn cdn_plotly_js() -> String {
r##"<script src="https://cdn.plot.ly/plotly-2.12.1.min.js"></script>"##.to_string()
}

pub fn to_json(&self) -> String {
serde_json::to_string(self).unwrap()
}
Expand Down
7 changes: 2 additions & 5 deletions plotly/templates/plot.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,8 @@
<body>
<div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/es5/tex-svg.js"></script>
{% if remote_plotly_js -%}
<script src="https://cdn.plot.ly/plotly-2.12.1.min.js"></script>
{% else -%}
<script type="text/javascript">{% include "plotly.min.js" %}</script>
{% endif -%}

{{plotly_js_source}}

<div id="plotly-html-element" class="plotly-graph-div" style="height:100%; width:100%;"></div>

Expand Down
9 changes: 3 additions & 6 deletions plotly/templates/static_plot.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,8 @@
<body>
<div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/es5/tex-mml-chtml.js"></script>
{% if remote_plotly_js -%}
<script src="https://cdn.plot.ly/plotly-2.12.1.min.js"></script>
{% else -%}
<script type="text/javascript">{% include "plotly.min.js" %}</script>
{% endif -%}

{{plotly_js_source}}

<div id="plotly-html-element" hidden></div>
<img id="plotly-img-element"></img>
Expand All @@ -33,4 +30,4 @@
</script>
</div>
</body>
</html>
</html>

0 comments on commit 4e7d681

Please sign in to comment.