JamieMason / syncpack

Consistent dependency versions in large JavaScript Monorepos.
https://jamiemason.github.io/syncpack/
MIT License
1.46k stars 51 forks source link

package.version triggers a mismatch when using workspace:* protocol #238

Closed battis closed 3 months ago

battis commented 3 months ago

Description

In a monorepo using pnpm, each package has its own package.json file that lists its current version in the version field and depends on another package using the workspace:* protocol:

/packages/a/package.json

{
  "name": "@app/a",
  "version": "1.2.3"
}

/packages/b/package.json

{
  "name": "@app/b",
  "dependencies": {
    "@app/a": "workspace:*"
  }
}

With the following modified example config (modified to include non-dev dependencies as well):

/.syncpackrc

{
  "versionGroups": [
    {
      "label": "Use workspace protocol when developing local packages",
      "dependencies": ["$LOCAL"],
      "pinVersion": "workspace:*"
    }
  ]
}

When running syncpack this is identified as a mismatch:

syncpack list

= Use workspace protocol when developing local packages ========================
     1x @app/a:
        ✘ 1.2.3 → workspace:* [PinnedMismatch]

Even more excitingly, if sync fix-mismatches is run, the the @app/a package.json is updated thus:

/packages/a/package.json

{
  "name": "@app/a",
  "version": "workspace:*"
}

Suggested Solution

If I am correctly understanding what is going on, then the package.version field should not be identified as a mismatch -- only the dependency versions should be. That is, it should be fine for local packages to maintain their own versioning within the monorepo, but the other packages should not be depending on a specific version (per .syncpackrc) but instead depend only on `workspace:*.

And fix-mismatches should not update the version field of a package, since that is an information source, not a dependency.

Help Needed

It is entirely possible that I'm misunderstanding what syncpack is reporting, but I think this is a bug and not desired behavior?

JamieMason commented 3 months ago

Thanks @battis, this catches people out all the time.

EDIT: Try this fix.

battis commented 3 months ago

@JamieMason That indeed fixes it! Thank you! My head swims thinking through how "dependencyTypes": ["!local"] makes it work, but I think I get it.

JamieMason commented 3 months ago

Great, this is what the config is trying to do:

local is a keyword just like dev, prod, peer etc which refers to the version properties of the package.json files from your own packages being developed in your monorepo.

Instead of writing out all the dependency names we use these keywords, a bit like variables.

When you use !local instead of local you're saying: include all the other types except this one.

battis commented 3 months ago

Elegant!

mikededo commented 3 months ago

Hey @JamieMason, I'm using Turbopack on my monrepo, with bun as a package manager, and yet I'm not able to make it work with the solution you propose.
I have a similar file structure as @battis commented, and all my local dependencies are being updated from workspace:* to 0.0.0, which is the version specified in each package/app package.json.

Here's an example output:

= Default Version Group ========================================================
     ...
     3x @monorepo/actions:
        ✘ workspace:* → 0.0.0 [LocalPackageMismatch]
     ...

My syncpack.config.js it only contains the proposed solution:

// @ts-check

/** @type {import("syncpack").RcFile} */
const config = {
  versionGroups: [
    {
      label: 'Use workspace protocol when developing local packages',
      dependencies: ['$LOCAL'],
      dependencyTypes: ['!local'],
      pinVersion: 'workspace:*'
    }
  ]
};

module.exports = config;

Any idea? Currently running syncpack@12.4.0.

mikededo commented 3 months ago

Hmm, even though I'm using a name specified here at the root level, somehow, unless I use the --config <path> flag, the configuration is ignored 🤔

Edit: seems to only work with .syncpackrc, without specfying --config.

JamieMason commented 3 months ago

I wonder if it is similar to this problem, where an error is happening in the config but is not being surfaced yet.

SYNCPACK_VERBOSE=true syncpack list may throw up clues, but try renaming the config file to .cjs

mikededo commented 3 months ago

Well, working with .syncpackrc.json seems to work fine, so that should resolve the issue 🙏🏼👍🏼

JamieMason commented 3 months ago

Great, my best guess is maybe there was some ESM issue going on that syncpack is swallowing (will be fixed in #229), but I'm not sure.