Skip to content

Commit 2322d0e

Browse files
Use yarn when running in monorepo, facebook#3997
1 parent 22d9169 commit 2322d0e

File tree

9 files changed

+83
-42
lines changed

9 files changed

+83
-42
lines changed

packages/create-react-app/createReactApp.js

+8-3
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ const url = require('url');
4949
const hyperquest = require('hyperquest');
5050
const envinfo = require('envinfo');
5151
const os = require('os');
52-
52+
const findMonorepo = require('react-dev-utils/workspaceUtils').findMonorepo;
5353
const packageJson = require('./package.json');
5454

5555
// These files should be allowed to remain on a failed install,
@@ -216,7 +216,7 @@ function createApp(
216216
JSON.stringify(packageJson, null, 2) + os.EOL
217217
);
218218

219-
const useYarn = useNpm ? false : shouldUseYarn();
219+
const useYarn = useNpm ? false : shouldUseYarn(root);
220220
const originalDirectory = process.cwd();
221221
process.chdir(root);
222222
if (!useYarn && !checkThatNpmCanReadCwd()) {
@@ -288,7 +288,7 @@ function createApp(
288288
);
289289
}
290290

291-
function shouldUseYarn() {
291+
function isYarnAvailable() {
292292
try {
293293
execSync('yarnpkg --version', { stdio: 'ignore' });
294294
return true;
@@ -297,6 +297,11 @@ function shouldUseYarn() {
297297
}
298298
}
299299

300+
function shouldUseYarn(appDir) {
301+
const mono = findMonorepo(appDir);
302+
return (mono.isYarnWs && mono.isAppIncluded) || isYarnAvailable();
303+
}
304+
300305
function install(root, useYarn, usePnp, dependencies, verbose, isOnline) {
301306
return new Promise((resolve, reject) => {
302307
let command;

packages/create-react-app/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
"envinfo": "5.10.0",
2929
"fs-extra": "5.0.0",
3030
"hyperquest": "2.1.3",
31+
"react-dev-utils": "6.0.4",
3132
"semver": "5.5.1",
3233
"tar-pack": "3.4.1",
3334
"tmp": "0.0.33",

packages/react-dev-utils/package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@
4141
"typescriptFormatter.js",
4242
"WatchMissingNodeModulesPlugin.js",
4343
"WebpackDevServerUtils.js",
44-
"webpackHotDevClient.js"
44+
"webpackHotDevClient.js",
45+
"workspaceUtils.js"
4546
],
4647
"dependencies": {
4748
"@babel/code-frame": "7.0.0",
@@ -52,6 +53,7 @@
5253
"detect-port-alt": "1.1.6",
5354
"escape-string-regexp": "1.0.5",
5455
"filesize": "3.6.1",
56+
"find-pkg": "1.0.0",
5557
"find-up": "3.0.0",
5658
"global-modules": "1.0.0",
5759
"globby": "8.0.1",
+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/**
2+
* Copyright (c) 2018-present, Facebook, Inc.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
'use strict';
9+
const fs = require('fs');
10+
const path = require('path');
11+
const findPkg = require('find-pkg');
12+
const globby = require('globby');
13+
14+
const findPkgs = (rootPath, globPatterns) => {
15+
if (!globPatterns) {
16+
return [];
17+
}
18+
const globOpts = {
19+
cwd: rootPath,
20+
strict: true,
21+
absolute: true,
22+
};
23+
return globPatterns
24+
.reduce(
25+
(pkgs, pattern) =>
26+
pkgs.concat(globby.sync(path.join(pattern, 'package.json'), globOpts)),
27+
[]
28+
)
29+
.map(f => path.dirname(path.normalize(f)));
30+
};
31+
32+
const findMonorepo = appDir => {
33+
const monoPkgPath = findPkg.sync(path.resolve(appDir, '..'));
34+
const monoPkg = monoPkgPath && require(monoPkgPath);
35+
const patterns = monoPkg && monoPkg.workspaces;
36+
const isYarnWs = Boolean(patterns);
37+
const allPkgs = patterns && findPkgs(path.dirname(monoPkgPath), patterns);
38+
const isIncluded = dir => allPkgs && allPkgs.indexOf(dir) !== -1;
39+
const isAppIncluded = isIncluded(appDir);
40+
const pkgs = allPkgs
41+
? allPkgs.filter(f => fs.realpathSync(f) !== appDir)
42+
: [];
43+
44+
return {
45+
isAppIncluded,
46+
isYarnWs,
47+
pkgs,
48+
};
49+
};
50+
51+
module.exports = {
52+
findMonorepo,
53+
};

packages/react-scripts/config/paths.js

+9-31
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@
1111
const path = require('path');
1212
const fs = require('fs');
1313
const url = require('url');
14-
const findPkg = require('find-pkg');
15-
const globby = require('globby');
14+
const findMonorepo = require('react-dev-utils/workspaceUtils').findMonorepo;
1615

1716
// Make sure any symlinks in the project folder are resolved:
1817
// https://github.com/facebook/create-react-app/issues/637
@@ -159,37 +158,16 @@ module.exports.moduleFileExtensions = moduleFileExtensions;
159158

160159
module.exports.srcPaths = [module.exports.appSrc];
161160

162-
const findPkgs = (rootPath, globPatterns) => {
163-
const globOpts = {
164-
cwd: rootPath,
165-
strict: true,
166-
absolute: true,
167-
};
168-
return globPatterns
169-
.reduce(
170-
(pkgs, pattern) =>
171-
pkgs.concat(globby.sync(path.join(pattern, 'package.json'), globOpts)),
172-
[]
173-
)
174-
.map(f => path.dirname(path.normalize(f)));
175-
};
176-
177-
const getMonorepoPkgPaths = () => {
178-
const monoPkgPath = findPkg.sync(path.resolve(appDirectory, '..'));
179-
if (monoPkgPath) {
180-
// get monorepo config from yarn workspace
181-
const pkgPatterns = require(monoPkgPath).workspaces;
182-
const pkgPaths = findPkgs(path.dirname(monoPkgPath), pkgPatterns);
183-
// only include monorepo pkgs if app itself is included in monorepo
184-
if (pkgPaths.indexOf(appDirectory) !== -1) {
185-
return pkgPaths.filter(f => fs.realpathSync(f) !== appDirectory);
186-
}
187-
}
188-
return [];
189-
};
161+
module.exports.useYarn = fs.existsSync(
162+
path.join(module.exports.appPath, 'yarn.lock')
163+
);
190164

191165
if (checkForMonorepo) {
192166
// if app is in a monorepo (lerna or yarn workspace), treat other packages in
193167
// the monorepo as if they are app source
194-
Array.prototype.push.apply(module.exports.srcPaths, getMonorepoPkgPaths());
168+
const mono = findMonorepo(appDirectory);
169+
if (mono.isAppIncluded) {
170+
Array.prototype.push.apply(module.exports.srcPaths, mono.pkgs);
171+
}
172+
module.exports.useYarn = module.exports.useYarn || mono.isYarnWs;
195173
}

packages/react-scripts/package.json

-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@
4949
"find-pkg": "1.0.0",
5050
"fork-ts-checker-webpack-plugin-alt": "0.4.14",
5151
"fs-extra": "7.0.0",
52-
"globby": "7.1.1",
5352
"html-webpack-plugin": "4.0.0-alpha.2",
5453
"identity-obj-proxy": "3.0.0",
5554
"jest": "23.6.0",

packages/react-scripts/scripts/build.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ const printBuildError = require('react-dev-utils/printBuildError');
4747
const measureFileSizesBeforeBuild =
4848
FileSizeReporter.measureFileSizesBeforeBuild;
4949
const printFileSizesAfterBuild = FileSizeReporter.printFileSizesAfterBuild;
50-
const useYarn = fs.existsSync(paths.yarnLockFile);
5150

5251
// These sizes are pretty large. We'll warn for bundles exceeding them.
5352
const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024;
@@ -120,7 +119,7 @@ checkBrowsers(paths.appPath, isInteractive)
120119
publicUrl,
121120
publicPath,
122121
buildFolder,
123-
useYarn
122+
paths.useYarn
124123
);
125124
},
126125
err => {

packages/react-scripts/scripts/eject.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ inquirer
251251
}
252252
}
253253

254-
if (fs.existsSync(paths.yarnLockFile)) {
254+
if (paths.useYarn) {
255255
const windowsCmdFilePath = path.join(
256256
appPath,
257257
'node_modules',

packages/react-scripts/scripts/start.js

+7-3
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ const verifyTypeScriptSetup = require('./utils/verifyTypeScriptSetup');
3131
verifyTypeScriptSetup();
3232
// @remove-on-eject-end
3333

34-
const fs = require('fs');
3534
const chalk = require('chalk');
3635
const webpack = require('webpack');
3736
const WebpackDevServer = require('webpack-dev-server');
@@ -48,7 +47,6 @@ const paths = require('../config/paths');
4847
const config = require('../config/webpack.config.dev');
4948
const createDevServerConfig = require('../config/webpackDevServer.config');
5049

51-
const useYarn = fs.existsSync(paths.yarnLockFile);
5250
const isInteractive = process.stdout.isTTY;
5351

5452
// Warn and crash if required files are missing
@@ -95,7 +93,13 @@ checkBrowsers(paths.appPath, isInteractive)
9593
const appName = require(paths.appPackageJson).name;
9694
const urls = prepareUrls(protocol, HOST, port);
9795
// Create a webpack compiler that is configured with custom messages.
98-
const compiler = createCompiler(webpack, config, appName, urls, useYarn);
96+
const compiler = createCompiler(
97+
webpack,
98+
config,
99+
appName,
100+
urls,
101+
paths.useYarn
102+
);
99103
// Load proxy config
100104
const proxySetting = require(paths.appPackageJson).proxy;
101105
const proxyConfig = prepareProxy(proxySetting, paths.appPublic);

0 commit comments

Comments
 (0)