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

Cannot import ESM modules when modifying require.extensions #4350

Open
devjiwonchoi opened this issue Feb 27, 2024 · 0 comments
Open

Cannot import ESM modules when modifying require.extensions #4350

devjiwonchoi opened this issue Feb 27, 2024 · 0 comments

Comments

@devjiwonchoi
Copy link

devjiwonchoi commented Feb 27, 2024

TL;DR

How to require (or import) Native ESM modules while using a require hook like require.extensions.

Note: I do know that require.extensions is deprecated and is not recommended to modify, but as ts-node does, I am using this as a part of a temporary workaround.

Goal

I want to dynamic import a configuration file, jiwon.config.ts, which should import other JS/TS extensions successfully.

Restrictions

I cannot use other dependencies like webpack or esbuild to bundle and resolve the imports.
The only option is to use SWC.

Work Flow

  1. importConfig()
  2. looks for jiwon.config.ts, exists
  3. REGISTER REQUIRE HOOK
  4. readFile() the config
  5. SWC transform the code
  6. writeFile() the config as .js
  7. dynamic import jiwon.config.js

REGISTER REQUIRE HOOK

Why? To not bundle and do fewer operations on resolving the config file. Especially utilizing the high performance of SWC.

import { transformSync, type Options } from '@swc/core'

const originalJsHandler = require.extensions['.js']
const transformableExtensions = ['.ts', '.cts', '.mts', '.cjs', '.mjs']
const swcOptions: Options = {
    jsc: {
      target: 'es5',
      parser: {
        syntax: 'typescript',
      },
    },
    module: {
      type: 'commonjs',
    },
    isModule: 'unknown',
  }

function registerSWCTransform(swcOptions: Options, isESM: boolean) {
  // if (isESM) {
  // TODO: handle ESM
  // }

  for (const ext of transformableExtensions) {
    require.extensions[ext] = function (m: any, originalFileName) {
      const _compile = m._compile

      m._compile = function (code: string, filename: string) {
        const swc = transformSync(code, swcOptions)
        return _compile.call(this, swc.code, filename)
      }

      return originalJsHandler(m, originalFileName)
    }
  }
}

Current Status

By doing so, I've achieved to cover 90% of the expected & edge cases of resolving the config file.
The only thing that I am struggling with is:

  1. On the Native ESM project (package.json type: module), import the .js (ESM) file.
  2. On the CJS project, import the Native ESM package(also, .js).

They both have in common that the format is ESM but the extension is .js.

As I tried to overwrite the require.extensions['.js'], threw an error during the process of importing other .js files.

Requesting for Help

If you...

  1. know how to resolve requiring Native ESM .js file with the current status
  2. can suggest other ways to achieve the current goal than to register the require hook

please share your expertise and insights, will be very grateful for your help.

Node.js version

{
  node: '18.17.0',
  acorn: '8.8.2',
  ada: '2.5.0',
  ares: '1.19.1',
  brotli: '1.0.9',
  cldr: '43.0',
  icu: '73.1',
  llhttp: '6.0.11',
  modules: '108',
  napi: '9',
  nghttp2: '1.52.0',
  nghttp3: '0.7.0',
  ngtcp2: '0.8.1',
  openssl: '3.0.9+quic',
  simdutf: '3.2.12',
  tz: '2023c',
  undici: '5.22.1',
  unicode: '15.0',
  uv: '1.44.2',
  uvwasi: '0.0.18',
  v8: '10.2.154.26-node.26',
  zlib: '1.2.13.1-motley'
}

Example code

See above.

Operating system

Darwin MacBook-Pro.local 23.1.0 Darwin Kernel Version 23.1.0: Mon Oct  9 21:32:11 PDT 2023; root:xnu-10002.41.9~7/RELEASE_ARM64_T6030 arm64

Scope

Custom compiling through modifying require.extensions.

Module and version

Not applicable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant