Skip to content
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

Emit createRequire for TypeScript import = to match module: nodenext #4101

Closed
cspotcode opened this issue Mar 20, 2022 · 6 comments
Closed
Milestone

Comments

@cspotcode
Copy link
Contributor

Describe the feature

TypeScript's new module: nodenext will emit const require = createRequire() as necessary in ESM modules that have import = syntax. Without calling createRequire(), the code fails, because require is not defined in ES modules on nodejs.

import commonjs = require('commonjs'); 
import * as ecmascriptmodule from 'ecmascriptmodule';

commonjs, ecmascriptmodule;

When compiled by SWC using target=es2022 and module=es modules, I get: (playground link)

const commonjs = require('commonjs');
import * as ecmascriptmodule from 'ecmascriptmodule';
commonjs, ecmascriptmodule;

However, TypeScript will include a call to createRequire: (playground link)

import { createRequire as _createRequire } from "module";
const __require = _createRequire(import.meta.url);
const commonjs = __require("commonjs");
import * as ecmascriptmodule from 'ecmascriptmodule';
commonjs, ecmascriptmodule;

Is there any way to tell SWC to emit this createRequire call?

Babel plugin or link to the feature description

No response

Additional context

No response

@kdy1 kdy1 added this to the Planned milestone Mar 20, 2022
@cspotcode
Copy link
Contributor Author

Related to #4679

I may have some time for this soon; can anyone point me in the right direction to implement this fix?

In ts-node I'm hoping to ship support for TS's new nodenext/node16 modes -- mts, mjs, cts, cjs. But this is a blocker since it means the swc backend can't emit correct mts.

@kdy1
Copy link
Member

kdy1 commented May 17, 2022

First, you will have to add a module like nodenext to https://github.com/swc-project/swc/tree/fe1e62a5e7a4a0037ba8d158879fb68bf9c14520/crates/swc_ecma_transforms_module/src or alternatively add nodenext: bool to common js pass (https://github.com/swc-project/swc/blob/9a027ba7c2146ac4dbfce9478d1a259ff491a11f/crates/swc_ecma_transforms_module/src/common_js.rs)

For the latter, you would need to wrap util::Config like

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields, rename_all = "camelCase")]
pub struct Config {
#[serde(default)]
pub module_id: Option<String>,
#[serde(flatten, default)]
pub config: util::Config,
}


After then, you can add an import with a specifier named createRequire, using private_ident! (like

let ident = ident.unwrap_or_else(|| private_ident!("_default"));
).
Once you have it, you can add imports to the module, and replace/wrap require calls with createRequire

@cspotcode
Copy link
Contributor Author

cspotcode commented May 29, 2022

I've hit a snag and need some guidance.

This createRequire transformation should only happen when module type = es6, not Commonjs. So I implemented an es6 transformation that checked for the presence of any TsImportEqualsDecl and, when found, created the necessary import of createRequire and const require = createRequire(import.meta.url);

The problem is, typescript stripping runs before the es6 transformation. This means TsImportEqualsDecl does not exist by the time es6 runs.

How should the typescript stripping pass tell the es6 pass that a TsImportEqualsDecl was stripped?

I thought about the typescript stripping doing the createRequire, but the problem is that for module=Commonjs, we should not do that.

@magic-akari
Copy link
Member

I believe this feature is already available in swc.

swc playground

@kdy1
Copy link
Member

kdy1 commented Jun 30, 2022

Thank you!

@kdy1 kdy1 closed this as completed Jun 30, 2022
@kdy1 kdy1 modified the milestones: Planned, v1.2.206 Jun 30, 2022
@swc-bot
Copy link
Collaborator

swc-bot commented Oct 16, 2022

This closed issue has been automatically locked because it had no new activity for a month. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

@swc-project swc-project locked as resolved and limited conversation to collaborators Oct 16, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Development

Successfully merging a pull request may close this issue.

4 participants