Skip to content

Commit bfa8b8c

Browse files
committed
Use inline source maps during bundling
1 parent b769f7a commit bfa8b8c

File tree

4 files changed

+114
-26
lines changed

4 files changed

+114
-26
lines changed

src/bundler.rs

Lines changed: 66 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,17 @@ impl<'a, 'o, 's, P: SourceProvider> Bundler<'a, 'o, 's, P> {
237237
.flat_map(|s| s.stylesheet.as_ref().unwrap().sources.iter().cloned())
238238
.collect();
239239

240-
Ok(StyleSheet::new(sources, CssRuleList(rules), self.options.clone()))
240+
let mut stylesheet = StyleSheet::new(sources, CssRuleList(rules), self.options.clone());
241+
242+
stylesheet.source_map_urls = self
243+
.stylesheets
244+
.get_mut()
245+
.unwrap()
246+
.iter()
247+
.flat_map(|s| s.stylesheet.as_ref().unwrap().source_map_urls.iter().cloned())
248+
.collect();
249+
250+
Ok(stylesheet)
241251
}
242252

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

342+
let mut stylesheet = StyleSheet::parse(code, opts)?;
343+
332344
if let Some(source_map) = &self.source_map {
333-
let mut source_map = source_map.lock().unwrap();
334-
let source_index = source_map.add_source(filename);
335-
let _ = source_map.set_source_content(source_index as usize, code);
345+
// Only add source if we don't have an input source map.
346+
// If we do, this will be handled by the printer when remapping locations.
347+
let sm = stylesheet.source_map_url(0);
348+
if sm.is_none() || !sm.unwrap().starts_with("data") {
349+
let mut source_map = source_map.lock().unwrap();
350+
let source_index = source_map.add_source(filename);
351+
let _ = source_map.set_source_content(source_index as usize, code);
352+
}
336353
}
337354

338-
let mut stylesheet = StyleSheet::parse(code, opts)?;
339-
340355
// Collect and load dependencies for this stylesheet in parallel.
341356
let dependencies: Result<Vec<u32>, _> = stylesheet
342357
.rules
@@ -1759,4 +1774,49 @@ mod tests {
17591774
}
17601775
);
17611776
}
1777+
1778+
#[test]
1779+
fn test_source_map() {
1780+
let source = r#".imported {
1781+
content: "yay, file support!";
1782+
}
1783+
1784+
.selector {
1785+
margin: 1em;
1786+
background-color: #f60;
1787+
}
1788+
1789+
.selector .nested {
1790+
margin: 0.5em;
1791+
}
1792+
1793+
/*# sourceMappingURL=data:application/json;base64,ewoJInZlcnNpb24iOiAzLAoJInNvdXJjZVJvb3QiOiAicm9vdCIsCgkiZmlsZSI6ICJzdGRvdXQiLAoJInNvdXJjZXMiOiBbCgkJInN0ZGluIiwKCQkic2Fzcy9fdmFyaWFibGVzLnNjc3MiLAoJCSJzYXNzL19kZW1vLnNjc3MiCgldLAoJInNvdXJjZXNDb250ZW50IjogWwoJCSJAaW1wb3J0IFwiX3ZhcmlhYmxlc1wiO1xuQGltcG9ydCBcIl9kZW1vXCI7XG5cbi5zZWxlY3RvciB7XG4gIG1hcmdpbjogJHNpemU7XG4gIGJhY2tncm91bmQtY29sb3I6ICRicmFuZENvbG9yO1xuXG4gIC5uZXN0ZWQge1xuICAgIG1hcmdpbjogJHNpemUgLyAyO1xuICB9XG59IiwKCQkiJGJyYW5kQ29sb3I6ICNmNjA7XG4kc2l6ZTogMWVtOyIsCgkJIi5pbXBvcnRlZCB7XG4gIGNvbnRlbnQ6IFwieWF5LCBmaWxlIHN1cHBvcnQhXCI7XG59IgoJXSwKCSJtYXBwaW5ncyI6ICJBRUFBLFNBQVMsQ0FBQztFQUNSLE9BQU8sRUFBRSxvQkFBcUI7Q0FDL0I7O0FGQ0QsU0FBUyxDQUFDO0VBQ1IsTUFBTSxFQ0hELEdBQUc7RURJUixnQkFBZ0IsRUNMTCxJQUFJO0NEVWhCOztBQVBELFNBQVMsQ0FJUCxPQUFPLENBQUM7RUFDTixNQUFNLEVDUEgsS0FBRztDRFFQIiwKCSJuYW1lcyI6IFtdCn0= */"#;
1794+
1795+
let fs = TestProvider {
1796+
map: fs! {
1797+
"/a.css": r#"
1798+
@import "/b.css";
1799+
.a { color: red; }
1800+
"#,
1801+
"/b.css": source
1802+
},
1803+
};
1804+
1805+
let mut sm = parcel_sourcemap::SourceMap::new("/");
1806+
let mut bundler = Bundler::new(&fs, Some(&mut sm), ParserOptions::default());
1807+
let mut stylesheet = bundler.bundle(Path::new("/a.css")).unwrap();
1808+
stylesheet.minify(MinifyOptions::default()).unwrap();
1809+
stylesheet
1810+
.to_css(PrinterOptions {
1811+
source_map: Some(&mut sm),
1812+
minify: true,
1813+
..PrinterOptions::default()
1814+
})
1815+
.unwrap();
1816+
let map = sm.to_json(None).unwrap();
1817+
assert_eq!(
1818+
map,
1819+
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":[]}"#
1820+
);
1821+
}
17621822
}

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19790,7 +19790,7 @@ mod tests {
1979019790
let map = sm.to_json(None).unwrap();
1979119791
assert_eq!(
1979219792
map,
19793-
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":[]}"#
19793+
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":[]}"#
1979419794
);
1979519795
}
1979619796

src/printer.rs

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ pub struct Printer<'a, 'b, 'c, W> {
6161
pub(crate) sources: Option<&'c Vec<String>>,
6262
dest: &'a mut W,
6363
pub(crate) source_map: Option<&'a mut SourceMap>,
64+
pub(crate) source_maps: Vec<Option<SourceMap>>,
6465
pub(crate) loc: Location,
6566
indent: u8,
6667
line: u32,
@@ -83,6 +84,7 @@ impl<'a, 'b, 'c, W: std::fmt::Write + Sized> Printer<'a, 'b, 'c, W> {
8384
sources: None,
8485
dest,
8586
source_map: options.source_map,
87+
source_maps: Vec::new(),
8688
loc: Location {
8789
source_index: 0,
8890
line: 0,
@@ -205,17 +207,42 @@ impl<'a, 'b, 'c, W: std::fmt::Write + Sized> Printer<'a, 'b, 'c, W> {
205207
/// Adds a mapping to the source map, if any.
206208
pub fn add_mapping(&mut self, loc: Location) {
207209
self.loc = loc;
210+
208211
if let Some(map) = &mut self.source_map {
209-
map.add_mapping(
210-
self.line,
211-
self.col,
212-
Some(OriginalLocation {
212+
let mut original = OriginalLocation {
213213
original_line: loc.line,
214214
original_column: loc.column - 1,
215215
source: loc.source_index,
216216
name: None,
217-
}),
218-
)
217+
};
218+
219+
// Remap using input source map if possible.
220+
if let Some(Some(sm)) = self.source_maps.get_mut(loc.source_index as usize) {
221+
let mut found_mapping = false;
222+
if let Some(mapping) = sm.find_closest_mapping(loc.line, loc.column - 1) {
223+
if let Some(orig) = mapping.original {
224+
let sources_len = map.get_sources().len();
225+
let source_index = map.add_source(sm.get_source(orig.source).unwrap());
226+
original.original_line = orig.original_line;
227+
original.original_column = orig.original_column;
228+
original.source = source_index;
229+
original.name = orig.name;
230+
231+
if map.get_sources().len() > sources_len {
232+
let content = sm.get_source_content(orig.source).unwrap().to_owned();
233+
let _ = map.set_source_content(source_index as usize, &content);
234+
}
235+
236+
found_mapping = true;
237+
}
238+
}
239+
240+
if !found_mapping {
241+
return;
242+
}
243+
}
244+
245+
map.add_mapping(self.line, self.col, Some(original))
219246
}
220247
}
221248

src/stylesheet.rs

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ pub struct StyleSheet<'i, 'o> {
6666
/// Sources are referenced by index in the `loc` property of each rule.
6767
pub sources: Vec<String>,
6868
/// The source map URL extracted from the original style sheet.
69-
pub source_map_url: Option<String>,
69+
pub(crate) source_map_urls: Vec<Option<String>>,
7070
#[cfg_attr(feature = "serde", serde(skip))]
7171
/// The options the style sheet was originally parsed with.
7272
options: ParserOptions<'o, 'i>,
@@ -105,7 +105,7 @@ impl<'i, 'o> StyleSheet<'i, 'o> {
105105
pub fn new(sources: Vec<String>, rules: CssRuleList<'i>, options: ParserOptions<'o, 'i>) -> StyleSheet<'i, 'o> {
106106
StyleSheet {
107107
sources,
108-
source_map_url: None,
108+
source_map_urls: Vec::new(),
109109
rules,
110110
options,
111111
}
@@ -137,16 +137,20 @@ impl<'i, 'o> StyleSheet<'i, 'o> {
137137

138138
Ok(StyleSheet {
139139
sources: vec![options.filename.clone()],
140-
source_map_url: parser.current_source_map_url().map(|s| s.to_owned()),
140+
source_map_urls: vec![parser.current_source_map_url().map(|s| s.to_owned())],
141141
rules: CssRuleList(rules),
142142
options,
143143
})
144144
}
145145

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

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

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

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

223-
if let Some(sm) = printer.source_map {
224-
if let Some(mut input_sm) = self.source_map() {
225-
let _ = sm.extends(&mut input_sm);
226-
}
227-
}
228-
229230
Ok(ToCssResult {
230231
dependencies: printer.dependencies,
231232
code: dest,

0 commit comments

Comments
 (0)