Skip to content

Commit

Permalink
feat: support storybook 6.2.x-beta (#165)
Browse files Browse the repository at this point in the history
* chore: upgrade storybook

* up snaps

* prepare storybook v6.2 integration tests

* fix in semver usage

* first working version with storybook next

* up snap

* remove some non needed things

* fix tests

* try fixing node meomry max

* try fixing node meomry max 2nd try
  • Loading branch information
JohannesMerz authored Feb 23, 2021
1 parent eb3910e commit 06a8f89
Show file tree
Hide file tree
Showing 83 changed files with 3,787 additions and 1,039 deletions.
5 changes: 4 additions & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,15 @@ jobs:
executor: base
steps:
- init
- run:
name: up node memory maximum
command: NODE_OPTIONS=--max_old_space_size=4096
- run:
name: lint
command: yarn lint
- run:
name: unit tests
command: yarn test
command: yarn test -w 1
- run:
name: integration tests
command: yarn integration
Expand Down
9 changes: 7 additions & 2 deletions bin/integration.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,17 @@ function preparePackage {

function preparePackages {
preparePackage integration-tests
preparePackage integration-tests-storybook
preparePackage integration-tests-storybook-6_1_x
preparePackage integration-tests-storybook-6_2_x
}

function integration {
preparePackages
cd $PROJECT_ROOT && yarn jest --runInBand --config integration.jest.config.js --forceExit ${@}
runIntegration ${@:1}
}

function runIntegration {
cd $PROJECT_ROOT && yarn jest --runInBand --config integration.jest.config.js --forceExit ${@}
}

function integrationLocal {
Expand Down
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
"lint": "eslint packages/*/src/**/*.ts",
"updateReadmes": "lerna exec \"cp \\$LERNA_ROOT_PATH/README.md \\$PWD/README.md\""
},
"license" : "BSD-3-Clause",
"license": "BSD-3-Clause",
"devDependencies": {
"@types/jest": "24.0.15",
"@types/node": "14.14.31",
"@types/react": "16.9.41",
"@types/node": "12.12.6",
"@types/request-promise": "4.1.45",
"@typescript-eslint/eslint-plugin": "2.21.0",
"@typescript-eslint/eslint-plugin-tslint": "2.21.0",
Expand Down Expand Up @@ -44,5 +44,6 @@
},
"workspaces": [
"packages/*"
]
],
"nohoist": ["**/@storybook/**"]
}
1 change: 1 addition & 0 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"node-emoji": "^1.10.0",
"open": "^7.3.0",
"rimraf": "^2.6.3",
"semver": "^7.3.4",
"simple-git": "^2.4.0",
"webpack-dev-server": "^3.11.2",
"webpack-merge": "^5.1.4"
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/config/getProjectWebpackConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as pathUtils from 'path';
import { CiSettings } from './getCiSettings';
import { BaseConfig } from './types';
import { NonVerboseError } from '../errors';
import { softRequireResolve } from '../utils/softRequireResolve';
import { softRequireResolve } from '../utils/requireUtils';
import { getStorybookProjectWebpackConfig } from '../storybook';

import webpack = require('webpack');
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/debug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export enum DebugNamespaces {
UPLOAD = 'upload',
VALIDATE = 'validate',
WEBPACK_CONFIG = 'webpackConfig',
REQUIRE = 'require',
}

const debuggers = Object.values(DebugNamespaces).reduce(
Expand Down
25 changes: 25 additions & 0 deletions packages/cli/src/storybook/getProjectWebpackConfig/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/* eslint-disable camelcase */
import webpack from 'webpack';
import * as semver from 'semver';
import { getStorybookFramework, getStorybookVersion } from '../storybookUtils';
import { getV_6_1_X_StorybookProjectWebpackConfig } from './v6.1.x';
import { getV_6_2_X_StorybookProjectWebpackConfig } from './v6.2.x';
import debuggers, { DebugNamespaces } from '../../debug';

const debug = debuggers[DebugNamespaces.STORYBOOK];

export async function getStorybookProjectWebpackConfig(): Promise<webpack.Configuration | void> {
const framework = getStorybookFramework();
if (framework) {
debug(`storybook framework detected: ${framework}`);
const version = getStorybookVersion(framework);
debug(`storybook version: ${version}`);
if (semver.gte(semver.coerce(version), '6.2.0')) {
debug('version greater than 6.2.0, using V_6_2_X configuration');
return getV_6_2_X_StorybookProjectWebpackConfig(framework);
}
debug('version below 6.2.0, using V_6_1_X configuration');
return getV_6_1_X_StorybookProjectWebpackConfig(framework);
}
return undefined;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import webpack from 'webpack';

export function replaceDefaultMediaLoader(rules: webpack.RuleSetRule[]): webpack.RuleSetRule[] {
const defaultAssertLoaderIndex = rules.findIndex(
rule =>
rule.loader?.toString().includes('file-loader') &&
rule.test?.toString().includes('svg|ico|jpg|jpeg|png|apng|gif')
);

// if we find storybooks default asset loader we make sure to use the url loader instead
if (defaultAssertLoaderIndex >= 0) {
const ruleCopy = { ...rules[defaultAssertLoaderIndex] };

const newRules = [...rules];
newRules.splice(defaultAssertLoaderIndex, 1, {
...ruleCopy,
loader: 'url-loader', // we bundle all small assets into the js
options: { limit: 10000, name: 'static/media/[name].[hash:8].[ext]', esModule: false },
});
return newRules;
}
return rules;
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { getStorybookLoadOptions } from './storybookUtils';
import { replaceWebpackRules } from '../utils/replaceWebpackRules';
import { getSbOption, getSbCliOptions } from './getSbOption';
import { getPackageFolder } from '../utils/getPackageFolder';
import * as path from 'path';
import { getStorybookFrameworkLoadOptions } from '../storybookUtils';
import { replaceWebpackRules } from '../../utils/replaceWebpackRules';
import { getSbOption, getSbCliOptions } from '../getSbOption';
import { getPackageFolder } from '../../utils/getPackageFolder';
import { replaceDefaultMediaLoader } from './replaceLoaders';
import { StorybookFramework } from '../types';

import webpack = require('webpack');

const path = require('path');

async function getWebpackConfig(loadOptions) {
// we have to load all those libs dynamically as they are all optional
// eslint-disable-next-line import/no-extraneous-dependencies
Expand Down Expand Up @@ -36,39 +37,17 @@ async function getWebpackConfig(loadOptions) {
return replaceWebpackRules(webpackConfig, replaceDefaultMediaLoader);
}

export async function getStorybookProjectWebpackConfig(): Promise<webpack.Configuration | void> {
const loadConfig = getStorybookLoadOptions();
if (loadConfig) {
return getWebpackConfig(loadConfig);
}
// eslint-disable-next-line camelcase
export async function getV_6_1_X_StorybookProjectWebpackConfig(
framework: StorybookFramework
): Promise<webpack.Configuration | void> {
const loadConfig = getStorybookFrameworkLoadOptions(framework);

return undefined;
return getWebpackConfig(loadConfig);
}

function getOutputDir(givenOutputDir) {
return path.isAbsolute(givenOutputDir)
? givenOutputDir
: path.join(process.cwd(), givenOutputDir);
}

function replaceDefaultMediaLoader(rules: webpack.RuleSetRule[]): webpack.RuleSetRule[] {
const defaultAssertLoaderIndex = rules.findIndex(
rule =>
rule.loader?.toString().includes('file-loader') &&
rule.test?.toString().includes('svg|ico|jpg|jpeg|png|apng|gif')
);

// if we find storybooks default asset loader we make sure to use the url loader instead
if (defaultAssertLoaderIndex >= 0) {
const ruleCopy = { ...rules[defaultAssertLoaderIndex] };

const newRules = [...rules];
newRules.splice(defaultAssertLoaderIndex, 1, {
...ruleCopy,
loader: 'url-loader', // we bundle all small assets into the js
options: { limit: 10000, name: 'static/media/[name].[hash:8].[ext]', esModule: false },
});
return newRules;
}
return rules;
}
74 changes: 74 additions & 0 deletions packages/cli/src/storybook/getProjectWebpackConfig/v6.2.x.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import * as path from 'path';
import { getStorybookFrameworkLoadOptions } from '../storybookUtils';
import { replaceWebpackRules } from '../../utils/replaceWebpackRules';
import { getSbOption, getSbCliOptions } from '../getSbOption';
import { getPackageFolder } from '../../utils/getPackageFolder';
import { replaceDefaultMediaLoader } from './replaceLoaders';
import { StorybookFramework } from '../types';

import webpack = require('webpack');

async function getWebpackConfig(loadOptions) {
// we have to load all those libs dynamically as they are all optional
const {
getPreviewBuilder,
// eslint-disable-next-line import/no-extraneous-dependencies
} = require('@storybook/core-server/dist/cjs/utils/get-preview-builder');
// eslint-disable-next-line import/no-extraneous-dependencies
const { loadAllPresets } = require('@storybook/core-common');
const cliOptions = getSbCliOptions();
const configDir = getSbOption('configDir', './.storybook');

const previewBuilder = await getPreviewBuilder(configDir);

const coreOptions = {
...loadOptions,
...cliOptions,
configType: 'PRODUCTION',
outputDir: getOutputDir(getSbOption('outputDir', './storybook-static')),
configDir,
ignorePreview: !!cliOptions.previewUrl,
docsMode: !!cliOptions.docs,
};

const presets = await loadAllPresets({
...coreOptions,
corePresets: [
require.resolve('@storybook/core-server/dist/cjs/presets/common-preset'),
require.resolve('@storybook/core-server/dist/cjs/presets/manager-preset'),
...previewBuilder.corePresets,
require.resolve('@storybook/core-server/dist/cjs/presets/babel-cache-preset'),
],
overridePresets: previewBuilder.overridePresets,
});

const fullOptions = {
...coreOptions,
presets,
};

const webpackConfig = await previewBuilder.getConfig(fullOptions);

// Add node_modules of SB core in case resolvers are placed there by npm/yarn
webpackConfig.resolveLoader = webpackConfig.resolveLoader || {};
const corePackagePath = getPackageFolder('@storybook/core-server');
webpackConfig.resolveLoader.modules = webpackConfig.resolveLoader?.modules || ['node_modules'];
webpackConfig.resolveLoader.modules.push(path.join(corePackagePath, 'node_modules'));

return replaceWebpackRules(webpackConfig, replaceDefaultMediaLoader);
}

// eslint-disable-next-line camelcase
export async function getV_6_2_X_StorybookProjectWebpackConfig(
framework: StorybookFramework
): Promise<webpack.Configuration | void> {
const loadConfig = getStorybookFrameworkLoadOptions(framework);

return getWebpackConfig(loadConfig);
}

function getOutputDir(givenOutputDir) {
return path.isAbsolute(givenOutputDir)
? givenOutputDir
: path.join(process.cwd(), givenOutputDir);
}
21 changes: 17 additions & 4 deletions packages/cli/src/storybook/storybookUtils.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { softRequireResolve } from '../utils/softRequireResolve';
import { requireFromPaths, softRequireResolve } from '../utils/requireUtils';
import { StorybookFramework } from './types';

const frameworkToPackageMap = {
[StorybookFramework.REACT]: '@storybook/react',
};

const frameworkToLoadOptionsMap = {
[StorybookFramework.REACT]: '@storybook/react/dist/server/options',
[StorybookFramework.REACT]: [
'@storybook/react/dist/server/options',
'@storybook/react/dist/cjs/server/options',
],
};

export function getStorybookLoadOptions() {
Expand All @@ -22,11 +25,21 @@ export function getStorybookLoadOptions() {
}

export function getStorybookFrameworkLoadOptions(framework: StorybookFramework) {
return require(frameworkToLoadOptionsMap[framework]).default;
const possibleImports = frameworkToLoadOptionsMap[framework];

return requireFromPaths<any>(possibleImports).default;
}

export function getStorybookFramework(): StorybookFramework | undefined {
const sbFrameworkKey = Object.keys(StorybookFramework).find(storybookFrameworkIsInstalled);
if (sbFrameworkKey) {
return StorybookFramework[sbFrameworkKey];
}
return undefined;
}

export function storybookIsInstalled(): boolean {
return !!Object.keys(StorybookFramework).find(storybookFrameworkIsInstalled);
return !!getStorybookFramework();
}

export function storybookFrameworkIsInstalled(framework: StorybookFramework): boolean {
Expand Down
10 changes: 10 additions & 0 deletions packages/cli/src/utils/requireUtils.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import * as path from 'path';
import { softRequireResolve } from './requireUtils';

test('return the path if file exists', () => {
expect(softRequireResolve('./requireUtils')).toEqual(path.resolve(__dirname, 'requireUtils.ts'));
});

test('return undefined otherwise', () => {
expect(softRequireResolve('./unknown')).toEqual(undefined);
});
33 changes: 33 additions & 0 deletions packages/cli/src/utils/requireUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import debuggers, { DebugNamespaces } from '../debug';

const debug = debuggers[DebugNamespaces.REQUIRE];

export function softRequireResolve(pathName) {
try {
return require.resolve(pathName);
} catch {
return undefined;
}
}

export function requireFromPaths<T>(paths: Array<string>): T {
for (let i = 0; i < paths.length; i += 1) {
try {
return require(paths[i]);
} catch (e) {
debug(`not found under ${paths[i]}`);
}
}
throw new Error(`module not found - ${paths.join(',')}`);
}

export function resolveFromPaths(paths: Array<string>): string {
for (let i = 0; i < paths.length; i += 1) {
try {
return require.resolve(paths[i]);
} catch (e) {
debug(`not found under ${paths[i]}`);
}
}
throw new Error(`module not found - ${paths.join(',')}`);
}
12 changes: 0 additions & 12 deletions packages/cli/src/utils/softRequireResolve.spec.ts

This file was deleted.

7 changes: 0 additions & 7 deletions packages/cli/src/utils/softRequireResolve.ts

This file was deleted.

2 changes: 1 addition & 1 deletion packages/integration-test-utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export function writeTestResult(name, content) {

export function getTestResult(name) {
return JSON.parse(
fs.readFileSync(path.resolve(TEST_RESULT_FOLDER, `${name}.json`), { encoding: 'uft8' })
fs.readFileSync(path.resolve(TEST_RESULT_FOLDER, `${name}.json`), { encoding: 'utf8' })
);
}

Expand Down
Loading

0 comments on commit 06a8f89

Please sign in to comment.