How does node work with Yarn Plug-n-Play? - node.js

Yarn 2.0 is bringing PnP to the table, but I don't really understand how I can run javascript with the simple node command anymore if the file has dependencies in the npm registry. node looks for node_modules folders to find dependencies, but since PnP removes the node_modules folder entirely, do I need to use a command other than node now? Or will node introduce some new flag to read the .pnp.js file instad of recursively looking upwards for the nearest node_modules?

Answer from Yarn 2 PnP docs:
Because Node had no concept of packages, it also didn't know whether a file was meant to be accessed (versus being available by the sheer virtue of hoisting). It was entirely possible that the code you wrote worked one day in development but broke later in production because you forgot to list one of your dependencies in your package.json.
For your answer that can you can you run using command node index.js.
You need to add a script in your package.json scripts section like "start": "node index.js" and then run yarn run start

yarn node index.js. See the yarn 2 (berry) docs. https://yarnpkg.com/cli/node

Related

Yarn workspaces with babel, ts, etc?

Is there a "correct" way to have globally available scripts w/ yarn workspaces?
Let's take typescript as an example. If I install it at the root level using yarn add -W typescript it's not available in any of my workspaces:
child-workspace$ yarn tsc
yarn run v1.22.10
error Command "tsc" not found.
Now I can install tsc into every workspace, along with babel, jest, etc etc etc, but that's awfully redundant. I'm looking for a way to have tools at the global level that are used by each of the workspaces.
Even better, if possible, would be if there were a way to have a "build" workspace and have all the scripts from that globally available so they can be cleanly separated from the workspace root.

Node JS/ Angular

I have installed Node JS and then imported an existing work project in Visual Studio Code. After that I ran npm install in the project folder, then run npm start and the app comes up fine. However, if I run an ng command I get an error telling me "ng is not valid command", even though the Angular CLI is in the modules folder.
I tried manually installing Angular CLI globally and set system path to point to the npm folder, and then the ng command works fine. What I don't understand is why do I need to install CLI globally if I just want to run that command within the project where the module is already present?
As a general rule then you will need to install globally any commands you wish to use (without NPX). This isn't really a restriction of NPM so much as it is a fundamental way in which command line programs work. The OS will only look in fixed predefined locations set in PATH. This applies to any Node based tool such as grunt or ng or whatever.
(While some systems do look for executables relative to the current working directory, or can be configured to, it's generally not a good or reliable method and NPM doesn't rely on this behaviour).
For something like the Angular CLI then installing it globally should be fine and is what many people will do. As a general rule if it is a command you want to run, rather than a dependency for a project, you can consider installing it globally. You'll notice that on the Angular CLI page the example does exactly that.
In many cases however you might want to run a command from a local project. Perhaps for a build script or something else where you want to keep it isolated. In that case you instead prefix your command with npx which will look inside the local project for commands.

How to set an environment variable to be used during "npm install"?

Our coorporate network is very closed down, so a normal method of:
npm install cypress#3.4.1
Doesnt work since it is being blocked by a proxy, we need to provide the parameter CYPRESS_INSTALL_BINARYin the following way with the help of cross-env (since we have mainly Microsoft environments here).
cross-env CYPRESS_INSTALL_BINARY='\\localserver\cypress\3.4.1\cypress.zip' npm install cypress#3.4.1
This is easy to do on first install, but the problem is that everyone on the team needs to run this command. And I want it to be possible to just type npm install and they will get all requirements automatically. This is extra obvious when we want to update the cypress package, since the binary url needs to change each time.
I tried to add a preinstall script to my package.json like so:
"scripts": {
...
"preinstall": "cross-env CYPRESS_INSTALL_BINARY='\\localserver\cypress\3.4.1\cypress.zip'",
...
},
But it seems like that environment variable set by cross-env is "gone" after preinstall is finished and install begins, since cypress tries and fails to download from the web. I am okay with it being temporary, but it needs to persist over the install-command. Also seen solutions with .env files but none of those have support for the install step as far as I can see.
My current solution is to run the entire cypress installation in the preinstall step, and it works but seems uneccessary to run a double install each time.
So, what I am asking for, is a way to let a developer just run the following commands on a brand new computer and be done.
git clone ...
cd ...
npm install
How can I do that?
Same situation on my side, except that I want to prevent the installation of cypress on the local machine.
Solved it by adding a .npmrc into the root of the project and adding to version control.
Contents of .npmrc:
CYPRESS_INSTALL_BINARY=0
Since the environment variable is used on install time, the solution with cross-env was not possible, since one cannot be sure that cross-env has been already installed.
Let me know whether it helped or you have already another solution.
I ended up creating a tool that takes care of supplying the correct binary, depending on environment:
https://github.com/tomasbjerre/dictator-cypress
I have it internally at my company. When we need a new version of Cypress, we release a new version of this tool internally.
I add the tool as a preinstall script:
...
"scripts": {
"preinstall": "npx dictator-cypress#0.0.28",
...
So that it runs when someone does npm install:
...
Copy linux cypress to cypress.zip
Applying: copy linux-x64/cypress.zip to .
.npmrc should have reference to cypress binary
Up to date: .npmrc should have lines
.gitignore should include the copied zip
Up to date: .gitignore should have lines
...

How to test cli (global link) with yarn?

I am trying to test a cli (feathers-cli) that I am working on. I have cloned it's primary dependancy (feathers-generator) and made my modifications, this is what I have done.
Gone into feathers-generator (master branch) and run yarn link
Gone into feathers-cli (3.0 branch) and run yarn link "feathers-generator"
Run yarn link
created a new directory, removed my existing version of feathers-cli
Run yarn link "feathers-cli" then run yarn global add "feathers-cli"
feathers however, at this point it is using the regular version it has pulled from npm. I have looked through the yarn docs and can't seem to find anything about globally linking packages. How do I approach this?
With yarn v1.19 you can do:
yarn global add file:/fullpath/to/myproject
Yarn, unfortunately, does not seem to support this directly in any way. The best thing I've found is to symbolically link the file to the user's yarn bin folder.
On Windows: %LOCALAPPDATA%/Yarn/bin
On Linux: ~/.yarn/bin/
Easiest way is to test within a node project, even if it's a global cli tool.
Example
Say I want to test a global tool my-yarn-cli, which has a few commands new, --help, --version, etc...
In the cli tool directory, yarn link this makes the local version of my-yarn-cli available to yarn.
In an empty project use yarn link my-yarn-cli, this adds a reference to the local version of my-yarn-cli
Test out commands using yarn as a proxy, for example:
yarn my-yarn-cli --help
yarn my-yarn-cli --version
yarn my-yarn-cli new TEST_ARGUMENT
This has been a useful workflow for me, and is much better than messing with symlinks or copying directories.

How do I monitor symlinked modules with Nodemon?

I’m developing a module in Node.js which I’ve npm-linked into another projects node_modules folder. I’d like to restart this other projects server upon file changes in my module. Nodemon ignores node_modules by default, but I assumed I could override this using nodemon --watch node_modules/my_module – but can’t get it to work. If I temporarily remove node_modules from Nodemons lib/config/defaults.js it works, which probably confirms that the problem has to do with overriding default behavior.
Using nodemon 1.2.1, I'm able to do the following to get watches working with an npm link:
$ nodemon --watch . --watch $(realpath node_modules/my_module)
Basically...you have to watch the directory you're in (your project directory), and then specify a watch to the symlink itself. nodemon by default ignores node_modules, so explicitly specifying the watch fixes this. You may try updating your version of nodemon if this doesn't work for you.

Resources