Skip to content

Commit 3c8a90a

Browse files
authored
Add configuration option to configure .store folder in pnpm mode (#6710)
This changes adds a configuration option to configure `node_modules/.store` folder when using `nodeLinker: pnpm`. It adds an option `pnpmStoreFolder` to .yarnrc.yml which will be used when installing with pnpm Mode. ## What's the problem this PR addresses? In our CI system we run a few copies of js repos for different architectures in parralel. We want to share the .store folder between the multiple runs, so we have to hoist it outside of the sourceroot. This adds an option to configure this. ``` nodeLinker: pnpm pnpmStoreFolder: ../cache/.store ``` Resolves #6623 ... ## How did you fix it? * Added `configuration` field to `plugin-pnpm` that defines the new option `pnpmStoreFolder` I'm open to naming suggestions. I just followed the pattern defined by `plugin-nm` of prefixing settings with the plugin name like `nmHoistingLimits`, `nmMode` & `nmSelfReferences`. As well as by `plugin-pnp` with setting `pnpUnpluggedFolder` I followed the Folder suffix to match `cacheFolder`, `patchFolder`, `globalFolder`, `virtualFolder` & `pnpUnpluggedFolder`. * Updated the function ` getStoreLocation(project: Project)` to get the setting from the configuration rather than a hardcoded default. * Add type for configuration to match other built-in plugins * Add documentation to docusaurus json file (local testing for this failed) * Added a unittest that makes sure the links are correct ... ## Checklist <!--- Don't worry if you miss something, chores are automatically tested. --> <!--- This checklist exists to help you remember doing the chores when you submit a PR. --> <!--- Put an `x` in all the boxes that apply. --> - [x] I have read the [Contributing Guide](https://yarnpkg.com/advanced/contributing). <!-- See https://yarnpkg.com/advanced/contributing#preparing-your-pr-to-be-released for more details. --> <!-- Check with `yarn version check` and fix with `yarn version check -i` --> - [x] I have set the packages that need to be released for my changes to be effective. <!-- The "Testing chores" workflow validates that your PR follows our guidelines. --> <!-- If it doesn't pass, click on it to see details as to what your PR might be missing. --> - [ ] I will check that all automated PR checks pass before the PR gets reviewed.
1 parent 6b3f3e7 commit 3c8a90a

File tree

5 files changed

+95
-3
lines changed

5 files changed

+95
-3
lines changed

.yarn/versions/81e42c15.yml

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
releases:
2+
"@yarnpkg/cli": minor
3+
"@yarnpkg/plugin-pnpm": minor
4+
5+
declined:
6+
- "@yarnpkg/plugin-compat"
7+
- "@yarnpkg/plugin-constraints"
8+
- "@yarnpkg/plugin-dlx"
9+
- "@yarnpkg/plugin-essentials"
10+
- "@yarnpkg/plugin-init"
11+
- "@yarnpkg/plugin-interactive-tools"
12+
- "@yarnpkg/plugin-nm"
13+
- "@yarnpkg/plugin-npm-cli"
14+
- "@yarnpkg/plugin-pack"
15+
- "@yarnpkg/plugin-patch"
16+
- "@yarnpkg/plugin-pnp"
17+
- "@yarnpkg/plugin-stage"
18+
- "@yarnpkg/plugin-typescript"
19+
- "@yarnpkg/plugin-version"
20+
- "@yarnpkg/plugin-workspace-tools"
21+
- "@yarnpkg/builder"
22+
- "@yarnpkg/core"
23+
- "@yarnpkg/doctor"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import {xfs, ppath} from '@yarnpkg/fslib';
2+
3+
const {
4+
fs: {FsLinkType, determineLinkType},
5+
} = require(`pkg-tests-core`);
6+
7+
const customStoreFolderName = `.customStore`;
8+
9+
describe(`Features`, () => {
10+
describe(`pnpmStoreLocation`, () => {
11+
test(
12+
`it should create the store at custom path and symlink all files to the custom store location`,
13+
makeTemporaryEnv(
14+
{
15+
dependencies: {[`no-deps`]: `1.0.0`},
16+
},
17+
{
18+
nodeLinker: `pnpm`,
19+
pnpmStoreFolder: customStoreFolderName,
20+
winLinkType: `symlinks`,
21+
},
22+
async ({path, run, source}) => {
23+
await run(`install`);
24+
25+
// Ensure that the customized folder is created
26+
const absolutePnpmStorePath = ppath.join(path, customStoreFolderName);
27+
expect(xfs.existsSync(absolutePnpmStorePath)).toEqual(true);
28+
29+
// Ensure that the default node_modules/.store folder is not created
30+
expect(xfs.existsSync(ppath.join(path, `node_modules`, `.store`))).toEqual(false);
31+
32+
// Ensure that the installed package is a symbolic link
33+
const installedPackagePath = ppath.join(path, `node_modules`, `no-deps`);
34+
expect(await determineLinkType(installedPackagePath)).toEqual(FsLinkType.SYMBOLIC);
35+
36+
// Ensure that the link target is a relative path
37+
const installedPackageLinkTarget = await xfs.readlinkPromise(installedPackagePath);
38+
expect(ppath.isAbsolute(installedPackageLinkTarget)).toBeFalsy();
39+
40+
// Ensure that the resolved link target is within the customized pnpmStoreFolder.
41+
const resolvedPackageLinkTarget = ppath.join(ppath.dirname(installedPackagePath), installedPackageLinkTarget);
42+
expect(ppath.contains(absolutePnpmStorePath, resolvedPackageLinkTarget)).toBeTruthy();
43+
},
44+
),
45+
);
46+
});
47+
});

packages/docusaurus/static/configuration/yarnrc.json

+8
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,14 @@
481481
"type": "string",
482482
"default": "pnp"
483483
},
484+
"pnpmStoreFolder": {
485+
"_package": "@yarnpkg/plugin-pnpm",
486+
"title": "Path where the pnpm store will be stored",
487+
"description": "By default, the store is stored in the `node_modules/.store` of the project. Sometimes in CI scenario's it is convenient to store this in a different location so it can be cached and reused.",
488+
"type": "string",
489+
"format": "uri-reference",
490+
"examples": [".cache/.store"]
491+
},
484492
"winLinkType": {
485493
"_package": "@yarnpkg/core",
486494
"title": "Define whether to use junctions or symlinks when creating links on Windows.",

packages/plugin-pnpm/sources/PnpmLinker.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ function getNodeModulesLocation(project: Project) {
309309
}
310310

311311
function getStoreLocation(project: Project) {
312-
return ppath.join(getNodeModulesLocation(project), `.store`);
312+
return project.configuration.get(`pnpmStoreFolder`);
313313
}
314314

315315
function getPackagePaths(locator: Locator, {project}: {project: Project}) {

packages/plugin-pnpm/sources/index.ts

+16-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,24 @@
1-
import {Plugin} from '@yarnpkg/core';
1+
import {Plugin, SettingsType} from '@yarnpkg/core';
2+
import {PortablePath} from '@yarnpkg/fslib';
23

3-
import {PnpmLinker} from './PnpmLinker';
4+
import {PnpmLinker} from './PnpmLinker';
45

56
export {PnpmLinker};
67

8+
declare module '@yarnpkg/core' {
9+
interface ConfigurationValueMap {
10+
pnpmStoreFolder: PortablePath;
11+
}
12+
}
13+
714
const plugin: Plugin = {
15+
configuration: {
16+
pnpmStoreFolder: {
17+
description: `By default, the store is stored in the 'node_modules/.store' of the project. Sometimes in CI scenario's it is convenient to store this in a different location so it can be cached and reused.`,
18+
type: SettingsType.ABSOLUTE_PATH,
19+
default: `./node_modules/.store`,
20+
},
21+
},
822
linkers: [
923
PnpmLinker,
1024
],

0 commit comments

Comments
 (0)