Skip to content

Commit

Permalink
fix(storybook): fix the no-root migration (#14914)
Browse files Browse the repository at this point in the history
  • Loading branch information
mandarini committed Feb 10, 2023
1 parent 47a4ff4 commit 496620e
Show file tree
Hide file tree
Showing 5 changed files with 479 additions and 98 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -98,43 +98,52 @@ exports[`Add addon-essentials to project-level main.js files should add addon-es

exports[`Add addon-essentials to project-level main.js files should add addon-essentials to main.js|ts where possible 4`] = `
"
// project: react-rollup
const rootMain = require('../../../.storybook/main');
const { mergeConfig } = require('vite');
const viteTsConfigPaths = require('vite-tsconfig-paths').default;
// Use the following syntax to add addons!
rootMain.addons.push('@storybook/addon-essentials', '@storybook/addon-a11y');
rootMain.stories.push(
...['../src/lib/**/*.stories.mdx', '../src/lib/**/*.stories.@(js|jsx|ts|tsx)']
);
module.exports = {
...rootMain,
core: { ...rootMain.core, builder: 'webpack5' },
stories: [
...rootMain.stories,
'../src/app/**/*.stories.mdx',
'../src/app/**/*.stories.@(js|jsx|ts|tsx)',
],
addons: ['@storybook/addon-essentials', ...rootMain.addons, '@nrwl/react/plugins/storybook'],
webpackFinal: async (config, { configType }) => {
// apply any global webpack configs that might have been specified in .storybook/main.js
if (rootMain.webpackFinal) {
config = await rootMain.webpackFinal(config, { configType });
}
module.exports = rootMain;
// add your own webpack tweaks if needed
return config;
},
async viteFinal(config, { configType }) {
return mergeConfig(config, {
plugins: [
viteTsConfigPaths({
root: '../../../',
}),
],
});
},
};
module.exports.core = { ...module.exports.core, builder: 'webpack5' };
"
`;

exports[`Add addon-essentials to project-level main.js files should add addon-essentials to main.js|ts where possible 5`] = `
"
// project: react-rollup-3
const rootMain = require('../../../.storybook/main');
// Use the following syntax to add addons!
rootMain.addons.push('@storybook/addon-essentials', );
rootMain.stories.push(
...['../src/lib/**/*.stories.mdx', '../src/lib/**/*.stories.@(js|jsx|ts|tsx)']
);
module.exports = rootMain;
module.exports.core = { ...module.exports.core, builder: 'webpack5' };
"
`;

exports[`Add addon-essentials to project-level main.js files should add addon-essentials to main.js|ts where possible 6`] = `
"
// project: react-rollup-4
const rootMain = require('../../../.storybook/main');
rootMain.addons.push('@storybook/addon-essentials');
rootMain.stories.push(
...['../src/lib/**/*.stories.mdx', '../src/lib/**/*.stories.@(js|jsx|ts|tsx)']
);
module.exports = rootMain;
module.exports.core = { ...module.exports.core, builder: 'webpack5' };
"
`;

exports[`Add addon-essentials to project-level main.js files should add addon-essentials to main.js|ts where possible 7`] = `
"
const rootMain = require('../../../.storybook/main');
const { mergeConfig } = require('vite');
Expand Down Expand Up @@ -172,7 +181,7 @@ exports[`Add addon-essentials to project-level main.js files should add addon-es
"
`;

exports[`Add addon-essentials to project-level main.js files should add addon-essentials to main.js|ts where possible 6`] = `
exports[`Add addon-essentials to project-level main.js files should add addon-essentials to main.js|ts where possible 8`] = `
"
some invalid stuff
"
Expand Down Expand Up @@ -292,40 +301,52 @@ exports[`Add addon-essentials to project-level main.js files should remove the r

exports[`Add addon-essentials to project-level main.js files should remove the root config import and delete root file 4`] = `
"
// project: react-rollup
// Use the following syntax to add addons!
const { mergeConfig } = require('vite');
const viteTsConfigPaths = require('vite-tsconfig-paths').default;
module.exports = {
core: { builder: 'webpack5' },
stories: [
'../src/app/**/*.stories.mdx',
'../src/app/**/*.stories.@(js|jsx|ts|tsx)',
],
addons: ['@storybook/addon-essentials', '@nrwl/react/plugins/storybook'],
webpackFinal: async (config, { configType }) => {
// apply any global webpack configs that might have been specified in .storybook/main.js
// add your own webpack tweaks if needed
module.exports = rootMain;
return config;
},
async viteFinal(config, { configType }) {
return mergeConfig(config, {
plugins: [
viteTsConfigPaths({
root: '../../../',
}),
],
});
},
};
"
module.exports.core = { ...module.exports.core, builder: 'webpack5' };
module.exports.addons = ['@storybook/addon-essentials', '@storybook/addon-a11y'];
module.exports.stories = ['../src/lib/**/*.stories.mdx', '../src/lib/**/*.stories.@(js|jsx|ts|tsx)'];
"
`;

exports[`Add addon-essentials to project-level main.js files should remove the root config import and delete root file 5`] = `
"
// project: react-rollup-3
// Use the following syntax to add addons!
module.exports = rootMain;
module.exports.core = { ...module.exports.core, builder: 'webpack5' };
module.exports.addons = ['@storybook/addon-essentials'];
module.exports.stories = ['../src/lib/**/*.stories.mdx', '../src/lib/**/*.stories.@(js|jsx|ts|tsx)'];
"
`;

exports[`Add addon-essentials to project-level main.js files should remove the root config import and delete root file 6`] = `
"
// project: react-rollup-4
module.exports = rootMain;
module.exports.core = { ...module.exports.core, builder: 'webpack5' };
module.exports.addons = ['@storybook/addon-essentials'];
module.exports.stories = ['../src/lib/**/*.stories.mdx', '../src/lib/**/*.stories.@(js|jsx|ts|tsx)'];
"
`;

exports[`Add addon-essentials to project-level main.js files should remove the root config import and delete root file 7`] = `
"
const { mergeConfig } = require('vite');
Expand Down Expand Up @@ -360,7 +381,7 @@ exports[`Add addon-essentials to project-level main.js files should remove the r
"
`;

exports[`Add addon-essentials to project-level main.js files should remove the root config import and delete root file 6`] = `
exports[`Add addon-essentials to project-level main.js files should remove the root config import and delete root file 8`] = `
"
some invalid stuff
"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ describe('Add addon-essentials to project-level main.js files', () => {
expect(
tree.read('libs/react-rollup/.storybook/main.js', 'utf-8')
).toMatchSnapshot();
expect(
tree.read('libs/react-rollup-3/.storybook/main.js', 'utf-8')
).toMatchSnapshot();
expect(
tree.read('libs/react-rollup-4/.storybook/main.js', 'utf-8')
).toMatchSnapshot();
expect(
tree.read('libs/react-vite/.storybook/main.js', 'utf-8')
).toMatchSnapshot();
Expand Down Expand Up @@ -110,6 +116,12 @@ describe('Add addon-essentials to project-level main.js files', () => {
expect(
tree.read('libs/react-rollup/.storybook/main.js', 'utf-8')
).toMatchSnapshot();
expect(
tree.read('libs/react-rollup-3/.storybook/main.js', 'utf-8')
).toMatchSnapshot();
expect(
tree.read('libs/react-rollup-4/.storybook/main.js', 'utf-8')
).toMatchSnapshot();
expect(
tree.read('libs/react-vite/.storybook/main.js', 'utf-8')
).toMatchSnapshot();
Expand Down Expand Up @@ -192,6 +204,56 @@ export function addAllProjectsToWorkspace(tree: Tree) {
some invalid stuff
`
);
} else if (name === 'react-rollup') {
tree.write(
`${project.targets['build-storybook']?.options?.configDir}/main.js`,
`
// project: ${name}
const rootMain = require('../../../.storybook/main');
// Use the following syntax to add addons!
rootMain.addons.push('@storybook/addon-a11y');
rootMain.stories.push(
...['../src/lib/**/*.stories.mdx', '../src/lib/**/*.stories.@(js|jsx|ts|tsx)']
);
module.exports = rootMain;
module.exports.core = { ...module.exports.core, builder: 'webpack5' };
`
);
} else if (name === 'react-rollup-3') {
tree.write(
`${project.targets['build-storybook']?.options?.configDir}/main.js`,
`
// project: ${name}
const rootMain = require('../../../.storybook/main');
// Use the following syntax to add addons!
rootMain.addons.push();
rootMain.stories.push(
...['../src/lib/**/*.stories.mdx', '../src/lib/**/*.stories.@(js|jsx|ts|tsx)']
);
module.exports = rootMain;
module.exports.core = { ...module.exports.core, builder: 'webpack5' };
`
);
} else if (name === 'react-rollup-4') {
tree.write(
`${project.targets['build-storybook']?.options?.configDir}/main.js`,
`
// project: ${name}
const rootMain = require('../../../.storybook/main');
rootMain.stories.push(
...['../src/lib/**/*.stories.mdx', '../src/lib/**/*.stories.@(js|jsx|ts|tsx)']
);
module.exports = rootMain;
module.exports.core = { ...module.exports.core, builder: 'webpack5' };
`
);
} else {
tree.write(
`${project.targets['build-storybook']?.options?.configDir}/main.js`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
} from '@nrwl/devkit';
import { forEachExecutorOptions } from '@nrwl/workspace/src/utilities/executor-options-utils';
import { tsquery } from '@phenomnomnominal/tsquery';
import ts = require('typescript');
import { removeRootConfig } from './remove-root-config';

/**
Expand Down Expand Up @@ -229,6 +230,63 @@ function transformMainJsTs(tree: Tree, mainJsTsPath: string): boolean {
]);
tree.write(mainJsTsPath, mainJsTs);
return true;
} else {
/**
* main.js has potentially a different structure
* sort of like this:
* rootMain.addons.push(' ...)
* rootMain.stories.push(' ...)
* Like in older versions of Nx
*/

const { rootMainVariableName, importExpression } =
getRootMainVariableName(mainJsTs);

// If there is a PropertyAccessExpression with the text rootMain.addons
// then check if it has addon-essentials, if not add it
const addonsPropertyAccessExpression = tsquery.query(
mainJsTs,
`PropertyAccessExpression:has([expression.name="${rootMainVariableName}"]):has([name="addons"])`
)?.[0];

if (rootMainVariableName && importExpression) {
if (
addonsPropertyAccessExpression?.getText() ===
`${rootMainVariableName}.addons.push`
) {
const parentCallExpression = addonsPropertyAccessExpression.parent;

// see if parentCallExpression contains a StringLiteral with the text '@storybook/addon-essentials'
const hasAddonEssentials = !!tsquery
.query(
parentCallExpression,
`StringLiteral:has([text="@storybook/addon-essentials"])`
)?.[0]
?.getText();

if (!hasAddonEssentials) {
mainJsTs = applyChangesToString(mainJsTs, [
{
type: ChangeType.Insert,
index: addonsPropertyAccessExpression.getEnd() + 1,
text: `'@storybook/addon-essentials', `,
},
]);
tree.write(mainJsTsPath, mainJsTs);
return true;
}
} else {
mainJsTs = applyChangesToString(mainJsTs, [
{
type: ChangeType.Insert,
index: importExpression.getEnd() + 1,
text: `${rootMainVariableName}.addons.push('@storybook/addon-essentials');`,
},
]);
tree.write(mainJsTsPath, mainJsTs);
return true;
}
}
}
return false;
}
Expand Down Expand Up @@ -264,3 +322,49 @@ function removeStoriesArrayFromRootIfEmpty(
}
}
}

export function getRootMainVariableName(mainJsTs: string): {
rootMainVariableName: string;
importExpression: ts.Node;
} {
const requireVariableStatement = tsquery.query(
mainJsTs,
`VariableStatement:has(CallExpression:has(Identifier[name="require"]))`
);

let rootMainVariableName;
let importExpression;

if (requireVariableStatement.length) {
importExpression = requireVariableStatement.find((statement) => {
const requireCallExpression = tsquery.query(
statement,
'CallExpression:has(Identifier[name="require"])'
);
return requireCallExpression?.[0]?.getText()?.includes('.storybook/main');
});

if (importExpression) {
rootMainVariableName = tsquery
.query(importExpression, 'Identifier')?.[0]
?.getText();
}
} else {
const importDeclarations = tsquery.query(mainJsTs, 'ImportDeclaration');
importExpression = importDeclarations.find((statement) => {
const stringLiteral = tsquery.query(statement, 'StringLiteral');
return stringLiteral?.[0]?.getText()?.includes('.storybook/main');
});

if (importExpression) {
rootMainVariableName = tsquery
.query(importExpression, 'ImportSpecifier')?.[0]
?.getText();
}
}

return {
rootMainVariableName,
importExpression,
};
}
Loading

0 comments on commit 496620e

Please sign in to comment.