What could go wrong with `yarn publish`?

October 2nd, 2020

Is there anyone who runs yarn publish to release your library to npm registry? If you don't, you might want to skip this post. If you do, or if you're just interested, bear with me for a minute.

If you run yarn publish, it will run yarn pack under the hood to package your library. I've discovered a severe bug in yarn pack, which wrongly includes unexpected files in a specific case.

In your package.json, you might have files property like the following:

package.json

"files": [
"src"
],

It's okay until you add a negative expression like the following:

package.json

"files": [
"src",
"!**/__tests__/**"
],

When there is a negative expression, yarn pack wrongly packs the whole directory, ignoring files property, .gitignore, and even .npmignore. This means not only unnecessary files but also critical files like .env can be included in the release.

When I filed this issue, I've discovered other similar reports regarding the misinterpretation of files property by yarn pack.

A quick workaround would be to use npm publish, but it was not that simple.

test.sh

#!/bin/bash
yarn config get registry
npm config get registry

If you run ./test.sh, what do you expect?

https://registry.yarnpkg.com/
https://registry.npmjs.org/

Yes. It's correct. Then let's see what happens if it's run by npm or yarn.

package.json

"scripts": {
"test": "./test.sh"
},

If you run npm run test, what will happen?

https://registry.yarnpkg.com/
https://registry.npmjs.org/

Same, correct. But if you run yarn run test, you will get something spooky:

https://registry.yarnpkg.com/
https://registry.yarnpkg.com/

Yes. Inside yarn's context, npm config get registry returns the one from yarn. It seems yarn overwrites the environment variable on runtime. Then why is it a problem? When you have a script running npm publish and run the script using yarn run xxx, yarn will fail npm publish. It was reported before.

So if you have a setting like the following:

// package.json
{
"scripts": {
"release": "./release.sh"
}
...
}
// release.sh
npm publish

yarn run release won't work. You have to run npm run release. But if you must use yarn run release, there is a workaround.

cat ~/.yarnrc
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
registry "https://registry.yarnpkg.com/"
email xxx@yyy.com
lastUpdateCheck <timestamp>
username xyz

Update the registry to https://registry.npmjs.org/ in the file. However, it will only work on your computer, and your colleagues will have the same problem. So a slightly better workaround is the following:

release.sh

npm_config_registry=https://registry.npmjs.org/ npm publish

Then yarn run release will work.

Until it gets fixed or you step up and fix it, use the workaround above or run npm run release instead.

By the way, don't release your library on your computer. Let your CI/CD do it for you. That's way safer. Shamelessly plugging, I use Ship.js for automated release on CI/CD.


I'm Eunjae -

A software engineer
focused on web development.
I'm working at Algolia, in Paris.
Feel free to connect!

© 2020 Eunjae Lee