Skip to content

Commit f8ff2b6

Browse files
authored
chore: source maps for preprocessors + tests (#10459)
Add source map merging for preprocessors and get tests passing. - fixed some issues around the `sources` array where they weren't calculated relative to the input correctly - adjusted some CSS tests because due to our own CSS parser the AST is less granular, so there are less mappings now. Don't think this is a problem, but worth thinking about - removed enableSourcemap but only log a warning, the reason this was introduced was to mitigate a bug in Vite which occured when having the source map inlined into the SSR'd output. Since SSR doesn't contain inlined CSS anymore (and if it did, we would omit the source map) the reason for which it was introduced no longer exists - files without js mapping in it have no source mappings yet (originally added in Svelte 4 for #6092)
1 parent 4b274dd commit f8ff2b6

File tree

102 files changed

+926
-1358
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

102 files changed

+926
-1358
lines changed

.changeset/silly-laws-happen.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"svelte": patch
3+
---
4+
5+
fix: add proper source map support

packages/svelte/src/compiler/css/Stylesheet.js

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@ import MagicString from 'magic-string';
22
import { walk } from 'zimmerframe';
33
import { ComplexSelector } from './Selector.js';
44
import { hash } from './utils.js';
5-
// import compiler_warnings from '../compiler_warnings.js';
6-
// import { extract_ignores_above_position } from '../utils/extract_svelte_ignore.js';
75
import { create_attribute } from '../phases/nodes.js'; // TODO move this
6+
import { merge_with_preprocessor_map } from '../utils/mapped_code.js';
87

98
const regex_css_browser_prefix = /^-((webkit)|(moz)|(o)|(ms))-/;
109
const regex_name_boundary = /^[\s,;}]$/;
@@ -337,7 +336,7 @@ export class Stylesheet {
337336
/** @type {import('#compiler').Style | null} */
338337
ast;
339338

340-
/** @type {string} */
339+
/** @type {string} Path of Svelte file the CSS is in */
341340
filename;
342341

343342
/** @type {boolean} */
@@ -471,20 +470,23 @@ export class Stylesheet {
471470
}
472471

473472
/**
474-
* @param {string} file
475473
* @param {string} source
476-
* @param {boolean} dev
474+
* @param {import('#compiler').ValidatedCompileOptions} options
477475
*/
478-
render(file, source, dev) {
476+
render(source, options) {
479477
// TODO neaten this up
480478
if (!this.ast) throw new Error('Unexpected error');
481479

482480
const code = new MagicString(source);
483481

482+
// Generate source mappings for the style sheet nodes we have.
483+
// Note that resolution is a bit more coarse than in Svelte 4 because
484+
// our own CSS AST is not as detailed with regards to the node values.
484485
walk(/** @type {import('#compiler').Css.Node} */ (this.ast), null, {
485-
_: (node) => {
486+
_: (node, { next }) => {
486487
code.addSourcemapLocation(node.start);
487488
code.addSourcemapLocation(node.end);
489+
next();
488490
}
489491
});
490492

@@ -495,19 +497,27 @@ export class Stylesheet {
495497
code.remove(0, this.ast.content.start);
496498

497499
for (const child of this.children) {
498-
child.prune(code, dev);
500+
child.prune(code, options.dev);
499501
}
500502

501503
code.remove(/** @type {number} */ (this.ast.content.end), source.length);
502504

503-
return {
505+
const css = {
504506
code: code.toString(),
505507
map: code.generateMap({
508+
// include source content; makes it easier/more robust looking up the source map code
506509
includeContent: true,
510+
// generateMap takes care of calculating source relative to file
507511
source: this.filename,
508-
file
512+
file: options.cssOutputFilename || this.filename
509513
})
510514
};
515+
merge_with_preprocessor_map(css, options, css.map.sources[0]);
516+
if (options.dev && options.css === 'injected' && css.code) {
517+
css.code += `\n/*# sourceMappingURL=${css.map.toUrl()} */`;
518+
}
519+
520+
return css;
511521
}
512522

513523
/** @param {import('../phases/types.js').ComponentAnalysis} analysis */

packages/svelte/src/compiler/phases/1-parse/index.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import full_char_code_at from './utils/full_char_code_at.js';
77
import { error } from '../../errors.js';
88
import { create_fragment } from './utils/create.js';
99
import read_options from './read/options.js';
10+
import { getLocator } from 'locate-character';
1011

1112
const regex_position_indicator = / \(\d+:\d+\)$/;
1213

@@ -41,13 +42,16 @@ export class Parser {
4142
/** @type {LastAutoClosedTag | undefined} */
4243
last_auto_closed_tag;
4344

45+
locate;
46+
4447
/** @param {string} template */
4548
constructor(template) {
4649
if (typeof template !== 'string') {
4750
throw new TypeError('Template must be a string');
4851
}
4952

5053
this.template = template.trimEnd();
54+
this.locate = getLocator(this.template, { offsetLine: 1 });
5155

5256
let match_lang;
5357

@@ -133,6 +137,18 @@ export class Parser {
133137
}
134138
}
135139

140+
/**
141+
* offset -> line/column
142+
* @param {number} start
143+
* @param {number} end
144+
*/
145+
get_location(start, end) {
146+
return {
147+
start: /** @type {import('locate-character').Location_1} */ (this.locate(start)),
148+
end: /** @type {import('locate-character').Location_1} */ (this.locate(end))
149+
};
150+
}
151+
136152
current() {
137153
return this.stack[this.stack.length - 1];
138154
}
@@ -297,7 +313,6 @@ export class Parser {
297313
*/
298314
export function parse(template) {
299315
const parser = new Parser(template);
300-
301316
return parser.root;
302317
}
303318

packages/svelte/src/compiler/phases/1-parse/read/context.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export default function read_pattern(parser) {
2828
type: 'Identifier',
2929
name,
3030
start,
31+
loc: parser.get_location(start, parser.index),
3132
end: parser.index,
3233
typeAnnotation: annotation
3334
};

0 commit comments

Comments
 (0)