Skip to content

feat: Add support for config files in CommonJS format#1367

Open
tylerbutler wants to merge 9 commits intochangesets:mainfrom
tylerbutler:feat/config-formats
Open

feat: Add support for config files in CommonJS format#1367
tylerbutler wants to merge 9 commits intochangesets:mainfrom
tylerbutler:feat/config-formats

Conversation

@tylerbutler
Copy link
Copy Markdown

@tylerbutler tylerbutler commented May 28, 2024

Fixes #1125.

The changesets configuration file can now be in CommonJS (config.cjs) format in addition to JSON. Despite being code, the expected format/type of the CJS config object is the same as the JSON format (that is, a WrittenConfig object).

To limit potential back-compat issues, the .changeset/config.json path is checked first, and if that file exists, the current code is used to load the config. The new code is only invoked when a config.json file is not found. In the future it may be worthwhile to unify the code more completely.

I didn't add support for .js files because there is code elsewhere that assumes such a file is a V1 changesets config file. To limit the size of this change, only .cjs config files will be loaded. A future change could add to this list and fully remove code related to the V1 config format.

.mjs files were included in an earlier version of this PR but was removed because the test infrastructure seems to always parse them as CJS despite the file extension.

.jsonc support was also included in an earlier version of this PR but was removed because the jsonc parser (tiny-jsonc) exhibited similar behavior as with .mjs files. That is, in the test environment the module was parsed as CJS despite being ESM.

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented May 28, 2024

🦋 Changeset detected

Latest commit: 21bede0

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages
Name Type
@changesets/config Minor
@changesets/cli Minor
@changesets/apply-release-plan Patch
@changesets/get-release-plan Patch

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

@codesandbox-ci
Copy link
Copy Markdown

codesandbox-ci bot commented May 28, 2024

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

@codecov
Copy link
Copy Markdown

codecov bot commented May 28, 2024

Codecov Report

Attention: Patch coverage is 92.30769% with 1 lines in your changes are missing coverage. Please review.

Project coverage is 80.11%. Comparing base (ffb9d97) to head (21bede0).

Files Patch % Lines
packages/config/src/index.ts 92.30% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1367      +/-   ##
==========================================
+ Coverage   80.05%   80.11%   +0.06%     
==========================================
  Files          53       53              
  Lines        2201     2213      +12     
  Branches      647      654       +7     
==========================================
+ Hits         1762     1773      +11     
- Misses        435      436       +1     
  Partials        4        4              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@tylerbutler tylerbutler changed the title feat: Add support for configs in CommonJS and ES6 module format feat: Add support for config files in CommonJS format May 28, 2024
@tylerbutler tylerbutler marked this pull request as ready for review May 28, 2024 01:46
@Andarist
Copy link
Copy Markdown
Member

A big issue with this is that the config would no longer be static and it's quite nice to just read the JSON file as-is in environments that might have limited scripting capabilities (such as our https://github.com/changesets/bot )

I wonder, why do you need this config to be dynamic in the first place?

@tylerbutler
Copy link
Copy Markdown
Author

tylerbutler commented May 28, 2024

The original reason I pursued a config format change was for comment support. Comments are particularly useful for fixed and linked package configs. "Why are these packages versioned together?" is an easy question to answer if there's a comment above the entry in the config.

Fundamentally, config formats that don't support comments have proven to be a hassle maintenance-wise (we have similar serious issues with package.json itself for the same reason - "why is this package using an old version of library X?" for example). In an earlier iteration I tried adding support for JSONC only but ran into problems in test where the library I used to parse the JSONC was being treated as CJS even though it's ESM.

I wonder, why do you need this config to be dynamic in the first place?

Our repo setup is admittedly very unique, but my main motivation for dynamic configs is to make it easier for us to manage the lists of fixed and linked packages. Glob support is awesome but doesn't work for us because our package scopes aren't uniform (that is, some @scopeA packages are in one fixed group and some @scopeA packages are in another, and we have multiple scopes).

As we add and remove packages from the monorepo, I'd like the changeset config to "just work." We already have some custom tools that understand how our packages are related and versioned, so we could easily output lists of packages that should be fixed/linked either directly in the config or to other JSON files that are then loaded in the config.cjs.

Another approach I have considered is writing a "changesets configuration writer" tool that updates the changesets config as part of our build. That approach works but is more custom code and process than I would like. Nor does it address the "config can't have comments" problem.

Finally, I tried doing what we do for package.json, which is add additional fields like "pnpmOverridesComments" to package.json where we document various things. We don't love that but it's the best we can do given node's dependence on it. That doesn't work for the changesets config (last I checked - it's been a few months) because it is checked against a schema and unknown fields cause the config to be rejected.

in environments that might have limited scripting capabilities

Can you elaborate on those limited capabilities? Are there environments where require or import aren't available to load configs?

@Andarist
Copy link
Copy Markdown
Member

Andarist commented Jun 1, 2024

That doesn't work for the changesets config (last I checked - it's been a few months) because it is checked against a schema and unknown fields cause the config to be rejected.

Hm, that's surprising to me - I don't think we do it but I could certainly be wrong. If that's the case we could possibly lift this restriction.

we could easily output lists of packages that should be fixed/linked either directly in the config or to other JSON files that are then loaded in the config.cjs.

My current recommendation is to do the former. One can sync their Changesets config using a different script.

Another approach I have considered is writing a "changesets configuration writer" tool that updates the changesets config as part of our build. That approach works but is more custom code and process than I would like. Nor does it address the "config can't have comments" problem.

This sounds like the solution mentioned above, I'm not sure how it's different. Re custom code: I recognize the potential problem but I'm trying to take into consideration multiple factor here. Re comments: I think this addresses that problem already, your source of truth would have those comments.

Can you elaborate on those limited capabilities? Are there environments where require or import aren't available to load configs?

They are available but executing arbitrary scripts is a security risk

@tylerbutler
Copy link
Copy Markdown
Author

Are you suggesting there's no world where this is merged? If that's the case then I'll just move on to a full custom solution. I was hoping to avoid a bunch of custom work but if I have to go that route anyway then the benefits of changesets dismisses significantly for me. That's ok, just disappointing.

@tylerbutler
Copy link
Copy Markdown
Author

That doesn't work for the changesets config (last I checked - it's been a few months) because it is checked against a schema and unknown fields cause the config to be rejected.

Hm, that's surprising to me - I don't think we do it but I could certainly be wrong. If that's the case we could possibly lift this restriction.

I think I was wrong about this - there doesn't seem to be any schema validation - sorry about that!

Can you elaborate on those limited capabilities? Are there environments where require or import aren't available to load configs?

They are available but executing arbitrary scripts is a security risk

Ahh, of course. Makes sense. If I were to refactor this PR to add support for JSONC/JSON5 in addition to JSON, would that address those concerns?

@Andarist
Copy link
Copy Markdown
Member

Andarist commented Jun 6, 2024

JSON5 seems like an easier sell - yes. I don't think we currently ever write to .changeset/config.json but we are writing to .changeset/pre.json. We should make sure that those stay updatable and that "extensions" like comments are not lost in the process.

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.

Support comments in config files

2 participants