Skip to content

Commit 5a967d2

Browse files
committed
starting to implement yarn 2 plug-n-play compatibility
1 parent 462af2d commit 5a967d2

File tree

8 files changed

+554
-368
lines changed

8 files changed

+554
-368
lines changed

.github/workflows/nodejs.yml

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,18 @@ jobs:
2828
run: yarn deduplicate:check
2929

3030
test:
31-
name: Test on Node ${{ matrix.node }} and ${{ matrix.os }}
31+
name: Test on Node ${{ matrix.node }} and ${{ matrix.os }}, yarn2?:${{ matrix.should_use_yarn2 }}
3232

3333
runs-on: ${{ matrix.os }}
3434
strategy:
3535
matrix:
3636
node: ['10.x', '12.x', '14.x']
3737
os: [ubuntu-latest, windows-latest, macOS-latest]
38+
should_use_yarn2: [false]
39+
include:
40+
- node: '10.x'
41+
os: ubuntu-latest
42+
should_use_yarn2: true
3843

3944
steps:
4045
- name: Checkout repo
@@ -47,5 +52,20 @@ jobs:
4752
- name: Install deps and build (with cache)
4853
uses: bahmutov/npm-install@v1
4954

55+
- name: Restore yarn2 cache
56+
if: ${{ matrix.should_use_yarn2 }}
57+
uses: actions/cache@v2
58+
with:
59+
path: |
60+
test/yarn2/.yarn/cache
61+
test/yarn2/yarn.lock
62+
key: cache-key
63+
64+
- name: Setup for yarn2
65+
if: ${{ matrix.should_use_yarn2 }}
66+
run: |
67+
echo 'yarnPath: .yarn/releases/yarn-sources.cjs' >> .yarnrc.yml && yarn && yarn node ./test/utils/prepare-for-yarn2.js && yarn && yarn --version
68+
5069
- name: Test package
51-
run: yarn test:post-build
70+
run: |
71+
yarn --version && yarn node -p 'process.versions.pnp' && yarn test:post-build

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,10 @@ tester-react
77
package-lock.json
88
# Local Netlify folder
99
.netlify
10+
11+
# Files created when running tests under yarn2
12+
/.yarn
13+
!/.yarn/releases
14+
/.yarnrc.yml
15+
/.pnp.js
16+

.yarn/releases/yarn-sources.cjs

Lines changed: 55 additions & 0 deletions
Large diffs are not rendered by default.

package.json

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
"babel-plugin-transform-rename-import": "^2.3.0",
6666
"camelcase": "^6.0.0",
6767
"chalk": "^4.0.0",
68+
"create-require": "^1.0.2",
6869
"enquirer": "^2.3.4",
6970
"eslint": "^6.1.0",
7071
"eslint-config-prettier": "^6.0.0",
@@ -77,7 +78,7 @@
7778
"eslint-plugin-react-hooks": "^2.2.0",
7879
"execa": "^4.0.3",
7980
"fs-extra": "^9.0.0",
80-
"jest": "^25.3.0",
81+
"jest": "^25.4.0",
8182
"jest-watch-typeahead": "^0.5.0",
8283
"jpjs": "^1.2.1",
8384
"lodash.merge": "^4.6.2",
@@ -94,11 +95,12 @@
9495
"semver": "^7.1.1",
9596
"shelljs": "^0.8.3",
9697
"tiny-glob": "^0.2.6",
97-
"ts-jest": "^25.3.1",
98+
"ts-jest": "^25.5.1",
9899
"tslib": "^1.9.3",
99-
"typescript": "^3.7.3"
100+
"typescript": "3.7.3"
100101
},
101102
"devDependencies": {
103+
"@jest/types": "^25.4.0",
102104
"@types/eslint": "^6.1.2",
103105
"@types/fs-extra": "^9.0.1",
104106
"@types/lodash": "^4.14.161",
@@ -114,6 +116,7 @@
114116
"cssnano": "^4.1.10",
115117
"doctoc": "^1.4.0",
116118
"husky": "^4.2.2",
119+
"lodash": "^4.17.20",
117120
"np": "^6.4.0",
118121
"pretty-quick": "^2.0.0",
119122
"react": "^16.8.6",
@@ -123,6 +126,7 @@
123126
"styled-components": "^5.0.1",
124127
"tiny-invariant": "^1.1.0",
125128
"tiny-warning": "^1.0.3",
129+
"type-fest": "^0.13.1",
126130
"yarn-deduplicate": "^2.1.1"
127131
},
128132
"husky": {

src/createJestConfig.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,39 @@
11
import { Config } from '@jest/types';
2+
import path from 'path';
3+
import createRequire from 'create-require';
24

35
export type JestConfigOptions = Partial<Config.InitialOptions>;
46

57
export function createJestConfig(
68
_: (relativePath: string) => void,
79
rootDir: string
810
): JestConfigOptions {
11+
function resolveRelativeTo(file: string, moduleSpecifier: string) {
12+
const req = createRequire(file);
13+
try {
14+
return req.resolve(moduleSpecifier);
15+
} catch {
16+
return null;
17+
}
18+
}
19+
function resolveBabelJest() {
20+
const jestLocation =
21+
resolveRelativeTo(path.join(rootDir, 'file.js'), 'jest') ||
22+
require.resolve('jest');
23+
const jestCoreLocation = resolveRelativeTo(jestLocation, '@jest/core')!;
24+
const jestConfigLocation = resolveRelativeTo(
25+
jestCoreLocation,
26+
'jest-config'
27+
)!;
28+
return (
29+
resolveRelativeTo(path.join(rootDir, 'file.js'), 'babel-jest') ||
30+
resolveRelativeTo(jestConfigLocation, 'babel-jest')!
31+
);
32+
}
933
const config: JestConfigOptions = {
1034
transform: {
1135
'.(ts|tsx)$': require.resolve('ts-jest/dist'),
12-
'.(js|jsx)$': require.resolve('babel-jest'), // jest's default
36+
'.(js|jsx)$': resolveBabelJest(), // jest's default
1337
},
1438
transformIgnorePatterns: ['[/\\\\]node_modules[/\\\\].+\\.(js|jsx)$'],
1539
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],

test/utils/fixture.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ export const rootDir = process.cwd();
55

66
shell.config.silent = true;
77

8+
export function isYarn2() {
9+
return !!process.versions.pnp;
10+
}
11+
812
export function setupStageWithFixture(
913
testDir: string,
1014
stageName: string,
@@ -15,11 +19,13 @@ export function setupStageWithFixture(
1519
shell.exec(
1620
`cp -a ${rootDir}/test/${testDir}/fixtures/${fixtureName}/. ${stagePath}/`
1721
);
18-
shell.ln(
19-
'-s',
20-
path.join(rootDir, 'node_modules'),
21-
path.join(stagePath, 'node_modules')
22-
);
22+
if (!isYarn2()) {
23+
shell.ln(
24+
'-s',
25+
path.join(rootDir, 'node_modules'),
26+
path.join(stagePath, 'node_modules')
27+
);
28+
}
2329
shell.cd(stagePath);
2430
}
2531

test/utils/prepare-for-yarn2.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* yarn 2 requires each package.json to declare the dependencies used by files within its subdirectory.
3+
* tsdx tests are written to use the exact same set of dependencies as the root package.json.
4+
*
5+
* Before running tests under yarn2 PnP, we copy all dependencies and devDependencies from the root
6+
* to each sub-package.json. We also declare these subdirectories as workspaces so `yarn`
7+
* recognizes and resolves them all.
8+
*/
9+
10+
const fs = require('fs-extra');
11+
const shell = require('shelljs');
12+
13+
shell.cd(__dirname);
14+
shell.cd('../..');
15+
const rootPkg = fs.readJSONSync('package.json');
16+
// Declare all stages as workspaces so that a single `yarn` invocation resolves them all.
17+
rootPkg.workspaces = {
18+
workspaces: ['test/e2e/fixtures/*', 'test/integration/fixtures/*', 'stage-*'],
19+
};
20+
fs.writeJSONSync('package.json', rootPkg, { spaces: 2 });
21+
22+
// Copy all root dependencies onto each test package.json
23+
for (const pkgPath of [
24+
shell.ls('test/e2e/fixtures/*/package.json'),
25+
shell.ls('test/integration/fixtures/*/package.json'),
26+
]
27+
.join(',')
28+
.split(',')) {
29+
const pkg = fs.readJSONSync(`./${pkgPath}`);
30+
pkg.dependencies = Object.assign({}, pkg.dependencies, rootPkg.dependencies);
31+
pkg.devDependencies = Object.assign(
32+
{},
33+
pkg.devDependencies,
34+
rootPkg.devDependencies
35+
);
36+
fs.writeJSONSync(pkgPath, pkg, { spaces: 2 });
37+
}

0 commit comments

Comments
 (0)