Skip to content

Commit

Permalink
feat(qwik-nx): storybook generator (#110)
Browse files Browse the repository at this point in the history
* feat(qwik-nx): storybook generator

* refactor: cleanup storybook config

* test(qwik-nx): tests for storybook
  • Loading branch information
dmitry-stepanenko committed Mar 30, 2023
1 parent 9456a9d commit a07d5e8
Show file tree
Hide file tree
Showing 27 changed files with 693 additions and 15 deletions.
113 changes: 113 additions & 0 deletions e2e/qwik-nx-e2e/tests/storybook.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import {
checkFilesExist,
ensureNxProject,
runNxCommandAsync,
uniq,
} from '@nrwl/nx-plugin/testing';

import {
runCommandUntil,
promisifiedTreeKill,
killPort,
killPorts,
} from '@qwikifiers/e2e/utils';

const STORYBOOK_PORT = 4400;

describe('qwikNxVite plugin e2e', () => {
beforeAll(async () => {
await killPorts(STORYBOOK_PORT);
ensureNxProject('qwik-nx', 'dist/packages/qwik-nx');
}, 10000);

afterAll(async () => {
// `nx reset` kills the daemon, and performs
// some work which can help clean up e2e leftovers
await runNxCommandAsync('reset');
});

describe('should be able to import components from libraries', () => {
const appProject = uniq('qwik-nx');
const libProject = uniq('qwik-nx');
const secondLibProject = uniq('qwik-nx');
beforeAll(async () => {
await runNxCommandAsync(
`generate qwik-nx:app ${appProject} --e2eTestRunner=none --no-interactive`
);
await runNxCommandAsync(
`generate qwik-nx:library ${libProject} --no-interactive`
);
await runNxCommandAsync(
`generate qwik-nx:storybook-configuration ${appProject} --no-interactive`
);
await runNxCommandAsync(
`generate qwik-nx:storybook-configuration ${libProject} --no-interactive`
);
}, 200000);

describe('Applying storybook for existing application', () => {
checkStorybookIsBuiltAndServed(appProject, 'apps', false);
});
describe('Applying storybook for existing library', () => {
checkStorybookIsBuiltAndServed(libProject, 'libs', false);
});

describe('Generating a new library with storybook configuration', () => {
beforeAll(async () => {
await runNxCommandAsync(
`generate qwik-nx:library ${secondLibProject} --storybookConfiguration=true --no-interactive`
);
}, 200000);
checkStorybookIsBuiltAndServed(secondLibProject, 'libs', true);
});
});
});

function checkStorybookIsBuiltAndServed(
projectName: string,
type: 'apps' | 'libs',
hasTsStories: boolean
) {
it(`should be able to build storybook for the "${projectName}"`, async () => {
const result = await runNxCommandAsync(`build-storybook ${projectName}`);
expect(result.stdout).toContain(
`Successfully ran target build-storybook for project ${projectName}`
);
expect(() =>
checkFilesExist(`dist/storybook/${projectName}/index.html`)
).not.toThrow();
}, 200000);

it(`should serve storybook for the "${projectName}"`, async () => {
let resultOutput: string | undefined;
const p = await runCommandUntil(
`run ${projectName}:storybook`,
(output) => {
if (
output.includes('Local:') &&
output.includes(`:${STORYBOOK_PORT}`)
) {
resultOutput = output;
return true;
}
return false;
}
);

// it is expected that projects won't have stories by default and storybook should recognize it.
expect(resultOutput).toContain(
`No story files found for the specified pattern: ${type}/${projectName}/**/*.stories.mdx`
);
if (!hasTsStories) {
expect(resultOutput).toContain(
`No story files found for the specified pattern: ${type}/${projectName}/**/*.stories.@(js|jsx|ts|tsx)`
);
}
try {
await promisifiedTreeKill(p.pid!, 'SIGKILL');
await killPort(STORYBOOK_PORT);
} catch {
// ignore
}
}, 200000);
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"@nrwl/js": "15.8.2",
"@nrwl/linter": "15.8.2",
"@nrwl/nx-plugin": "15.8.2",
"@nrwl/storybook": "15.8.2",
"@nrwl/vite": "15.8.2",
"@nrwl/workspace": "15.8.2",
"@nxkit/playwright": "^2.1.2",
Expand Down
5 changes: 5 additions & 0 deletions packages/qwik-nx/generators.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@
"factory": "./src/generators/remote/generator",
"schema": "./src/generators/remote/schema.json",
"description": "Generate a remote Qwik application for the micro frontend setup"
},
"storybook-configuration": {
"factory": "./src/generators/storybook-configuration/generator",
"schema": "./src/generators/storybook-configuration/schema.json",
"description": "Adds Storybook configuration to a project."
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Canvas, Story } from '@storybook/addon-docs';
import { <%- className %> } from './<%- fileName %>';

# <%- className %> Component

## Purpose

{/* Why the component is needed */}

## Example

{/* Common copy/paste example that people can throw into their templates and ts */}

~~~tsx
<<%- className %> param="value" />
~~~

## Use case examples

{/* Examples based on use cases */}

### Primary

<Canvas>
<Story id="<%- className.toLowerCase() %>--primary" />
</Canvas>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { Meta } from 'storybook-framework-qwik';
import { <%- className %> } from './<%- fileName %>';
import doc from './<%- fileName %>.doc.mdx';

export default {
title: '<%- className %>',
tags: ['autodocs'],
parameters: {
docs: {
page: doc,
},
},
argTypes: {
// put component params here
},
render(args) {
return <<%- className %> {...args}/>;
},
} as Meta;

export const Primary = {};
10 changes: 10 additions & 0 deletions packages/qwik-nx/src/generators/component/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
Tree,
} from '@nrwl/devkit';
import { addStyledModuleDependencies } from '../../utils/add-styled-dependencies';
import { ensureMdxTypeInTsConfig } from '../../utils/ensure-file-utils';
import { ComponentGeneratorSchema } from './schema';

interface NormalizedSchema extends ComponentGeneratorSchema {
Expand Down Expand Up @@ -95,6 +96,15 @@ function createComponentFiles(tree: Tree, options: NormalizedSchema) {
templateOptions
);
}
if (options.generateStories) {
generateFiles(
tree,
joinPathFragments(__dirname, 'files/storybook'),
componentDir,
templateOptions
);
ensureMdxTypeInTsConfig(tree, options.project);
}
}

export async function componentGenerator(
Expand Down
1 change: 1 addition & 0 deletions packages/qwik-nx/src/generators/component/schema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export interface ComponentGeneratorSchema {
style?: 'none' | 'css' | 'scss' | 'styl' | 'less';
skipTests?: boolean;
flat?: boolean;
generateStories?: boolean;
}
4 changes: 4 additions & 0 deletions packages/qwik-nx/src/generators/component/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@
"type": "boolean",
"description": "Create component at the source root rather than its own directory.",
"default": false
},
"generateStories": {
"description": "Create Storybook stories for the component",
"type": "boolean"
}
},
"required": ["name", "project"]
Expand Down
4 changes: 2 additions & 2 deletions packages/qwik-nx/src/generators/e2e-project/generator.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ describe('e2e project', () => {
.spyOn(getInstalledNxVersionModule, 'getInstalledNxVersion')
.mockReturnValue('15.6.0');

beforeEach(() => {
beforeEach(async () => {
appTree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
appGenerator(appTree, {
await appGenerator(appTree, {
name: 'myapp',
e2eTestRunner: 'none',
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ describe('cloudflare-pages-integration generator', () => {
project: projectName,
};

beforeEach(() => {
beforeEach(async () => {
appTree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });

applicationGenerator(appTree, {
await applicationGenerator(appTree, {
name: projectName,
e2eTestRunner: 'none',
linter: Linter.None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,7 @@ export default defineConfig({
}),
],
mode: 'lib',
// Configuration for building your library.
// Configuration for building your library.
// See: https://vitejs.dev/guide/build.html#library-mode
build: {
lib: {
Expand Down Expand Up @@ -164,6 +163,10 @@ Array [
"path": "libs/mylib/vite.config.ts",
"type": "CREATE",
},
Object {
"path": "libs/mylib/src/root.tsx",
"type": "CREATE",
},
Object {
"path": "libs/mylib/src/lib/mylib.tsx",
"type": "CREATE",
Expand Down Expand Up @@ -261,6 +264,10 @@ Array [
"path": "libs/mylib/.eslintrc.json",
"type": "CREATE",
},
Object {
"path": "libs/mylib/src/root.tsx",
"type": "CREATE",
},
Object {
"path": "libs/mylib/src/lib/mylib.tsx",
"type": "CREATE",
Expand Down Expand Up @@ -404,6 +411,10 @@ Array [
"path": "libs/mylib/vite.config.ts",
"type": "CREATE",
},
Object {
"path": "libs/mylib/src/root.tsx",
"type": "CREATE",
},
Object {
"path": "libs/mylib/src/lib/mylib.tsx",
"type": "CREATE",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@
"isolatedModules": true,
"outDir": "tmp",
"noEmit": true,
"types": ["node", "vite/client"<% if(setupVitest) { %> , "vitest" <% } %>]
"types": [
"node",
"vite/client",
<% if(setupVitest) { %>"vitest", <% } %>
<% if(storybookConfiguration) { %>"mdx", <% } %>
]
},
"files": [],
"include": [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ export default defineConfig({
}),
<% } %>
],
<% if(buildable) { %> mode: 'lib',
// Configuration for building your library.
<% if(buildable) { %> // Configuration for building your library.
// See: https://vitejs.dev/guide/build.html#library-mode
build: {
lib: {
Expand Down
19 changes: 18 additions & 1 deletion packages/qwik-nx/src/generators/library/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import { initGenerator } from '@nrwl/vite';
import { addCommonQwikDependencies } from '../../utils/add-common-qwik-dependencies';
import { getQwikLibProjectTargets } from './utils/get-qwik-lib-project-params';
import { normalizeOptions } from './utils/normalize-options';
import storybookConfigurationGenerator from '../storybook-configuration/generator';
import { ensureRootTsxExists } from '../../utils/ensure-file-utils';

export async function libraryGenerator(
tree: Tree,
Expand Down Expand Up @@ -62,7 +64,6 @@ async function addLibrary(
linter: Linter.None,
importPath: options.importPath,
strict: options.strict,
standaloneConfig: options.standaloneConfig,
unitTestRunner: 'none',
skipBabelrc: true,
skipFormat: true,
Expand All @@ -84,6 +85,8 @@ async function addLibrary(
templateOptions
);

ensureRootTsxExists(tree, options.projectName);

if (!options.setupVitest) {
tree.delete(`${options.projectRoot}/tsconfig.spec.json`);
}
Expand All @@ -95,11 +98,16 @@ async function addLibrary(
}
}

if (options.storybookConfiguration) {
tasks.push(await configureStorybook(tree, options));
}

const componentGeneratorTask = await componentGenerator(tree, {
name: options.name,
skipTests: !options.setupVitest,
style: options.style,
project: options.projectName,
generateStories: options.storybookConfiguration,
flat: true,
});

Expand All @@ -126,4 +134,13 @@ async function configureVite(tree: Tree, options: NormalizedSchema) {
return callback;
}

async function configureStorybook(
tree: Tree,
options: NormalizedSchema
): Promise<GeneratorCallback> {
return storybookConfigurationGenerator(tree, {
name: options.projectName,
});
}

export default libraryGenerator;
3 changes: 2 additions & 1 deletion packages/qwik-nx/src/generators/library/schema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ export interface LibraryGeneratorSchema {
importPath?: string;
strict?: boolean;
buildable?: boolean;
standaloneConfig?: boolean;
storybookConfiguration?: boolean;
}

type NormalizedRequiredPropsNames =
| 'style'
| 'unitTestRunner'
| 'linter'
| 'storybookConfiguration'
| 'buildable';
type NormalizedRequiredProps = Required<
Pick<LibraryGeneratorSchema, NormalizedRequiredPropsNames>
Expand Down
Loading

0 comments on commit a07d5e8

Please sign in to comment.