Skip to content

Commit 06fa9cc

Browse files
authored
Rollup merge of rust-lang#57011 - QuietMisdreavus:static-root-path, r=GuillaumeGomez
rustdoc: add new CLI flag to load static files from a different location This PR adds a new CLI flag to rustdoc, `--static-root-path`, which controls how rustdoc links pages to the CSS/JS/font static files bundled with the output. By default, these files are linked with a series of `../` which is calculated per-page to link it to the documentation root - i.e. a relative link to the directory given by `-o`. This is causing problems for docs.rs, because even though docs.rs has saved one copy of these files and is dispatching them dynamically, browsers have no way of knowing that these are the same files and can cache them. This can allow it to link these files as, for example, `/rustdoc.css` instead of `../../rustdoc.css`, creating a single location that the files are loaded from. I made sure to only change links for the *static* files, those that don't change between crates. Files like the search index, aliases, the source files listing, etc, are still linked with relative links. r? @GuillaumeGomez cc @onur
2 parents edeae30 + 8dc8d7a commit 06fa9cc

File tree

6 files changed

+107
-22
lines changed

6 files changed

+107
-22
lines changed

src/doc/rustdoc/src/unstable-features.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,3 +402,18 @@ Using `index-page` option enables `enable-index-page` option as well.
402402
### `--enable-index-page`: generate a default index page for docs
403403

404404
This feature allows the generation of a default index-page which lists the generated crates.
405+
406+
### `--static-root-path`: control how static files are loaded in HTML output
407+
408+
Using this flag looks like this:
409+
410+
```bash
411+
$ rustdoc src/lib.rs -Z unstable-options --static-root-path '/cache/'
412+
```
413+
414+
This flag controls how rustdoc links to its static files on HTML pages. If you're hosting a lot of
415+
crates' docs generated by the same version of rustdoc, you can use this flag to cache rustdoc's CSS,
416+
JavaScript, and font files in a single location, rather than duplicating it once per "doc root"
417+
(grouping of crate docs generated into the same output directory, like with `cargo doc`). Per-crate
418+
files like the search index will still load from the documentation root, but anything that gets
419+
renamed with `--resource-suffix` will load from the given path.

src/librustdoc/config.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,9 @@ pub struct RenderOptions {
181181
/// A file to use as the index page at the root of the output directory. Overrides
182182
/// `enable_index_page` to be true if set.
183183
pub index_page: Option<PathBuf>,
184+
/// An optional path to use as the location of static files. If not set, uses combinations of
185+
/// `../` to reach the documentation root.
186+
pub static_root_path: Option<String>,
184187

185188
// Options specific to reading standalone Markdown files
186189

@@ -433,6 +436,7 @@ impl Options {
433436
let markdown_playground_url = matches.opt_str("markdown-playground-url");
434437
let crate_version = matches.opt_str("crate-version");
435438
let enable_index_page = matches.opt_present("enable-index-page") || index_page.is_some();
439+
let static_root_path = matches.opt_str("static-root-path");
436440

437441
let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
438442

@@ -471,6 +475,7 @@ impl Options {
471475
enable_minification,
472476
enable_index_page,
473477
index_page,
478+
static_root_path,
474479
markdown_no_toc,
475480
markdown_css,
476481
markdown_playground_url,

src/librustdoc/html/layout.rs

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,20 @@ pub struct Page<'a> {
2626
pub title: &'a str,
2727
pub css_class: &'a str,
2828
pub root_path: &'a str,
29+
pub static_root_path: Option<&'a str>,
2930
pub description: &'a str,
3031
pub keywords: &'a str,
3132
pub resource_suffix: &'a str,
33+
pub extra_scripts: &'a [&'a str],
34+
pub static_extra_scripts: &'a [&'a str],
3235
}
3336

3437
pub fn render<T: fmt::Display, S: fmt::Display>(
3538
dst: &mut dyn io::Write, layout: &Layout, page: &Page, sidebar: &S, t: &T,
36-
css_file_extension: bool, themes: &[PathBuf], extra_scripts: &[&str])
39+
css_file_extension: bool, themes: &[PathBuf])
3740
-> io::Result<()>
3841
{
42+
let static_root_path = page.static_root_path.unwrap_or(page.root_path);
3943
write!(dst,
4044
"<!DOCTYPE html>\
4145
<html lang=\"en\">\
@@ -46,20 +50,20 @@ pub fn render<T: fmt::Display, S: fmt::Display>(
4650
<meta name=\"description\" content=\"{description}\">\
4751
<meta name=\"keywords\" content=\"{keywords}\">\
4852
<title>{title}</title>\
49-
<link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}normalize{suffix}.css\">\
50-
<link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}rustdoc{suffix}.css\" \
53+
<link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}normalize{suffix}.css\">\
54+
<link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}rustdoc{suffix}.css\" \
5155
id=\"mainThemeStyle\">\
5256
{themes}\
53-
<link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}dark{suffix}.css\">\
54-
<link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}light{suffix}.css\" \
57+
<link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}dark{suffix}.css\">\
58+
<link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}light{suffix}.css\" \
5559
id=\"themeStyle\">\
56-
<script src=\"{root_path}storage{suffix}.js\"></script>\
57-
<noscript><link rel=\"stylesheet\" href=\"{root_path}noscript{suffix}.css\"></noscript>\
60+
<script src=\"{static_root_path}storage{suffix}.js\"></script>\
61+
<noscript><link rel=\"stylesheet\" href=\"{static_root_path}noscript{suffix}.css\"></noscript>\
5862
{css_extension}\
5963
{favicon}\
6064
{in_header}\
6165
<style type=\"text/css\">\
62-
#crate-search{{background-image:url(\"{root_path}down-arrow{suffix}.svg\");}}\
66+
#crate-search{{background-image:url(\"{static_root_path}down-arrow{suffix}.svg\");}}\
6367
</style>\
6468
</head>\
6569
<body class=\"rustdoc {css_class}\">\
@@ -77,11 +81,13 @@ pub fn render<T: fmt::Display, S: fmt::Display>(
7781
</nav>\
7882
<div class=\"theme-picker\">\
7983
<button id=\"theme-picker\" aria-label=\"Pick another theme!\">\
80-
<img src=\"{root_path}brush{suffix}.svg\" width=\"18\" alt=\"Pick another theme!\">\
84+
<img src=\"{static_root_path}brush{suffix}.svg\" \
85+
width=\"18\" \
86+
alt=\"Pick another theme!\">\
8187
</button>\
8288
<div id=\"theme-choices\"></div>\
8389
</div>\
84-
<script src=\"{root_path}theme{suffix}.js\"></script>\
90+
<script src=\"{static_root_path}theme{suffix}.js\"></script>\
8591
<nav class=\"sub\">\
8692
<form class=\"search-form js-only\">\
8793
<div class=\"search-container\">\
@@ -96,7 +102,9 @@ pub fn render<T: fmt::Display, S: fmt::Display>(
96102
type=\"search\">\
97103
</div>\
98104
<a id=\"settings-menu\" href=\"{root_path}settings.html\">\
99-
<img src=\"{root_path}wheel{suffix}.svg\" width=\"18\" alt=\"Change settings\">\
105+
<img src=\"{static_root_path}wheel{suffix}.svg\" \
106+
width=\"18\" \
107+
alt=\"Change settings\">\
100108
</a>\
101109
</div>\
102110
</form>\
@@ -157,19 +165,23 @@ pub fn render<T: fmt::Display, S: fmt::Display>(
157165
window.currentCrate = \"{krate}\";\
158166
</script>\
159167
<script src=\"{root_path}aliases.js\"></script>\
160-
<script src=\"{root_path}main{suffix}.js\"></script>\
168+
<script src=\"{static_root_path}main{suffix}.js\"></script>\
169+
{static_extra_scripts}\
161170
{extra_scripts}\
162171
<script defer src=\"{root_path}search-index.js\"></script>\
163172
</body>\
164173
</html>",
165174
css_extension = if css_file_extension {
166-
format!("<link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}theme{suffix}.css\">",
167-
root_path = page.root_path,
175+
format!("<link rel=\"stylesheet\" \
176+
type=\"text/css\" \
177+
href=\"{static_root_path}theme{suffix}.css\">",
178+
static_root_path = static_root_path,
168179
suffix=page.resource_suffix)
169180
} else {
170181
String::new()
171182
},
172183
content = *t,
184+
static_root_path = static_root_path,
173185
root_path = page.root_path,
174186
css_class = page.css_class,
175187
logo = if layout.logo.is_empty() {
@@ -197,12 +209,17 @@ pub fn render<T: fmt::Display, S: fmt::Display>(
197209
.filter_map(|t| t.file_stem())
198210
.filter_map(|t| t.to_str())
199211
.map(|t| format!(r#"<link rel="stylesheet" type="text/css" href="{}{}{}.css">"#,
200-
page.root_path,
212+
static_root_path,
201213
t,
202214
page.resource_suffix))
203215
.collect::<String>(),
204216
suffix=page.resource_suffix,
205-
extra_scripts=extra_scripts.iter().map(|e| {
217+
static_extra_scripts=page.static_extra_scripts.iter().map(|e| {
218+
format!("<script src=\"{static_root_path}{extra_script}.js\"></script>",
219+
static_root_path=static_root_path,
220+
extra_script=e)
221+
}).collect::<String>(),
222+
extra_scripts=page.extra_scripts.iter().map(|e| {
206223
format!("<script src=\"{root_path}{extra_script}.js\"></script>",
207224
root_path=page.root_path,
208225
extra_script=e)

src/librustdoc/html/render.rs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,9 @@ struct SharedContext {
140140
/// Suffix to be added on resource files (if suffix is "-v2" then "light.css" becomes
141141
/// "light-v2.css").
142142
pub resource_suffix: String,
143+
/// Optional path string to be used to load static files on output pages. If not set, uses
144+
/// combinations of `../` to reach the documentation root.
145+
pub static_root_path: Option<String>,
143146
}
144147

145148
impl SharedContext {
@@ -506,6 +509,7 @@ pub fn run(mut krate: clean::Crate,
506509
extension_css,
507510
extern_html_root_urls,
508511
resource_suffix,
512+
static_root_path,
509513
..
510514
} = options;
511515

@@ -533,6 +537,7 @@ pub fn run(mut krate: clean::Crate,
533537
sort_modules_alphabetically,
534538
themes,
535539
resource_suffix,
540+
static_root_path,
536541
};
537542

538543
// If user passed in `--playground-url` arg, we fill in crate name here
@@ -1080,9 +1085,12 @@ themePicker.onblur = handleThemeButtonsBlur;
10801085
title: "Index of crates",
10811086
css_class: "mod",
10821087
root_path: "./",
1088+
static_root_path: cx.shared.static_root_path.deref(),
10831089
description: "List of crates",
10841090
keywords: BASIC_KEYWORDS,
10851091
resource_suffix: &cx.shared.resource_suffix,
1092+
extra_scripts: &[],
1093+
static_extra_scripts: &[],
10861094
};
10871095
krates.push(krate.name.clone());
10881096
krates.sort();
@@ -1101,7 +1109,7 @@ themePicker.onblur = handleThemeButtonsBlur;
11011109
try_err!(layout::render(&mut w, &cx.shared.layout,
11021110
&page, &(""), &content,
11031111
cx.shared.css_file_extension.is_some(),
1104-
&cx.shared.themes, &[]), &dst);
1112+
&cx.shared.themes), &dst);
11051113
try_err!(w.flush(), &dst);
11061114
}
11071115
}
@@ -1367,15 +1375,17 @@ impl<'a> SourceCollector<'a> {
13671375
title: &title,
13681376
css_class: "source",
13691377
root_path: &root_path,
1378+
static_root_path: self.scx.static_root_path.deref(),
13701379
description: &desc,
13711380
keywords: BASIC_KEYWORDS,
13721381
resource_suffix: &self.scx.resource_suffix,
1382+
extra_scripts: &["source-files"],
1383+
static_extra_scripts: &[&format!("source-script{}", self.scx.resource_suffix)],
13731384
};
13741385
layout::render(&mut w, &self.scx.layout,
13751386
&page, &(""), &Source(contents),
13761387
self.scx.css_file_extension.is_some(),
1377-
&self.scx.themes, &["source-files",
1378-
&format!("source-script{}", page.resource_suffix)])?;
1388+
&self.scx.themes)?;
13791389
w.flush()?;
13801390
self.scx.local_sources.insert(p.clone(), href);
13811391
Ok(())
@@ -1957,9 +1967,12 @@ impl Context {
19571967
title: "List of all items in this crate",
19581968
css_class: "mod",
19591969
root_path: "../",
1970+
static_root_path: self.shared.static_root_path.deref(),
19601971
description: "List of all items in this crate",
19611972
keywords: BASIC_KEYWORDS,
19621973
resource_suffix: &self.shared.resource_suffix,
1974+
extra_scripts: &[],
1975+
static_extra_scripts: &[],
19631976
};
19641977
let sidebar = if let Some(ref version) = cache().crate_version {
19651978
format!("<p class='location'>Crate {}</p>\
@@ -1974,7 +1987,7 @@ impl Context {
19741987
try_err!(layout::render(&mut w, &self.shared.layout,
19751988
&page, &sidebar, &all,
19761989
self.shared.css_file_extension.is_some(),
1977-
&self.shared.themes, &[]),
1990+
&self.shared.themes),
19781991
&final_file);
19791992

19801993
// Generating settings page.
@@ -1994,7 +2007,7 @@ impl Context {
19942007
try_err!(layout::render(&mut w, &layout,
19952008
&page, &sidebar, &settings,
19962009
self.shared.css_file_extension.is_some(),
1997-
&themes, &[]),
2010+
&themes),
19982011
&settings_file);
19992012

20002013
Ok(())
@@ -2036,10 +2049,13 @@ impl Context {
20362049
let page = layout::Page {
20372050
css_class: tyname,
20382051
root_path: &self.root_path(),
2052+
static_root_path: self.shared.static_root_path.deref(),
20392053
title: &title,
20402054
description: &desc,
20412055
keywords: &keywords,
20422056
resource_suffix: &self.shared.resource_suffix,
2057+
extra_scripts: &[],
2058+
static_extra_scripts: &[],
20432059
};
20442060

20452061
{
@@ -2052,7 +2068,7 @@ impl Context {
20522068
&Sidebar{ cx: self, item: it },
20532069
&Item{ cx: self, item: it },
20542070
self.shared.css_file_extension.is_some(),
2055-
&self.shared.themes, &[])?;
2071+
&self.shared.themes)?;
20562072
} else {
20572073
let mut url = self.root_path();
20582074
if let Some(&(ref names, ty)) = cache().paths.get(&it.def_id) {

src/librustdoc/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#![feature(crate_visibility_modifier)]
2626
#![feature(const_fn)]
2727
#![feature(drain_filter)]
28+
#![feature(inner_deref)]
2829

2930
#![recursion_limit="256"]
3031

@@ -338,6 +339,13 @@ fn opts() -> Vec<RustcOptGroup> {
338339
"enable-index-page",
339340
"To enable generation of the index page")
340341
}),
342+
unstable("static-root-path", |o| {
343+
o.optopt("",
344+
"static-root-path",
345+
"Path string to force loading static files from in output pages. \
346+
If not set, uses combinations of '../' to reach the documentation root.",
347+
"PATH")
348+
}),
341349
]
342350
}
343351

src/test/rustdoc/static-root-path.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// compile-flags:-Z unstable-options --static-root-path /cache/
12+
13+
// @has static_root_path/struct.SomeStruct.html
14+
// @matches - '"/cache/main\.js"'
15+
// @!matches - '"\.\./main\.js"'
16+
// @matches - '"\.\./search-index\.js"'
17+
// @!matches - '"/cache/search-index\.js"'
18+
pub struct SomeStruct;
19+
20+
// @has src/static_root_path/static-root-path.rs.html
21+
// @matches - '"/cache/source-script\.js"'
22+
// @!matches - '"\.\./\.\./source-script\.js"'
23+
// @matches - '"\.\./\.\./source-files.js"'
24+
// @!matches - '"/cache/source-files\.js"'

0 commit comments

Comments
 (0)