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 CJS to ESM #859

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

tjlahr
Copy link

@tjlahr tjlahr commented Mar 20, 2025

WIP / HOLD MERGE

  • tabtab autocompletion relies on module.parent and doesn't work with ESM
  • personally, I had difficulties getting tabtab to work even on main (generators showing up as "[object Object]" for example)
  • I'm skipping the broken tabtab test for now, while the rest of the change is under review.
  • Would love any suggestions on how to solve for old tabtab.

This PR migrates Yo to ECMAScript modules (ESM).

Most of the lines changed are related to the import/export syntax itself.

However, a few libraries and techniques had to be updated in order to work around older and non-ESM issue. I've listed those changes below.

Purpose of this pull request?

Switch from CJS to ESM in order to solve issue 787.

What changes did you make?

  • switch project to type=module
  • adopt import/export syntax throughout codebase
  • update meow (ESM support since v10)
  • remove global-tunnel-ng branch since we're > Node 10
  • replace proxyquire (no ESM) with testdouble
  • replace nyc (no ESM) with c8
  • shim __dirname
  • remove unused --no-update-notifier in CLI

Is there anything you'd like reviewers to focus on?

* switch project to type=module
* adopt import/export syntax throughout codebase
* update meow (ESM support since v10)
* remove global-tunnel-ng branch since we're > Node 10
* replace proxyquire (no ESM) with testdouble
* replace nyc (no ESM) with c8
* shim __dirname
* remove unused --no-update-notifier in CLI
* [WIP] disable failing tabtab test
Copy link

socket-security bot commented Mar 20, 2025

New, updated, and removed dependencies detected. Learn more about Socket for GitHub ↗︎

Package New capabilities Transitives Size Publisher
npm/[email protected] Transitive: environment, filesystem, shell +37 2.85 MB
npm/[email protected]13.2.0 None 0 419 kB sindresorhus
npm/[email protected] None +4 14.3 kB sindresorhus

🚮 Removed packages: npm/[email protected]

View full report↗︎

// `global-tunnel-ng` works only with Node.js v10 and below.
require('global-tunnel-ng').initialize();
}
bootstrap();
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can eliminate this branching because we're > Node 10.
Simply import and call bootstrap.

@@ -33,7 +28,7 @@ const tabtab = new Tabtab.Commands.default({
});

const cli = gens.map(gen => {
const minicli = meow({autoHelp: false, autoVersion: true, pkg, argv: gen});
const minicli = meow({autoHelp: false, autoVersion: true, pkg, argv: gen, importMeta: import.meta});
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small tweak to support the latest meow version.

router.registerRoute('install', routes.install);
router.registerRoute('exit', routes.exit);
router.registerRoute('clearConfig', routes.clearConfig);
router.registerRoute('home', routes.home);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I collected these into a routes object that can be imported at once.

@@ -53,7 +52,7 @@ module.exports = async app => {
}

return fullname().then(name => {
const allo = (name && isString(name)) ? `'Allo ${name.split(' ')[0]}! ` : '\'Allo! ';
const allo = (name && _.isString(name)) ? `'Allo ${name.split(' ')[0]}! ` : '\'Allo! ';
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will occasionally inline lodash if it's a one-off and the specific method was imported directly.

*/
export const getDirname = fileUrl => {
return path.dirname(fileURLToPath(fileUrl));
};
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

__dirname shim.

I did not write a corresponding test for this because __dirname is used all over the place anyway and failures here would show up as failures there. Also, it's tiny and the test would be 99% mock setup.

"test": "nyc mocha --timeout=30000",
"coverage": "nyc report --reporter=text-lcov | coveralls"
"test": "c8 mocha --timeout=30000",
"coverage": "c8 report --reporter=text-lcov | coveralls"
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"registry-url": "^5.1.0",
"sinon": "^19.0.2",
"testdouble": "^3.20.2",
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also considered sinon and rewiremock as alternatives here but this was the most seamless.

If this were my project, I'd switch to jest and use their module mocking.

});
});

it('should return the version', cb => {
const cp = execFile('node', [
path.resolve(__dirname, '..', pkg.bin.yo),
'--version',
'--no-update-notifier'
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't find any evidence that this is used anywhere.

@@ -31,7 +34,7 @@ describe('Completion', () => {
this.env = createEnv();
});

describe('Test completion STDOUT output', () => {
describe.skip('Test completion STDOUT output', () => {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WIP - see comment about tabtab relying on module.parent

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

Successfully merging this pull request may close these issues.

1 participant