Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 0 additions & 36 deletions .claude/skills/running-tests.md

This file was deleted.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
},
"workspaces": [
"documentation",
"website",
"packages/*",
"tests/acceptance-tests",
"tests/acceptance-tests/pkg-tests-core",
Expand Down
2 changes: 2 additions & 0 deletions website/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
dist/
.astro/
40 changes: 40 additions & 0 deletions website/astro.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import react from '@astrojs/react';
import sitemap from '@astrojs/sitemap';
import tailwindcss from '@tailwindcss/vite';
import {defineConfig} from 'astro/config';
import remarkDirective from 'remark-directive';

import rehypeDocs from './plugins/rehype-docs.mjs';
import rehypeFootnoteTooltips from './plugins/rehype-footnote-tooltips.mjs';
import remarkAutolinkFields from './plugins/remark-autolink-fields.mjs';
import remarkBluesky from './plugins/remark-bluesky.mjs';
import remarkDocs from './plugins/remark-docs.mjs';
import remarkMermaid from './plugins/remark-mermaid.mjs';

export default defineConfig({
site: `https://v6.yarnpkg.com`,
integrations: [react(), sitemap({filter: page => !page.includes(`/presentation/`)})],
build: {
format: `file`,
},
vite: {
plugins: [tailwindcss()],
optimizeDeps: {
include: [
`prettier/standalone`,
`prettier/plugins/babel`,
`prettier/plugins/estree`,
`prettier/plugins/typescript`,
`prettier/plugins/postcss`,
`prettier/plugins/html`,
`prettier/plugins/markdown`,
`prettier/plugins/yaml`,
],
},
},
markdown: {
syntaxHighlight: false,
remarkPlugins: [remarkDirective, remarkBluesky, remarkMermaid, remarkDocs, remarkAutolinkFields],
rehypePlugins: [rehypeDocs, rehypeFootnoteTooltips],
},
});
49 changes: 49 additions & 0 deletions website/config/navigation.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"topbar": [
{ "label": "Install", "key": "install", "href": "/getting-started/" },
{ "label": "Concepts", "key": "concepts", "href": "/concepts/switch/" },
{ "label": "Reference", "key": "reference", "href": "/configuration/manifest/" },
{ "label": "Extra", "key": "extra", "href": "/appendix/workspaces-and-peer-deps/" },
{ "label": "Benchmarks", "key": "benchmarks", "href": "/benchmarks/" },
{ "label": "Quiz", "key": "quiz", "href": "/quiz/" },
{ "label": "Blog", "key": "blog", "href": "/blog" }
],
"categoryToSidebar": {
"getting-started": "getting-started",
"concepts": "concepts",
"appendix": "extra",
"appendixes": "extra",
"contributing": "extra",
"advanced": "advanced",
"protocols": "reference",
"reference": "reference"
},
"sidebars": {
"getting-started": { "sections": ["getting-started"] },
"concepts": { "sections": ["concepts"] },
"advanced": { "sections": ["advanced"] },
"appendix": { "sections": ["appendix"] },
"contributing": { "sections": ["contributing"] },
"extra": { "sections": ["appendix", "contributing"] },
"reference": {
"links": [
{ "label": "Manifest — package.json", "href": "/configuration/manifest/", "page": "manifest" },
{ "label": "Settings — .yarnrc.yml", "href": "/configuration/yarnrc/", "page": "yarnrc" },
{ "label": "Yarn CLI", "href": "/cli/install/" },
{ "label": "Yarn Switch CLI", "href": "/switch/switch/" },
{ "label": "Protocols", "href": "/protocol/npm/", "pagePrefix": "protocol/" }
],
"protocols": [
{ "label": "exec:", "href": "/protocol/exec/", "page": "protocol/exec" },
{ "label": "file:", "href": "/protocol/file/", "page": "protocol/file" },
{ "label": "git:", "href": "/protocol/git/", "page": "protocol/git" },
{ "label": "jsr:", "href": "/protocol/jsr/", "page": "protocol/jsr" },
{ "label": "link:", "href": "/protocol/link/", "page": "protocol/link" },
{ "label": "npm:", "href": "/protocol/npm/", "page": "protocol/npm" },
{ "label": "patch:", "href": "/protocol/patch/", "page": "protocol/patch" },
{ "label": "portal:", "href": "/protocol/portal/", "page": "protocol/portal" },
{ "label": "workspace:", "href": "/protocol/workspace/", "page": "protocol/workspace" }
]
}
}
}
120 changes: 120 additions & 0 deletions website/config/quiz.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
{
"questions": [
{
"slug": "exec-protocol",
"question": "Can Yarn run a Node.js script at install time to dynamically generate a package on the fly?",
"answer": true,
"wrongLine": "Actually — yes, via the <code>exec:</code> protocol.",
"rightLine": "Correct — it's called the <code>exec:</code> protocol.",
"explain": [
"The <code>exec:</code> protocol lets you point a dependency at a generator script instead of a tarball. Yarn runs that script in a temporary directory at fetch time, and whatever files it produces become the package.",
"The script runs in a special context with an <code>execEnv</code> global that provides the target directory and other metadata. Useful for codegen, platform-specific builds, or any case where a static package isn't enough."
]
},
{
"slug": "builtin-node",
"question": "Can Yarn lock and manage the exact Node.js version used by your project?",
"answer": true,
"wrongLine": "It can — Node.js is treated as a regular locked dependency.",
"rightLine": "Right — and it's locked in <code>yarn.lock</code> like any other package.",
"explain": [
"Yarn lets you declare Node.js as a project dependency via <code>@builtin/node</code>. The version is pinned in <code>yarn.lock</code>, and Yarn automatically downloads the correct binary for each developer's OS and architecture.",
"This means every contributor gets the exact same Node.js version without needing nvm, fnm, or any external version manager — it's part of the dependency graph."
]
},
{
"slug": "pre-post-scripts",
"question": "Does Yarn run <code>prestart</code> automatically before <code>yarn start</code>?",
"answer": false,
"wrongLine": "Unlike npm, Yarn intentionally dropped arbitrary <code>pre</code>/<code>post</code> hooks.",
"rightLine": "Right — Yarn chose clarity over convention.",
"explain": [
"Yarn only supports a handful of well-defined lifecycle hooks (<code>prepack</code>, <code>postpack</code>, <code>postinstall</code>, etc.) and deliberately doesn't run arbitrary <code>pre*</code> and <code>post*</code> scripts.",
"The reasoning: implicit hooks made execution flow hard to follow and debug. If you need to run something before <code>start</code>, Yarn encourages you to make it explicit — for instance via task dependencies or a composite script."
]
},
{
"slug": "ghost-deps",
"question": "Can Yarn throw an error if a package tries to <code>require()</code> a dependency it never declared?",
"answer": true,
"wrongLine": "It does — these are called ghost dependencies, and Yarn catches them.",
"rightLine": "Exactly — Plug'n'Play enforces the dependency contract.",
"explain": [
"With traditional <code>node_modules</code>, hoisting lets packages accidentally import dependencies they don't declare. It works until the hoisting layout changes, then it breaks unpredictably.",
"Under Plug'n'Play, Yarn resolves every <code>require()</code> against the package's declared dependencies. If a package tries to reach something it doesn't list, Yarn throws immediately — surfacing the bug before it hits production."
]
},
{
"slug": "workspace-git",
"question": "Can Yarn install a single workspace from a remote Git repository — without cloning the entire monorepo yourself?",
"answer": true,
"wrongLine": "It can — using the <code>#workspace=</code> syntax on a Git URL.",
"rightLine": "Correct — and not all package managers support this.",
"explain": [
"Yarn's <code>git:</code> protocol supports a <code>#workspace=name</code> fragment. For example, <code>yarn add my-lib@org/monorepo#workspace=my-lib</code> clones the repo, builds the target workspace, and installs just that package.",
"Yarn even auto-detects the repo's package manager from its lock file (Yarn, npm, or pnpm) so it can pack the workspace correctly."
]
},
{
"slug": "constraints-fix",
"question": "Can Yarn automatically fix inconsistent dependency versions across workspaces in a monorepo?",
"answer": true,
"wrongLine": "It can — via <code>yarn constraints --fix</code>.",
"rightLine": "Right — constraints are both a linter and an auto-fixer.",
"explain": [
"Yarn Constraints let you write declarative rules in JavaScript or TypeScript (via <code>yarn.config.cjs</code>) that describe the expected state of every <code>package.json</code> in the project.",
"Run <code>yarn constraints</code> to audit, or <code>yarn constraints --fix</code> to auto-correct. A typical rule: \"every workspace that depends on <code>react</code> must use the same version\" — and Yarn rewrites the manifests for you."
]
},
{
"slug": "no-node-modules",
"question": "Does Yarn support <code>node_modules</code> installs?",
"answer": true,
"wrongLine": "It does — even though Plug'n'Play is the default.",
"rightLine": "Right — even though Plug'n'Play is the default.",
"explain": [
"Since Yarn 2, the default install strategy is Plug'n'Play. Dependencies live as compressed archives in a cache, and a generated <code>.pnp.cjs</code> file tells Node.js where to find each package — no <code>node_modules</code> tree, no phantom dependencies, no hoisting ambiguity.",
"If you prefer a classic layout, you can still opt in with <code>nodeLinker: node-modules</code> in <code>.yarnrc.yml</code>. There's also a <code>pnpm</code> linker mode as a middle ground."
]
},
{
"slug": "parallel-topo",
"question": "Can Yarn run a script in every workspace in parallel while still respecting the dependency graph?",
"answer": true,
"wrongLine": "It can — topological parallelism is built in.",
"rightLine": "Correct — one command, no extra tool needed.",
"explain": [
"<code>yarn workspaces foreach --all --parallel --topological run build</code> runs <code>build</code> in every workspace, starting with leaves and working up the dependency tree. Independent workspaces run in parallel; dependent ones wait.",
"Add <code>--jobs 4</code> to cap concurrency, or <code>--interlaced</code> to stream logs live instead of buffering per workspace."
]
},
{
"slug": "catalog",
"question": "Can Yarn let all monorepo workspaces share a single, centralized set of dependency version ranges?",
"answer": true,
"wrongLine": "It can — that's what the <code>catalog:</code> protocol is for.",
"rightLine": "Right — and it's transparent at publish time.",
"explain": [
"Define shared version ranges in a <code>catalog</code> field, then reference them from any workspace with <code>\"react\": \"catalog:\"</code>. Every workspace gets the same range without duplicating it in each <code>package.json</code>.",
"When you publish, Yarn transparently replaces <code>catalog:</code> references with the actual version range — so consumers never see the protocol and your packages work on any registry."
]
},
{
"slug": "npmrc",
"question": "Does Yarn read its configuration from <code>.npmrc</code>?",
"answer": false,
"wrongLine": "It doesn't — Yarn uses its own <code>.yarnrc.yml</code> format.",
"rightLine": "Right — Yarn has its own configuration system.",
"explain": [
"Yarn 2+ uses <code>.yarnrc.yml</code> — a YAML-based configuration file with a completely different schema from npm's <code>.npmrc</code>. Settings like registry URLs, linker mode, and plugin configuration all live here.",
"This is a common migration pitfall: npm-specific settings in <code>.npmrc</code> (like <code>registry</code> or <code>always-auth</code>) won't be picked up by Yarn. You need to translate them into their <code>.yarnrc.yml</code> equivalents."
]
}
],
"levels": [
{ "min": 0, "title": "Curious", "tag": "Plenty to discover — Yarn has more tricks than most devs realize." },
{ "min": 4, "title": "Familiar", "tag": "You know the basics. A few surprises still lurking in the manual." },
{ "min": 7, "title": "Fluent", "tag": "Confidently above average. You've read past the install section." },
{ "min": 10, "title": "Expert", "tag": "You might be on the Yarn team. Or you should apply." }
]
}
3 changes: 3 additions & 0 deletions website/config/rc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"version": "v5.0.0-rc.2"
}
3 changes: 3 additions & 0 deletions website/config/stable.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"version": "v4.8.1"
}
22 changes: 22 additions & 0 deletions website/config/tips.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[
"Yarn's <span class=\"mono\">exec:</span> protocol can run a Node.js script at install time to generate a package on the fly — useful for codegen or platform-specific builds.",
"You can declare Node.js itself as a project dependency via <span class=\"mono\">@builtin/node</span>. The version is locked in <span class=\"mono\">yarn.lock</span>, and every contributor gets the exact same binary.",
"Scripts with a colon in their name (like <span class=\"mono\">g:tsc</span>) can be called from any workspace — <span class=\"mono\">$INIT_CWD</span> tells you where the call came from.",
"Yarn Constraints use a declarative model: you describe the expected state of every <span class=\"mono\">package.json</span>, and Yarn diffs reality against it — no <span class=\"mono\">if</span> checks needed.",
"When you use zero-installs, storing archives <em>uncompressed</em> in Git actually saves space: Git's delta algorithm works better, shrinking one test repo from 2.1 GiB to 1.25 GiB.",
"The <span class=\"mono\">portal:</span> protocol links to a local package <em>and</em> resolves its own dependencies, while <span class=\"mono\">link:</span> treats the target as an opaque folder with no deps.",
"Yarn automatically applies a curated list of known ghost-dependency fixes from the ecosystem so you don't have to add common <span class=\"mono\">packageExtensions</span> yourself.",
"Virtual packages solve the peer-dependency problem by creating separate instances of the same package for each unique set of peers — something flat <span class=\"mono\">node_modules</span> can't do.",
"Virtual packages use a virtual filesystem layer, not symlinks — avoiding <span class=\"mono\">realpath</span> issues and improving Windows compatibility.",
"Yarn's architecture supports multiple linkers simultaneously. A JavaScript package could theoretically depend on a Python package, each resolved by its own linker.",
"When using <span class=\"mono\">git:</span> dependencies, Yarn detects whether the repo uses Yarn, npm, or pnpm (via its lock file) and packs it with the right tool automatically.",
"Yarn's telemetry is batched roughly every seven days, not per-command. The data goes through <span class=\"mono\">registry.yarnpkg.com</span>, which is just a CNAME to npm's registry — no Yarn backend ever sees the HTTP logs.",
"The <span class=\"mono\">.pnp.cjs</span> file is fully deterministic — you can commit it to version control without creating unnecessary diffs across machines.",
"Yarn maintains an unofficial patch for TypeScript that adds PnP support. It's applied to every downloaded TypeScript version, even if you're using <span class=\"mono\">node-modules</span> linker.",
"Task dependencies support mixed parallelism: suffix a dep with <span class=\"mono\">&amp;</span> to run it in parallel, omit it for a sequential barrier — all in one definition.",
"The <span class=\"mono\">file:</span> protocol copies the folder into the cache rather than linking it. To pick up local changes, run <span class=\"mono\">YARN_UPDATE_FILE_CACHE=1 yarn install</span>.",
"Workspace profiles can extend other profiles, letting you compose complex dev-dependency sets from simple building blocks — but they deliberately only cover devDependencies.",
"Yarn can resolve <span class=\"mono\">yarn.lock</span> merge conflicts automatically. When it detects Git conflict markers, it merges both sides and re-resolves.",
"The <span class=\"mono\">jsr:</span> protocol locks the exact tarball URL in <span class=\"mono\">yarn.lock</span> — because the JSR registry may regenerate tarballs, each revision gets a new immutable URL.",
"You can run a hybrid monorepo: PnP for most workspaces, <span class=\"mono\">node-modules</span> for specific ones that need it — using separate lock files and <span class=\"mono\">pnpIgnorePatterns</span>."
]
43 changes: 43 additions & 0 deletions website/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"devDependencies": {
"puppeteer": "^24.42.0"
},
"name": "@yarnpkg/website",
"type": "module",
"scripts": {
"dev": "astro dev",
"build": "astro build && node --experimental-strip-types scripts/generate-og.ts",
"preview": "astro preview",
"record": "node --experimental-strip-types scripts/record-terminal.ts"
},
"dependencies": {
"@astrojs/react": "^5.0.4",
"@astrojs/sitemap": "^3.7.2",
"@clipanion/astro": "../scripts/@clipanion-astro.tgz",
"@clipanion/tools": "../scripts/@clipanion-tools.tgz",
"@iconify-json/octicon": "^1.2.23",
"@iconify-json/simple-icons": "^1.2.79",
"@monaco-editor/react": "^4.7.0",
"@tailwindcss/vite": "^4.2.4",
"@tanstack/react-router": "^1.169.1",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"algoliasearch": "^5.52.0",
"astro": "^5.9.3",
"mermaid": "^11.0.0",
"prettier": "^3.5.0",
"react": "^19.2.5",
"react-dom": "^19.2.5",
"rehype-raw": "^7.0.0",
"rehype-stringify": "^10.0.1",
"remark-directive": "^4.0.0",
"remark-gfm": "^4.0.1",
"remark-parse": "^11.0.0",
"remark-rehype": "^11.1.2",
"shiki": "^4.0.2",
"tailwindcss": "^4.2.4",
"unified": "^11.0.5",
"unist-util-visit": "^5.1.0",
"vite": "^8.0.9"
}
}
Loading
Loading