Skip to content

Commit

Permalink
Use inline source maps during bundling
Browse files Browse the repository at this point in the history
  • Loading branch information
devongovett committed Sep 11, 2022
1 parent b769f7a commit bfa8b8c
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 26 deletions.
72 changes: 66 additions & 6 deletions src/bundler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,17 @@ impl<'a, 'o, 's, P: SourceProvider> Bundler<'a, 'o, 's, P> {
.flat_map(|s| s.stylesheet.as_ref().unwrap().sources.iter().cloned())
.collect();

Ok(StyleSheet::new(sources, CssRuleList(rules), self.options.clone()))
let mut stylesheet = StyleSheet::new(sources, CssRuleList(rules), self.options.clone());

stylesheet.source_map_urls = self
.stylesheets
.get_mut()
.unwrap()
.iter()
.flat_map(|s| s.stylesheet.as_ref().unwrap().source_map_urls.iter().cloned())
.collect();

Ok(stylesheet)
}

fn find_filename(&self, source_index: u32) -> String {
Expand Down Expand Up @@ -329,14 +339,19 @@ impl<'a, 'o, 's, P: SourceProvider> Bundler<'a, 'o, 's, P> {
opts.filename = filename.to_owned();
opts.source_index = source_index;

let mut stylesheet = StyleSheet::parse(code, opts)?;

if let Some(source_map) = &self.source_map {
let mut source_map = source_map.lock().unwrap();
let source_index = source_map.add_source(filename);
let _ = source_map.set_source_content(source_index as usize, code);
// Only add source if we don't have an input source map.
// If we do, this will be handled by the printer when remapping locations.
let sm = stylesheet.source_map_url(0);
if sm.is_none() || !sm.unwrap().starts_with("data") {
let mut source_map = source_map.lock().unwrap();
let source_index = source_map.add_source(filename);
let _ = source_map.set_source_content(source_index as usize, code);
}
}

let mut stylesheet = StyleSheet::parse(code, opts)?;

// Collect and load dependencies for this stylesheet in parallel.
let dependencies: Result<Vec<u32>, _> = stylesheet
.rules
Expand Down Expand Up @@ -1759,4 +1774,49 @@ mod tests {
}
);
}

#[test]
fn test_source_map() {
let source = r#".imported {
content: "yay, file support!";
}
.selector {
margin: 1em;
background-color: #f60;
}
.selector .nested {
margin: 0.5em;
}
/*# sourceMappingURL=data:application/json;base64,ewoJInZlcnNpb24iOiAzLAoJInNvdXJjZVJvb3QiOiAicm9vdCIsCgkiZmlsZSI6ICJzdGRvdXQiLAoJInNvdXJjZXMiOiBbCgkJInN0ZGluIiwKCQkic2Fzcy9fdmFyaWFibGVzLnNjc3MiLAoJCSJzYXNzL19kZW1vLnNjc3MiCgldLAoJInNvdXJjZXNDb250ZW50IjogWwoJCSJAaW1wb3J0IFwiX3ZhcmlhYmxlc1wiO1xuQGltcG9ydCBcIl9kZW1vXCI7XG5cbi5zZWxlY3RvciB7XG4gIG1hcmdpbjogJHNpemU7XG4gIGJhY2tncm91bmQtY29sb3I6ICRicmFuZENvbG9yO1xuXG4gIC5uZXN0ZWQge1xuICAgIG1hcmdpbjogJHNpemUgLyAyO1xuICB9XG59IiwKCQkiJGJyYW5kQ29sb3I6ICNmNjA7XG4kc2l6ZTogMWVtOyIsCgkJIi5pbXBvcnRlZCB7XG4gIGNvbnRlbnQ6IFwieWF5LCBmaWxlIHN1cHBvcnQhXCI7XG59IgoJXSwKCSJtYXBwaW5ncyI6ICJBRUFBLFNBQVMsQ0FBQztFQUNSLE9BQU8sRUFBRSxvQkFBcUI7Q0FDL0I7O0FGQ0QsU0FBUyxDQUFDO0VBQ1IsTUFBTSxFQ0hELEdBQUc7RURJUixnQkFBZ0IsRUNMTCxJQUFJO0NEVWhCOztBQVBELFNBQVMsQ0FJUCxPQUFPLENBQUM7RUFDTixNQUFNLEVDUEgsS0FBRztDRFFQIiwKCSJuYW1lcyI6IFtdCn0= */"#;

let fs = TestProvider {
map: fs! {
"/a.css": r#"
@import "/b.css";
.a { color: red; }
"#,
"/b.css": source
},
};

let mut sm = parcel_sourcemap::SourceMap::new("/");
let mut bundler = Bundler::new(&fs, Some(&mut sm), ParserOptions::default());
let mut stylesheet = bundler.bundle(Path::new("/a.css")).unwrap();
stylesheet.minify(MinifyOptions::default()).unwrap();
stylesheet
.to_css(PrinterOptions {
source_map: Some(&mut sm),
minify: true,
..PrinterOptions::default()
})
.unwrap();
let map = sm.to_json(None).unwrap();
assert_eq!(
map,
r#"{"version":3,"sourceRoot":null,"mappings":"ACAA,uCCGA,2CAAA,8BFDQ","sources":["a.css","sass/_demo.scss","stdin"],"sourcesContent":["\n @import \"/b.css\";\n .a { color: red; }\n ",".imported {\n content: \"yay, file support!\";\n}","@import \"_variables\";\n@import \"_demo\";\n\n.selector {\n margin: $size;\n background-color: $brandColor;\n\n .nested {\n margin: $size / 2;\n }\n}"],"names":[]}"#
);
}
}
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19790,7 +19790,7 @@ mod tests {
let map = sm.to_json(None).unwrap();
assert_eq!(
map,
r#"{"version":3,"sourceRoot":null,"mappings":"AEAA,uCFGA,2CAAA","sources":["stdin","sass/_variables.scss","sass/_demo.scss"],"sourcesContent":["@import \"_variables\";\n@import \"_demo\";\n\n.selector {\n margin: $size;\n background-color: $brandColor;\n\n .nested {\n margin: $size / 2;\n }\n}","$brandColor: #f60;\n$size: 1em;",".imported {\n content: \"yay, file support!\";\n}"],"names":[]}"#
r#"{"version":3,"sourceRoot":null,"mappings":"AAAA,uCCGA,2CAAA","sources":["sass/_demo.scss","stdin"],"sourcesContent":[".imported {\n content: \"yay, file support!\";\n}","@import \"_variables\";\n@import \"_demo\";\n\n.selector {\n margin: $size;\n background-color: $brandColor;\n\n .nested {\n margin: $size / 2;\n }\n}"],"names":[]}"#
);
}

Expand Down
39 changes: 33 additions & 6 deletions src/printer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ pub struct Printer<'a, 'b, 'c, W> {
pub(crate) sources: Option<&'c Vec<String>>,
dest: &'a mut W,
pub(crate) source_map: Option<&'a mut SourceMap>,
pub(crate) source_maps: Vec<Option<SourceMap>>,
pub(crate) loc: Location,
indent: u8,
line: u32,
Expand All @@ -83,6 +84,7 @@ impl<'a, 'b, 'c, W: std::fmt::Write + Sized> Printer<'a, 'b, 'c, W> {
sources: None,
dest,
source_map: options.source_map,
source_maps: Vec::new(),
loc: Location {
source_index: 0,
line: 0,
Expand Down Expand Up @@ -205,17 +207,42 @@ impl<'a, 'b, 'c, W: std::fmt::Write + Sized> Printer<'a, 'b, 'c, W> {
/// Adds a mapping to the source map, if any.
pub fn add_mapping(&mut self, loc: Location) {
self.loc = loc;

if let Some(map) = &mut self.source_map {
map.add_mapping(
self.line,
self.col,
Some(OriginalLocation {
let mut original = OriginalLocation {
original_line: loc.line,
original_column: loc.column - 1,
source: loc.source_index,
name: None,
}),
)
};

// Remap using input source map if possible.
if let Some(Some(sm)) = self.source_maps.get_mut(loc.source_index as usize) {
let mut found_mapping = false;
if let Some(mapping) = sm.find_closest_mapping(loc.line, loc.column - 1) {
if let Some(orig) = mapping.original {
let sources_len = map.get_sources().len();
let source_index = map.add_source(sm.get_source(orig.source).unwrap());
original.original_line = orig.original_line;
original.original_column = orig.original_column;
original.source = source_index;
original.name = orig.name;

if map.get_sources().len() > sources_len {
let content = sm.get_source_content(orig.source).unwrap().to_owned();
let _ = map.set_source_content(source_index as usize, &content);
}

found_mapping = true;
}
}

if !found_mapping {
return;
}
}

map.add_mapping(self.line, self.col, Some(original))
}
}

Expand Down
27 changes: 14 additions & 13 deletions src/stylesheet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ pub struct StyleSheet<'i, 'o> {
/// Sources are referenced by index in the `loc` property of each rule.
pub sources: Vec<String>,
/// The source map URL extracted from the original style sheet.
pub source_map_url: Option<String>,
pub(crate) source_map_urls: Vec<Option<String>>,
#[cfg_attr(feature = "serde", serde(skip))]
/// The options the style sheet was originally parsed with.
options: ParserOptions<'o, 'i>,
Expand Down Expand Up @@ -105,7 +105,7 @@ impl<'i, 'o> StyleSheet<'i, 'o> {
pub fn new(sources: Vec<String>, rules: CssRuleList<'i>, options: ParserOptions<'o, 'i>) -> StyleSheet<'i, 'o> {
StyleSheet {
sources,
source_map_url: None,
source_map_urls: Vec::new(),
rules,
options,
}
Expand Down Expand Up @@ -137,16 +137,20 @@ impl<'i, 'o> StyleSheet<'i, 'o> {

Ok(StyleSheet {
sources: vec![options.filename.clone()],
source_map_url: parser.current_source_map_url().map(|s| s.to_owned()),
source_map_urls: vec![parser.current_source_map_url().map(|s| s.to_owned())],
rules: CssRuleList(rules),
options,
})
}

/// Returns the inline source map associated with the style sheet.
pub fn source_map(&self) -> Option<SourceMap> {
let source_map_url = self.source_map_url.as_ref()?;
SourceMap::from_data_url("/", source_map_url).ok()
/// Returns the source map URL for the source at the given index.
pub fn source_map_url(&self, source_index: usize) -> Option<&String> {
self.source_map_urls.get(source_index)?.as_ref()
}

/// Returns the inline source map associated with the source at the given index.
pub fn source_map(&self, source_index: usize) -> Option<SourceMap> {
SourceMap::from_data_url("/", self.source_map_url(source_index)?).ok()
}

/// Minify and transform the style sheet for the provided browser targets.
Expand Down Expand Up @@ -200,6 +204,9 @@ impl<'i, 'o> StyleSheet<'i, 'o> {
let mut printer = Printer::new(&mut dest, options);

printer.sources = Some(&self.sources);
if printer.source_map.is_some() {
printer.source_maps = self.sources.iter().enumerate().map(|(i, _)| self.source_map(i)).collect();
}

if let Some(config) = &self.options.css_modules {
let mut references = HashMap::new();
Expand All @@ -220,12 +227,6 @@ impl<'i, 'o> StyleSheet<'i, 'o> {
self.rules.to_css(&mut printer)?;
printer.newline()?;

if let Some(sm) = printer.source_map {
if let Some(mut input_sm) = self.source_map() {
let _ = sm.extends(&mut input_sm);
}
}

Ok(ToCssResult {
dependencies: printer.dependencies,
code: dest,
Expand Down

0 comments on commit bfa8b8c

Please sign in to comment.