Skip to content

Commit

Permalink
fix(react): add migration to install @nrwl/webpack if needed by Story…
Browse files Browse the repository at this point in the history
…book
  • Loading branch information
jaysoo authored and Jack Hsu committed Jan 19, 2023
1 parent 8880e3e commit 6c0ffb0
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 38 deletions.
16 changes: 11 additions & 5 deletions packages/react/plugins/storybook/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@ import {
readJsonFile,
workspaceRoot,
} from '@nrwl/devkit';
import {
composePlugins,
getBaseWebpackPartial,
} from '@nrwl/webpack/src/utils/config';
import { composePlugins } from '@nrwl/webpack/src/utils/config';
import { NormalizedWebpackExecutorOptions } from '@nrwl/webpack/src/executors/webpack/schema';
import { checkAndCleanWithSemver } from '@nrwl/workspace/src/utilities/version-utils';
import { join } from 'path';
Expand All @@ -17,7 +14,6 @@ import { Configuration, DefinePlugin, WebpackPluginInstance } from 'webpack';
import * as mergeWebpack from 'webpack-merge';
import { mergePlugins } from './merge-plugins';
import { withReact } from '../with-react';
import { withNx, withWeb } from '@nrwl/webpack';

// This is shamelessly taken from CRA and modified for NX use
// https://github.com/facebook/create-react-app/blob/4784997f0682e75eb32a897b4ffe34d735912e6c/packages/react-scripts/config/env.js#L71
Expand Down Expand Up @@ -96,7 +92,17 @@ export const webpack = async (
logger.info(
'=> Loading Nrwl React Storybook preset from "@nrwl/react/plugins/storybook"'
);
// In case anyone is missing dep and did not run migrations.
// See: https://github.com/nrwl/nx/issues/14455
try {
require.resolve('@nrwl/webpack');
} catch {
throw new Error(
`'@nrwl/webpack' package is not installed. Install it and try again.`
);
}

const { withNx, withWeb } = require('@nrwl/webpack');
const tsconfigPath = join(options.configDir, 'tsconfig.json');

const builderOptions: NormalizedWebpackExecutorOptions = {
Expand Down
6 changes: 6 additions & 0 deletions packages/storybook/migrations.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@
"version": "15.4.6-beta.0",
"description": "Refactor the Storybook target options",
"factory": "./src/migrations/update-15-4-6/refactor-executor-options"
},
"update-15-5-3": {
"cli": "nx",
"version": "15.5.3-beta.0",
"description": "Add @nrwl/webpack if it is missing and is used.",
"factory": "./src/migrations/update-15-5-3/ensure-webpack-package"
}
},
"packageJsonUpdates": {
Expand Down
3 changes: 3 additions & 0 deletions packages/storybook/src/generators/init/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ function checkDependenciesInstalled(host: Tree, schema: Schema) {
devDependencies['@babel/core'] = babelCoreVersion;
devDependencies['@babel/preset-typescript'] =
babelPresetTypescriptVersion;
if (schema.bundler === 'webpack') {
devDependencies['@nrwl/webpack'] = nxVersion;
}
}

if (schema.uiFramework === '@storybook/web-components') {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
import {
readJson,
writeJson,
addProjectConfiguration,
Tree,
} from '@nrwl/devkit';
import update from './ensure-webpack-package';

describe('ensure-webpack-package', () => {
let tree: Tree;

beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
writeJson(tree, 'package.json', {
dependencies: {},
devDependencies: {
'@nrwl/react': '15.5.0',
},
});
});

it.each`
config
${'main.ts'}
${'main.js'}
`(
'should install @nrwl/webpack if it is needed by React project',
async ({ config }) => {
addProjectConfiguration(tree, 'myapp', {
root: 'myapp',
});
tree.write(
`myapp/.storybook/${config}`,
`
module.exports = {
addons: ['@nrwl/react/plugins/storybook']
};
`
);

await update(tree);

const packageJson = readJson(tree, 'package.json');
expect(packageJson.devDependencies).toEqual({
'@nrwl/react': expect.any(String),
'@nrwl/webpack': expect.any(String),
});
}
);

it.each`
config
${'main.ts'}
${'main.js'}
${null}
`(
'should not install @nrwl/webpack if it is not needed by React project',
async ({ config }) => {
addProjectConfiguration(tree, 'myapp', {
root: 'myapp',
});

if (config) {
tree.write(
`myapp/.storybook/${config}`,
`
module.exports = {
addons: []
};
`
);
}

await update(tree);

const packageJson = readJson(tree, 'package.json');
expect(packageJson.devDependencies).toEqual({
'@nrwl/react': expect.any(String),
});
}
);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import {
addDependenciesToPackageJson,
getProjects,
joinPathFragments,
Tree,
} from '@nrwl/devkit';
import { nxVersion } from '../../utils/versions';

// Add @nrwl/webpack as needed.
// See: https://github.com/nrwl/nx/issues/14455
export default async function update(tree: Tree) {
const projects = getProjects(tree);
const reactPlugin = '@nrwl/react/plugins/storybook';
let shouldInstall = false;

for (const [, config] of projects) {
let sbConfigPath = joinPathFragments(config.root, '.storybook/main.ts');

if (!tree.exists(sbConfigPath)) {
sbConfigPath = joinPathFragments(config.root, '.storybook/main.js');
}

if (!tree.exists(sbConfigPath)) {
continue;
}

const sbConfig = tree.read(sbConfigPath, 'utf-8');
if (sbConfig.includes(reactPlugin)) {
shouldInstall = true;
break;
}
}

if (shouldInstall) {
return addDependenciesToPackageJson(
tree,
{},
{ '@nrwl/webpack': nxVersion }
);
}
}
44 changes: 11 additions & 33 deletions packages/webpack/src/generators/init/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@ import {
addDependenciesToPackageJson,
convertNxGenerator,
formatFiles,
GeneratorCallback,
Tree,
} from '@nrwl/devkit';
import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
import { swcCoreVersion } from '@nrwl/js/src/utils/versions';

import { Schema } from './schema';
Expand All @@ -21,54 +19,34 @@ import {
import { addBabelInputs } from '@nrwl/js/src/utils/add-babel-inputs';

export async function webpackInitGenerator(tree: Tree, schema: Schema) {
const tasks: GeneratorCallback[] = [];

if (schema.compiler === 'babel') {
addBabelInputs(tree);
}
const devDependencies = {};

if (schema.compiler === 'swc') {
const swcInstallTask = addDependenciesToPackageJson(
tree,
{},
{
'@swc/helpers': swcHelpersVersion,
'@swc/core': swcCoreVersion,
'swc-loader': swcLoaderVersion,
}
);
tasks.push(swcInstallTask);
devDependencies['@swc/helpers'] = swcHelpersVersion;
devDependencies['@swc/core'] = swcCoreVersion;
devDependencies['swc-loader'] = swcLoaderVersion;
}

if (schema.compiler === 'tsc') {
const tscInstallTask = addDependenciesToPackageJson(
tree,
{},
{ tslib: tsLibVersion }
);
tasks.push(tscInstallTask);
devDependencies['tslib'] = tsLibVersion;
}

if (schema.uiFramework === 'react') {
const reactInstallTask = addDependenciesToPackageJson(
tree,
{},
{
'@pmmmwh/react-refresh-webpack-plugin':
reactRefreshWebpackPluginVersion,
'@svgr/webpack': svgrWebpackVersion,
'react-refresh': reactRefreshVersion,
'url-loader': urlLoaderVersion,
}
);
tasks.push(reactInstallTask);
devDependencies['@pmmmwh/react-refresh-webpack-plugin'] =
reactRefreshWebpackPluginVersion;
devDependencies['@svgr/webpack'] = svgrWebpackVersion;
devDependencies['react-refresh'] = reactRefreshVersion;
devDependencies['url-loader'] = urlLoaderVersion;
}

if (!schema.skipFormat) {
await formatFiles(tree);
}

return runTasksInSerial(...tasks);
return addDependenciesToPackageJson(tree, {}, devDependencies);
}

export default webpackInitGenerator;
Expand Down

0 comments on commit 6c0ffb0

Please sign in to comment.