You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
RUM-12185: Support aliased import paths for local SVG discovery - #1352
Adds support for resolving aliased local SVG imports during Session Replay asset discovery.
Supports TypeScript/JavaScript path mappings and babel-plugin-module-resolver, including .babelrc, function-form plugin configurations, and Windows paths. Includes regression coverage for the supported configurations.
Handle alias entries in babel-plugin-module-resolver that resolve to absolute paths, not just relative ones
Detect aliased SVG imports whose specifier has no .svg extension (alias points directly at the file)
Add support for metro.config.js's resolver.extraNodeModules, matching Metro's own scoped-specifier parsing
Before
After
Motivation
What inspired you to submit this pull request?
Additional Notes
Anything else we should know when reviewing?
Review checklist (to be filled by reviewers)
Feature or bugfix MUST have appropriate tests
Make sure you discussed the feature or bugfix with the maintaining team in an Issue
Make sure each commit and the PR mention the Issue number (cf the CONTRIBUTING doc)
If this PR is auto-generated, please make sure also to manually update the code related to the change
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Adds support for resolving aliased local .svg imports during Session Replay asset discovery, so ReactNativeSVG.buildSvgMap() can map SVG components even when imports use TS/JS path mappings or babel-plugin-module-resolver.
Changes:
Introduces PathAliasResolver to resolve non-relative SVG import specifiers via babel-plugin-module-resolver and tsconfig.json/jsconfig.jsonpaths.
Updates ReactNativeSVG.buildSvgMap() to use the resolver (and reset cached alias config between runs).
Adds regression tests and a benchmark scenario exercising aliased SVG imports.
Reviewed changes
Copilot reviewed 7 out of 8 changed files in this pull request and generated 2 comments.
Show a summary per file
File
Description
yarn.lock
Adds lock entries for tsconfig-paths and babel-plugin-module-resolver (and transitive deps).
isRelativePath() only matches ./ and ../ with forward slashes, so module-resolver results like src/components/icon.svg or Windows-style ..\\src\\icon.svg will be treated as non-relative and discarded, preventing alias resolution.
function isRelativePath(value: string): boolean {
return /^\.?\.\//.test(value);
}
isRelativePath() only matches ./... paths; it does not match ../... (or deeper) relative paths. babel-plugin-module-resolver can legally return ../... when an alias resolves outside the importing file’s directory, and the current check would incorrectly treat that as non-relative and return null (falling back to unresolved resolution).
function isRelativePath(value: string): boolean {
return /^\.?\.\//.test(value);
}
parseExtraNodeModulesSpecifier() returns subpath including a leading "/". Passing that into path.join(target, subpath) causes Node to discard target (because an absolute segment resets the join), so extraNodeModules aliases like assets/icon.svg will resolve to /icon.svg instead of ${target}/icon.svg.
isRelativePath() only matches sources starting with ./ (due to ^\.?\.\/), so it will incorrectly treat ../... (and Windows .\\/..\\) paths returned by babel-plugin-module-resolver as non-relative and skip resolution. That can break aliases whose replacement uses parent-directory segments.
function isRelativePath(value: string): boolean {
return /^\.?\.\//.test(value);
}
Same issue as the ImportDeclaration handler: relative/absolute re-export sources that don't end in .svg can never be resolved by PathAliasResolver, so collecting them for the second pass is unnecessary overhead.
const source = path.node.source?.value;
if (!source) {
return;
}
if (source.endsWith('.svg')) {
const resolved = this.resolveImportSource(
file,
source
);
this.populateExportedSvgNames(path, resolved);
return;
}
const candidateNames: string[] = [];
for (const spec of path.node.specifiers) {
if (spec.type !== 'ExportSpecifier') {
continue;
}
// spec.exported is the name consumers import under
// ('default' would be wrong for `export { default as Logo }`)
const exported = spec.exported;
const name = getNodeName(
this.t,
this.t.isStringLiteral(exported)
? exported.value
: exported.name
);
if (name) {
candidateNames.push(name);
}
}
if (!candidateNames.length) {
return;
}
pendingBareSources.push({
file,
source,
candidateNames,
populate: resolved =>
this.populateExportedSvgNames(path, resolved)
});
}
isRelativePath() only recognizes ./ and ../ with forward slashes. On Windows, babel-plugin-module-resolver commonly returns relative paths using backslashes (e.g. .\\src\\... / ..\\...), which will be treated as non-relative here and make aliased imports fail to resolve on Windows.
function isRelativePath(value: string): boolean {
return /^\.?\.\//.test(value);
}
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
A Windows-path handling bug in PathAliasResolver can prevent module-resolver relative outputs using backslashes from being recognized and resolved correctly.
isRelativePath() only detects POSIX-style ./ and ../ prefixes. On Windows, babel-plugin-module-resolver (or user config) can yield relative paths using backslashes (e.g. .\\src\\components\\icon.svg), which would be treated as non-relative and make alias resolution incorrectly fall back to null.
function isRelativePath(value: string): boolean {
return /^\.?\.\//.test(value);
}
The new benchmark aliases hardcode files under benchmarks/node_modules/@react-native/debugger-frontend, but this package is not a direct benchmark dependency. The lockfile has both 0.76.9 and 0.78.2 transitively; node-modules hoisting does not guarantee the expected 0.78.2 files at that path, so the benchmark may fail to bundle or exercise these cases. Declare @react-native/debugger-frontend at the benchmark's React Native version (0.78.2) and update the lockfile, or use an explicitly owned fixture.
Validate alias-resolved SVG targets before caching
If an alias maps to a missing .svg file, the nonempty resolver result is stored as a valid entry here without checking the target. A module-resolver or Metro alias can yield a path even when no file exists; a later JSX transform then fails to read it and skips the SVG. Check that alias-resolved .svg targets are real files before populating the map, both for sources ending in .svg and for extensionless aliases at lines 61–62. The existing missing-path test only exercises tsconfig-paths.
Prevent wildcard exports from overriding explicit names
Wildcard traversal also runs when this barrel has an explicit export of the same name. For export { Logo } from './nonSvg'; export * from './svgBarrel';, JavaScript selects the explicit Logo, but following the wildcard can assign the SVG to the consuming JSX binding and wrap the wrong component. Record explicit exported names (including direct SVG and deferred bare exports), and only follow a wildcard for names not explicitly exported by that barrel.
Reuse Babel bindings across equivalent configurations
moduleResolverBindings is keyed by filename, so loadPartialConfig() runs again for each distinct source file with a reachable bare import, even when they share the same Babel configuration. On a large React Native project this can repeatedly load the full config and plugins during one SVG scan, including for ordinary JSX component imports. Reuse the resolved binding across files whose Babel configuration is equivalent, while preserving file-specific Babel overrides and separate monorepo configs.
An existing unversioned svg-map.json is accepted here and buildSvgMap() returns before rescanning. That cache was generated before aliased imports were discovered, so a build without a platform can keep missing aliased SVGs after upgrading until the asset generator rewrites the cache. Invalidate or regenerate legacy caches for discovery (and update the legacy-cache test), rather than treating them as a complete map.
Override does not disable Datadog instrumentation for fixtures
benchmarks/babel.config.js:33
Babel merges plugins from overrides with the top-level plugins array; it does not replace the top-level Datadog plugin for these files. As a result, the fixture files still run the svgTracking: true instance (or Babel reports a duplicate-plugin error), so this override cannot disable direct fixture instrumentation and the benchmark cases do not isolate alias discovery as intended. Move the enabled Datadog plugin into an override that excludes the fixture directory, rather than adding a second disabled instance.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Adds support for resolving aliased local SVG imports during Session Replay asset discovery.
Supports TypeScript/JavaScript path mappings and babel-plugin-module-resolver, including .babelrc, function-form plugin configurations, and Windows paths. Includes regression coverage for the supported configurations.
Handle alias entries in babel-plugin-module-resolver that resolve to absolute paths, not just relative ones
Detect aliased SVG imports whose specifier has no .svg extension (alias points directly at the file)
Add support for metro.config.js's resolver.extraNodeModules, matching Metro's own scoped-specifier parsing
Before

After

Motivation
What inspired you to submit this pull request?
Additional Notes
Anything else we should know when reviewing?
Review checklist (to be filled by reviewers)