feat(storybook): migrator for webpack 5
This commit is contained in:
parent
0f85b49065
commit
fd3868c94e
@ -98,6 +98,12 @@
|
|||||||
"version": "13.0.0-beta.0",
|
"version": "13.0.0-beta.0",
|
||||||
"description": "Update tsconfig.json to use `jsxImportSource` to support css prop",
|
"description": "Update tsconfig.json to use `jsxImportSource` to support css prop",
|
||||||
"factory": "./src/migrations/update-13-0-0/update-emotion-setup"
|
"factory": "./src/migrations/update-13-0-0/update-emotion-setup"
|
||||||
|
},
|
||||||
|
"migrate-storybook-to-webpack-5-13.0.0": {
|
||||||
|
"cli": "nx",
|
||||||
|
"version": "13.0.0-beta.0",
|
||||||
|
"description": "Migrate Storybook to use webpack 5",
|
||||||
|
"factory": "./src/migrations/update-13-0-0/migrate-storybook-to-webpack-5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"packageJsonUpdates": {
|
"packageJsonUpdates": {
|
||||||
|
|||||||
@ -0,0 +1,361 @@
|
|||||||
|
import { readJson, Tree, updateJson } from '@nrwl/devkit';
|
||||||
|
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
||||||
|
import { migrateStorybookToWebPack5 } from './migrate-storybook-to-webpack-5';
|
||||||
|
|
||||||
|
describe('migrateStorybookToWebPack5', () => {
|
||||||
|
let tree: Tree;
|
||||||
|
beforeEach(() => {
|
||||||
|
tree = createTreeWithEmptyWorkspace();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add packages needed by Storybook if workspace has the @storybook/react package', async () => {
|
||||||
|
updateJson(tree, 'package.json', (json) => {
|
||||||
|
json.devDependencies = {
|
||||||
|
'@storybook/react': '~6.3.0',
|
||||||
|
};
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
await migrateStorybookToWebPack5(tree);
|
||||||
|
|
||||||
|
const json = readJson(tree, '/package.json');
|
||||||
|
|
||||||
|
expect(json.devDependencies['@storybook/builder-webpack5']).toBe('~6.3.0');
|
||||||
|
expect(json.devDependencies['@storybook/manager-webpack5']).toBe('~6.3.0');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not add the webpack Storybook packages again if they already exist', async () => {
|
||||||
|
let newTree = createTreeWithEmptyWorkspace();
|
||||||
|
updateJson(newTree, 'package.json', (json) => {
|
||||||
|
json.dependencies = {
|
||||||
|
'@storybook/react': '~6.3.0',
|
||||||
|
'@storybook/builder-webpack5': '~6.3.0',
|
||||||
|
'@storybook/manager-webpack5': '~6.3.0',
|
||||||
|
};
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
await migrateStorybookToWebPack5(newTree);
|
||||||
|
const json = readJson(newTree, '/package.json');
|
||||||
|
expect(json.devDependencies['@storybook/builder-webpack5']).toBeUndefined();
|
||||||
|
expect(json.devDependencies['@storybook/manager-webpack5']).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not add Storybook packages if @storybook/react does not exist', async () => {
|
||||||
|
updateJson(tree, 'package.json', (json) => {
|
||||||
|
json.devDependencies = {
|
||||||
|
'@storybook/angular': '~6.3.0',
|
||||||
|
};
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
await migrateStorybookToWebPack5(tree);
|
||||||
|
const json = readJson(tree, '/package.json');
|
||||||
|
expect(json.devDependencies['@storybook/builder-webpack5']).toBeUndefined();
|
||||||
|
expect(json.devDependencies['@storybook/manager-webpack5']).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('updating project-level .storybook/main.js configurations for webpack 5', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
updateJson(tree, 'package.json', (json) => {
|
||||||
|
json.devDependencies = {
|
||||||
|
'@storybook/react': '~6.3.0',
|
||||||
|
};
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
updateJson(tree, 'workspace.json', (json) => {
|
||||||
|
json = {
|
||||||
|
...json,
|
||||||
|
projects: {
|
||||||
|
...json.projects,
|
||||||
|
'test-one': {
|
||||||
|
targets: {
|
||||||
|
storybook: {
|
||||||
|
options: {
|
||||||
|
uiFramework: '@storybook/react',
|
||||||
|
config: {
|
||||||
|
configFolder: 'libs/test-one/.storybook',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'test-two': {
|
||||||
|
targets: {
|
||||||
|
storybook: {
|
||||||
|
options: {
|
||||||
|
uiFramework: '@storybook/react',
|
||||||
|
config: {
|
||||||
|
configFolder: 'libs/test-two/.storybook',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
tree.write(
|
||||||
|
`.storybook/main.js`,
|
||||||
|
`module.exports = {
|
||||||
|
stories: [],
|
||||||
|
addons: ['@storybook/addon-essentials'],
|
||||||
|
// uncomment the property below if you want to apply some webpack config globally
|
||||||
|
// webpackFinal: async (config, { configType }) => {
|
||||||
|
// // Make whatever fine-grained changes you need that should apply to all storybook configs
|
||||||
|
|
||||||
|
// // Return the altered config
|
||||||
|
// return config;
|
||||||
|
// },
|
||||||
|
};
|
||||||
|
`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when main.js uses new syntax', () => {
|
||||||
|
it('should update the project-level .storybook/main.js if there is a core object', async () => {
|
||||||
|
tree.write(
|
||||||
|
`libs/test-one/.storybook/main.js`,
|
||||||
|
`const rootMain = require('../../../.storybook/main');
|
||||||
|
module.exports = {
|
||||||
|
...rootMain,
|
||||||
|
|
||||||
|
core: { ...rootMain.core },
|
||||||
|
stories: [
|
||||||
|
...rootMain.stories,
|
||||||
|
'../src/lib/**/*.stories.mdx',
|
||||||
|
'../src/lib/**/*.stories.@(js|jsx|ts|tsx)',
|
||||||
|
],
|
||||||
|
addons: [...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 });
|
||||||
|
}
|
||||||
|
|
||||||
|
// add your own webpack tweaks if needed
|
||||||
|
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
};`
|
||||||
|
);
|
||||||
|
|
||||||
|
tree.write(
|
||||||
|
`libs/test-two/.storybook/main.js`,
|
||||||
|
`const rootMain = require('../../../.storybook/main');
|
||||||
|
module.exports = {
|
||||||
|
...rootMain,
|
||||||
|
core: { ...rootMain.core },
|
||||||
|
stories: [
|
||||||
|
...rootMain.stories,
|
||||||
|
'../src/lib/**/*.stories.mdx',
|
||||||
|
'../src/lib/**/*.stories.@(js|jsx|ts|tsx)',
|
||||||
|
],
|
||||||
|
addons: [...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 });
|
||||||
|
}
|
||||||
|
|
||||||
|
// add your own webpack tweaks if needed
|
||||||
|
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
};`
|
||||||
|
);
|
||||||
|
|
||||||
|
await migrateStorybookToWebPack5(tree);
|
||||||
|
|
||||||
|
const projectOne = tree.read(
|
||||||
|
`libs/test-one/.storybook/main.js`,
|
||||||
|
'utf-8'
|
||||||
|
);
|
||||||
|
expect(projectOne).toContain(`builder: 'webpack5'`);
|
||||||
|
const projectTwo = tree.read(
|
||||||
|
`libs/test-two/.storybook/main.js`,
|
||||||
|
'utf-8'
|
||||||
|
);
|
||||||
|
expect(projectTwo).toContain(`builder: 'webpack5'`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update the project-level .storybook/main.js if there is not a core object', async () => {
|
||||||
|
tree.write(
|
||||||
|
`libs/test-one/.storybook/main.js`,
|
||||||
|
`const rootMain = require('../../../.storybook/main');
|
||||||
|
module.exports = {
|
||||||
|
...rootMain,
|
||||||
|
|
||||||
|
stories: [
|
||||||
|
...rootMain.stories,
|
||||||
|
'../src/lib/**/*.stories.mdx',
|
||||||
|
'../src/lib/**/*.stories.@(js|jsx|ts|tsx)',
|
||||||
|
],
|
||||||
|
addons: [...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 });
|
||||||
|
}
|
||||||
|
|
||||||
|
// add your own webpack tweaks if needed
|
||||||
|
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
};`
|
||||||
|
);
|
||||||
|
|
||||||
|
tree.write(
|
||||||
|
`libs/test-two/.storybook/main.js`,
|
||||||
|
`const rootMain = require('../../../.storybook/main');
|
||||||
|
module.exports = {
|
||||||
|
...rootMain,
|
||||||
|
|
||||||
|
stories: [
|
||||||
|
...rootMain.stories,
|
||||||
|
'../src/lib/**/*.stories.mdx',
|
||||||
|
'../src/lib/**/*.stories.@(js|jsx|ts|tsx)',
|
||||||
|
],
|
||||||
|
addons: [...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 });
|
||||||
|
}
|
||||||
|
|
||||||
|
// add your own webpack tweaks if needed
|
||||||
|
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
};`
|
||||||
|
);
|
||||||
|
|
||||||
|
await migrateStorybookToWebPack5(tree);
|
||||||
|
const projectOne = tree.read(
|
||||||
|
`libs/test-one/.storybook/main.js`,
|
||||||
|
'utf-8'
|
||||||
|
);
|
||||||
|
expect(projectOne).toContain(`builder: 'webpack5'`);
|
||||||
|
const projectTwo = tree.read(
|
||||||
|
`libs/test-two/.storybook/main.js`,
|
||||||
|
'utf-8'
|
||||||
|
);
|
||||||
|
expect(projectTwo).toContain(`builder: 'webpack5'`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not do anything if project-level .storybook/main.js is invalid', async () => {
|
||||||
|
tree.write(
|
||||||
|
`libs/test-one/.storybook/main.js`,
|
||||||
|
`const rootMain = require('../../../.storybook/main');
|
||||||
|
module.exports = {
|
||||||
|
};`
|
||||||
|
);
|
||||||
|
|
||||||
|
tree.write(
|
||||||
|
`libs/test-two/.storybook/main.js`,
|
||||||
|
`const rootMain = require('../../../.storybook/main');
|
||||||
|
module.exports = {
|
||||||
|
...rootMain,
|
||||||
|
},
|
||||||
|
};`
|
||||||
|
);
|
||||||
|
|
||||||
|
await migrateStorybookToWebPack5(tree);
|
||||||
|
const projectOne = tree.read(
|
||||||
|
`libs/test-one/.storybook/main.js`,
|
||||||
|
'utf-8'
|
||||||
|
);
|
||||||
|
expect(projectOne).not.toContain(`builder: 'webpack5'`);
|
||||||
|
const projectTwo = tree.read(
|
||||||
|
`libs/test-two/.storybook/main.js`,
|
||||||
|
'utf-8'
|
||||||
|
);
|
||||||
|
expect(projectTwo).not.toContain(`builder: 'webpack5'`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when main.js uses old syntax', () => {
|
||||||
|
it('should update the project-level .storybook/main.js if there is a core object', async () => {
|
||||||
|
tree.write(
|
||||||
|
`libs/test-one/.storybook/main.js`,
|
||||||
|
`const rootMain = require('../../../.storybook/main');
|
||||||
|
|
||||||
|
rootMain.core = {
|
||||||
|
...rootMain.core
|
||||||
|
};
|
||||||
|
// 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;`
|
||||||
|
);
|
||||||
|
|
||||||
|
tree.write(
|
||||||
|
`libs/test-two/.storybook/main.js`,
|
||||||
|
`const rootMain = require('../../../.storybook/main');
|
||||||
|
|
||||||
|
rootMain.core = { ...rootMain.core, builder: 'webpack5' };
|
||||||
|
// 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;`
|
||||||
|
);
|
||||||
|
|
||||||
|
await migrateStorybookToWebPack5(tree);
|
||||||
|
|
||||||
|
const projectOne = tree.read(
|
||||||
|
`libs/test-one/.storybook/main.js`,
|
||||||
|
'utf-8'
|
||||||
|
);
|
||||||
|
expect(projectOne).toContain(`builder: 'webpack5'`);
|
||||||
|
const projectTwo = tree.read(
|
||||||
|
`libs/test-two/.storybook/main.js`,
|
||||||
|
'utf-8'
|
||||||
|
);
|
||||||
|
expect(projectTwo).toContain(`builder: 'webpack5'`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update the project-level .storybook/main.js if there is not a core object', async () => {
|
||||||
|
tree.write(
|
||||||
|
`libs/test-one/.storybook/main.js`,
|
||||||
|
`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;`
|
||||||
|
);
|
||||||
|
|
||||||
|
tree.write(
|
||||||
|
`libs/test-two/.storybook/main.js`,
|
||||||
|
`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;`
|
||||||
|
);
|
||||||
|
|
||||||
|
await migrateStorybookToWebPack5(tree);
|
||||||
|
const projectOne = tree.read(
|
||||||
|
`libs/test-one/.storybook/main.js`,
|
||||||
|
'utf-8'
|
||||||
|
);
|
||||||
|
expect(projectOne).toContain(`builder: 'webpack5'`);
|
||||||
|
const projectTwo = tree.read(
|
||||||
|
`libs/test-two/.storybook/main.js`,
|
||||||
|
'utf-8'
|
||||||
|
);
|
||||||
|
expect(projectTwo).toContain(`builder: 'webpack5'`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,46 @@
|
|||||||
|
import { Tree, logger, updateJson, readJson } from '@nrwl/devkit';
|
||||||
|
import {
|
||||||
|
migrateToWebPack5,
|
||||||
|
workspaceHasStorybookForReact,
|
||||||
|
} from './webpack5-changes-utils';
|
||||||
|
|
||||||
|
let needsInstall = false;
|
||||||
|
|
||||||
|
export async function migrateStorybookToWebPack5(tree: Tree) {
|
||||||
|
const packageJson = readJson(tree, 'package.json');
|
||||||
|
if (workspaceHasStorybookForReact(packageJson)) {
|
||||||
|
updateJson(tree, 'package.json', (json) => {
|
||||||
|
json.dependencies = json.dependencies || {};
|
||||||
|
json.devDependencies = json.devDependencies || {};
|
||||||
|
|
||||||
|
if (
|
||||||
|
!json.dependencies['@storybook/builder-webpack5'] &&
|
||||||
|
!json.devDependencies['@storybook/builder-webpack5']
|
||||||
|
) {
|
||||||
|
needsInstall = true;
|
||||||
|
json.devDependencies['@storybook/builder-webpack5'] =
|
||||||
|
workspaceHasStorybookForReact(packageJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
!json.dependencies['@storybook/manager-webpack5'] &&
|
||||||
|
!json.devDependencies['@storybook/manager-webpack5']
|
||||||
|
) {
|
||||||
|
needsInstall = true;
|
||||||
|
json.devDependencies['@storybook/manager-webpack5'] =
|
||||||
|
workspaceHasStorybookForReact(packageJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
await migrateToWebPack5(tree);
|
||||||
|
|
||||||
|
if (needsInstall) {
|
||||||
|
logger.info(
|
||||||
|
'Please make sure to run npm install or yarn install to get the latest packages added by this migration'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default migrateStorybookToWebPack5;
|
||||||
@ -0,0 +1,322 @@
|
|||||||
|
import { getProjects, Tree } from '@nrwl/devkit';
|
||||||
|
import {
|
||||||
|
logger,
|
||||||
|
formatFiles,
|
||||||
|
applyChangesToString,
|
||||||
|
ChangeType,
|
||||||
|
} from '@nrwl/devkit';
|
||||||
|
|
||||||
|
import ts = require('typescript');
|
||||||
|
import { findNodes } from '@nrwl/workspace/src/utilities/typescript/find-nodes';
|
||||||
|
|
||||||
|
export async function migrateToWebPack5(tree: Tree) {
|
||||||
|
allReactProjectsWithStorybookConfiguration(tree).forEach((project) => {
|
||||||
|
editProjectMainJs(
|
||||||
|
tree,
|
||||||
|
`${project.storybookConfigPath}/main.js`,
|
||||||
|
project.projectName
|
||||||
|
);
|
||||||
|
});
|
||||||
|
await formatFiles(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function workspaceHasStorybookForReact(
|
||||||
|
packageJson: any
|
||||||
|
): string | undefined {
|
||||||
|
return (
|
||||||
|
packageJson.dependencies['@storybook/react'] ||
|
||||||
|
packageJson.devDependencies['@storybook/react']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function allReactProjectsWithStorybookConfiguration(tree: Tree): {
|
||||||
|
projectName: string;
|
||||||
|
storybookConfigPath: string;
|
||||||
|
}[] {
|
||||||
|
const projects = getProjects(tree);
|
||||||
|
const reactProjectsThatHaveStorybookConfiguration: {
|
||||||
|
projectName: string;
|
||||||
|
storybookConfigPath: string;
|
||||||
|
}[] = [...projects.entries()]
|
||||||
|
?.filter(
|
||||||
|
([_, projectConfig]) =>
|
||||||
|
projectConfig.targets &&
|
||||||
|
projectConfig.targets.storybook &&
|
||||||
|
projectConfig.targets.storybook.options
|
||||||
|
)
|
||||||
|
?.map(([projectName, projectConfig]) => {
|
||||||
|
if (
|
||||||
|
projectConfig.targets &&
|
||||||
|
projectConfig.targets.storybook &&
|
||||||
|
projectConfig.targets.storybook.options?.config?.configFolder &&
|
||||||
|
projectConfig.targets.storybook.options?.uiFramework ===
|
||||||
|
'@storybook/react'
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
projectName,
|
||||||
|
storybookConfigPath:
|
||||||
|
projectConfig.targets.storybook.options.config.configFolder,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return reactProjectsThatHaveStorybookConfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function editProjectMainJs(
|
||||||
|
tree: Tree,
|
||||||
|
projectMainJsFile: string,
|
||||||
|
projectName: string
|
||||||
|
) {
|
||||||
|
let newContents: string;
|
||||||
|
let moduleExportsIsEmptyOrNonExistentOrInvalid = false;
|
||||||
|
let alreadyHasBuilder: any;
|
||||||
|
const rootMainJsExists = tree.exists(projectMainJsFile);
|
||||||
|
let moduleExportsFull: ts.Node[] = [];
|
||||||
|
|
||||||
|
if (rootMainJsExists) {
|
||||||
|
const file = getTsSourceFile(tree, projectMainJsFile);
|
||||||
|
const appFileContent = tree.read(projectMainJsFile, 'utf-8');
|
||||||
|
newContents = appFileContent;
|
||||||
|
moduleExportsFull = findNodes(file, [ts.SyntaxKind.ExpressionStatement]);
|
||||||
|
|
||||||
|
if (moduleExportsFull && moduleExportsFull[0]) {
|
||||||
|
const moduleExports = moduleExportsFull[0];
|
||||||
|
|
||||||
|
const listOfStatements = findNodes(moduleExports, [
|
||||||
|
ts.SyntaxKind.SyntaxList,
|
||||||
|
]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keep the index of the stories node
|
||||||
|
* to put the core object before it
|
||||||
|
* if it does not exist already
|
||||||
|
*/
|
||||||
|
|
||||||
|
let indexOfStoriesNode = -1;
|
||||||
|
|
||||||
|
const hasCoreObject = listOfStatements[0]?.getChildren()?.find((node) => {
|
||||||
|
if (
|
||||||
|
node &&
|
||||||
|
node.getText().length > 0 &&
|
||||||
|
indexOfStoriesNode < 0 &&
|
||||||
|
node?.getText().startsWith('stories')
|
||||||
|
) {
|
||||||
|
indexOfStoriesNode = node.getStart();
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
node?.kind === ts.SyntaxKind.PropertyAssignment &&
|
||||||
|
node?.getText().startsWith('core')
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (hasCoreObject) {
|
||||||
|
const contentsOfCoreNode = hasCoreObject.getChildren().find((node) => {
|
||||||
|
return node.kind === ts.SyntaxKind.ObjectLiteralExpression;
|
||||||
|
});
|
||||||
|
const everyAttributeInsideCoreNode = contentsOfCoreNode
|
||||||
|
.getChildren()
|
||||||
|
.find((node) => node.kind === ts.SyntaxKind.SyntaxList);
|
||||||
|
|
||||||
|
alreadyHasBuilder = everyAttributeInsideCoreNode
|
||||||
|
.getChildren()
|
||||||
|
.find((node) => node.getText() === "builder: 'webpack5'");
|
||||||
|
|
||||||
|
if (!alreadyHasBuilder) {
|
||||||
|
newContents = applyChangesToString(newContents, [
|
||||||
|
{
|
||||||
|
type: ChangeType.Insert,
|
||||||
|
index: contentsOfCoreNode.getEnd() - 1,
|
||||||
|
text: ", builder: 'webpack5'",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
} else if (indexOfStoriesNode >= 0) {
|
||||||
|
/**
|
||||||
|
* Does not have core object,
|
||||||
|
* so just write one, at the start.
|
||||||
|
*/
|
||||||
|
newContents = applyChangesToString(newContents, [
|
||||||
|
{
|
||||||
|
type: ChangeType.Insert,
|
||||||
|
index: indexOfStoriesNode - 1,
|
||||||
|
text: "core: { ...rootMain.core, builder: 'webpack5' }, ",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
/**
|
||||||
|
* Module exports is empty or does not
|
||||||
|
* contain stories - most probably invalid
|
||||||
|
*/
|
||||||
|
moduleExportsIsEmptyOrNonExistentOrInvalid = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/**
|
||||||
|
* module.exports does not exist
|
||||||
|
*/
|
||||||
|
moduleExportsIsEmptyOrNonExistentOrInvalid = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
moduleExportsIsEmptyOrNonExistentOrInvalid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (moduleExportsIsEmptyOrNonExistentOrInvalid) {
|
||||||
|
const usesOldSyntax = checkMainJsForOldSyntax(
|
||||||
|
moduleExportsFull,
|
||||||
|
newContents
|
||||||
|
);
|
||||||
|
if (moduleExportsFull.length > 0 && usesOldSyntax) {
|
||||||
|
newContents = usesOldSyntax;
|
||||||
|
tree.write(projectMainJsFile, newContents);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
logger.info(
|
||||||
|
`Please configure Storybook for project "${projectName}"", since it has not been configured properly.`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!alreadyHasBuilder) {
|
||||||
|
tree.write(projectMainJsFile, newContents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function checkMainJsForOldSyntax(
|
||||||
|
nodeList: ts.Node[],
|
||||||
|
fileContent: string
|
||||||
|
): string | undefined {
|
||||||
|
let alreadyContainsBuilder = false;
|
||||||
|
let coreNode: ts.Node | undefined;
|
||||||
|
let hasCoreNode = false;
|
||||||
|
const lastIndexOfFirstNode = nodeList[0].getEnd();
|
||||||
|
|
||||||
|
if (!fileContent.includes('stories.push') || nodeList.length === 0) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go through the node list and find if the core object exists
|
||||||
|
// If it does, then we need to check if it has the builder property
|
||||||
|
// If it does not, then we need to add it
|
||||||
|
for (let topNode of nodeList) {
|
||||||
|
if (
|
||||||
|
topNode.kind === ts.SyntaxKind.ExpressionStatement &&
|
||||||
|
topNode.getChildren()?.length > 0
|
||||||
|
) {
|
||||||
|
for (let node of topNode.getChildren()) {
|
||||||
|
if (
|
||||||
|
node.kind === ts.SyntaxKind.BinaryExpression &&
|
||||||
|
node.getChildren()?.length
|
||||||
|
) {
|
||||||
|
for (let childNode of node.getChildren()) {
|
||||||
|
if (
|
||||||
|
childNode.kind === ts.SyntaxKind.PropertyAccessExpression &&
|
||||||
|
childNode.getChildren()?.length
|
||||||
|
) {
|
||||||
|
for (let grandChildNode of childNode.getChildren()) {
|
||||||
|
if (
|
||||||
|
grandChildNode.kind === ts.SyntaxKind.Identifier &&
|
||||||
|
grandChildNode.getText() === 'core'
|
||||||
|
) {
|
||||||
|
coreNode = node;
|
||||||
|
hasCoreNode = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hasCoreNode) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hasCoreNode) {
|
||||||
|
if (coreNode.getChildren()?.length) {
|
||||||
|
for (let coreChildNode of coreNode.getChildren()) {
|
||||||
|
if (
|
||||||
|
coreChildNode.kind === ts.SyntaxKind.ObjectLiteralExpression &&
|
||||||
|
coreChildNode.getChildren()?.length
|
||||||
|
) {
|
||||||
|
for (let coreChildNodeChild of coreChildNode.getChildren()) {
|
||||||
|
if (coreChildNodeChild.kind === ts.SyntaxKind.SyntaxList) {
|
||||||
|
for (let coreChildNodeGrandChild of coreChildNodeChild.getChildren()) {
|
||||||
|
if (
|
||||||
|
coreChildNodeGrandChild.kind ===
|
||||||
|
ts.SyntaxKind.PropertyAssignment &&
|
||||||
|
coreChildNodeGrandChild.getText().startsWith('builder')
|
||||||
|
) {
|
||||||
|
for (let coreChildNodeGrandChildChild of coreChildNodeGrandChild.getChildren()) {
|
||||||
|
if (
|
||||||
|
coreChildNodeGrandChildChild.kind ===
|
||||||
|
ts.SyntaxKind.StringLiteral &&
|
||||||
|
coreChildNodeGrandChildChild.getText() ===
|
||||||
|
'webpack5'
|
||||||
|
) {
|
||||||
|
alreadyContainsBuilder = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (alreadyContainsBuilder) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (alreadyContainsBuilder) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (alreadyContainsBuilder) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hasCoreNode) {
|
||||||
|
if (alreadyContainsBuilder) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
// Add builder
|
||||||
|
const indexOfCoreNodeEnd = coreNode.getEnd();
|
||||||
|
fileContent = applyChangesToString(fileContent, [
|
||||||
|
{
|
||||||
|
type: ChangeType.Insert,
|
||||||
|
index: indexOfCoreNodeEnd - 1,
|
||||||
|
text: ", builder: 'webpack5'",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasCoreNode) {
|
||||||
|
fileContent = applyChangesToString(fileContent, [
|
||||||
|
{
|
||||||
|
type: ChangeType.Insert,
|
||||||
|
index: lastIndexOfFirstNode + 1,
|
||||||
|
text: "rootMain.core = { ...rootMain.core, builder: 'webpack5' };\n",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getTsSourceFile(host: Tree, path: string): ts.SourceFile {
|
||||||
|
const buffer = host.read(path);
|
||||||
|
if (!buffer) {
|
||||||
|
throw new Error(`Could not read TS file (${path}).`);
|
||||||
|
}
|
||||||
|
const content = buffer.toString();
|
||||||
|
const source = ts.createSourceFile(
|
||||||
|
path,
|
||||||
|
content,
|
||||||
|
ts.ScriptTarget.Latest,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
return source;
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user