Skip to content

Commit

Permalink
feat(es/transforms): Add module.outFileExtension (#9784)
Browse files Browse the repository at this point in the history
**Description:**

Summary of Changes:

1. Adds an `outFileExtension` property to every module configuration
option struct
2. passes this configuration through to the resolver function and
changes all hard-coded `"js"` checks to use the new parameter
3. As a matter of backwards compatibility, structures default to "js" if
nothing is provided
4. `@swc/core` snapshot tests for each module using `resolveFully` and
`outFileExtension` (Please check the rendered output of the snapshots to
make sure you don't have any issues with it).
1. QOL - updates `@swc/core` jest config to use explicit module names
(this was because the mapping util in jest was exploding when it would
try to load in the .node files that were over 512MB)
5. QOL - updates the test script to pass through any existing
NODE_OPTIONS - this allows debugging tools to add their own inspect
configurations while preserving our esm module flag

**Note**

This is a rudimentary fix to:
#3067 (comment).
I had to implement it locally since I could not find a workaround in my
timeline.

I do know that @kdy1 said they would work on it a few days ago, so I am
opening this to either provide some visibility to a solution that works
for me if they haven't started or to let them switch to PR critique if
that feels more valuable for their time on this issue. Let me know if
this should be closed due to a better implementation already being in
the works.


**Related issue:**

 - Closes #3067

---------

Co-authored-by: Donny/강동윤 <kdy1997.dev@gmail.com>
  • Loading branch information
hanseltime and kdy1 authored Dec 9, 2024
1 parent e05e4c7 commit e04c7b3
Show file tree
Hide file tree
Showing 69 changed files with 1,048 additions and 28 deletions.
5 changes: 5 additions & 0 deletions .changeset/heavy-apes-collect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
swc_ecma_transforms_module: major
---

Feat out file extension resolution
49 changes: 34 additions & 15 deletions crates/swc/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ use swc_ecma_transforms::{
self,
path::{ImportResolver, NodeImportResolver, Resolver},
rewriter::import_rewriter,
EsModuleConfig,
util, EsModuleConfig,
},
optimization::{const_modules, json_parse, simplifier},
proposals::{
Expand Down Expand Up @@ -1400,22 +1400,39 @@ impl ModuleConfig {

let base_url = base_url.to_path_buf();
let resolver = match config {
None => build_resolver(base_url, paths, false),
None => build_resolver(base_url, paths, false, &util::Config::default_js_ext()),
Some(ModuleConfig::Es6(config)) | Some(ModuleConfig::NodeNext(config)) => {
build_resolver(base_url, paths, config.resolve_fully)
}
Some(ModuleConfig::CommonJs(config)) => {
build_resolver(base_url, paths, config.resolve_fully)
}
Some(ModuleConfig::Umd(config)) => {
build_resolver(base_url, paths, config.config.resolve_fully)
}
Some(ModuleConfig::Amd(config)) => {
build_resolver(base_url, paths, config.config.resolve_fully)
}
Some(ModuleConfig::SystemJs(config)) => {
build_resolver(base_url, paths, config.resolve_fully)
build_resolver(
base_url,
paths,
config.config.resolve_fully,
&config.config.out_file_extension,
)
}
Some(ModuleConfig::CommonJs(config)) => build_resolver(
base_url,
paths,
config.resolve_fully,
&config.out_file_extension,
),
Some(ModuleConfig::Umd(config)) => build_resolver(
base_url,
paths,
config.config.resolve_fully,
&config.config.out_file_extension,
),
Some(ModuleConfig::Amd(config)) => build_resolver(
base_url,
paths,
config.config.resolve_fully,
&config.config.out_file_extension,
),
Some(ModuleConfig::SystemJs(config)) => build_resolver(
base_url,
paths,
config.config.resolve_fully,
&config.config.out_file_extension,
),
};

Some((base, resolver))
Expand Down Expand Up @@ -1733,6 +1750,7 @@ fn build_resolver(
mut base_url: PathBuf,
paths: CompiledPaths,
resolve_fully: bool,
file_extension: &str,
) -> SwcImportResolver {
static CACHE: Lazy<DashMap<(PathBuf, CompiledPaths, bool), SwcImportResolver, ARandomState>> =
Lazy::new(Default::default);
Expand Down Expand Up @@ -1772,6 +1790,7 @@ fn build_resolver(
swc_ecma_transforms::modules::path::Config {
base_dir: Some(base_url.clone()),
resolve_fully,
file_extension: file_extension.to_owned(),
},
);
Arc::new(r)
Expand Down
21 changes: 21 additions & 0 deletions crates/swc/tests/fixture/issues-3xxx/3067/amd/input/.swcrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"jsc": {
"parser": {
"syntax": "typescript",
"dynamicImport": true,
},
"target": "es2020",
"baseUrl": ".",
"paths": {
"@print/c": ["./packages/c/src/index.js"],
},
"externalHelpers": true,
},
"module": {
"type": "amd",
"resolveFully": true,
// This should say "resolve this fully to .mjs".
// Normally should be paired with --out-file-extension in the cli
"outFileExtension": "mjs",
},
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Simulate accessing a .js file in a third party package that shouldn't be edited
import something from 'lodash/dist/something.js'
export function displayC(): string {
something()
return 'Display C'
}
14 changes: 14 additions & 0 deletions crates/swc/tests/fixture/issues-3xxx/3067/amd/input/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

import { displayB } from './inner/b'
import { displayC } from '@print/c'
import { merge } from 'lodash'

async function display() {
const displayA = await import('./inner/a').then(c => c.displayA)
console.log(displayA())
console.log(displayB())
console.log(displayC())
const foo = merge({}, { a: 22 })
}

display()
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function displayA() {
return 'Display A'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function displayB() {
return 'Display B'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Simulate accessing a .js file in a third party package that shouldn't be edited
define([
"require",
"exports",
"@swc/helpers/_/_interop_require_default",
"lodash/dist/something.js"
], function(require, exports, _interop_require_default, _something) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "displayC", {
enumerable: true,
get: function() {
return displayC;
}
});
_something = /*#__PURE__*/ _interop_require_default._(_something);
function displayC() {
(0, _something.default)();
return 'Display C';
}
});
25 changes: 25 additions & 0 deletions crates/swc/tests/fixture/issues-3xxx/3067/amd/output/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
define([
"require",
"exports",
"@swc/helpers/_/_interop_require_wildcard",
"./inner/b/index.mjs",
"../packages/c/src/index.mjs",
"lodash"
], function(require, exports, _interop_require_wildcard, _b, _c, _lodash) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
async function display() {
const displayA = await new Promise((resolve, reject)=>require([
"./inner/a/index.mjs"
], (m)=>resolve(/*#__PURE__*/ _interop_require_wildcard._(m)), reject)).then((c)=>c.displayA);
console.log(displayA());
console.log((0, _b.displayB)());
console.log((0, _c.displayC)());
const foo = (0, _lodash.merge)({}, {
a: 22
});
}
display();
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
define([
"require",
"exports"
], function(require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "displayA", {
enumerable: true,
get: function() {
return displayA;
}
});
function displayA() {
return 'Display A';
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
define([
"require",
"exports"
], function(require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "displayB", {
enumerable: true,
get: function() {
return displayB;
}
});
function displayB() {
return 'Display B';
}
});
21 changes: 21 additions & 0 deletions crates/swc/tests/fixture/issues-3xxx/3067/commonjs/input/.swcrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"jsc": {
"parser": {
"syntax": "typescript",
"dynamicImport": true,
},
"target": "es2020",
"baseUrl": ".",
"paths": {
"@print/c": ["./packages/c/src/index.js"],
},
"externalHelpers": true,
},
"module": {
"type": "commonjs",
"resolveFully": true,
// This should say "resolve this fully to .mjs".
// Normally should be paired with --out-file-extension in the cli
"outFileExtension": "mjs",
},
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Simulate accessing a .js file in a third party package that shouldn't be edited
import something from 'lodash/dist/something.js'
export function displayC(): string {
something()
return 'Display C'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

import { displayB } from './inner/b'
import { displayC } from '@print/c'
import { merge } from 'lodash'

async function display() {
const displayA = await import('./inner/a').then(c => c.displayA)
console.log(displayA())
console.log(displayB())
console.log(displayC())
const foo = merge({}, { a: 22 })
}

display()
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function displayA() {
return 'Display A'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function displayB() {
return 'Display B'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Simulate accessing a .js file in a third party package that shouldn't be edited
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "displayC", {
enumerable: true,
get: function() {
return displayC;
}
});
const _interop_require_default = require("@swc/helpers/_/_interop_require_default");
const _something = /*#__PURE__*/ _interop_require_default._(require("lodash/dist/something.js"));
function displayC() {
(0, _something.default)();
return 'Display C';
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
const _b = require("./inner/b/index.mjs");
const _c = require("../packages/c/src/index.mjs");
const _lodash = require("lodash");
async function display() {
const displayA = await Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard._(require("./inner/a/index.mjs"))).then((c)=>c.displayA);
console.log(displayA());
console.log((0, _b.displayB)());
console.log((0, _c.displayC)());
const foo = (0, _lodash.merge)({}, {
a: 22
});
}
display();
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "displayA", {
enumerable: true,
get: function() {
return displayA;
}
});
function displayA() {
return 'Display A';
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "displayB", {
enumerable: true,
get: function() {
return displayB;
}
});
function displayB() {
return 'Display B';
}
21 changes: 21 additions & 0 deletions crates/swc/tests/fixture/issues-3xxx/3067/es6/input/.swcrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"jsc": {
"parser": {
"syntax": "typescript",
"dynamicImport": true,
},
"target": "es2020",
"baseUrl": ".",
"paths": {
"@print/c": ["./packages/c/src/index.js"],
},
"externalHelpers": true,
},
"module": {
"type": "es6",
"resolveFully": true,
// This should say "resolve this fully to .mjs".
// Normally should be paired with --out-file-extension in the cli
"outFileExtension": "mjs",
},
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Simulate accessing a .js file in a third party package that shouldn't be edited
import something from 'lodash/dist/something.js'
export function displayC(): string {
something()
return 'Display C'
}
14 changes: 14 additions & 0 deletions crates/swc/tests/fixture/issues-3xxx/3067/es6/input/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

import { displayB } from './inner/b'
import { displayC } from '@print/c'
import { merge } from 'lodash'

async function display() {
const displayA = await import('./inner/a').then(c => c.displayA)
console.log(displayA())
console.log(displayB())
console.log(displayC())
const foo = merge({}, { a: 22 })
}

display()
Loading

0 comments on commit e04c7b3

Please sign in to comment.