parent
4d5cc73c9b
commit
9bb5d0d7db
@ -6,7 +6,7 @@
|
|||||||
},
|
},
|
||||||
"ignorePatterns": ["**/*.ts"],
|
"ignorePatterns": ["**/*.ts"],
|
||||||
"plugins": ["@typescript-eslint", "@nx"],
|
"plugins": ["@typescript-eslint", "@nx"],
|
||||||
"extends": [],
|
"extends": ["plugin:storybook/recommended"],
|
||||||
"rules": {
|
"rules": {
|
||||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||||
"no-restricted-imports": ["error", "create-nx-workspace"],
|
"no-restricted-imports": ["error", "create-nx-workspace"],
|
||||||
|
|||||||
@ -15,9 +15,9 @@ describe('Storybook executors for Angular', () => {
|
|||||||
const angularStorybookLib = uniq('test-ui-ng-lib');
|
const angularStorybookLib = uniq('test-ui-ng-lib');
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
newProject();
|
newProject();
|
||||||
createTestUILib(angularStorybookLib);
|
runCLI(`g @nx/angular:library ${angularStorybookLib} --no-interactive`);
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nrwl/angular:storybook-configuration ${angularStorybookLib} --configureCypress --generateStories --generateCypressSpecs --no-interactive`
|
`generate @nx/angular:storybook-configuration ${angularStorybookLib} --configureCypress --generateStories --generateCypressSpecs --no-interactive`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -25,8 +25,7 @@ describe('Storybook executors for Angular', () => {
|
|||||||
cleanupProject();
|
cleanupProject();
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: Enable on SB7
|
describe('serve and build storybook', () => {
|
||||||
xdescribe('serve and build storybook', () => {
|
|
||||||
afterAll(() => killPorts());
|
afterAll(() => killPorts());
|
||||||
|
|
||||||
it('should serve an Angular based Storybook setup', async () => {
|
it('should serve an Angular based Storybook setup', async () => {
|
||||||
@ -49,6 +48,7 @@ describe('Storybook executors for Angular', () => {
|
|||||||
xdescribe('run cypress tests using storybook', () => {
|
xdescribe('run cypress tests using storybook', () => {
|
||||||
it('should execute e2e tests using Cypress running against Storybook', async () => {
|
it('should execute e2e tests using Cypress running against Storybook', async () => {
|
||||||
if (runCypressTests()) {
|
if (runCypressTests()) {
|
||||||
|
addTestButtonToUILib(angularStorybookLib);
|
||||||
writeFileSync(
|
writeFileSync(
|
||||||
tmpProjPath(
|
tmpProjPath(
|
||||||
`apps/${angularStorybookLib}-e2e/src/e2e/test-button/test-button.component.cy.ts`
|
`apps/${angularStorybookLib}-e2e/src/e2e/test-button/test-button.component.cy.ts`
|
||||||
@ -82,10 +82,9 @@ describe('Storybook executors for Angular', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
export function createTestUILib(libName: string): void {
|
function addTestButtonToUILib(libName: string): void {
|
||||||
runCLI(`g @nrwl/angular:library ${libName} --no-interactive`);
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`g @nrwl/angular:component test-button --project=${libName} --no-interactive`
|
`g @nx/angular:component test-button --project=${libName} --no-interactive`
|
||||||
);
|
);
|
||||||
|
|
||||||
writeFileSync(
|
writeFileSync(
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
checkFilesExist,
|
checkFilesExist,
|
||||||
cleanupProject,
|
cleanupProject,
|
||||||
|
getSelectedPackageManager,
|
||||||
killPorts,
|
killPorts,
|
||||||
readJson,
|
readJson,
|
||||||
runCLI,
|
runCLI,
|
||||||
@ -10,6 +11,7 @@ import {
|
|||||||
uniq,
|
uniq,
|
||||||
} from '@nrwl/e2e/utils';
|
} from '@nrwl/e2e/utils';
|
||||||
import { writeFileSync } from 'fs';
|
import { writeFileSync } from 'fs';
|
||||||
|
import { createFileSync } from 'fs-extra';
|
||||||
|
|
||||||
describe('Storybook generators and executors for standalone workspaces - using React + Vite', () => {
|
describe('Storybook generators and executors for standalone workspaces - using React + Vite', () => {
|
||||||
const wsName = uniq('react');
|
const wsName = uniq('react');
|
||||||
@ -22,10 +24,11 @@ describe('Storybook generators and executors for standalone workspaces - using R
|
|||||||
appName,
|
appName,
|
||||||
style: 'css',
|
style: 'css',
|
||||||
bundler: 'vite',
|
bundler: 'vite',
|
||||||
|
packageManager: getSelectedPackageManager(),
|
||||||
});
|
});
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nrwl/react:storybook-configuration ${appName} --generateStories --no-interactive`
|
`generate @nx/react:storybook-configuration ${appName} --generateStories --no-interactive`
|
||||||
);
|
);
|
||||||
|
|
||||||
runCLI(`report`);
|
runCLI(`report`);
|
||||||
@ -50,8 +53,7 @@ describe('Storybook generators and executors for standalone workspaces - using R
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: Use --storybook7Configuration and re-enable this test - or else it NEEDS NODE 16
|
describe('serve storybook', () => {
|
||||||
xdescribe('serve storybook', () => {
|
|
||||||
afterEach(() => killPorts());
|
afterEach(() => killPorts());
|
||||||
|
|
||||||
it('should serve a React based Storybook setup that uses Vite', async () => {
|
it('should serve a React based Storybook setup that uses Vite', async () => {
|
||||||
@ -59,73 +61,86 @@ describe('Storybook generators and executors for standalone workspaces - using R
|
|||||||
return /Storybook.*started/gi.test(output);
|
return /Storybook.*started/gi.test(output);
|
||||||
});
|
});
|
||||||
p.kill();
|
p.kill();
|
||||||
}, 40000);
|
}, 60000);
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: Use --storybook7Configuration and re-enable this test - or else it NEEDS NODE 16
|
describe('build storybook', () => {
|
||||||
xdescribe('build storybook', () => {
|
|
||||||
it('should build a React based storybook that uses Vite', () => {
|
it('should build a React based storybook that uses Vite', () => {
|
||||||
runCLI(`run ${appName}:build-storybook --verbose`);
|
runCLI(`run ${appName}:build-storybook --verbose`);
|
||||||
checkFilesExist(`dist/storybook/${appName}/index.html`);
|
checkFilesExist(`dist/storybook/${appName}/index.html`);
|
||||||
}, 40000);
|
}, 60000);
|
||||||
|
|
||||||
// This test makes sure path resolution works
|
// This needs fixing on the Storybook side
|
||||||
|
// vite paths resolution is not working on standalone
|
||||||
xit('should build a React based storybook that references another lib and uses Vite', () => {
|
xit('should build a React based storybook that references another lib and uses Vite', () => {
|
||||||
const reactLib = uniq('test-lib-react');
|
const anotherReactLib = uniq('test-another-lib-react');
|
||||||
runCLI(`generate @nrwl/react:lib ${reactLib} --no-interactive`);
|
runCLI(`generate @nx/react:lib ${anotherReactLib} --no-interactive`);
|
||||||
// create a React component we can reference
|
// create a React component we can reference
|
||||||
|
createFileSync(tmpProjPath(`${anotherReactLib}/src/lib/mytestcmp.tsx`));
|
||||||
writeFileSync(
|
writeFileSync(
|
||||||
tmpProjPath(`${reactLib}/src/lib/mytestcmp.tsx`),
|
tmpProjPath(`${anotherReactLib}/src/lib/mytestcmp.tsx`),
|
||||||
`
|
`
|
||||||
import React from 'react';
|
export function MyTestCmp() {
|
||||||
|
|
||||||
/* eslint-disable-next-line */
|
|
||||||
export interface MyTestCmpProps {}
|
|
||||||
|
|
||||||
export const MyTestCmp = (props: MyTestCmpProps) => {
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h1>Welcome to test cmp!</h1>
|
<h1>Welcome to OtherLib!</h1>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
export default MyTestCmp;
|
export default MyTestCmp;
|
||||||
`
|
`
|
||||||
);
|
);
|
||||||
// update index.ts and export it
|
// update index.ts and export it
|
||||||
writeFileSync(
|
writeFileSync(
|
||||||
tmpProjPath(`${reactLib}/src/index.ts`),
|
tmpProjPath(`${anotherReactLib}/src/index.ts`),
|
||||||
`
|
`
|
||||||
export * from './lib/mytestcmp';
|
export * from './lib/mytestcmp';
|
||||||
`
|
`
|
||||||
);
|
);
|
||||||
|
|
||||||
// create a story in the first lib to reference the cmp from the 2nd lib
|
// create a component and a story in the first lib to reference the cmp from the 2nd lib
|
||||||
|
createFileSync(tmpProjPath(`src/app/test-button.tsx`));
|
||||||
writeFileSync(
|
writeFileSync(
|
||||||
tmpProjPath(`${reactLib}/src/lib/myteststory.stories.tsx`),
|
tmpProjPath(`src/app/test-button.tsx`),
|
||||||
`
|
`
|
||||||
import React from 'react';
|
import { MyTestCmp } from '@${wsName}/${anotherReactLib}';
|
||||||
|
|
||||||
import { MyTestCmp, MyTestCmpProps } from '@${wsName}/${reactLib}';
|
export function TestButton() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<MyTestCmp />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default TestButton;
|
||||||
component: MyTestCmp,
|
`
|
||||||
title: 'MyTestCmp',
|
);
|
||||||
|
|
||||||
|
// create a story in the first lib to reference the cmp from the 2nd lib
|
||||||
|
createFileSync(tmpProjPath(`src/app/test-button.stories.tsx`));
|
||||||
|
writeFileSync(
|
||||||
|
tmpProjPath(`src/app/test-button.stories.tsx`),
|
||||||
|
`
|
||||||
|
import type { Meta } from '@storybook/react';
|
||||||
|
import { TestButton } from './test-button';
|
||||||
|
|
||||||
|
const Story: Meta<typeof TestButton> = {
|
||||||
|
component: TestButton,
|
||||||
|
title: 'TestButton',
|
||||||
};
|
};
|
||||||
|
export default Story;
|
||||||
|
|
||||||
export const primary = () => {
|
export const Primary = {
|
||||||
/* eslint-disable-next-line */
|
args: {},
|
||||||
const props: MyTestCmpProps = {};
|
|
||||||
|
|
||||||
return <MyTestCmp />;
|
|
||||||
};
|
};
|
||||||
`
|
`
|
||||||
);
|
);
|
||||||
|
|
||||||
// build React lib
|
// build React lib
|
||||||
runCLI(`run ${reactLib}:build-storybook --verbose`);
|
runCLI(`run ${appName}:build-storybook --verbose`);
|
||||||
checkFilesExist(`dist/storybook/${reactLib}/index.html`);
|
checkFilesExist(`dist/storybook/${appName}/index.html`);
|
||||||
}, 40000);
|
}, 60000);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -2,47 +2,28 @@ import {
|
|||||||
checkFilesExist,
|
checkFilesExist,
|
||||||
cleanupProject,
|
cleanupProject,
|
||||||
killPorts,
|
killPorts,
|
||||||
|
newProject,
|
||||||
runCLI,
|
runCLI,
|
||||||
runCommandUntil,
|
runCommandUntil,
|
||||||
tmpProjPath,
|
tmpProjPath,
|
||||||
uniq,
|
uniq,
|
||||||
getPackageManagerCommand,
|
|
||||||
runCommand,
|
|
||||||
newProject,
|
|
||||||
updateJson,
|
|
||||||
} from '@nrwl/e2e/utils';
|
} from '@nrwl/e2e/utils';
|
||||||
import { writeFileSync } from 'fs';
|
import { writeFileSync } from 'fs';
|
||||||
|
|
||||||
describe('Storybook generators and executors for monorepos', () => {
|
// TODO: re-enable once the issue is fixed with long build times
|
||||||
const previousPM = process.env.SELECTED_PM;
|
describe.skip('Storybook generators and executors for monorepos', () => {
|
||||||
const reactStorybookLib = uniq('test-ui-lib-react');
|
const reactStorybookLib = uniq('test-ui-lib-react');
|
||||||
let proj;
|
let proj;
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
process.env.SELECTED_PM = 'yarn';
|
proj = newProject();
|
||||||
proj = newProject({
|
runCLI(`generate @nx/react:lib ${reactStorybookLib} --no-interactive`);
|
||||||
packageManager: 'yarn',
|
|
||||||
});
|
|
||||||
runCLI(`generate @nrwl/react:lib ${reactStorybookLib} --no-interactive`);
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nrwl/react:storybook-configuration ${reactStorybookLib} --generateStories --no-interactive --bundler=webpack`
|
`generate @nx/react:storybook-configuration ${reactStorybookLib} --generateStories --no-interactive --bundler=webpack`
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO(jack): Overriding enhanced-resolve to 5.10.0 now until the package is fixed.
|
|
||||||
// TODO: Use --storybook7Configuration and remove this
|
|
||||||
// See: https://github.com/webpack/enhanced-resolve/issues/362
|
|
||||||
updateJson('package.json', (json) => {
|
|
||||||
json['overrides'] = {
|
|
||||||
'enhanced-resolve': '5.10.0',
|
|
||||||
};
|
|
||||||
|
|
||||||
return json;
|
|
||||||
});
|
|
||||||
runCommand(getPackageManagerCommand().install);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
cleanupProject();
|
cleanupProject();
|
||||||
process.env.SELECTED_PM = previousPM;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('serve and build storybook', () => {
|
describe('serve and build storybook', () => {
|
||||||
@ -57,18 +38,18 @@ describe('Storybook generators and executors for monorepos', () => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
p.kill();
|
p.kill();
|
||||||
}, 50000);
|
}, 60000);
|
||||||
|
|
||||||
it('should build a React based storybook setup that uses webpack', () => {
|
it('should build a React based storybook setup that uses webpack', () => {
|
||||||
// build
|
// build
|
||||||
runCLI(`run ${reactStorybookLib}:build-storybook --verbose`);
|
runCLI(`run ${reactStorybookLib}:build-storybook --verbose`);
|
||||||
checkFilesExist(`dist/storybook/${reactStorybookLib}/index.html`);
|
checkFilesExist(`dist/storybook/${reactStorybookLib}/index.html`);
|
||||||
}, 50000);
|
}, 60000);
|
||||||
|
|
||||||
// This test makes sure path resolution works
|
// This test makes sure path resolution works
|
||||||
it('should build a React based storybook that references another lib and uses webpack', () => {
|
it('should build a React based storybook that references another lib and uses webpack', () => {
|
||||||
const anotherReactLib = uniq('test-another-lib-react');
|
const anotherReactLib = uniq('test-another-lib-react');
|
||||||
runCLI(`generate @nrwl/react:lib ${anotherReactLib} --no-interactive`);
|
runCLI(`generate @nx/react:lib ${anotherReactLib} --no-interactive`);
|
||||||
// create a React component we can reference
|
// create a React component we can reference
|
||||||
writeFileSync(
|
writeFileSync(
|
||||||
tmpProjPath(`libs/${anotherReactLib}/src/lib/mytestcmp.tsx`),
|
tmpProjPath(`libs/${anotherReactLib}/src/lib/mytestcmp.tsx`),
|
||||||
@ -117,6 +98,6 @@ describe('Storybook generators and executors for monorepos', () => {
|
|||||||
// build React lib
|
// build React lib
|
||||||
runCLI(`run ${reactStorybookLib}:build-storybook --verbose`);
|
runCLI(`run ${reactStorybookLib}:build-storybook --verbose`);
|
||||||
checkFilesExist(`dist/storybook/${reactStorybookLib}/index.html`);
|
checkFilesExist(`dist/storybook/${reactStorybookLib}/index.html`);
|
||||||
}, 50000);
|
}, 60000);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,12 +1,16 @@
|
|||||||
|
/* eslint-disable storybook/no-uninstalled-addons */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
core: { builder: 'webpack5' },
|
stories: ['../src/app/**/*.stories.@(mdx|js|jsx|ts|tsx)'],
|
||||||
stories: [
|
|
||||||
'../src/app/**/*.stories.mdx',
|
|
||||||
'../src/app/**/*.stories.@(js|jsx|ts|tsx)',
|
|
||||||
],
|
|
||||||
addons: [
|
addons: [
|
||||||
'@storybook/addon-essentials',
|
'@storybook/addon-essentials',
|
||||||
'@nx/react/plugins/storybook',
|
'@nx/react/plugins/storybook',
|
||||||
'storybook-dark-mode',
|
'storybook-dark-mode',
|
||||||
],
|
],
|
||||||
|
framework: {
|
||||||
|
name: '@storybook/react-webpack5',
|
||||||
|
options: {},
|
||||||
|
},
|
||||||
|
docs: {
|
||||||
|
autodocs: true,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -245,7 +245,6 @@
|
|||||||
"storybook": {
|
"storybook": {
|
||||||
"executor": "@nx/storybook:storybook",
|
"executor": "@nx/storybook:storybook",
|
||||||
"options": {
|
"options": {
|
||||||
"uiFramework": "@storybook/react",
|
|
||||||
"port": 4400,
|
"port": 4400,
|
||||||
"configDir": "graph/client/.storybook"
|
"configDir": "graph/client/.storybook"
|
||||||
},
|
},
|
||||||
@ -259,7 +258,6 @@
|
|||||||
"executor": "@nx/storybook:build",
|
"executor": "@nx/storybook:build",
|
||||||
"outputs": ["{options.outputDir}"],
|
"outputs": ["{options.outputDir}"],
|
||||||
"options": {
|
"options": {
|
||||||
"uiFramework": "@storybook/react",
|
|
||||||
"configDir": "graph/client/.storybook",
|
"configDir": "graph/client/.storybook",
|
||||||
"outputDir": "dist/storybook/graph-client"
|
"outputDir": "dist/storybook/graph-client"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,8 +1,12 @@
|
|||||||
|
/* eslint-disable storybook/no-uninstalled-addons */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
core: { builder: 'webpack5' },
|
stories: ['../src/lib/**/*.stories.@(mdx|js|jsx|ts|tsx)'],
|
||||||
stories: [
|
|
||||||
'../src/lib/**/*.stories.mdx',
|
|
||||||
'../src/lib/**/*.stories.@(js|jsx|ts|tsx)',
|
|
||||||
],
|
|
||||||
addons: ['@storybook/addon-essentials', '@nx/react/plugins/storybook'],
|
addons: ['@storybook/addon-essentials', '@nx/react/plugins/storybook'],
|
||||||
|
framework: {
|
||||||
|
name: '@storybook/react-webpack5',
|
||||||
|
options: {},
|
||||||
|
},
|
||||||
|
docs: {
|
||||||
|
autodocs: true,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -10,7 +10,6 @@
|
|||||||
"storybook": {
|
"storybook": {
|
||||||
"executor": "@nx/storybook:storybook",
|
"executor": "@nx/storybook:storybook",
|
||||||
"options": {
|
"options": {
|
||||||
"uiFramework": "@storybook/react",
|
|
||||||
"port": 4400,
|
"port": 4400,
|
||||||
"configDir": "graph/ui-components/.storybook"
|
"configDir": "graph/ui-components/.storybook"
|
||||||
},
|
},
|
||||||
@ -24,7 +23,6 @@
|
|||||||
"executor": "@nx/storybook:build",
|
"executor": "@nx/storybook:build",
|
||||||
"outputs": ["{options.outputDir}"],
|
"outputs": ["{options.outputDir}"],
|
||||||
"options": {
|
"options": {
|
||||||
"uiFramework": "@storybook/react",
|
|
||||||
"configDir": "graph/ui-components/.storybook",
|
"configDir": "graph/ui-components/.storybook",
|
||||||
"outputDir": "dist/storybook/graph-ui-components"
|
"outputDir": "dist/storybook/graph-ui-components"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,8 +1,12 @@
|
|||||||
|
/* eslint-disable storybook/no-uninstalled-addons */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
core: { builder: 'webpack5' },
|
stories: ['../src/lib/**/*.stories.@(mdx|js|jsx|ts|tsx)'],
|
||||||
stories: [
|
|
||||||
'../src/lib/**/*.stories.mdx',
|
|
||||||
'../src/lib/**/*.stories.@(js|jsx|ts|tsx)',
|
|
||||||
],
|
|
||||||
addons: ['@storybook/addon-essentials', '@nx/react/plugins/storybook'],
|
addons: ['@storybook/addon-essentials', '@nx/react/plugins/storybook'],
|
||||||
|
framework: {
|
||||||
|
name: '@storybook/react-webpack5',
|
||||||
|
options: {},
|
||||||
|
},
|
||||||
|
docs: {
|
||||||
|
autodocs: true,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -10,7 +10,6 @@
|
|||||||
"storybook": {
|
"storybook": {
|
||||||
"executor": "@nx/storybook:storybook",
|
"executor": "@nx/storybook:storybook",
|
||||||
"options": {
|
"options": {
|
||||||
"uiFramework": "@storybook/react",
|
|
||||||
"port": 4400,
|
"port": 4400,
|
||||||
"configDir": "graph/ui-graph/.storybook"
|
"configDir": "graph/ui-graph/.storybook"
|
||||||
},
|
},
|
||||||
@ -24,7 +23,6 @@
|
|||||||
"executor": "@nx/storybook:build",
|
"executor": "@nx/storybook:build",
|
||||||
"outputs": ["{options.outputDir}"],
|
"outputs": ["{options.outputDir}"],
|
||||||
"options": {
|
"options": {
|
||||||
"uiFramework": "@storybook/react",
|
|
||||||
"configDir": "graph/ui-graph/.storybook",
|
"configDir": "graph/ui-graph/.storybook",
|
||||||
"outputDir": "dist/storybook/graph-ui-graph"
|
"outputDir": "dist/storybook/graph-ui-graph"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,8 +1,12 @@
|
|||||||
|
/* eslint-disable storybook/no-uninstalled-addons */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
core: { builder: 'webpack5' },
|
stories: ['../src/lib/**/*.stories.@(mdx|js|jsx|ts|tsx)'],
|
||||||
stories: [
|
|
||||||
'../src/lib/**/*.stories.mdx',
|
|
||||||
'../src/lib/**/*.stories.@(js|jsx|ts|tsx)',
|
|
||||||
],
|
|
||||||
addons: ['@storybook/addon-essentials', '@nx/react/plugins/storybook'],
|
addons: ['@storybook/addon-essentials', '@nx/react/plugins/storybook'],
|
||||||
|
framework: {
|
||||||
|
name: '@storybook/react-webpack5',
|
||||||
|
options: {},
|
||||||
|
},
|
||||||
|
docs: {
|
||||||
|
autodocs: true,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -10,7 +10,6 @@
|
|||||||
"storybook": {
|
"storybook": {
|
||||||
"executor": "@nx/storybook:storybook",
|
"executor": "@nx/storybook:storybook",
|
||||||
"options": {
|
"options": {
|
||||||
"uiFramework": "@storybook/react",
|
|
||||||
"port": 4400,
|
"port": 4400,
|
||||||
"configDir": "graph/ui-tooltips/.storybook"
|
"configDir": "graph/ui-tooltips/.storybook"
|
||||||
},
|
},
|
||||||
@ -24,7 +23,6 @@
|
|||||||
"executor": "@nx/storybook:build",
|
"executor": "@nx/storybook:build",
|
||||||
"outputs": ["{options.outputDir}"],
|
"outputs": ["{options.outputDir}"],
|
||||||
"options": {
|
"options": {
|
||||||
"uiFramework": "@storybook/react",
|
|
||||||
"configDir": "graph/ui-tooltips/.storybook",
|
"configDir": "graph/ui-tooltips/.storybook",
|
||||||
"outputDir": "dist/storybook/graph-ui-tooltips"
|
"outputDir": "dist/storybook/graph-ui-tooltips"
|
||||||
},
|
},
|
||||||
|
|||||||
16
package.json
16
package.json
@ -72,13 +72,12 @@
|
|||||||
"@rollup/plugin-node-resolve": "^13.0.4",
|
"@rollup/plugin-node-resolve": "^13.0.4",
|
||||||
"@rollup/plugin-url": "^7.0.0",
|
"@rollup/plugin-url": "^7.0.0",
|
||||||
"@schematics/angular": "~15.2.0",
|
"@schematics/angular": "~15.2.0",
|
||||||
"@storybook/addon-essentials": "^6.5.15",
|
"@storybook/addon-essentials": "^7.0.2",
|
||||||
"@storybook/angular": "^6.5.15",
|
"@storybook/angular": "^7.0.2",
|
||||||
"@storybook/builder-webpack5": "^6.5.15",
|
"@storybook/core-server": "^7.0.2",
|
||||||
"@storybook/core-server": "^6.5.15",
|
"@storybook/react": "^7.0.2",
|
||||||
"@storybook/manager-webpack5": "^6.5.15",
|
"@storybook/react-webpack5": "^7.0.2",
|
||||||
"@storybook/react": "^6.5.15",
|
"@storybook/types": "^7.0.2",
|
||||||
"@storybook/types": "^7.0.0-alpha.44",
|
|
||||||
"@svgr/rollup": "^6.1.2",
|
"@svgr/rollup": "^6.1.2",
|
||||||
"@svgr/webpack": "^6.1.2",
|
"@svgr/webpack": "^6.1.2",
|
||||||
"@swc-node/register": "^1.4.2",
|
"@swc-node/register": "^1.4.2",
|
||||||
@ -149,6 +148,7 @@
|
|||||||
"eslint-plugin-jsx-a11y": "6.6.1",
|
"eslint-plugin-jsx-a11y": "6.6.1",
|
||||||
"eslint-plugin-react": "7.31.11",
|
"eslint-plugin-react": "7.31.11",
|
||||||
"eslint-plugin-react-hooks": "4.6.0",
|
"eslint-plugin-react-hooks": "4.6.0",
|
||||||
|
"eslint-plugin-storybook": "^0.6.11",
|
||||||
"express": "^4.18.1",
|
"express": "^4.18.1",
|
||||||
"fast-xml-parser": "^4.0.9",
|
"fast-xml-parser": "^4.0.9",
|
||||||
"file-loader": "^6.2.0",
|
"file-loader": "^6.2.0",
|
||||||
@ -222,7 +222,7 @@
|
|||||||
"source-map": "0.7.3",
|
"source-map": "0.7.3",
|
||||||
"source-map-loader": "^3.0.0",
|
"source-map-loader": "^3.0.0",
|
||||||
"source-map-support": "0.5.19",
|
"source-map-support": "0.5.19",
|
||||||
"storybook-dark-mode": "^1.1.2",
|
"storybook-dark-mode": "^3.0.0",
|
||||||
"style-loader": "^3.3.0",
|
"style-loader": "^3.3.0",
|
||||||
"styled-components": "5.3.6",
|
"styled-components": "5.3.6",
|
||||||
"stylus": "^0.55.0",
|
"stylus": "^0.55.0",
|
||||||
|
|||||||
@ -1,12 +1,17 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`StorybookConfiguration generator should configure storybook to use webpack 5 1`] = `
|
exports[`StorybookConfiguration generator should configure storybook to use webpack 5 1`] = `
|
||||||
"module.exports = {
|
"const config = {
|
||||||
core: { builder: 'webpack5' },
|
stories: ['../**/*.stories.@(js|jsx|ts|tsx|mdx)'],
|
||||||
stories: ['../**/*.stories.mdx', '../**/*.stories.@(js|jsx|ts|tsx)'],
|
|
||||||
addons: ['@storybook/addon-essentials'],
|
addons: ['@storybook/addon-essentials'],
|
||||||
|
framework: {
|
||||||
|
name: '@storybook/angular',
|
||||||
|
options: {},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
|
|
||||||
// To customize your webpack configuration you can use the webpackFinal field.
|
// To customize your webpack configuration you can use the webpackFinal field.
|
||||||
// Check https://storybook.js.org/docs/react/builders/webpack#extending-storybooks-webpack-config
|
// Check https://storybook.js.org/docs/react/builders/webpack#extending-storybooks-webpack-config
|
||||||
// and https://nx.dev/packages/storybook/documents/custom-builder-configs
|
// and https://nx.dev/packages/storybook/documents/custom-builder-configs
|
||||||
|
|||||||
@ -24,27 +24,35 @@ describe('Build storybook', () => {
|
|||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
options = {
|
options = {
|
||||||
configDir: join(__dirname, `/../../utils/test-configs/.storybook`),
|
configDir: join(__dirname, `/../../utils/test-configs/.storybook`),
|
||||||
uiFramework: '@storybook/react',
|
|
||||||
outputDir: `/root/dist/storybook`,
|
outputDir: `/root/dist/storybook`,
|
||||||
};
|
};
|
||||||
|
|
||||||
context = executorContext as ExecutorContext;
|
context = executorContext as ExecutorContext;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call the storybook buildStaticStandalone', async () => {
|
it('should call the storybook build', async () => {
|
||||||
const loggerSpy = jest.spyOn(logger, 'info');
|
const loggerSpy = jest.spyOn(logger, 'info');
|
||||||
|
|
||||||
const standaloneSpy = jest
|
const buildSpy = jest
|
||||||
.spyOn(build, 'buildStaticStandalone')
|
.spyOn(build, 'build')
|
||||||
.mockImplementation(() => Promise.resolve());
|
.mockImplementation(() => Promise.resolve());
|
||||||
|
|
||||||
const result = await storybookBuilder(options, context);
|
const result = await storybookBuilder(options, context);
|
||||||
|
|
||||||
expect(standaloneSpy).toHaveBeenCalled();
|
expect(buildSpy).toHaveBeenCalled();
|
||||||
expect(loggerSpy).toHaveBeenCalledWith(`NX ui framework: @storybook/react`);
|
expect(loggerSpy).toHaveBeenNthCalledWith(
|
||||||
expect(loggerSpy).toHaveBeenCalledWith(
|
1,
|
||||||
`NX Storybook files available in /root/dist/storybook`
|
'NX Storybook builder starting ...'
|
||||||
);
|
);
|
||||||
|
expect(loggerSpy).toHaveBeenNthCalledWith(
|
||||||
|
2,
|
||||||
|
'NX Storybook builder finished ...'
|
||||||
|
);
|
||||||
|
expect(loggerSpy).toHaveBeenNthCalledWith(
|
||||||
|
3,
|
||||||
|
'NX Storybook files available in /root/dist/storybook'
|
||||||
|
);
|
||||||
|
|
||||||
expect(result.success).toBeTruthy();
|
expect(result.success).toBeTruthy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -51,15 +51,22 @@ export default async function buildStorybookExecutor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function runInstance(options: CLIOptions, storybook7: boolean): Promise<void> {
|
function runInstance(
|
||||||
|
options: CLIOptions,
|
||||||
|
storybook7: boolean
|
||||||
|
): Promise<void | {
|
||||||
|
port: number;
|
||||||
|
address: string;
|
||||||
|
networkAddress: string;
|
||||||
|
}> {
|
||||||
const env = process.env.NODE_ENV ?? 'production';
|
const env = process.env.NODE_ENV ?? 'production';
|
||||||
process.env.NODE_ENV = env;
|
process.env.NODE_ENV = env;
|
||||||
|
|
||||||
if (storybook7) {
|
if (storybook7) {
|
||||||
return build['build']({
|
return build.build({
|
||||||
...options,
|
...options,
|
||||||
mode: 'static',
|
mode: 'static',
|
||||||
} as any); // TODO(katerina): Change to actual types when Storybook 7
|
});
|
||||||
} else {
|
} else {
|
||||||
const nodeVersion = process.version.slice(1).split('.');
|
const nodeVersion = process.version.slice(1).split('.');
|
||||||
if (+nodeVersion[0] === 18) {
|
if (+nodeVersion[0] === 18) {
|
||||||
|
|||||||
@ -1,45 +1,31 @@
|
|||||||
import { fs as fsMock, vol } from 'memfs';
|
|
||||||
import * as fs from 'fs';
|
|
||||||
|
|
||||||
import { ExecutorContext } from '@nx/devkit';
|
import { ExecutorContext } from '@nx/devkit';
|
||||||
|
|
||||||
jest.mock('@storybook/core-server', () => ({
|
jest.mock('@storybook/core-server', () => ({
|
||||||
buildDev: jest.fn().mockImplementation(() => Promise.resolve()),
|
buildDev: jest.fn().mockImplementation(() => Promise.resolve()),
|
||||||
build: jest.fn().mockImplementation(() => Promise.resolve()),
|
build: jest.fn().mockImplementation(() =>
|
||||||
|
Promise.resolve({
|
||||||
|
port: 4400,
|
||||||
|
})
|
||||||
|
),
|
||||||
}));
|
}));
|
||||||
import { buildDev } from '@storybook/core-server';
|
import { build } from '@storybook/core-server';
|
||||||
|
|
||||||
import storybookExecutor from './storybook.impl';
|
import storybookExecutor from './storybook.impl';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { readFileSync } from 'fs-extra';
|
|
||||||
import { CLIOptions } from '@storybook/types';
|
import { CLIOptions } from '@storybook/types';
|
||||||
import { CommonNxStorybookConfig } from '../../utils/models';
|
import { CommonNxStorybookConfig } from '../../utils/models';
|
||||||
|
|
||||||
// TODO(katerina): Update when Storybook 7
|
|
||||||
|
|
||||||
describe('@nx/storybook:storybook', () => {
|
describe('@nx/storybook:storybook', () => {
|
||||||
let context: ExecutorContext;
|
let context: ExecutorContext;
|
||||||
let options: CLIOptions & CommonNxStorybookConfig;
|
let options: CLIOptions & CommonNxStorybookConfig;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// preserve original package.json file to memory
|
|
||||||
const rootPath = join(__dirname, `../../../../../`);
|
const rootPath = join(__dirname, `../../../../../`);
|
||||||
const packageJsonPath = join(
|
|
||||||
rootPath,
|
|
||||||
`node_modules/@storybook/react/package.json`
|
|
||||||
);
|
|
||||||
const storybookPath = join(rootPath, '.storybook');
|
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
uiFramework: '@storybook/react',
|
|
||||||
port: 4400,
|
port: 4400,
|
||||||
configDir: storybookPath,
|
configDir: join(__dirname, `/../../utils/test-configs/.storybook`),
|
||||||
};
|
};
|
||||||
vol.fromJSON({
|
|
||||||
[packageJsonPath]: readFileSync(packageJsonPath).toString(),
|
|
||||||
});
|
|
||||||
vol.mkdirSync(storybookPath, {
|
|
||||||
recursive: true,
|
|
||||||
});
|
|
||||||
context = {
|
context = {
|
||||||
root: rootPath,
|
root: rootPath,
|
||||||
cwd: rootPath,
|
cwd: rootPath,
|
||||||
@ -54,22 +40,7 @@ describe('@nx/storybook:storybook', () => {
|
|||||||
targets: {
|
targets: {
|
||||||
build: {
|
build: {
|
||||||
executor: '@nx/web:webpack',
|
executor: '@nx/web:webpack',
|
||||||
options: {
|
options: {},
|
||||||
compiler: 'babel',
|
|
||||||
outputPath: 'dist/apps/webre',
|
|
||||||
index: 'apps/webre/src/index.html',
|
|
||||||
baseHref: '/',
|
|
||||||
main: 'apps/webre/src/main.tsx',
|
|
||||||
polyfills: 'apps/webre/src/polyfills.ts',
|
|
||||||
tsConfig: 'apps/webre/tsconfig.app.json',
|
|
||||||
assets: [
|
|
||||||
'apps/webre/src/favicon.ico',
|
|
||||||
'apps/webre/src/assets',
|
|
||||||
],
|
|
||||||
styles: ['apps/webre/src/styles.css'],
|
|
||||||
scripts: [],
|
|
||||||
webpackConfig: '@nx/react/plugins/webpack',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
storybook: {
|
storybook: {
|
||||||
executor: '@nx/storybook:storybook',
|
executor: '@nx/storybook:storybook',
|
||||||
@ -82,16 +53,18 @@ describe('@nx/storybook:storybook', () => {
|
|||||||
nxJsonConfiguration: {},
|
nxJsonConfiguration: {},
|
||||||
isVerbose: false,
|
isVerbose: false,
|
||||||
};
|
};
|
||||||
jest.mock('fs', () => fsMock);
|
|
||||||
jest.spyOn(fs, 'statSync').mockReturnValue({
|
|
||||||
isDirectory: () => true,
|
|
||||||
} as fs.Stats);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should provide options to storybook', async () => {
|
it('should provide options to storybook', async () => {
|
||||||
const iterator = storybookExecutor(options, context);
|
const iterator = storybookExecutor(options, context);
|
||||||
const { value } = await iterator.next();
|
const { value } = await iterator.next();
|
||||||
expect(value).toEqual({ success: true });
|
expect(value).toEqual({
|
||||||
expect(buildDev).toHaveBeenCalled();
|
success: true,
|
||||||
|
info: {
|
||||||
|
baseUrl: 'http://localhost:4400',
|
||||||
|
port: 4400,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(build).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -24,17 +24,14 @@ export default async function* storybookExecutor(
|
|||||||
storybookConfigExistsCheck(options.configDir, context.projectName);
|
storybookConfigExistsCheck(options.configDir, context.projectName);
|
||||||
if (storybook7) {
|
if (storybook7) {
|
||||||
const buildOptions: CLIOptions = options;
|
const buildOptions: CLIOptions = options;
|
||||||
const result: { port: number } = await runInstance(
|
const result = await runInstance(buildOptions, storybook7);
|
||||||
buildOptions,
|
|
||||||
storybook7
|
|
||||||
);
|
|
||||||
yield {
|
yield {
|
||||||
success: true,
|
success: true,
|
||||||
info: {
|
info: {
|
||||||
port: result?.port,
|
port: result?.['port'],
|
||||||
baseUrl: `${options.https ? 'https' : 'http'}://${
|
baseUrl: `${options.https ? 'https' : 'http'}://${
|
||||||
options.host ?? 'localhost'
|
options.host ?? 'localhost'
|
||||||
}:${result?.port}`,
|
}:${result?.['port']}`,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
await new Promise<{ success: boolean }>(() => {});
|
await new Promise<{ success: boolean }>(() => {});
|
||||||
@ -58,18 +55,24 @@ export default async function* storybookExecutor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function runInstance(options: CLIOptions, storybook7: boolean) {
|
function runInstance(
|
||||||
|
options: CLIOptions,
|
||||||
|
storybook7: boolean
|
||||||
|
): Promise<void | {
|
||||||
|
port: number;
|
||||||
|
address: string;
|
||||||
|
networkAddress: string;
|
||||||
|
}> {
|
||||||
const env = process.env.NODE_ENV ?? 'development';
|
const env = process.env.NODE_ENV ?? 'development';
|
||||||
process.env.NODE_ENV = env;
|
process.env.NODE_ENV = env;
|
||||||
|
|
||||||
if (storybook7) {
|
if (storybook7) {
|
||||||
return build['build']({
|
return build.build({
|
||||||
...options,
|
...options,
|
||||||
mode: 'dev',
|
mode: 'dev',
|
||||||
} as any); // TODO(katerina): Change to actual types when Storybook 7
|
});
|
||||||
} else {
|
} else {
|
||||||
// TODO(katerina): Remove when Storybook 7
|
// TODO(katerina): Remove when Storybook 7
|
||||||
return build.buildDev({
|
return build['buildDev']({
|
||||||
...options,
|
...options,
|
||||||
configType: env.toUpperCase(),
|
configType: env.toUpperCase(),
|
||||||
mode: 'dev',
|
mode: 'dev',
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
addDependenciesToPackageJson,
|
addDependenciesToPackageJson,
|
||||||
convertNxGenerator,
|
convertNxGenerator,
|
||||||
|
detectPackageManager,
|
||||||
GeneratorCallback,
|
GeneratorCallback,
|
||||||
readJson,
|
readJson,
|
||||||
readNxJson,
|
readNxJson,
|
||||||
@ -76,6 +77,17 @@ function checkDependenciesInstalled(host: Tree, schema: Schema) {
|
|||||||
devDependencies['@storybook/react-native'] = storybookReactNativeVersion;
|
devDependencies['@storybook/react-native'] = storybookReactNativeVersion;
|
||||||
} else {
|
} else {
|
||||||
devDependencies[schema.uiFramework] = storybook7VersionToInstall;
|
devDependencies[schema.uiFramework] = storybook7VersionToInstall;
|
||||||
|
const isPnpm = detectPackageManager(host.root) === 'pnpm';
|
||||||
|
if (isPnpm) {
|
||||||
|
// If it's pnpm, it needs the framework without the builder
|
||||||
|
// as a dependency too (eg. @storybook/react)
|
||||||
|
const matchResult = schema.uiFramework?.match(/^@storybook\/(\w+)/);
|
||||||
|
const uiFrameworkWithoutBuilder = matchResult ? matchResult[0] : null;
|
||||||
|
if (uiFrameworkWithoutBuilder) {
|
||||||
|
devDependencies[uiFrameworkWithoutBuilder] =
|
||||||
|
storybook7VersionToInstall;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
devDependencies['@storybook/core-server'] = storybook7VersionToInstall;
|
devDependencies['@storybook/core-server'] = storybook7VersionToInstall;
|
||||||
devDependencies['@storybook/addon-essentials'] = storybook7VersionToInstall;
|
devDependencies['@storybook/addon-essentials'] = storybook7VersionToInstall;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user