You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

163 lines
6.6 KiB

  1. // @remove-file-on-eject
  2. /**
  3. * Copyright (c) 2015-present, Facebook, Inc.
  4. *
  5. * This source code is licensed under the MIT license found in the
  6. * LICENSE file in the root directory of this source tree.
  7. */
  8. 'use strict';
  9. const chalk = require('chalk');
  10. const fs = require('fs');
  11. const path = require('path');
  12. // We assume that having wrong versions of these
  13. // in the tree will likely break your setup.
  14. // This is a relatively low-effort way to find common issues.
  15. function verifyPackageTree() {
  16. const depsToCheck = [
  17. // These are packages most likely to break in practice.
  18. // See https://github.com/facebook/create-react-app/issues/1795 for reasons why.
  19. // I have not included Babel here because plugins typically don't import Babel (so it's not affected).
  20. 'babel-eslint',
  21. 'babel-jest',
  22. 'babel-loader',
  23. 'eslint',
  24. 'jest',
  25. 'webpack',
  26. 'webpack-dev-server',
  27. ];
  28. // Inlined from semver-regex, MIT license.
  29. // Don't want to make this a dependency after ejecting.
  30. const getSemverRegex = () =>
  31. /\bv?(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[\da-z-]+(?:\.[\da-z-]+)*)?(?:\+[\da-z-]+(?:\.[\da-z-]+)*)?\b/gi;
  32. const ownPackageJson = require('../../package.json');
  33. const expectedVersionsByDep = {};
  34. // Gather wanted deps
  35. depsToCheck.forEach(dep => {
  36. const expectedVersion = ownPackageJson.dependencies[dep];
  37. if (!expectedVersion) {
  38. throw new Error('This dependency list is outdated, fix it.');
  39. }
  40. if (!getSemverRegex().test(expectedVersion)) {
  41. throw new Error(
  42. `The ${dep} package should be pinned, instead got version ${expectedVersion}.`
  43. );
  44. }
  45. expectedVersionsByDep[dep] = expectedVersion;
  46. });
  47. // Verify we don't have other versions up the tree
  48. let currentDir = __dirname;
  49. // eslint-disable-next-line no-constant-condition
  50. while (true) {
  51. const previousDir = currentDir;
  52. currentDir = path.resolve(currentDir, '..');
  53. if (currentDir === previousDir) {
  54. // We've reached the root.
  55. break;
  56. }
  57. const maybeNodeModules = path.resolve(currentDir, 'node_modules');
  58. if (!fs.existsSync(maybeNodeModules)) {
  59. continue;
  60. }
  61. depsToCheck.forEach(dep => {
  62. const maybeDep = path.resolve(maybeNodeModules, dep);
  63. if (!fs.existsSync(maybeDep)) {
  64. return;
  65. }
  66. const maybeDepPackageJson = path.resolve(maybeDep, 'package.json');
  67. if (!fs.existsSync(maybeDepPackageJson)) {
  68. return;
  69. }
  70. const depPackageJson = JSON.parse(
  71. fs.readFileSync(maybeDepPackageJson, 'utf8')
  72. );
  73. const expectedVersion = expectedVersionsByDep[dep];
  74. if (depPackageJson.version !== expectedVersion) {
  75. console.error(
  76. chalk.red(
  77. `\nThere might be a problem with the project dependency tree.\n` +
  78. `It is likely ${chalk.bold(
  79. 'not'
  80. )} a bug in Create React App, but something you need to fix locally.\n\n`
  81. ) +
  82. `The ${chalk.bold(
  83. ownPackageJson.name
  84. )} package provided by Create React App requires a dependency:\n\n` +
  85. chalk.green(
  86. ` "${chalk.bold(dep)}": "${chalk.bold(expectedVersion)}"\n\n`
  87. ) +
  88. `Don't try to install it manually: your package manager does it automatically.\n` +
  89. `However, a different version of ${chalk.bold(
  90. dep
  91. )} was detected higher up in the tree:\n\n` +
  92. ` ${chalk.bold(chalk.red(maybeDep))} (version: ${chalk.bold(
  93. chalk.red(depPackageJson.version)
  94. )}) \n\n` +
  95. `Manually installing incompatible versions is known to cause hard-to-debug issues.\n\n` +
  96. chalk.red(
  97. `If prefer to ignore this check, add ${chalk.bold(
  98. 'SKIP_PREFLIGHT_CHECK=true'
  99. )} to an ${chalk.bold('.env')} file in your project.\n` +
  100. `That will permanently disable this message but you might encounter other issues.\n\n`
  101. ) +
  102. `To ${chalk.green(
  103. 'fix'
  104. )} the dependency tree, try following the steps below in the exact order:\n\n` +
  105. ` ${chalk.cyan('1.')} Delete ${chalk.bold(
  106. 'package-lock.json'
  107. )} (${chalk.underline('not')} ${chalk.bold(
  108. 'package.json'
  109. )}!) and/or ${chalk.bold('yarn.lock')} in your project folder.\n` +
  110. ` ${chalk.cyan('2.')} Delete ${chalk.bold(
  111. 'node_modules'
  112. )} in your project folder.\n` +
  113. ` ${chalk.cyan('3.')} Remove "${chalk.bold(
  114. dep
  115. )}" from ${chalk.bold('dependencies')} and/or ${chalk.bold(
  116. 'devDependencies'
  117. )} in the ${chalk.bold(
  118. 'package.json'
  119. )} file in your project folder.\n` +
  120. ` ${chalk.cyan('4.')} Run ${chalk.bold(
  121. 'npm install'
  122. )} or ${chalk.bold(
  123. 'yarn'
  124. )}, depending on the package manager you use.\n\n` +
  125. `In most cases, this should be enough to fix the problem.\n` +
  126. `If this has not helped, there are a few other things you can try:\n\n` +
  127. ` ${chalk.cyan('5.')} If you used ${chalk.bold(
  128. 'npm'
  129. )}, install ${chalk.bold(
  130. 'yarn'
  131. )} (http://yarnpkg.com/) and repeat the above steps with it instead.\n` +
  132. ` This may help because npm has known issues with package hoisting which may get resolved in future versions.\n\n` +
  133. ` ${chalk.cyan('6.')} Check if ${chalk.bold(
  134. maybeDep
  135. )} is outside your project directory.\n` +
  136. ` For example, you might have accidentally installed something in your home folder.\n\n` +
  137. ` ${chalk.cyan('7.')} Try running ${chalk.bold(
  138. `npm ls ${dep}`
  139. )} in your project folder.\n` +
  140. ` This will tell you which ${chalk.underline(
  141. 'other'
  142. )} package (apart from the expected ${chalk.bold(
  143. ownPackageJson.name
  144. )}) installed ${chalk.bold(dep)}.\n\n` +
  145. `If nothing else helps, add ${chalk.bold(
  146. 'SKIP_PREFLIGHT_CHECK=true'
  147. )} to an ${chalk.bold('.env')} file in your project.\n` +
  148. `That would permanently disable this preflight check in case you want to proceed anyway.\n\n` +
  149. chalk.cyan(
  150. `P.S. We know this message is long but please read the steps above :-) We hope you find them helpful!\n`
  151. )
  152. );
  153. process.exit(1);
  154. }
  155. });
  156. }
  157. }
  158. module.exports = verifyPackageTree;