homer0 / cjs2esm

Transforms a project that uses CommonJS to ES Modules.

Home Page:https://homer0.github.io/cjs2esm

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Named Export Generation Fails on NodeJS Project

tubbo opened this issue · comments

I'm converting a NodeJS project from CJS to ESM, and pretty much everything works with this CLI which is lovely in comparison to figuring out how jscodeshift and 5to6-codemod works! Our actual goal is to migrate everything to TypeScript, but in order to get import statements working properly, I need to do some conversions into ESM before running ts-migrate to mitigate errors and warnings.

Most of the codemods work, but named-export-generation always fails for me. This occurs when I run it using this CLI, but also when I run the codemods directly with jscodeshift and a locally installed version of 5to6-codemod. I'm running the same versions as this project specifies in package.json.

Before:

const { GCLOUD_IMAGE_STORAGE_BUCKET_NAME } = process.env
const { DateTime } = require('luxon')
const { logger } = require('../../../../logger')
const { imageStorage } = require('./client')

const getSignedUploadUrl = async (filename, mimeType) => {
  // ...
}

module.exports = {
  getSignedUploadUrl,
}

After:

const { GCLOUD_IMAGE_STORAGE_BUCKET_NAME } = process.env
import { DateTime } from 'luxon';
import { logger } from '../../../../logger';
import { imageStorage } from './client.js';

const getSignedUploadUrl = async (filename, mimeType) => {
  // ...
}

export default {
  getSignedUploadUrl,
};

What I want here is for getSignedUploadUrl() to become a named export (export const), and for the default export to be deleted, because that's how my project typically imports functions like this. When you use Node with ESM, though, it doesn't recognize this older style of exporting, so I get errors all over the place unless manually go through and change named imports and exports myself, which kinda defeats the purpose of a codemod.

Not sure if this is the right place to put this, because I know the issue still exists in 5to6-codemod, but it didn't seem like that project was still getting any updates...

@tubbo 👋 So sorry that this is 3 months late... I'll never figure out GitHub notifications for new issues 😭

The reason you are getting that result is because you are overwriting the exports, which is totally valid in commonjs, and something I used to do before trying to use TypeScript with JSDoc :P.

When you overwrite the module.exports/exports, you are creating something like a "commonjs export default"; if you want named exports, you need to "add" your exports to the exports object:

module.exports.getSIgnedUploadUrl = getSIgnedUploadUrl;
// or
exports.getSIgnedUploadUrl = getSIgnedUploadUrl;

Here's an example of that in this same project.

Btw, the thing I mentioned regarding JSDoc, is that, when you want to import a type from a JS file that uses commonjs, if you overwrite the exports, you need to do something like this:

/**
 * @typedef {import('./file')['Something']} Something
 */

And sometimes it could break JSDoc; while, if you "add" to the exports object, you could use dot notation:

/**
 * @typedef {import('./file').Something} Something
 */

Again, sorry it took me so long to respond, I hope it wasn't a blocker for your migration, or that you found a workaround.