Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions plotly_static/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ serde_json = "1.0"

### Feature Flags

- To use static export, enable exactly one of the driver features below.
- `chromedriver`: Use Chromedriver and Chrome/Chromium browser for rendering and export
- `geckodriver`: Use Geckodriver Firefox browser for rendering for rendering and export
- `webdriver_download`: Auto-download the chosen WebDriver binary
Expand Down
11 changes: 6 additions & 5 deletions plotly_static/build.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
#![cfg_attr(
not(any(feature = "geckodriver", feature = "chromedriver")),
allow(unused)
)]

use std::env;
use std::fs;
use std::path::{Path, PathBuf};
Expand All @@ -12,10 +17,6 @@ use webdriver_downloader::prelude::*;
#[cfg(all(feature = "geckodriver", feature = "chromedriver"))]
compile_error!("Only one of 'geckodriver' or 'chromedriver' features can be enabled at a time.");

// Enforce that at least one driver feature is enabled
#[cfg(not(any(feature = "geckodriver", feature = "chromedriver")))]
compile_error!("At least one of 'geckodriver' or 'chromedriver' features must be enabled.");

#[cfg(target_os = "windows")]
const DRIVER_EXT: &str = ".exe";
#[cfg(not(target_os = "windows"))]
Expand Down Expand Up @@ -199,7 +200,7 @@ fn setup_driver(config: &WebdriverDownloadConfig) -> Result<()> {
Ok(())
}

#[cfg(feature = "chromedriver")]
#[cfg(all(feature = "chromedriver", not(feature = "geckodriver")))]
fn get_chrome_path() -> Result<PathBuf> {
if let Ok(chrome_path) = env::var(BROWSER_BIN_PATH_ENV) {
let path = PathBuf::from(&chrome_path);
Expand Down
88 changes: 51 additions & 37 deletions plotly_static/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@
//!
//! ## Features and Dependencies
//!
//! ### Required Features
//! ### Driver Features
//!
//! You must enable one of the following features:
//! To use static export, enable one of the following features:
//!
//! - `chromedriver`: Use Chrome/Chromium for rendering
//! - `geckodriver`: Use Firefox for rendering
Expand Down Expand Up @@ -294,6 +294,7 @@ use fantoccini::{wd::Capabilities, Client, ClientBuilder};
#[cfg(not(any(test, feature = "debug")))]
use log::{debug, error, warn};
use serde::Serialize;
#[cfg(any(feature = "chromedriver", feature = "geckodriver"))]
use serde_json::map::Map as JsonMap;
use urlencoding::encode;
use webdriver::WebDriver;
Expand Down Expand Up @@ -927,6 +928,10 @@ pub struct AsyncStaticExporter {
pdf_export_timeout: u32,

/// Browser command-line flags (e.g., "--headless", "--no-sandbox")
#[cfg_attr(
not(any(feature = "chromedriver", feature = "geckodriver")),
allow(dead_code)
)]
webdriver_browser_caps: Vec<String>,

/// Cached WebDriver client for session reuse
Expand Down Expand Up @@ -1121,46 +1126,55 @@ impl AsyncStaticExporter {
}

fn build_webdriver_caps(&self) -> Result<Capabilities> {
// Define browser capabilities (copied to avoid reordering existing code)
let mut caps = JsonMap::new();
let mut browser_opts = JsonMap::new();
let browser_args = self.webdriver_browser_caps.clone();

browser_opts.insert("args".to_string(), serde_json::json!(browser_args));

// Add Chrome binary capability if BROWSER_PATH is set
#[cfg(feature = "chromedriver")]
if let Ok(chrome_path) = std::env::var("BROWSER_PATH") {
browser_opts.insert("binary".to_string(), serde_json::json!(chrome_path));
debug!("Added Chrome binary capability: {chrome_path}");
}
// Add Firefox binary capability if BROWSER_PATH is set
#[cfg(feature = "geckodriver")]
if let Ok(firefox_path) = std::env::var("BROWSER_PATH") {
browser_opts.insert("binary".to_string(), serde_json::json!(firefox_path));
debug!("Added Firefox binary capability: {firefox_path}");
}

// Add Firefox-specific preferences for CI environments
#[cfg(feature = "geckodriver")]
#[cfg(not(any(feature = "chromedriver", feature = "geckodriver")))]
{
let prefs = common::get_firefox_ci_preferences();
browser_opts.insert("prefs".to_string(), serde_json::json!(prefs));
debug!("Added Firefox preferences for CI compatibility");
Err(anyhow!(
"Static image export requires enabling either the 'chromedriver' or 'geckodriver' feature."
))
}
#[cfg(any(feature = "chromedriver", feature = "geckodriver"))]
{
// Define browser capabilities (copied to avoid reordering existing code)
let mut caps = JsonMap::new();
let mut browser_opts = JsonMap::new();
let browser_args = self.webdriver_browser_caps.clone();

browser_opts.insert("args".to_string(), serde_json::json!(browser_args));

// Add Chrome binary capability if BROWSER_PATH is set
#[cfg(feature = "chromedriver")]
if let Ok(chrome_path) = std::env::var("BROWSER_PATH") {
browser_opts.insert("binary".to_string(), serde_json::json!(chrome_path));
debug!("Added Chrome binary capability: {chrome_path}");
}
// Add Firefox binary capability if BROWSER_PATH is set
#[cfg(feature = "geckodriver")]
if let Ok(firefox_path) = std::env::var("BROWSER_PATH") {
browser_opts.insert("binary".to_string(), serde_json::json!(firefox_path));
debug!("Added Firefox binary capability: {firefox_path}");
}

caps.insert(
"browserName".to_string(),
serde_json::json!(get_browser_name()),
);
caps.insert(
get_options_key().to_string(),
serde_json::json!(browser_opts),
);
// Add Firefox-specific preferences for CI environments
#[cfg(feature = "geckodriver")]
{
let prefs = common::get_firefox_ci_preferences();
browser_opts.insert("prefs".to_string(), serde_json::json!(prefs));
debug!("Added Firefox preferences for CI compatibility");
}

caps.insert(
"browserName".to_string(),
serde_json::json!(get_browser_name()),
);
caps.insert(
get_options_key().to_string(),
serde_json::json!(browser_opts),
);

debug!("WebDriver capabilities: {caps:?}");
debug!("WebDriver capabilities: {caps:?}");

Ok(caps)
Ok(caps)
}
}

#[cfg(target_os = "windows")]
Expand Down
3 changes: 3 additions & 0 deletions plotly_static/src/webdriver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ const WEBDRIVER_BIN: &str = "geckodriver";
#[cfg(feature = "chromedriver")]
const WEBDRIVER_BIN: &str = "chromedriver";

#[cfg(not(any(feature = "chromedriver", feature = "geckodriver")))]
const WEBDRIVER_BIN: &str = "webdriver";

/// Default WebDriver port
pub(crate) const WEBDRIVER_PORT: u32 = 4444;
/// Default WebDriver URL
Expand Down
Loading