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

Is there a good way to force developers to use yarn instead of npm? #1

Open
alexanderwallin opened this issue Dec 16, 2016 · 24 comments
Labels

Comments

@alexanderwallin
Copy link
Owner

This experimental module came from the discussion in yarnpkg/yarn#1732, where the question was how to prohibit the use of npm on a project and point developers to using yarn instead.

This module doesn't really solve that problem, but merely logs things that are easy to miss. @farisj tried a couple of other things, but none did work.

So the question is, is there a way or hack to for instance hijack npm install? Should this even be necessary?

@yuchi
Copy link

yuchi commented Feb 4, 2017

Isn’t this a little bit rude?

Seriously, suggesting yarn is one thing, forcing it is another. There’s a contract that both are respecting, and that npm carefully crafted in years. Also you are incorrectly inferring that there’s just npm and yarn, but actually there are tons of other package managers for completely unexpected environments — from atom to Java platforms.

@yuchi
Copy link

yuchi commented Feb 4, 2017

So my question is, why would you ever want to force it?

@farisj
Copy link

farisj commented Feb 5, 2017

My own use case for this is such: I am working on a medium size team and we are considering moving one of our applications to yarn over npm. However, I'd want to ensure everyone on my team is using yarn commands over npm. Yes, I can tell everyone to use yarn run over npm run, but I want to correct for human error and force that behavior.

With Rails and Bundler, for instance, bundler will prevent me from booting my rails server if I don't prepend my commands with bundle exec in scenarios where I'm working with the wrong versions of gems. This behavior ensures we're using all of the gems specified in the Gemfile.lock, even if people have global gems installed elsewhere, etc.

It would greatly ease the transition of my coworkers remembering to use yarn on our app if they had no choice about the matter. For me, this feature is about managing a team and ensuring that everyone has the same setup. Just having the yarn.lock file is pointless if I can't get my fellow employees to use it.

@yuchi , your comment about this issue being rude is unnecessary. I agree that I wouldn't want to force other developers to use it outside of my own company, but internally we are trying to optimize our workflow across the team, so having a way to force the use of yarn is very desirable to me.

@yuchi
Copy link

yuchi commented Feb 5, 2017

@farisj it‘s totally understandable then, but I’m scared by the possibility of this practice becoming widespread. We’ve seen this on the iojs/node debate—and while this one is not an issue on political ground, I’m a little disenchanted on people by now.

To support my question, I got to this repo by because someone I follow stargazed it. But the rationale you explained was nowhere to be found. A little warning «don’t use it on modules—for enterprise use only!» would help a lot in communicating the goal of this project.

@alexanderwallin
Copy link
Owner Author

I agree the README does not explain the purpose of this – almost entirely experimental – repo very well. I'll add a clearer description!

I disagree that the enforcing of a certain tool is any more rude than choosing a database or linting code. Like @farisj said, it's about assuring quality and shipping software that works.

@alexanderwallin
Copy link
Owner Author

b4740bc

@yuchi
Copy link

yuchi commented Feb 6, 2017

Thank you!! Looks great :)

By the way probably I will be using it in a project or two, so thanks twice!

@alexanderwallin
Copy link
Owner Author

Ah, cool! Please come back with any feedback you might have.

@rafayepes
Copy link

I have the exact same situation as @farisj explained above. What's the point of using yarn if I can't make sure that yarn.lock doesn't get out of sync? Want to avoid other to run npm i or modifying directly package.json without using yarn

@Sinewyk
Copy link

Sinewyk commented Apr 7, 2017

npm and yarn seem to both extend the process.env when executing scripts ... https://github.com/npm/npm/blob/5d17fc945bcf48b69bc0dc4741028762f6bca02c/lib/utils/lifecycle.js#L76 and https://github.com/yarnpkg/yarn/blob/508c959080c52183697602f52ebb95b086b6b3d3/src/util/execute-lifecycle-script.js#L33 ...

So I just went full dictator and this is what I got:
"preinstall": "node -e \"if (process.env.npm_execpath.indexOf('yarn') === -1) throw new Error('Use yarn for installing: https://yarnpkg.com/en/docs/install')\"",

It does the job.

@alexanderwallin
Copy link
Owner Author

Holy moly! That's some impressive digging. Feel free to fire away a PR if you want.

@AndersDJohnson
Copy link

AndersDJohnson commented May 6, 2017

Just released a module that includes a CLI to do this (useful for preinstall scripts): https://github.com/AndersDJohnson/use-yarn

Stay tuned, as I may have more ideas coming, especially around CI.

FYI @alexanderwallin @Sinewyk @farisj @rafayepes

@AndersDJohnson
Copy link

AndersDJohnson commented May 7, 2017

I've also just released a helper for Danger to check for missing yarn.lock changes on CI:
https://github.com/AndersDJohnson/danger-yarn-lock

FYI @alexanderwallin @Sinewyk @farisj @rafayepes

@rafayepes
Copy link

rafayepes commented May 8, 2017

I solve that with husky and lint-staged and adding the following to package.json:

{
  "scripts": {
     "precommit": "lint-staged"
  },
  "lint-staged": {
    "+(package.json|yarn.lock)": [
      "node ./scripts/yarn-check.js"
    ]
  },
  "devDependencies": {
    "husky": "^0.13.2",
    "lint-staged": "^3.4.0"
  }
}

And then, that yarn-check.js script is

'use strict';

const execSync = require('child_process').execSync;
const chalk = require('chalk');

try {
    execSync('yarn check').toString();
} catch (error) {
    console.log(
        '\n' +
            chalk.red(`  This project uses ${chalk.underline.bold('yarn')} to install all JavaScript dependencies.\n`) +
            chalk.red(`  Please don't modify the dependencies manually in package.json nor use npm install to update them.\n`) +
            chalk.dim('    Please run ') +
            chalk.reset('yarn add [package-name]') +
            chalk.dim(' to install any new dependency\n') +
            chalk.dim('    or') +
            chalk.reset(' yarn upgrade [package@version]') +
            chalk.dim(' to upgrade a dependency to a specific version.\n') +
            chalk.dim(
                '    Ensure you commit both the package.json and the yarn.lock files together.\n'
            ) +
            chalk.dim('    Check out ') +
            chalk.underline.blue('https://yarnpkg.com/en/docs/cli/') +
            chalk.dim(' for more information.') +
            `\n`
    );
    process.exit(1);
    throw error;
}

FYI @alexanderwallin @Sinewyk @farisj @adjohnson916

@AndersDJohnson
Copy link

@rafayepes Nice! That works on local machines, but yarn check could be run on CI too.

@rafayepes
Copy link

@AndersDJohnson on CI you can install dependencies using yarn install --frozen-lockfile --non-interactive, which will fail if yarn.lock was not properly updated.

@rafayepes
Copy link

rafayepes commented Nov 9, 2017

@alexanderwallin I've found that running yarn check on precommit and yarn install --frozen-lockfile --non-interactive to install dependencies on CI ensures that yarn is used instead of npm. Does that answer your initial question?

As extra info, we are also running now yarn install --pure-lockfile --non-interactive on both postcheckout and postmerge, to ensure everyone has always latest dependencies installed

@amorist
Copy link

amorist commented Jul 17, 2018

npm install packageName how hook

@alexanderwallin
Copy link
Owner Author

@rafayepes It seems you've got some nice solutions going here. I think I'll leave this issue open indefinitely to allow different solutions to be published, but big thanks for sharing!

(Not a yarn user myself, so won't evaluate specific solutions.)

🎈

@skoshy
Copy link

skoshy commented Oct 19, 2019

The above helps for plain npm installs, but doesn't work when installing/adding a package to an app. To solve for this, I intentionally create a broken package-lock.json file with the following inside it

See_package-lock.json

Please don't use npm within this repo; please use yarn instead.

This makes it so when I npm i or npm i --save-dev typescript, this occurs:

image

This does create a warning when yarn installing/adding, but I think that's fine as this definitively prevents using npm.

@alanhe421
Copy link

alanhe421 commented Jul 26, 2020

  1. add script

package.json

    "preinstall": "node ./scripts/checkYarn.js",

npm will auto-execute the script.

  1. checkYarn.js
if (!/yarn\.js$/.test(process.env.npm_execpath || '')) {
  console.warn(
    '\u001b[33mThis repository requires Yarn 1.x for scripts to work properly.\u001b[39m\n'
  )
  process.exit(1)
}

when you execute npm install, it will error

image

@tktcorporation
Copy link

Set engines in package.json

{
...
  "engines": {
    "npm": "use yarn instead of npm."
  }
}

When you use npm i

npm ERR! code ENOTSUP
npm ERR! notsup Unsupported engine for {project-name}@{version}: wanted: {"npm":"use yarn instead of npm."} (current: {"node":"14.5.0","npm":"6.14.5"})
npm ERR! notsup Not compatible with your version of node/npm: {project-name}@{version}
npm ERR! notsup Not compatible with your version of node/npm: {project-name}@{version}
npm ERR! notsup Required: {"npm":"use yarn instead of npm."}
npm ERR! notsup Actual:   {"npm":"6.14.5","node":"14.5.0"}

@alexanderwallin
Copy link
Owner Author

alexanderwallin commented Sep 25, 2020

@tktcorporation Do you put that in the project's package.json? Or in this package which you install as a dependency?

@tktcorporation
Copy link

tktcorporation commented Sep 25, 2020

@alexanderwallin

@tktcorporation Do you put that in the project's package.json? Or in this package which you install as a dependency?

I put it like this.

{
  "name": "sample",
  "version": "1",
  "description": "",
  "author": "tktcorporation",
  "engines": {
    "npm": "use yarn instead of npm."
  },
  "scripts": {
    "build": "tsc",
  },
  "dependencies": {},
  "devDependencies": {}
}

and write engine-strict=true on a file .npmrc

ref: https://qiita.com/suin/items/a7bf214f48eb9b2d9afc

Another

I found another way to do that.

{
  "name": "sample",
  "version": "1",
  "description": "",
  "author": "tktcorporation",
  "scripts": {
    "preinstall": "npx only-allow yarn"
  },
  "dependencies": {},
  "devDependencies": {}
}

It is needed to put "preinstall": "npx only-allow yarn" to scripts.
And it is not needed to install only-allow

ref: https://qiita.com/suin/items/e0fbdd9af1150138a65c

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

10 participants