beenotung / fix-esm-import-path

Auto fix import path for esm compatibility
https://www.npmjs.com/package/fix-esm-import-path
BSD 2-Clause "Simplified" License
50 stars 7 forks source link

Add extensions to third-party imports without export maps #2

Open ysulyma opened 2 years ago

ysulyma commented 2 years ago

This module has solved a lot of my headaches, but there are still some edge cases. To work with ESM, the code

import {useContextBridge} from "@react-three/drei/core/useContextBridge";

needs to be rewritten to

import {useContextBridge} from "@react-three/drei/core/useContextBridge.js";

which this module currently doesn't do. (Note that @react-three/drei doesn't use the exports field.) I don't want to put the .js in my .ts source since the CJS version should (probably?) import @react-three/drei/core/useContextBridge.cjs.js.

beenotung commented 1 year ago

It seems you need to support both commonjs and esm.

I also encountered similar case, my workaround is the modify the source using custom script when running/building for different env... For example: https://github.com/beenotung/ts-liveview/blob/v5.6.0/scripts/dev.ts#L126-L135

(My case is the server is running in esm, but database migration tool (knex) need to run in commonjs, and they have shared import)

beenotung commented 11 months ago

I just try to import the useContextBridge.js file with .js extension, it seems simply adding .js extension is not enough.

The error message when running the file:

import { useContextBridge } from '@react-three/drei/core/useContextBridge.js'
         ^^^^^^^^^^^^^^^^
SyntaxError: Named export 'useContextBridge' not found. The requested module '@react-three/drei/core/useContextBridge.js' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:

import pkg from '@react-three/drei/core/useContextBridge.js';
const { useContextBridge } = pkg;
beenotung commented 11 months ago

I figured out a way to fix your case.

First we import it as below:

import * as pkg from '@react-three/drei/core/useContextBridge.js'
const { useContextBridge } = pkg

Then we modify the package.json of @react-three/drei to set "type": "module".

Step 2 is required because the useContextBridge.js is importing react with esm import statement as below, instead of with require():

import * as React from 'react';

The package @react-three/drei appear to be a commonjs package but it is using esm syntax.

We cannot blindly change all imported third-party packages from commonjs into esm packages because they maybe using require() which is not available to esm packages.

If we want to address this problem from fix-esm-import-path we may use an explicit package name list but that seems out of the scope of this package.

In this case, if we cannot fix the problem on @react-three/drei directly (e.g. if they don't agree to change to esm or they don't want to publish the package using commonjs format with require() instead of import/export), we can solve this problem by either: