- 
          
 - 
                Notifications
    
You must be signed in to change notification settings  - Fork 1.3k
 
fix: rewriteRelativeImportExtensions with TypeScript path aliases #11219
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Fixes #11143 ## Problem When both `rewriteRelativeImportExtensions: true` and `jsc.paths` were configured, the extension rewriting would not work for imports using path aliases. For example: - Input: `export { a } from "@/util/index.ts";` - Previous output: `export { a } from "./util/index.ts";` (extension NOT rewritten) - Fixed output: `export { a } from "./util/index.js";` (extension correctly rewritten) ## Root Cause The transformation passes were executing in the wrong order: 1. `typescript_import_rewriter()` ran first, checking for relative paths (`./` or `../`) 2. Since `@/util/index.ts` doesn't start with `./` or `../`, it skipped rewriting 3. `import_rewriter()` ran second and resolved `@/util/index.ts` → `./util/index.ts` 4. But the extension rewriter had already run, so `.ts` was never rewritten to `.js` ## Solution Integrated extension rewriting directly into `NodeImportResolver`: 1. Added `rewrite_import_extensions: bool` field to `Config` in `path.rs` 2. Implemented `rewrite_extension()` method that applies the same logic as TypeScript's `rewriteRelativeImportExtensions` after path resolution 3. Updated the main config to pass this flag through to the resolver 4. Modified the pass logic to skip the separate `typescript_import_rewriter` pass when using a resolver with extension rewriting enabled This ensures extension rewriting happens AFTER path alias resolution, fixing the issue. ## Changes - `crates/swc_ecma_transforms_module/src/path.rs`: - Added `rewrite_import_extensions` field to `Config` struct - Implemented `rewrite_extension()` helper method - Applied extension rewriting in `to_specifier()` after path resolution - `crates/swc/src/config/mod.rs`: - Updated `build_resolver()` to accept `rewrite_import_extensions` parameter - Updated `get_resolver()` to accept and pass through the flag - Modified resolver cache key to include `rewrite_import_extensions` - Updated pass logic to conditionally use separate rewriter only when needed ## Tests Added comprehensive test in `crates/swc/tests/fixture/issues-11xxx/11143/` covering: - Path aliases with `.ts` → `.js` - Path aliases with `.tsx` → `.jsx` - Path aliases with `.mts` → `.mjs` - Path aliases with `.cts` → `.cjs` - Regular relative imports (regression test) - Export all statements - Dynamic imports 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
| 
           
  | 
    
    
      
        1 similar comment
      
    
  
    | 
           
  | 
    
          
 | 
    
| 
           🤖 This pull request has been linked to DevBird Task #1189 View the task details and manage the automated development workflow in DevBird. Learn more about DevBird here or the announcement blog post here.  | 
    
          📋 DevBird Task PromptFix the bug where  Problem DescriptionWhen SWC is configured with both: 
 The extension rewriting fails for aliased imports. For example: 
 Regular relative imports like  Root Cause AnalysisThe issue occurs due to the order of transformation passes in  
 The execution order is: 
 Technical ContextKey files: 
 Documentation References
 Solution ApproachThere are two potential solutions: Option 1 (Recommended): Integrate extension rewriting into import_rewriterModify the  
 Benefits: 
 Option 2 (Alternative): Reorder the passesModify  
 Benefits: 
 Drawbacks: 
 Implementation StepsFor Option 1 (Recommended): 
 Testing RequirementsCreate comprehensive tests covering: 
 Success Criteria
 Important Notes from CLAUDE.md
 Issue Reference
 Branch NameUse branch name:  This comment was automatically added by DevBird. You can disable this feature in DevBird Settings.  | 
    
| 
           Claude finished @DeLino[bot]'s task —— View job Code Review CompleteI've conducted a thorough review of PR #11219 that fixes the  ✅ Overall Assessment: Excellent ImplementationThis is a well-designed fix that properly addresses the root cause of the issue. The solution is elegant, performant, and maintains backward compatibility. 🎯 Core Implementation Review
 | 
    
          Binary Sizes
 Commit: ab4a6f3  | 
    
          
CodSpeed Performance ReportMerging #11219 will not alter performanceComparing  Summary
  | 
    
Description
Fixes #11143
This PR fixes a bug where
rewriteRelativeImportExtensions: truedoesn't work correctly when TypeScript path aliases (jsc.paths) are configured.Problem
When both settings were enabled:
rewriteRelativeImportExtensions: truejsc.pathswith path aliases (e.g.,"@/*": [".//*"])The extension rewriting would fail for aliased imports:
Root Cause
The transformation passes were executing in the wrong order:
typescript_import_rewriter()ran first, checking if imports start with./or../@/util/index.tsdoesn't match that pattern, it skipped extension rewritingimport_rewriter()ran second and resolved the alias:@/util/index.ts→./util/index.ts.tswas never rewritten to.jsSolution
Integrated extension rewriting directly into
NodeImportResolver:rewrite_import_extensionsfield to the resolver'sConfigstructtypescript_import_rewriterwhen using a resolver with extension rewriting enabledThis ensures extensions are rewritten after path aliases are resolved, fixing the issue.
Changes
crates/swc_ecma_transforms_module/src/path.rs:
rewrite_import_extensionsfield toConfigrewrite_extension()helper methodto_specifier()after path resolutioncrates/swc/src/config/mod.rs:
build_resolver()to acceptrewrite_import_extensionsparameterget_resolver()to pass through the flagTests
Added comprehensive test in
crates/swc/tests/fixture/issues-11xxx/11143/covering:.ts→.js.tsx→.jsx.mts→.mjs.cts→.cjsRelated
rewriteRelativeImportExtensions: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-7.html