Skip to content

feat(source-map): add extract option#7340

Merged
chenjiahan merged 3 commits intoweb-infra-dev:mainfrom
zalishchuk:source-map-extract
Mar 19, 2026
Merged

feat(source-map): add extract option#7340
chenjiahan merged 3 commits intoweb-infra-dev:mainfrom
zalishchuk:source-map-extract

Conversation

@zalishchuk
Copy link
Copy Markdown
Contributor

Summary

Adds a output.sourceMap.extract option, so Rspack's rules[].extractSourceMap can be enabled.

This implementation supports JS extraction only. I considered CSS extraction as well, but the current CSS pipeline does not preserve upstream CSS source maps end to end. Keeping sourceMap.extract as its own namespace still gives a clear place to support CSS in the future if that becomes possible.

Related Links

Checklist

  • Tests updated (or not required).
  • Documentation updated (or not required).

Copilot AI review requested due to automatic review settings March 18, 2026 02:15
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds an output.sourceMap.extract configuration namespace to enable Rspack’s rules[].extractSourceMap, allowing Rsbuild to preserve upstream JavaScript source maps (e.g. from packages shipping .js + .js.map).

Changes:

  • Extend output.sourceMap config/types/defaults with a new extract option.
  • Apply extractSourceMap: true via a dedicated Rspack rule when extraction is enabled (with optional include/exclude filtering).
  • Add unit + e2e coverage and update docs/snapshots accordingly.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
website/docs/en/config/output/source-map.mdx Documents the new sourceMap.extract option and examples.
packages/core/src/types/config.ts Adds public types for SourceMapExtract / SourceMapExtractTarget and wires extract into SourceMap.
packages/core/src/defaultConfig.ts Sets output.sourceMap.extract default to false.
packages/core/src/plugins/sourceMap.ts Implements extraction rule injection (extractSourceMap: true) with include/exclude support.
packages/core/src/index.ts Re-exports the new types from the public entrypoint.
packages/core/tests/sourceMap.test.ts Adds unit tests verifying rule injection + include/exclude normalization behavior.
packages/core/tests/snapshots/environments.test.ts.snap Updates snapshots for the normalized environment config (extract: false).
e2e/cases/source-map/extract/src/index.js New e2e entry importing a package intended to have upstream maps.
e2e/cases/source-map/extract/index.test.ts New e2e assertions that upstream maps are preserved when extraction is enabled.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1090 to +1091
* Whether to extract source map from matching JavaScript files.
* `true` means extract from all files matched by the built-in JS rule.
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.

Maybe we can add the extractSourceMap: true option to the built-in rule when extract is true, instead of creating a new rule.

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.

@chenjiahan Do you expect sourceMap.extract to follow the built-in SWC rule scope?

I kept it separate because the built-in JS rule handles transpilation and typically ignores node_modules, while extraction mainly targets upstream maps from dependencies

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.

That makes sense. A separate rule provides more flexibility when handling node_modules. 👍

Comment thread e2e/cases/source-map/extract/src/index.js
Comment thread website/docs/en/config/output/source-map.mdx
Comment thread website/docs/en/config/output/source-map.mdx
Copilot AI review requested due to automatic review settings March 18, 2026 02:48
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a new output.sourceMap.extract configuration namespace to enable extracting upstream JavaScript source maps (via Rspack rules[].extractSourceMap) so packages that ship .js + .js.map can preserve original mappings in the final output.

Changes:

  • Extend output.sourceMap config/type definitions to include extract (boolean or { js?: ... }) with default false.
  • Implement extraction rule injection in plugin-source-map by adding a dedicated Rspack rule with extractSourceMap: true plus optional include/exclude.
  • Add unit + e2e coverage and update environment normalization snapshots; document the new option.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
website/docs/en/config/output/source-map.mdx Documents sourceMap.extract, updates type/default snippets, adds usage examples.
packages/core/tests/sourceMap.test.ts Unit tests to assert extract rules are added/normalized correctly.
packages/core/tests/snapshots/environments.test.ts.snap Snapshot updates for normalized sourceMap.extract: false.
packages/core/src/types/config.ts Introduces SourceMapExtract* types and wires extract into SourceMap / normalized output config.
packages/core/src/plugins/sourceMap.ts Adds pre-chain handler to inject extractSourceMap rule for JS with include/exclude support.
packages/core/src/index.ts Exports SourceMapExtract and SourceMapExtractTarget as public types.
packages/core/src/defaultConfig.ts Adds sourceMap.extract: false to default normalized output config.
e2e/cases/source-map/extract/src/index.js New e2e fixture consuming a package with an upstream sourcemap.
e2e/cases/source-map/extract/index.test.ts E2E test validating upstream sourcemaps are preserved when extraction is enabled.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread website/docs/en/config/output/source-map.mdx
Copy link
Copy Markdown
Member

@chenjiahan chenjiahan left a comment

Choose a reason for hiding this comment

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

Thank you! ❤️

@chenjiahan chenjiahan merged commit eb6cd87 into web-infra-dev:main Mar 19, 2026
8 of 9 checks passed
@chenjiahan chenjiahan changed the title feat(source-map): add extraction option feat(source-map): add extract option Mar 19, 2026
@zalishchuk
Copy link
Copy Markdown
Contributor Author

@chenjiahan Hi! I didn't expect this to merge so quickly, as I'm unsure if this configuration scheme is the best we can get. Also, since we can't change the "test" property for the rule itself, do you have any ideas on how we can do this properly?

CRA (outdated, but whatever) uses source-map-loader for .css files too, I am not sure that this does something since the behavior of source map chain for CSS in both webpack/rspack/rsbuild...

@chenjiahan
Copy link
Copy Markdown
Member

@zalishchuk At first glance, this API design feels a bit verbose to me, though I haven’t come up with a simpler alternative.

Adding a test option sounds reasonable, and I can see it being useful in some scenarios. Would you like to submit a PR?

In the long term, I think we should support CSS source maps. But they don’t work well in some scenarios right now, for example web-infra-dev/rspack#10274 and users probably don’t rely on CSS source maps heavily. So it might make sense to revisit this and add support later.

@zalishchuk
Copy link
Copy Markdown
Contributor Author

@chenjiahan Sorry for the late reply. Yes, I will think about the best way to configure all these properties.

@zalishchuk
Copy link
Copy Markdown
Contributor Author

Hi @chenjiahan, wanted to ask your opinion on the sourceMap.extract API shape.

After giving it some more thought, I wonder if extract.js and the future extract.css might be an unnecessary layer of API nesting, since at their core, they are simply extract rules with different default test regexes.

  • Keep supporting the current extract.js shape for backward compatibility.
  • Mark extract.js as deprecated in docs/types.
  • Recommend the flat object shape going forward.
  • Keep extract: true as the current default JS behavior for compatibility.
  • Still provide an easy way to enable/disable JS and CSS extraction separately. If the flat object defaults to JS only, users should not have to write a regex just to enable CSS extraction.

Maybe that means adding a simple preset field, similar to other Rsbuild options that use type:

sourceMap: {
  extract: {
    /** 'js' | 'css' | 'all' */
    type: 'all',
    include: [/node_modules[\\/]some-package[\\/]/],
  },
}

For more flexibility, users could still use tools.rspack and add a custom extractSourceMap rule themselves. Another option is to expose test directly in sourceMap.extract, but maybe that makes the Rsbuild API too close to Rspack for the common case.

Compared with the current schema:

type CurrentSourceMapExtract =
  | boolean
  | {
      js?:
        | boolean
        | {
            include?: Rspack.RuleSetCondition[];
            exclude?: Rspack.RuleSetCondition[];
          };
      /** future */
      // css?: boolean | {
      //   include?: Rspack.RuleSetCondition[];
      //   exclude?: Rspack.RuleSetCondition[];
      // };
    };
  • Current: extract.js is a target namespace, but today there is only one real target.
  • Current: future extract.css would duplicate the same include / exclude shape with a different built-in matcher.
  • Proposed: extract directly describes one extraction rule, and type chooses the built-in matcher preset.
  • Proposed: advanced matching can still be handled by test or by tools.rspack.

Example config with the proposed schema:

import { defineConfig } from '@rsbuild/core';

export default defineConfig({
  output: {
    sourceMap: {
      js: 'source-map',
      css: true,
      extract: {
        type: 'all',
        include: [/node_modules[\\/]some-package[\\/]/],
        // test: /\.js$/, // optional override of the built-in matcher
      },
    },
  },
});

The final shape could be something like:

type SourceMapExtractTarget = {
  /**
   * Specifies which built-in source map extraction rules should be enabled.
   * @default 'js'
   */
  type?: 'js' | 'css' | 'all';
  /** Optional escape hatch to override the built-in matcher. */
  test?: Rspack.RuleSetCondition;
  /** Include matched files whose existing source maps should be extracted. */
  include?: Rspack.RuleSetCondition[];
  /** Exclude matched files whose existing source maps should not be extracted. */
  exclude?: Rspack.RuleSetCondition[];
};

type DeprecatedSourceMapExtractTarget = {
  /** @deprecated Use `sourceMap.extract.type` instead. */
  js?: boolean | SourceMapExtractTarget;
  /** @deprecated Use `sourceMap.extract.type` instead. */
  css?: boolean | SourceMapExtractTarget;
};

type SourceMapExtract =
  | boolean
  | SourceMapExtractTarget
  | DeprecatedSourceMapExtractTarget;

Do you think this direction makes sense for Rsbuild, or would you prefer to keep extract.js as the main API in case we want target-specific defaults, like CSS, later?

@chenjiahan
Copy link
Copy Markdown
Member

Thanks for the proposal! I agree that the new API design looks cleaner and more elegant, and the points above are largely in line with my thoughts.

My guess is that extract.js hasn't been widely used yet, so deprecating it early and introducing a better API would be a good direction.

PRs are very welcome if you have time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants