Skip to content

Support index source maps. - #6399

Merged
mstange merged 1 commit into
firefox-devtools:mainfrom
mstange:push-uvwklquoymzu
Oct 19, 2026
Merged

mstange merged 1 commit into
firefox-devtools:mainfrom
mstange:push-uvwklquoymzu

Conversation

@mstange

@mstange mstange commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Main | Deploy preview

profiler-edit wasn't applying the source map from the VideoSite-Polymer workload.

This workload's source map is an "index source map". This happened more or less by accident; the workload has a build script which does the following:

  // ...
  const chunks = ["base", "main"].map(c => fs.readFileSync(r(`out/chunks/${c}.js`), "utf8"));
  fs.mkdirSync(r("dist"), { recursive: true });
  fs.writeFileSync(r("dist/app.js"), OUTER_PREFIX + chunks.join("\n") + OUTER_SUFFIX + "//# sourceMappingURL=app.js.map\n");
  // An index source map for dist/app.js
  let line = OUTER_PREFIX.split("\n").length - 1;
  const sections = chunks.map((text, i) => {
    const s = { offset: { line, column: 0 }, map: JSON.parse(fs.readFileSync(r(`out/chunks/${["base", "main"][i]}.js.map`), "utf8")) };
    line += text.split("\n").length;
    return s;
  });
  const indexMap = JSON.stringify({ version: 3, file: "app.js", sections });

So the index source map in this case isn't really the output from a single bundler, it's the result of some custom stitching.

Either way, there doesn't seem to be a reason to reject such source maps. We already resolve them correctly when you gather a profile of that workload in the browser, it was just the "apply source map" UI button and profiler-edit which were rejecting them.

And Claude says that Closure can output index source maps in some cases.

@mstange
mstange requested a review from canova October 17, 2026 23:15
@codecov

codecov Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 89.47368% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 84.49%. Comparing base (439a940) to head (20e6f3c).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
src/app-logic/browser-connection.ts 0.00% 1 Missing ⚠️
src/profile-logic/source-maps/matching.ts 96.87% 1 Missing ⚠️
src/profile-query/function-annotate.ts 0.00% 1 Missing ⚠️
src/utils/query-api.ts 0.00% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main    #6399   +/-   ##
=======================================
  Coverage   84.48%   84.49%           
=======================================
  Files         357      357           
  Lines       38675    38693   +18     
  Branches    10957    10867   -90     
=======================================
+ Hits        32675    32692   +17     
- Misses       5565     5566    +1     
  Partials      435      435           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@canova canova left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yeah. I was considering supporting this while working on the source map support, but I decided not to support it because it's not used almost anywhere, and didn't want to complicate it for that.

But looking at the PR, it's not bad actually, so it's worth accepting.

And Claude says that Closure can output index source maps in some cases.

For the record, I remember doing some research about it then and I was confused at first, because at first I thought this was Clojure (the language) that supports it, but this is the Google Closure Compiler. Apparently it's a compiler that compiles (transpiles?) JS into a better JS? And when I checked, that compiler was defaulting to regular/flat source map v3, and there was no cli flag to change it to index maps. And index map can only be output via their Java API, so it still looks pretty unlikely to see it in the wild. But I guess we never know if someone else will want to support it in the future in one of their tools. And considering that this is not much to maintain I think we can add it.

This workload's source map is an "index source map". This happened more or less by accident; the workload has a build script which does the following:

Oh wow, interesting! 😄 Not for this PR ofc but I would also very much prefer if we can change that worload to output regular flat source maps and not index maps 😄

section !== null &&
typeof section === 'object' &&
_isPosition(section.offset) &&
_isSourceMap(section.map)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm currently we do a recursion here for index maps to see if their sections are also source maps, but if I'm not mistaken, an index map can't have an index map as its inner section. But this still accepts that case.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh good point. I've changed it and added a test. The library allows recursively nested index source maps but the spec does not.

@mstange

mstange commented Oct 19, 2026

Copy link
Copy Markdown
Contributor Author

this is the Google Closure Compiler. Apparently it's a compiler that compiles (transpiles?) JS into a better JS?

Yes, it is used a lot for Google internal sites (YouTube being one of them), and the React minified production bundle is also built with Closure (though they don't use the advanced annotations that could get them more aggressive minification).

that compiler was defaulting to regular/flat source map v3, and there was no cli flag to change it to index maps. And index map can only be output via their Java API, so it still looks pretty unlikely to see it in the wild.

Ah, indeed. Yes I agree it seems unlikely to appear in the wild.

This workload's source map is an "index source map". This happened more or less by accident; the workload has a build script which does the following:

Oh wow, interesting! 😄 Not for this PR ofc but I would also very much prefer if we can change that worload to output regular flat source maps and not index maps 😄

Hmm I can make that change but I am not entirely convinced.

@canova

canova commented Oct 19, 2026

Copy link
Copy Markdown
Member

Hmm I can make that change but I am not entirely convinced.

Why do you think an index map is better for this case? Is there a specific reason?

An index map has a sections array instead of a top-level mappings string.
Each section pairs a generated-code offset with an embedded source map
(ECMA-426 section 10). Closure Compiler output, for example, can come with
one. The source-map library already reads index maps, but
parseSourceMapFileContents rejected them, so profiler-edit's
--map-source-paths and the "apply source map file" button skipped them.

Accept and validate index maps, and widen the type of the parsed map to
RawSourceMap | RawIndexMap.
@mstange
mstange added this pull request to the merge queue Oct 19, 2026
Merged via the queue into firefox-devtools:main with commit 63e8a2f Oct 19, 2026
39 of 40 checks passed
@fatadel fatadel mentioned this pull request Oct 22, 2026
fatadel added a commit that referenced this pull request Oct 22, 2026
Changes:

[Markus Stange] Accept more fields from symbolication. (#6373)
[Markus Stange] Support index source maps. (#6399)
[fatadel] Make CompositorScreenshot markers schema-based (#6261)
[Markus Stange] Use inverted transforms in the tests for inverted call node paths. (#6393)
[fatadel] Expose and clear URL-imported call tree search in the CLI (#6387)
[Markus Stange] Make the scrollable editor view in the source view cover the full height of the panel, even if the source code is short. (#6405)
[Nazım Can Altınova] Silence profile loader logs in profile-querier-url tests (#6409)
[Nazım Can Altınova] Add `--js-sources-from-func-names` to `profiler-edit` (#6394)
[Nazım Can Altınova] Look for a source file's address proof in all of its frames (#6407)
[Markus Stange] Some preparations for a function list panel (#6401)
[fatadel] Use fractional seconds with adaptive precision for CLI marker timestamps (#6384)
[fatadel] 🔃 Sync: l10n -> main (October 22, 2026) (#6415)
[Markus Stange] Switch to TypeScript 7 (tsgo) and replace ESLint with oxlint (#6354)
[fatadel] Bump profiler-cli version to 0.12.0 (#6416)

And special thanks to our localizers:

el: Jim Spentzos
uk: Lobodzets, uya2521, Іhor Hordiichuk
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants