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

Switch from faux-ESM to real ESM exports #548

Open
6 of 7 tasks
karlhorky opened this issue Aug 16, 2022 · 15 comments
Open
6 of 7 tasks

Switch from faux-ESM to real ESM exports #548

karlhorky opened this issue Aug 16, 2022 · 15 comments

Comments

@karlhorky
Copy link

karlhorky commented Aug 16, 2022

Supersedes #512

Reporting an issue

Thank you for taking an interest in rrule! Please include the following in
your report:

  • Verify that you've looked through existing issues for duplicates before
    creating a new one
  • Code sample reproducing the issue. Be sure to include all input values you
    are using such as the exact RRule string and dates.
  • Expected output
  • Actual output
  • The version of rrule you are using 2.7.0
  • Your operating system macOS Monterey 12.4
  • Your local timezone (run $ date from the command line
    of the machine showing the bug)

The "module" field in package.json is non-official, and not a real ESM specification of npm: https://stackoverflow.com/a/42817320/1268612

Switching away from "module" to use the "exports" and "type": "module" fields in the package.json would allow for better compatibility with ESM, everywhere it is used.

You may even consider making it a pure ESM package, as mentioned here: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c

Expected output (see "type" and "exports" fields):

$ cat node_modules/rrule/package.json
{
  "name": "rrule",
  "version": "2.7.0",
  ...
  "main": "dist/es5/rrule.js",
  "type": "module",
  "exports": "./dist/esm/src/index.js",
  "types": "dist/esm/src/index.d.ts",
  ...
}

Actual output (see the outdated faux-ESM "module" field):

$ cat node_modules/rrule/package.json
{
  "name": "rrule",
  "version": "2.7.0",
  ...
  "main": "dist/es5/rrule.js",
  "module": "dist/esm/src/index.js",
  "types": "dist/esm/src/index.d.ts",
  ...
}

Does version 2.7.1 fix this? Short answer: No.

Longer answer (from #512 (comment) ):

@davidgoli thanks for the new 2.7.1 version!

However, it does not resolve the issue - rrule is still not published as ESM.

Importing and using rrule in the following file (import copied from the rrule readme) leads to an error.

index.mjs

import { RRule } from 'rrule';

console.log(RRule);

The error is this below:

$ node index.mjs
file:///Users/k/p/ical-move-events/index.mjs:1
import { RRule } from 'rrule';
         ^^^^^
SyntaxError: Named export 'RRule' not found. The requested module 'rrule' 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 'rrule';
const { RRule } = pkg;

    at ModuleJob._instantiate (node:internal/modules/esm/module_job:124:21)
    at async ModuleJob.run (node:internal/modules/esm/module_job:179:5)
    at async Loader.import (node:internal/modules/esm/loader:178:24)
    at async Object.loadESM (node:internal/process/esm_loader:68:5)
    at async handleMainPromise (node:internal/modules/run_main:63:12)

Luckily there is a workaround and it is printed out in the error message, but a lot of users will probably not notice it or not understand:

import pkg from 'rrule';
const { RRule } = pkg;

console.log(RRule);

Demo (on Replit)

https://replit.com/@karlhorky/MotionlessUsedLoop#index.mjs

file:///home/runner/MotionlessUsedLoop/index.mjs:1
import { RRule } from 'rrule';
         ^^^^^
SyntaxError: Named export 'RRule' not found. The requested module 'rrule' 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 'rrule';
const { RRule } = pkg;

    at ModuleJob._instantiate (node:internal/modules/esm/module_job:128:21)
    at async ModuleJob.run (node:internal/modules/esm/module_job:194:5)
    at async Promise.all (index 0)
    at async ESMLoader.import (node:internal/modules/esm/loader:385:24)
repl process died unexpectedly: exit status 1

Screen Shot 2022-10-19 at 09 58 52

@ryantan
Copy link

ryantan commented Oct 18, 2022

Is this closed now? I can do import { RRule } from 'rrule'; with no issues

@karlhorky
Copy link
Author

karlhorky commented Oct 19, 2022

@ryantan are you using ES Modules with Node.js? Eg. with "type": "module" or an *.mjs file, no other transpilers / compilers like TypeScript or Babel?

If not (eg. if you're using TypeScript), then probably internally it is translating it to a version that works with your Node.js version.

I have added this Replit to the original post to demonstrate the problem:

https://replit.com/@karlhorky/MotionlessUsedLoop#index.mjs

file:///home/runner/MotionlessUsedLoop/index.mjs:1
import { RRule } from 'rrule';
         ^^^^^
SyntaxError: Named export 'RRule' not found. The requested module 'rrule' 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 'rrule';
const { RRule } = pkg;

    at ModuleJob._instantiate (node:internal/modules/esm/module_job:128:21)
    at async ModuleJob.run (node:internal/modules/esm/module_job:194:5)
    at async Promise.all (index 0)
    at async ESMLoader.import (node:internal/modules/esm/loader:385:24)

Screen Shot 2022-10-19 at 09 58 52

@eytanProxi
Copy link

Any news ?

@splurgebudget
Copy link

Same - still getting this with 2.7.2

@caioamaral
Copy link

I'm stuck here too

@karlhorky
Copy link
Author

karlhorky commented Apr 5, 2023

Workaround

Until this issue is properly resolved, here are some things that you may want to try:

My solution is working for my project, which is using tsc, tsx and vite:

import pkg from 'rrule';
const { RRule } = pkg;

If you're getting an error about the default export, another thing to try is the import * as pkg ... syntax:

import * as pkg from 'rrule';
const { RRule } = pkg;

@splurgebudget
Copy link

splurgebudget commented Apr 7, 2023

@karlhorky 's workaround didn't work for me. I was trying to reuse the same code in both Node and on the frontend (browser)... and either of the options would fail on one or the other.

Ultimately, I fixed it using dynamic import like so:

let rrule = await import("rrule");
let RRule = rrule.RRule;
if (!RRule) RRule = rrule.default.RRule;

@karlhorky
Copy link
Author

Maybe your project is still CommonJS? You could try switching to ESM (ECMAScript Modules) by adding "type": "module" to your package.json (additional configuration may be needed).

@codingedgar
Copy link

codingedgar commented Jul 25, 2023

My workarround for working with Vite on the browser and node 20 / testing was:

import * as pkg from 'rrule';
const { RRule } =  pkg.default || pkg;

In case anyone needs help.

@mognutecnologia
Copy link

I had the same scenario as @splurgebudget , where I am sharing code between frontend and backend through Npm Workspaces Monorepo.
Solved it as @codingedgar , but tweaking a bit to pass through Typescript compilation, in case it helps somebody:

import * as pkg from "rrule";
const tsIgnorePkg = pkg as any;
const { RRule } = tsIgnorePkg.default || tsIgnorePkg;

@septatrix
Copy link

septatrix commented Sep 21, 2023

For me the workarounds do not work with Nuxt.js and I either get the above error about not being able to import rrule without it or the tslib module not being found when trying the workaround (though it would even be installed - not sure however why it would need it) :/

PS: I had rrule imported in several files split across my codebase (and third party packages) so my only option was to use the build.transpile option of nuxt. However, I also needed to add tslib to the list of packages which have to be transpiled for everything to function properly. That seems to have fixed it for me.

@michaelhays
Copy link

Any chance we can get this implemented? The faux-ESM of this package has caused me quite a few headaches over the past year.

I'm happy to create a PR if I could have some assurance that this is a priority.

@JohnRPB
Copy link

JohnRPB commented Apr 20, 2024

I also have issues with ESM on the one hand, or webpack bundling on the other, and the fix that works for me is re-exporting from a wrapper file like this:

import * as rrule from 'rrule';

const getDefault = pkg => pkg.default; 

export const RRule = rrule.RRule || getDefault(rrule)?.RRule;

By using a closure, we avoid webpack's "no default export" error.

@septatrix
Copy link

Even though I am generally not a huge fan of forking unless the maintainer has officially abandoned/archived a project it might be time to do this here. The last commit is 6 months old, the last release was 2 years ago, and there are a bunch of unresolved PRs.

I would be happy if @jkbrzt could give a statement on whether or not he would still like to maintain and keep this project alive? Maybe also @davidgoli who seems to have contributed a decent amount.

@davidgoli
Copy link
Collaborator

I don't have time to maintain this project any more, and I don't have a professional use for it at the moment either. I would be happy to hand the reins to someone who is more committed than I am.

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