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
Add exports
field to package.json
#7307
Conversation
This commit is necessary for Conditional exports (ESM and CJS). See https://nodejs.org/api/packages.html#conditional-exports Note: For backward compatibility, we may need to export `stylelint/lib/utils/*` files. The following script can easily output many `lib/utils/` settings. ```js import path from 'node:path'; import fg from 'fast-glob'; const exports = { '.': { import: './lib/index.mjs', require: './lib/index.cjs', }, './package.json': './package.json', }; const files = fg.sync('lib/utils/isStandardSyntax*.mjs', { ignore: '**/__tests__/**' }); for (const file of files) { const base = path.basename(file, '.mjs'); exports[`./lib/utils/${base}`] = { import: `./lib/utils/${base}.mjs`, require: `./lib/utils/${base}.cjs`, }; } console.log(JSON.stringify(exports, null, 2)); ```
🦋 Changeset detectedLatest commit: 72d7750 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
stylelint/docs/developer-guide/plugins.md Line 220 in 25140c0
Could you also update this paragraph? |
Good point. We should clarify the policy for the internal utilities here. The current documentation says:
In my opinion, we should keep the policy that we should expose utilities at a minimum because it may cause frequent breaking changes. However, if we restricted importing the internals by the So, I suggest the following:
Any thoughts? |
I like it because it's not restrictive and |
Fixed to |
The following is a test of
{
"dependencies": {
"stylelint": "github:stylelint/stylelint#add-exports-field"
}
} Run: $ npm install
...
$ node -pe 'require("stylelint/lib/utils/typeGuards.cjs")'
{
hasSource: [Function: hasSource],
isAtRule: [Function: isAtRule],
isComment: [Function: isComment],
isDeclaration: [Function: isDeclaration],
isDocument: [Function: isDocument],
isRoot: [Function: isRoot],
isRule: [Function: isRule],
isValueFunction: [Function: isValueFunction]
}
$ node -e 'import("stylelint/lib/utils/typeGuards.mjs").then(console.log)'
[Module: null prototype] {
hasSource: [Function: hasSource],
isAtRule: [Function: isAtRule],
isComment: [Function: isComment],
isDeclaration: [Function: isDeclaration],
isDocument: [Function: isDocument],
isRoot: [Function: isRoot],
isRule: [Function: isRule],
isValueFunction: [Function: isValueFunction]
} |
type
/exports
fields to package.json
exports
field to package.json
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to hear feedback about exporting lib/** files. Should we export all files? I worry about frequent breaking changes in the future, if we exposed all modules (including internal ones).
In #6866 (comment), we settled on not exporting more utils (e.g. because people shifting to standard CSS makes the isStandardSyntax*
utils less relevant and so on).
Am I right in thinking that our move to ESM will break people's imports anyway, regardless of whether we export the utils as the extensions have changed:
- require("stylelint/lib/utils/typeGuards.js")'
+ require("stylelint/lib/utils/typeGuards.cjs")'
Rather than apply another bandaid, we could take this opportunity to make it clear in our migration guide that plugin authors need to copy any internal utils they want (like stylelint-scss does). This clarification is likely worth it as the ambiguity has been problematic in the past, e.g. with stylelint-stylistic.
This will also address #7307 (comment), where changing back to .js
would be another breaking change for those importing internal .mjs
utils.
@jeddy3 Thanks for the feedback. I also don't want to change the policy we settled on #6866 (comment). And yes, the following code would break in 16.0.0: require("stylelint/lib/utils/typeGuards.js") But, if we have require("stylelint/lib/utils/typeGuards") On the other hand, if we do NOT provide
I'm worried that this breaking might be too strict. So I suggest:
Any thoughts? |
I'd assumed most people were using the
Your suggestion SGTM. It'll stagger the amount of people affected over two major releases, with the most happening in 17.0.0.
Let's add something to the migration guide as part of this pull request for this. And let's also use the opportunity to steer people in the right direction. Something along the lines of: Changed extension of internal filesWe've changed the extension of our internal files from
We don't recommend it, but you can unsafely continue to - require("stylelint/lib/utils/typeGuards.js")'
+ require("stylelint/lib/utils/typeGuards.cjs")' - import isStandardSyntaxAtRule from 'stylelint/lib/utils/isStandardSyntaxAtRule.js';
+ import isStandardSyntaxAtRule from 'stylelint/lib/utils/isStandardSyntaxAtRule.mjs'; |
Feel free to modify the documents directly if necessary. I'm not so confident in my English wording. 😅 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Talking about the non-addition of type
, here's an example of where it would have been useful: if we were keeping the utils extension as .js
to avoid breaking changes. In this scenario it would have been "type": "commonjs"
though.
Like @jeddy3, I was assuming—wrongly?—that extension-less usage would be rare. If it's really not the case then reverting to .js
from .cjs
for this folder might not be necessary.
For your information, suppose we provide pure ESM in 17.0.0 (the next to 16.0.0).
Then, most codes depending on import("stylelint"); //=> ✅ Not broken
import("stylelint/lib/utils/typeGuards.mjs"); //=> ❌ Broken due to invalid `.mjs`
import("stylelint/lib/utils/typeGuards"); //=> ❌ Broken due to no `exports`
require("stylelint"); //=> ❌ Broken due to ERR_REQUIRE_ESM |
I don't think that's necessary. Once we have |
Ah, my bad. You're correct. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thank you!
Closes #6258
Ref #5291
This Pull Request is necessary for Conditional exports (ESM and CJS).
Note: For backward compatibility, we may need to export
stylelint/lib/utils/*
files.The following script can easily output many
lib/utils/
settings.Script
I'd like to hear feedback about exporting
lib/**
files. Should we export all files? I worry about frequent breaking changes in the future, if we exposed all modules (including internal ones).Ideally, we should export utilities only through
stylelint.utils
, but actually we don't. Especially,isStandardSyntax*
utilities are necessary to write a plugin or a custom rule.