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

Update meow dependency #41

Merged
merged 25 commits into from
Dec 18, 2021
Merged

Update meow dependency #41

merged 25 commits into from
Dec 18, 2021

Conversation

ericcornelissen
Copy link
Contributor

No description provided.

Update the source code from CommonJS to ES modules style. This consists
of changing `require`s to `import from` statements, `module.exports` to
`export` statements, and in some cases the structure of imports and
exports as well. Notably when the old `require` statement also contained
some additional logic, which is not possible with import statements.
Update the meow dependency to ^10.1.1 - which is the latest version -
and update how it is used in accordance with breaking changes.
The migration to ES modules makes it more complicated to import config
files. Most notably, config files can no longer just be `require`d. So,
to read and parse config files, and to support ES modules and CommonJS
config files, cosmiconfig was added to load config files.
@ericcornelissen ericcornelissen added the dependencies Pull requests that update a dependency file label Nov 2, 2021
Update the source to remove remaining `module.exports` reference (in
parse.js). Update the source to be able to load rules as ESM using
`await import(...)` (in rule-loader.js), update dependent code
accordingly to await that import (see svglint.js).

Two tests are now marked as skipped, initial investigation suggests the
emitting of the "done" event at linting.js:79 doesn't work well in
combination with async/await.
package.json Outdated Show resolved Hide resolved
@LitoMore

This comment has been minimized.

Update ESLint to the latest major version for easier support of a config
file with an `.cjs` extension as well as better support for ESM. Fix
all the linting warnings/errors.
@ericcornelissen
Copy link
Contributor Author

ericcornelissen commented Dec 3, 2021

The current status of this Pull Request:

  • Refactored the source code from CommonJS to ESModules.
  • Updated Meow to a recent version.
  • The CLI is unchanged except for the fact that it now has a higher minimum NodeJS version requirement due to the source code being ESM.
  • The JavaScript API has changed from sync to async due to this change. In short, dynamically importing ESM appears to require async. Hence, to support ESM plugins it appears async is required.
  • Since the previous points already require a major version bump, I did not yet bother to look into providing a CommonJS version of either the CLI or JS API. Especially considering the fact that a transpiled CommonJS version of SVGLint would not be able to use ESM plugins, so from that viewpoint I'm also not sure if we even want to provide that option. EDIT: see this comment for an update.
  • It addresses Consider replacing meow dependency #34, Support ES Module configuration files #36, and likely Boolean options are parsed as arguments in CLI #44.

This means that a major version bump would be required to release this - for the NodeJS version requirement and the lack of CJS support and the JS API change.

@birjolaxew do you have any opinion on this? At the moment my opinion is leaning towards this solution - a mostly ESM-only solution with backwards compatibility support for CJS - because 1) it's simpler to implement and 2) it avoids any confusion due to someone trying to import an ESM config/plugin from the transpiled version of SVGLint.

If you disagree, there seem to be libraries to de-async functions which could help address the JS API changes and I can still try to look into transpiling to CJS.

Also, a correction to what I said before: not all v12 release of NodeJS support ESM, I believe (based on this) the first version with proper support is v12.20.0 (the latest v12, as of this comment, is v12.22.7).

Change from the approach in 033d7db
and replace the try-catch technique of importing by just using
`await import`. From some local testing it seems only that one is ever
used, making the catch branch effectively dead code.

Additionally, this fixes a bug introduced in
1e4eb07 where CJS config files were
imported but ignored since CJS is always `import`ed on the default
property.
@ericcornelissen ericcornelissen marked this pull request as ready for review December 3, 2021 20:43
@LitoMore
Copy link
Member

LitoMore commented Dec 3, 2021

The first version with proper support of ESM is v12.17.0. But meow and most of Sindre's packages are using node: protocol for imports, which is requiring v12.20.0.

Here is the discussion: sindresorhus/meta#15 (comment).

As 12.17 is the minimum required version for ESM support. 12.20 is the
minimum required version if you want to use the `node:` protocol [1],
which this project doesn't at the moment.

--
1. https://nodejs.org/api/esm.html#node-imports
package.json Outdated Show resolved Hide resolved
.github/workflows/test.yml Outdated Show resolved Hide resolved
@ericcornelissen
Copy link
Contributor Author

I unfortunately don't know enough about CJS/ESM support to really weigh in on this (nor the time to read up on it). Although breaking changes (especially when it comes to dropping support for Node versions) are frustrating, I trust that the pros outweighs the cons if that's the general opinion. I'd be happy with this solution.

No problem and thanks for the reply nonetheless, I was mainly interested in if you're okay with the major version change for this reason. I'll be doing some further testing to decrease the chances of any breaking changes affecting users that are using a compatible NodeJS version

Not sure if the rules should be named exports, but there are a few other places too.

Thanks for the feedback @sachinraja - I agree some of these are better as named exports, however my aim with this PR is to be a straightforward translation from CJS to ESM (+necessary changes to keep things working AND updating meow). Since CJS module.exports are equivalent to ESM default exports I stuck with that. Given there's already 4 things in the scope of this Pull Request I intend to exclude the refactoring w.r.t. export/import styles.

@sachinraja
Copy link

Given there's already 4 things in the scope of this Pull Request I intend to exclude the refactoring w.r.t. export/import styles.

This looks good to me then 👍

Use the `"file://"` prefix when loading CLI config and rules to ensure
importing always works on Windows.
Add a CommonJS version of the Node API of SVGLint by building it using
Rollup [1]. Update the package manifest to allow for importing/requiring
ESM and CJS (resp.) and `.gitignore` to ignore the generated CJS file.

One "custom" Rollup plugin (provided by Rollup but not included by
default) is used, namely `plugin-dynamic-import-vars` [2]. This plugin
ensures that dynamic imports are properly handled as the CJS output
generated by Rollup cannot dynamically import ESM rules. To make this
work the rule-loader had to be updated as well, unfortunately the
requirements of this plugin are quite strict and it is required that the
`"../rules"` path is hardcoded into the `import` statement. Furthermore
it has trouble detecting things that should be ignored, so errors are
disabled to prevent errors due to dynamic imports of external plugins.

--
1. https://rollupjs.org/guide/en/
2. https://www.npmjs.com/package/@rollup/plugin-dynamic-import-vars
@ericcornelissen
Copy link
Contributor Author

ericcornelissen commented Dec 14, 2021

I ended up trying to provide a CJS version of the API and I think I succeeded with f3e91a1. As a result this would now only be a breaking changes w.r.t.:

  • The minimum NodeJS version required to use the CLI.
  • The API, which went from sync to async.

On the positive side, this would remove the need to migrate for API users. On the negative side, going full ESM in the future will require an additional major version bump (whether that's because we want to or because a not-CLI-only dependency goes ESM only).

I'm personally of the opinion that we should go with the CJS support for now so that migrating is as easy as possible now and that the additional major version bump in the future isn't a huge deal. Does anyone in this thread have a different opinion?

Additionally, I would appreciate if anyone who has time could try these changes out locally (just copy this repo into node_modules) and report back any problems or successes + your Node version and Operating System. 🙂

@sachinraja
Copy link

sachinraja commented Dec 15, 2021

Just cloned locally and ran node bin/cli.js icon.svg and it worked for node 16, latest node 14 (14.18.2), and latest node 12. But I did get this error with node 14.0.0 <= 14.8.0 < 14.13.1:

internal/process/esm_loader.js:74
    internalBinding('errors').triggerUncaughtException(
                              ^

Error [ERR_UNSUPPORTED_ESM_URL_SCHEME]: Only file and data URLs are supported by the default ESM loader
    at Loader.defaultResolve [as _resolve] (internal/modules/esm/resolve.js:781:11)
    at Loader.resolve (internal/modules/esm/loader.js:85:40)
    at Loader.getModuleJob (internal/modules/esm/loader.js:229:28)
    at ModuleWrap.<anonymous> (internal/modules/esm/module_job.js:51:40)
    at link (internal/modules/esm/module_job.js:50:36) {
  code: 'ERR_UNSUPPORTED_ESM_URL_SCHEME'
}

@LitoMore
Copy link
Member

LitoMore commented Dec 15, 2021

@sachinraja You should not use node bin/cli.js to run the bin file. Please use these commands below to test:

npm link
svglint icon.svg

# Once you want to unlink
npm un -g svglint

Or just run ./bin/cli.js icons.svg directly.

@LitoMore
Copy link
Member

LitoMore commented Dec 15, 2021

@ericcornelissen You could refer to this test if you want to test ESM behaviors.

Also we can use execa to test our bin-script. The code will be:

// test/cli.spec.js
import execa from 'execa';

const {stdout} = async execa('../bin/cli.js', ['--help']);
expect(stdout).toBe(helpText);

Copy link
Member

@LitoMore LitoMore left a comment

Choose a reason for hiding this comment

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

Looks good to me. It would be better if the test can be improved.

@sachinraja
Copy link

sachinraja commented Dec 15, 2021

Or just run ./bin/cli.js icons.svg directly.

It shouldn't matter whether I run it with node or directly (that's all the shebang at the top of the file is doing anyway) but I get the same error with that. I also get it when I link the package.

@LitoMore
Copy link
Member

LitoMore commented Dec 15, 2021

It shouldn't matter whether I run it with node or directly.

Oh yes, you are right. I just missed some of your comments. I think you are using an unsupported Node.js version. Please refer to the engines field in package.json, we have already specified them in there. Users with an unsupported version will get a warning or error when they try to install our package.

FYI: https://docs.npmjs.com/cli/v8/configuring-npm/package-json#engines

For more ESM knowledge you can refer to https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c.

@sachinraja
Copy link

Please refer to the engines field in package.json, we have already specified them in there. Users with an unsupported version will get a warning or error when they try to install our package.

Ah you're right, didn't notice that change. npm doesn't seem to show the error when I just run npm install in the repo, but it does work when I try to install it into another project.

@ericcornelissen
Copy link
Contributor Author

Thanks so much for all the help @LitoMore and @sachinraja! 😄

Looks good to me. It would be better if the test can be improved.

I agree they can be improved in the way you suggested, but, once again, I'd like to keep that for a later PR. For now I just want to be sure that running the CLI under normal circumstances on all major OSes and with all supported NodeJS versions works - i.e. doesn't error - I don't care so much about the actual output yet. It's currently just a smoke test.

Also, just to be explicit about it, running with the --help or --version flag would not be a sufficient test as the CLI exists early with those flags. So, while it would be good to test that the CLI works with those flags, it's more important to run the CLI with (and without) a configuration file and SVGs to lint.

Ah you're right, didn't notice that change. npm doesn't seem to show the error when I just run npm install in the repo, but it does work when I try to install it into another project.

I added .npmrc in 047242b to prevent confusion like this in the future. Thanks for helping to figure out the problem @LitoMore 😃

@LitoMore
Copy link
Member

Also, just to be explicit about it, running with the --help or --version flag would not be a sufficient test as the CLI exists early with those flags.

I just give a simple demo to show how to use execa. 😄

@ericcornelissen ericcornelissen merged commit 2d242fe into simple-icons:master Dec 18, 2021
@ericcornelissen ericcornelissen deleted the update-meow branch December 18, 2021 22:07
@ericcornelissen
Copy link
Contributor Author

ericcornelissen commented Dec 18, 2021

Thanks once again @LitoMore and @sachinraja for feedback and testing 😃

@github-actions
Copy link

🎉 This PR is included in version 2.0.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
dependencies Pull requests that update a dependency file released
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants