Skip to content

Commit

Permalink
Make preset-create-react-app compatible with Yarn PnP/Yarn 2
Browse files Browse the repository at this point in the history
Use Plug'n'Play API to find `react-scripts` package location directly with the dependency tree. See https://yarnpkg.com/advanced/pnpapi
  • Loading branch information
gaetanmaisse committed Feb 24, 2020
1 parent fa0e147 commit 05c405e
Show file tree
Hide file tree
Showing 5 changed files with 930 additions and 1,378 deletions.
1 change: 1 addition & 0 deletions packages/preset-create-react-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"dependencies": {
"@storybook/node-logger": "^5.2.0",
"@types/webpack": "^4.41.2",
"pnp-webpack-plugin": "^1.6.4",
"react-docgen-typescript-loader": "^3.6.0",
"semver": "^7.1.3"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,27 @@ const getReactScriptsPath = (): string => {
return '';
};

export { getReactScriptsPath };
const getReactScriptsPathWithYarnPnp = (
packageName = 'react-scripts',
): string => {
// Use Plug'n'Play API to introspect the dependency tree at runtime, see: https://yarnpkg.com/advanced/pnpapi
// eslint-disable-next-line import/no-unresolved,@typescript-eslint/no-var-requires,global-require
const pnpApi = require('pnpapi');

// Get list of all dependencies of the project
const { packageDependencies } = pnpApi.getPackageInformation({
name: null,
reference: null,
});

// Get location of the package named `packageName`, this package must be
// listed as dependency to be able to find it's location (and no more just
// be present in node_modules folder)
const { packageLocation } = pnpApi.getPackageInformation(
pnpApi.getLocator(packageName, packageDependencies.get(packageName)),
);

return packageLocation;
};

export { getReactScriptsPath, getReactScriptsPathWithYarnPnp };
21 changes: 17 additions & 4 deletions packages/preset-create-react-app/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,31 @@
import { join, relative, resolve } from 'path';
import { Configuration } from 'webpack';
import { logger } from '@storybook/node-logger';
import PnpWebpackPlugin from 'pnp-webpack-plugin';
import { mergePlugins } from './helpers/mergePlugins';
import { getReactScriptsPath } from './helpers/getReactScriptsPath';
import {
getReactScriptsPath,
getReactScriptsPathWithYarnPnp,
} from './helpers/getReactScriptsPath';
import { processCraConfig } from './helpers/processCraConfig';
import { checkPresets } from './helpers/checkPresets';
import { getModulePath } from './helpers/getModulePath';
import { Options } from './options';

const CWD = process.cwd();
const REACT_SCRIPTS_PATH = getReactScriptsPath();
// When operating under PnP environments, this value will be set to a number
// indicating the version of the PnP standard, see: https://yarnpkg.com/advanced/pnpapi#processversionspnp
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const IS_USING_YARN_PNP = (process.versions as any).pnp;
const REACT_SCRIPTS_PATH = IS_USING_YARN_PNP
? getReactScriptsPathWithYarnPnp()
: getReactScriptsPath();
const OPTION_SCRIPTS_PACKAGE = 'scriptsPackageName';

// This loader is shared by both the `managerWebpack` and `webpack` functions.
const resolveLoader = {
modules: ['node_modules', join(REACT_SCRIPTS_PATH, 'node_modules')],
plugins: [PnpWebpackPlugin.moduleLoader(module)],
};

// Ensure that loaders are resolved from react-scripts.
Expand All @@ -37,7 +48,9 @@ const webpack = (
const scriptsPackageName = options[OPTION_SCRIPTS_PACKAGE];
if (typeof scriptsPackageName === 'string') {
try {
scriptsPath = require.resolve(scriptsPackageName);
scriptsPath = IS_USING_YARN_PNP
? getReactScriptsPathWithYarnPnp(scriptsPackageName)
: require.resolve(scriptsPackageName);
} catch (e) {
logger.warn(
`A \`${OPTION_SCRIPTS_PACKAGE}\` was provided, but couldn't be resolved.`,
Expand Down Expand Up @@ -118,7 +131,7 @@ const webpack = (
join(REACT_SCRIPTS_PATH, 'node_modules'),
...getModulePath(CWD),
],
plugins,
plugins: plugins.concat([PnpWebpackPlugin]),
},
resolveLoader,
};
Expand Down
1 change: 1 addition & 0 deletions packages/preset-create-react-app/typings.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
declare module 'pnp-webpack-plugin';
Loading

0 comments on commit 05c405e

Please sign in to comment.