以下の内容はhttps://let.blog.jp/tag/Yarnより取得しました。


依存パッケージの数を知りたい
◯ Yarn v1 の場合

yarn.lock のトップレベルキーの数
コメントの # 行は無視

const lines = fs.readFileSync("./yarn.lock").toString()
.split("\n")
.filter(x => x[0]?.trim() && x[0] !== "#")

console.log(lines.length)
console.log(lines.join("\n"))
42
accepts@^1.3.5:
cache-content-type@^1.0.0:
co@^4.6.0:
content-disposition@~0.5.2:
content-type@^1.0.4:
cookies@~0.9.0:
debug@^4.3.2:
deep-equal@~1.0.1:
delegates@^1.0.0:
depd@^2.0.0, depd@~2.0.0:
depd@~1.1.2:
...

◯ Yarn Berry

2 以降でも基本は同じ
だけど yarn.lock ファイルが YAML として有効なファイルになってるので YAML としてパースしてトップレベルキーの数を数える方法も取れる

2 以降の yarn.lock では自身もエントリとして存在する
「foo@workspace」 みたいなの
さらに __metadata という特殊なキーもあるので これらを除外する必要あり

const data = require("yaml").parse(fs.readFileSync("./yarn.lock").toString())

console.log(Object.keys(data).length - 2)
console.log(Object.keys(data).join("\n"))
42
"accepts@npm:^1.3.5":
"cache-content-type@npm:^1.0.0":
"co@npm:^4.6.0":
"content-disposition@npm:~0.5.2":
"content-type@npm:^1.0.4":
"cookies@npm:~0.9.0":
"debug@npm:^4.3.2":
"deep-equal@npm:~1.0.1":
"delegates@npm:^1.0.0":
"depd@npm:^2.0.0, depd@npm:~2.0.0":
"depd@npm:~1.1.2":
...

YAML ライブラリを入れなくても v1 と同じように行ごとの単純処理でも十分対応できる
YAML として有効なファイルになったことでキーは必ず 「"」 から始まってる
1 文字目が 「"」 という単純なカウントで済むので v1 より楽
この方法だと __metadata は含まれないので 自身のパッケージの数だけ除外すればいい

const lines = fs.readFileSync("./yarn.lock").toString()
.split("\n")
.filter(x => x[0] === '"')

console.log(lines.length - 1)
console.log(lines.join("\n"))
42
"accepts@npm:^1.3.5":
"cache-content-type@npm:^1.0.0":
"co@npm:^4.6.0":
"content-disposition@npm:~0.5.2":
"content-type@npm:^1.0.4":
"cookies@npm:~0.9.0":
"debug@npm:^4.3.2":
"deep-equal@npm:~1.0.1":
"delegates@npm:^1.0.0":
"depd@npm:^2.0.0, depd@npm:~2.0.0":
"depd@npm:~1.1.2":
...

Yarn Berry でゼロインストールにしてる場合は .yarn/cache にパッケージの zip ファイル一覧が並ぶのでこれを数えることもできる
.yarnrc.yml で enableGlobalCache: false になってると .yarn/cache にパッケージファイルが保存されてる
node_modules と違ってネストされないので同じ階層のファイル数で判断できる

ls .yarn/cache/ | wc -l
42

ここの方法だと自身は含まれないし __metadata キーもないので一番楽
一応 .gitignore が cache フォルダにあるけど隠しファイルなので ls に出てこない

◯ npm

package-lock.json の packages オブジェクトのキーの数
lock ファイルが JSON なので一番カンタンかも

トップレベルの packages プロパティにオブジェクトが入っていて このオブジェクトのキーがパッケージ一覧になってる
Yarn Berry 同様で自身(キーは 「""」)が含まれてるので それの除外が必要

const data = require("./package-lock.json")

console.log(Object.keys(data.packages).length - 1)
console.log(Object.keys(data.packages).join("\n"))
42
node_modules/accepts
node_modules/cache-content-type
node_modules/co
node_modules/content-disposition
node_modules/content-type
node_modules/cookies
node_modules/debug
node_modules/deep-equal
node_modules/delegates
node_modules/depd
...

◯ pnpm

pnpm-lock.yaml ファイルの packages オブジェクトのキーの数
npm に近いけど YAML なのでパースが面倒
単純な方法でやるなら 「  /」 から始まる行の数

const data = require("yaml").parse(fs.readFileSync("./pnpm-lock.yaml").toString())

console.log(Object.keys(data.packages).length - 1)
console.log(Object.keys(data.packages).join("\n"))
42
/accepts@1.3.8
/cache-content-type@1.0.1
/co@4.6.0
/content-disposition@0.5.4
/content-type@1.0.5
/cookies@0.9.1
/debug@4.3.4
/deep-equal@1.0.1
/delegates@1.0.0
/depd@1.1.2
/depd@2.0.0
/destroy@1.2.0
yarn berry はプロジェクト外部からの実行がつらい
yarn の v2 以降で pnp を使うときの問題です
berry はただでさえ使いづらいところが多いのに これのせいで特定の用途の場合は yarn v1 を使うようにしてます

適当に pnp のプロジェクトを作って パッケージを入れてそれを使うようにします

yarn init -2
yarn add dayjs

package.json はこんな感じです

{
"name": "pkg",
"packageManager": "yarn@4.1.1",
"dependencies": {
"dayjs": "^1.11.10"
},
"type": "module"
}

[index.js]
import dayjs from "dayjs"

console.log(dayjs().format("YYYY-MM-DD"))

package.json のあるフォルダで

yarn node index.js

を実行すると問題なく動きます

次に この package.json があるフォルダを dir1/foo/bar に配置して dir1 をカレントディレクトリとして実行しようとします

yarn node foo/bar/index.js

になりますが これだと依存パッケージを解決できずエラーです
カレントディレクトリを変更するために --cwd をつけて

yarn --cwd foo/bar node index.js

としてもエラーです

scripts にして yarn run を使えば行けるかなと思って試してみました

{
"name": "pkg",
"packageManager": "yarn@4.1.1",
"dependencies": {
"dayjs": "^1.11.10"
},
"type": "module",
"scripts": {
"start": "node index.js"
}
}

yarn --cwd foo/bar run start

しかしこれもダメでした
yarn run の場合は cwd なしだと scripts を認識できず start が見つからないエラーになるものです
それが 認識できて node index.js を実行してからエラーになってるので うまく動いてくれても良さそうなのですけど

エラーを見るとこんな感じです

root@787bf525a896:/dir1# yarn --cwd foo/bar node index.js
yarn node v1.22.22
warning package.json: No license field
node:internal/modules/esm/resolve:854
throw new ERR_MODULE_NOT_FOUND(packageName, fileURLToPath(base), null);
^

気になるのは v1.22.22 になってるところです
--cwd を考慮せず 今のカレントディレクトリで package.json を探して packageManager から yarn のバージョンを決めていそうです
--cwd を処理する時点では 1.22.22 で固定された後なので 期待する 4.1.1 にならないという動きみたいです
そうなるとわざわざカレントディレクトリを移動させないといけないですし それをしたくないようなところでは使えません

なにかと yarn の pnp は使いづらいのですよね
yarn v1 で node_modules を使う場合は カレントディレクトリを気にせず実行する .js ファイルから node_modules を探すのでカレントディレクトリによる問題は起きないです

未だに yarn berry には完全移行できてなくて 問題点が多いので いっそ pnpm の方に移ったほうがいいのかなと最近思ってます
npm run で npm が出す出力を消したい
JSON 形式でログを出力するスクリプトがあります

const log = (v) => console.log(JSON.stringify(v))

log({ value: 1 })
log({ value: 2 })

yarn berry で yarn start で実行すると

[root@60303402bf2f tmp]# yarn start
{"value":1}
{"value":2}

余分な出力がありません

しかし npm に置き換えると

[root@60303402bf2f tmp]# npm run start

> tmp@1.0.0 start
> node x.js

{"value":1}
{"value":2}

パッケージ名や 実行されるコマンドが出力されます
デバッグ時にはいいのですが 本番実行時に JSON 以外がログに混ざるのは避けたいので出力してほしくないです

--silent (-s) で消せるようです

[root@60303402bf2f tmp]# npm run start -s
{"value":1}
{"value":2}

この辺も yarn のほうが使いやすいなと思いましたが yarn v1 だとバージョンなどもっと色々出てました

[root@60303402bf2f tmp]# yarn run start
yarn run v1.22.22
$ node x.js
{"value":1}
{"value":2}
Done in 0.11s.

ウェブサーバーなど常駐プロセスの起動ならいらないですが CLI ツールとして使うなら実行時間が表示されるのは少し嬉しいかもしれません
git なしで yarn berry の init をエラーなく実行する
特に役立たない話

yarn init で berry の初期化をするとき git でリポジトリが自動で作られます
git が入っていないとエラーが起きます

[root@60303402bf2f foo]# yarn init -2
➤ YN0000: You don't seem to have Corepack enabled; we'll have to rely on yarnPath instead
➤ YN0000: Downloading https://repo.yarnpkg.com/4.1.1/packages/yarnpkg-cli/bin/yarn.js
➤ YN0000: Saving the new release in .yarn/releases/yarn-4.1.1.cjs
➤ YN0000: Done with warnings in 0s 140ms
➤ YN0000: · Yarn 4.1.1
➤ YN0000: ┌ Resolution step
➤ YN0000: └ Completed
➤ YN0000: ┌ Fetch step
➤ YN0000: └ Completed
➤ YN0000: ┌ Link step
➤ YN0000: └ Completed
➤ YN0000: · Done in 0s 127ms
Internal Error: Process git failed to spawn
at ChildProcess.<anonymous> (/foo/.yarn/releases/yarn-4.1.1.cjs:149:5568)
at ChildProcess.emit (node:events:518:28)
at ChildProcess._handle.onexit (node:internal/child_process:292:12)
at onErrorNT (node:internal/child_process:484:16)
at process.processTicksAndRejections (node:internal/process/task_queues:82:21)
error Command failed.
Exit code: 1
Command: /usr/bin/node
Arguments: /usr/local/bin/yarn init -2
Directory: /foo
Output:

info Visit https://yarnpkg.com/en/docs/cli/init for documentation about this command.

という感じ

git が入ってない環境で使うこともありますし git の初期化はスキップしたいです
ですが オプションに git の初期化をスキップする設定が見当たらないです

しかし .git フォルダがすでにあると初期化処理はスキップされるようになっています
https://github.com/yarnpkg/berry/blob/%40yarnpkg/cli/4.1.1/packages/plugin-init/sources/commands/init.ts#L252

つまり

mkdir .git
yarn init -2
rmdir .git

とすればエラーはなくなります

ただ上のリンクのソースコードを見ても分かる通り git の初期化処理は最後の処理です
エラーで途中終了しても init の処理は終わってるのでエラーを消しても特に何も変わりません

ログにエラーを出したくないということがあれば使えます
エラーが無い場合は Done の行までの出力になります
Yarn PnP を使うと JavaScript でライブラリの補完が出なくなる
Yarn4 から PnP を使おうとしています
速度面では問題もあるものの WSL やネットワーク越しの環境でサーバーを起動するようなケースはむしろ速くなってあまりデメリットもなさそうです
フロント関係でも Vite は Yarn PnP をサポートしてるので 開発用サーバーを起動できますし HMR も使えています
これなら PnP を普段遣いにしてもいいかも と思ってました

しかし VSCode との相性に問題がありました
VSCode は Yarn PnP でインストールされたパッケージを認識しないので 補完機能が動かなくなります
使い慣れてるライブラリだと特に問題を感じてなかったのですが 使い慣れないものや機能が多いライブラリを使ったときに補完が出ないのが結構不便でした
VSCode では JavaScript でもライブラリの関数の引数などは情報を見ることができるようになっています
選択式のところは補完の候補から選んだりもできます
これがないと毎回ライブラリの API のページを見ないといけないのが不便です

対応することはできるのですが 補完機能には TypeScript の機能が使われているので 実際には TypeScript を使わないのにライブラリの補完のためだけに TypeScript をプロジェクトにインストールしないといけないです

やり方はこんな感じです (参考)

VSCode の拡張機能の ZipFS をインストールします
これは Yarn のチームでメンテしてるもののようです
汎用的なものではなく Yarn PnP のためだけのものみたいですね

次にプロジェクトに TypeScript をインストールします

yarn add -D typescript

SDK をインストールします

yarn dlx @yarnpkg/sdks vscode

これを実行すると今のプロジェクトで使われてるツールを自動で認識して必要なものをインストールしてくれるようです
TypeScript 以外にも eslint が使われていたら eslint の SDK がインストールされます

あとは VSCode のコマンドから TypeScript のバージョンを切り替えます

Ctrl-Shift-P
→ TypeScript: Select TypeScript Version...
→ Use Workspace Version

VSCode 組み込みのものからワークスペースのものに切り替えると TypeScript の機能が有効になります
TypeScript をインストールしていないとワークスペースのバージョンが存在しないので切り替えができません

これでライブラリの補完ができるようになりました

ちなみに SDK のインストールですが TypeScript のみの環境ではこうなりました
.vscode フォルダに extensions.json と settings.json が追加されました
extensions.json では推奨される拡張機能に ZipFS が記載されて settings.json では↓のような内容が追加されています

{
"search.exclude": {
"**/.yarn": true,
"**/.pnp.*": true
},
"typescript.tsdk": ".yarn/sdks/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true
}

ここのパスにも記載がある .yarn/sdks/typescript に TypeScript の SDK がインストールされています

ライブラリの API の補完機能が欲しいだけなのにすごく面倒ですよね
TypeScript を使うプロジェクトなら最初からインストールしてるわけなので別にいいかとも思えますが シンプルな JavaScript のプロジェクトでやりたいものではないです
Yarn4 が出た
正式リリースされたようです
rc は 53 まであったようです

大きな変更はゼロインストール機能がデフォルトで無効になってるようです
ゼロインストールはそれ自体の ON/OFF はなくて PnP とオフラインミラーの両方を使うことで実現できるものです
PnP は Yarn4 でもデフォルトで有効なので オフラインミラーがオフになったようです
具体的には .yarnrc.yml の設定の enableGlobalCache のデフォルト値が true になりました

enableGlobalCache が true だとインストールするパッケージは 各プロジェクトのフォルダ内に保存されず全部のプロジェクトで共通になります
Linux 環境だと 「~/.yarn/berry/cache/」 に入ります
同じパッケージを複数のプロジェクトで使うときも実体はひとつなので効率的です
なのでデフォルト挙動としてはこっちで良いと思います
false にすると各プロジェクトフォルダに保存されるので Git にコミットしてゼロインストールにできます

他には yarnPath の代わりに Corepack が推奨されるようになったようです
とは言ってもまだ yarn init で作られる .yarnrc.yml に yarnPath の設定が記載されています
package.json には packageManager が追加されるようになっています

{
...
"packageManager": "yarn@4.0.0",
...
}

Constraints 機能にも変更があって JavaScript で書けるようになったようです
これまでは Prolog でしたが なぜ Prolog という状態でしたからね
記載する内容に適した言語なのでしょうけど Yarn を使うユーザー層を考えると全然違う言語過ぎて難しすぎました
気軽に使えるようになったのは良いですね
yarn の公式サイトが新しくなってた
久々に開いたら新しくなってました
https://yarnpkg.com/
綺麗なイラストもあっていい感じですね

yarn4

ドキュメントのサイトが新しくなるということは大きな更新でもあるのかなと見てみると新しいサイトは yarn4 をカバーしてるということみたいです
まだ rc ですが (といっても rc50) 近々リリース予定なのかもです

これまでの古いサイトは別ドメインになってました
https://v3.yarnpkg.com/

メジャーアップデートで大きく変わるのかなと思いましたが ドキュメントを軽く見た感じでは いつもの yarn2 系のようです
3 からの移行についてのページが見当たらないですし 影響の大きい変更はないのかも

CHANGELOG.md を見てみても一般ユーザー向けだと Node.js の古いバージョンのサポート終了やデフォルト値の変更や UI 改善や高速化などが主のようです
npm のローカルパッケージ参照機能が yarn より使えない
yarn は file: と link: で扱いを変えられる
file の場合はパッケージのフォルダを node_modules 内にコピーして link の場合はシンボリックリンクを作る
npm は file しかなくて file でシンボリックリンクが作られる
コピーはほぼ使わないから これだけだと npm でも問題ない

npm はリンクするパッケージ内の dependencies の扱いで問題が出る
リンク先がプロジェクト内のサブフォルダだと devDependencies も含めてインストールされる
プロジェクトのサブプロジェクトならテストなど開発用機能も使うだろうという判断?

実際には npm ライブラリをベースにバグ修正や自分用にカスタマイズで少しだけいじったものと置き換える使い方が多い
そういうときに devDependencies は要らない
だけどこれを除外する方法がなさそう
devDependencies を消して対処しかない?

workspace が使われてるパッケージだと devDependencies は workspace を前提にしていて単独だとインストールできない場合もある
production モードでインストールすれば devDependencies のインストールは回避できたと思うけど この方法だとメインの devDependencies も入らなくなってしまう
メインの devDependencies にはフォーマッターやテストなどの必要なものがあるのでインストールされないのは困る

またリンク先がプロジェクトフォルダの外だと動作が変わる
単にリンクされるだけで dependencies すらインストールされない
手動でリンク先で npm install コマンドを実行しろってことみたい
プロジェクト外なら複数箇所で共有されてるかもしれないからそのパッケージフォルダ内に node_modules を作って共有するというのもわからなくはないけど

ただ実際にはこれらの機能は使いづらいだけ
yarn ならプロジェクトの内外を気にせず リンクしたパッケージは他のパッケージと同じように扱われて dependencies のみインストールされる
これが求めてる挙動だけど npm だと同じことをする方法がなさそう

経験がないけど yarn の挙動だと問題が出る可能性はあるのかも
バージョン競合で node_modules 内のパッケージの中に node_modules がネストして作られることがある
そのときにリンクしたパッケージ内に部分的な node_modules ができて気持ち悪いことになる可能性があるのかも
1 箇所からの使用なら別にも気にしなければいいだけだけど 複数箇所からリンクしてると部分的な node_modules は問題になる可能性も?
yarn install で install されない
node_modules 内のパッケージのフォルダを直接消した場合は yarn install してもインストールされません

node_modules フォルダ中の .yarn-integrity ファイルにインストール関連の情報が保存されていて lockfileEntries にインストール済みパッケージとバージョンが書かれています
ここを見て更新の必要があるかを判断するので 実際にフォルダがなくても .yarn-integrity の情報と yarn.lock の情報が一致していれば最新状態と判断されます

フォルダを消してしまった場合は .yarn-integrity の中から再インストールしたいパッケージの行を削除すると yarn install でインストールできるようになります
探すのが面倒なら このファイルごと消してしまっても全部インストールされるので大丈夫です


直接ライブラリのソースをいじっていろいろ試して もとに戻したいからフォルダ消して再インストールしたかったのですが そういう場合は注意が必要です
yarn create が Windows だとエラーになる
yarn create を使ってみたらエラーが発生
ドキュメントにある例の "yarn create react-app my-app" コマンドで起きることを確認

エラーは 'C:\Program' が見つからないとかそういう感じのやつ
エラーメッセージを見る限りは単純にパスのクオート漏れ
yarn が内部で実行するコマンドで Node.js のパスを指定する部分で起きてる
Node.js の exe が Program Files 以下にあると使えないぽい

ソースを軽く見た感じだと exec じゃなくて spawn を使ってるし自動でクオートされてそうなんだけど
一応バージョンを最新まで上げてみたけど変わらなかった

Windows だと標準インストーラでも Nodist でも Program Files 以下になるからほとんどの人が動かない気がするのに結構前からこの状態
Windows で yarn create 使うような人がそもそも少ないのかも

仕方ないので 私は npm init で代替



[追記]

原因は spawn のオプションに shell: true を使ってるからだった
そのままコマンドプロンプトに打ち込む形になって command 変数にスペースがあるとエラーになる
shell: false にするとスペースがあっても大丈夫だけど 実行するのが .cmd ファイルなので shell: false だと動かない

shell: true のまま動かすために command 変数を "" でクオートする処理を追加する
修正するファイルは node_modules\yarn\lib\cli.js
babel+webpack の変換で大きく変わっているので 「child.spawn(command」 で検索しても見つからない
「.spawn(command, rest,」 で検索すると見つかるはず
その行の直前に↓のコードを追加

command = `"${command}"`

これで動くはず

ただ yarn create は create-react-app などのパッケージをグローバルインストールするようなので 失敗直後に create-react-app コマンドは使えるようになってる
わざわざ修正するよりも create-react-app などのコマンドを打つ方が早い
Nodist で yarn 使うときのパス
Windows に Nodist で Node.js を入れて yarn でパッケージをグローバルインストールすると自分でパスを通さないといけません
普通に Nodist をインストールすると 「C:\Program Files (x86)\Nodist」 にインストールされます
node.exe や npm.exe は 「C:\Program Files (x86)\Nodist\bin」 に保存されます
npm でグローバルにインストールしたパッケージのコマンドもここに配置されます
npm で yarn を入れたあとに確認してみると

user1@pc MINGW64 /c/Program Files (x86)/Nodist/bin
$ ls -1
bin/
etc/
node.exe*
node_modules/
nodist*
nodist.cmd
nodist.ps1
nodist.sh*
nodist_bash_profile_content.sh
npm.cmd
npm.exe*
yarn*
yarn.cmd
yarnpkg*

ここにはパスが通ってるので yarn コマンドは使えます
yarn でパッケージをグローバルインストールしたものはこのフォルダではなくそのさらに内側の bin フォルダにコマンドが配置されます
yarn で parcel をグローバルインストールしてみると

user1@pc MINGW64 /c/Program Files (x86)/Nodist/bin
$ ls bin -1
parcel*
parcel.cmd
parcel.cmd.ps1*
parcel.ps1*
parcel.ps1.cmd
parcel.ps1.ps1*

parcel はパスが通ってないのでそのままでは使えません
「C:\Program Files (x86)\Nodist\bin\bin」 にパスを通せばどこでも yarn でインストールしたツールが使えるようになります



以上の内容はhttps://let.blog.jp/tag/Yarnより取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14