From 31ba8b8e26a2c683cd1b008ce387689bff29250c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Maisse?= Date: Mon, 28 Sep 2020 20:21:51 +0200 Subject: [PATCH 01/21] refactor(core): migrate `manager` to TS --- ...-polyfills.js => conditional-polyfills.ts} | 2 +- .../src/client/manager/{index.js => index.ts} | 2 ++ .../manager/{provider.js => provider.ts} | 19 +++++++++++++++---- lib/core/src/typings.d.ts | 1 + 4 files changed, 19 insertions(+), 5 deletions(-) rename lib/core/src/client/manager/{conditional-polyfills.js => conditional-polyfills.ts} (88%) rename lib/core/src/client/manager/{index.js => index.ts} (83%) rename lib/core/src/client/manager/{provider.js => provider.ts} (52%) diff --git a/lib/core/src/client/manager/conditional-polyfills.js b/lib/core/src/client/manager/conditional-polyfills.ts similarity index 88% rename from lib/core/src/client/manager/conditional-polyfills.js rename to lib/core/src/client/manager/conditional-polyfills.ts index bf53cb028b2a..3f98ebc20a17 100644 --- a/lib/core/src/client/manager/conditional-polyfills.js +++ b/lib/core/src/client/manager/conditional-polyfills.ts @@ -6,7 +6,7 @@ export const importPolyfills = () => { if (!window.fetch) { // manually patch window.fetch; // see issue: - const patch = ({ default: fetch }) => { + const patch = ({ default: fetch }: any) => { window.fetch = fetch; }; diff --git a/lib/core/src/client/manager/index.js b/lib/core/src/client/manager/index.ts similarity index 83% rename from lib/core/src/client/manager/index.js rename to lib/core/src/client/manager/index.ts index e63acd2424a1..c5287efc10b4 100644 --- a/lib/core/src/client/manager/index.js +++ b/lib/core/src/client/manager/index.ts @@ -5,5 +5,7 @@ import { importPolyfills } from './conditional-polyfills'; importPolyfills().then(() => { const rootEl = document.getElementById('root'); + // FIXME: Fix Provider functions signatures + // @ts-ignore renderStorybookUI(rootEl, new Provider()); }); diff --git a/lib/core/src/client/manager/provider.js b/lib/core/src/client/manager/provider.ts similarity index 52% rename from lib/core/src/client/manager/provider.js rename to lib/core/src/client/manager/provider.ts index d40e0b1a7bf9..b40d8c6f9260 100644 --- a/lib/core/src/client/manager/provider.js +++ b/lib/core/src/client/manager/provider.ts @@ -1,9 +1,13 @@ import { Provider } from '@storybook/ui'; -import addons from '@storybook/addons'; +import addons, { AddonStore, Channel, Types } from '@storybook/addons'; import createChannel from '@storybook/channel-postmessage'; import Events from '@storybook/core-events'; export default class ReactProvider extends Provider { + private addons: AddonStore; + + private channel: Channel; + constructor() { super(); @@ -16,15 +20,22 @@ export default class ReactProvider extends Provider { this.channel = channel; } - getElements(type) { + // FIXME: Overload doesn't match function of super class + // @ts-ignore + getElements(type: Types) { return this.addons.getElements(type); } - getConfig() { + // FIXME: Define return type to avoid: + // TS4053: Return type of public method from exported class has or is using name 'Config' + // @ts-ignore + getConfig(): any { return this.addons.getConfig(); } - handleAPI(api) { + // FIXME: Overload doesn't match function of super class + // @ts-ignore + handleAPI(api: unknown) { this.addons.loadAddons(api); } } diff --git a/lib/core/src/typings.d.ts b/lib/core/src/typings.d.ts index 56e9012bf86f..b26e002ee403 100644 --- a/lib/core/src/typings.d.ts +++ b/lib/core/src/typings.d.ts @@ -1,2 +1,3 @@ declare module 'global'; declare module '@storybook/semver'; +declare module 'unfetch/dist/unfetch'; From adc31218364c923fc0fd0b59d82eafc7cf2136e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Maisse?= Date: Mon, 28 Sep 2020 20:25:45 +0200 Subject: [PATCH 02/21] refactor: export `Config` from `addons` as it is used in a public function Then use this interface in `core` to improve typings --- lib/addons/src/index.ts | 2 +- lib/core/src/client/manager/provider.ts | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/lib/addons/src/index.ts b/lib/addons/src/index.ts index 99945c21dd2e..c3729163fed4 100644 --- a/lib/addons/src/index.ts +++ b/lib/addons/src/index.ts @@ -38,7 +38,7 @@ interface Elements { [key: string]: Collection; } -interface Config { +export interface Config { theme?: ThemeVars; [key: string]: any; } diff --git a/lib/core/src/client/manager/provider.ts b/lib/core/src/client/manager/provider.ts index b40d8c6f9260..78c937b15f37 100644 --- a/lib/core/src/client/manager/provider.ts +++ b/lib/core/src/client/manager/provider.ts @@ -1,5 +1,5 @@ import { Provider } from '@storybook/ui'; -import addons, { AddonStore, Channel, Types } from '@storybook/addons'; +import addons, { AddonStore, Channel, Config, Types } from '@storybook/addons'; import createChannel from '@storybook/channel-postmessage'; import Events from '@storybook/core-events'; @@ -26,10 +26,7 @@ export default class ReactProvider extends Provider { return this.addons.getElements(type); } - // FIXME: Define return type to avoid: - // TS4053: Return type of public method from exported class has or is using name 'Config' - // @ts-ignore - getConfig(): any { + getConfig(): Config { return this.addons.getConfig(); } From 28eb52414fd3ebabf3f6102b06b4de30fa8d5a2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Maisse?= Date: Mon, 28 Sep 2020 20:30:12 +0200 Subject: [PATCH 03/21] refactor: improve typings of `Provider` --- lib/core/src/client/manager/index.ts | 2 -- lib/core/src/client/manager/provider.ts | 4 ---- lib/ui/src/provider.ts | 6 ++++-- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/lib/core/src/client/manager/index.ts b/lib/core/src/client/manager/index.ts index c5287efc10b4..e63acd2424a1 100644 --- a/lib/core/src/client/manager/index.ts +++ b/lib/core/src/client/manager/index.ts @@ -5,7 +5,5 @@ import { importPolyfills } from './conditional-polyfills'; importPolyfills().then(() => { const rootEl = document.getElementById('root'); - // FIXME: Fix Provider functions signatures - // @ts-ignore renderStorybookUI(rootEl, new Provider()); }); diff --git a/lib/core/src/client/manager/provider.ts b/lib/core/src/client/manager/provider.ts index 78c937b15f37..7cccd4f39f47 100644 --- a/lib/core/src/client/manager/provider.ts +++ b/lib/core/src/client/manager/provider.ts @@ -20,8 +20,6 @@ export default class ReactProvider extends Provider { this.channel = channel; } - // FIXME: Overload doesn't match function of super class - // @ts-ignore getElements(type: Types) { return this.addons.getElements(type); } @@ -30,8 +28,6 @@ export default class ReactProvider extends Provider { return this.addons.getConfig(); } - // FIXME: Overload doesn't match function of super class - // @ts-ignore handleAPI(api: unknown) { this.addons.loadAddons(api); } diff --git a/lib/ui/src/provider.ts b/lib/ui/src/provider.ts index deef40364b21..66355d8aa4b3 100644 --- a/lib/ui/src/provider.ts +++ b/lib/ui/src/provider.ts @@ -1,9 +1,11 @@ +import { Types } from '@storybook/addons'; + export default class Provider { - getElements() { + getElements(_type: Types) { throw new Error('Provider.getElements() is not implemented!'); } - handleAPI() { + handleAPI(_api: unknown) { throw new Error('Provider.handleAPI() is not implemented!'); } From e71835cb8426ae4106accaed8e1711681afc4237 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Maisse?= Date: Mon, 28 Sep 2020 21:24:40 +0200 Subject: [PATCH 04/21] refactor(core): migrate `utils` to TS --- lib/core/package.json | 2 ++ ...snap => merge-webpack-config.test.ts.snap} | 0 ...-files.test.js => interpret-files.test.ts} | 0 ...{interpret-files.js => interpret-files.ts} | 4 +-- ...-config.js => load-custom-babel-config.ts} | 11 +++--- ...onfig.js => load-custom-webpack-config.ts} | 2 +- ...file.js => load-manager-or-addons-file.ts} | 4 +-- ...file.js => load-preview-or-config-file.ts} | 2 +- ...g.test.js => merge-webpack-config.test.ts} | 0 ...pack-config.js => merge-webpack-config.ts} | 36 ++++++++++++++----- .../utils/{middleware.js => middleware.ts} | 2 +- ...rebuilt-manager.js => prebuilt-manager.ts} | 10 ++++-- .../{resolve-file.js => resolve-file.ts} | 0 ...b-cache.js => resolve-path-in-sb-cache.ts} | 2 +- .../{server-require.js => server-require.ts} | 10 +++--- .../{template.test.js => template.test.ts} | 0 .../server/utils/{template.js => template.ts} | 8 ++--- ...les.js => validate-configuration-files.ts} | 6 ++-- yarn.lock | 14 ++++++++ 19 files changed, 77 insertions(+), 36 deletions(-) rename lib/core/src/server/utils/__snapshots__/{merge-webpack-config.test.js.snap => merge-webpack-config.test.ts.snap} (100%) rename lib/core/src/server/utils/{interpret-files.test.js => interpret-files.test.ts} (100%) rename lib/core/src/server/utils/{interpret-files.js => interpret-files.ts} (85%) rename lib/core/src/server/utils/{load-custom-babel-config.js => load-custom-babel-config.ts} (91%) rename lib/core/src/server/utils/{load-custom-webpack-config.js => load-custom-webpack-config.ts} (85%) rename lib/core/src/server/utils/{load-manager-or-addons-file.js => load-manager-or-addons-file.ts} (89%) rename lib/core/src/server/utils/{load-preview-or-config-file.js => load-preview-or-config-file.ts} (88%) rename lib/core/src/server/utils/{merge-webpack-config.test.js => merge-webpack-config.test.ts} (100%) rename lib/core/src/server/utils/{merge-webpack-config.js => merge-webpack-config.ts} (51%) rename lib/core/src/server/utils/{middleware.js => middleware.ts} (88%) rename lib/core/src/server/utils/{prebuilt-manager.js => prebuilt-manager.ts} (88%) rename lib/core/src/server/utils/{resolve-file.js => resolve-file.ts} (100%) rename lib/core/src/server/utils/{resolve-path-in-sb-cache.js => resolve-path-in-sb-cache.ts} (91%) rename lib/core/src/server/utils/{server-require.js => server-require.ts} (90%) rename lib/core/src/server/utils/{template.test.js => template.test.ts} (100%) rename lib/core/src/server/utils/{template.js => template.ts} (76%) rename lib/core/src/server/utils/{validate-configuration-files.js => validate-configuration-files.ts} (91%) diff --git a/lib/core/package.json b/lib/core/package.json index e02de261afe7..d1c96d875c44 100644 --- a/lib/core/package.json +++ b/lib/core/package.json @@ -134,6 +134,8 @@ "webpack-virtual-modules": "^0.2.2" }, "devDependencies": { + "@types/mock-fs": "^4.10.0", + "@types/interpret": "^1.1.1", "mock-fs": "^4.12.0" }, "peerDependencies": { diff --git a/lib/core/src/server/utils/__snapshots__/merge-webpack-config.test.js.snap b/lib/core/src/server/utils/__snapshots__/merge-webpack-config.test.ts.snap similarity index 100% rename from lib/core/src/server/utils/__snapshots__/merge-webpack-config.test.js.snap rename to lib/core/src/server/utils/__snapshots__/merge-webpack-config.test.ts.snap diff --git a/lib/core/src/server/utils/interpret-files.test.js b/lib/core/src/server/utils/interpret-files.test.ts similarity index 100% rename from lib/core/src/server/utils/interpret-files.test.js rename to lib/core/src/server/utils/interpret-files.test.ts diff --git a/lib/core/src/server/utils/interpret-files.js b/lib/core/src/server/utils/interpret-files.ts similarity index 85% rename from lib/core/src/server/utils/interpret-files.js rename to lib/core/src/server/utils/interpret-files.ts index f92df25d4d13..280c10c76a7e 100644 --- a/lib/core/src/server/utils/interpret-files.js +++ b/lib/core/src/server/utils/interpret-files.ts @@ -14,13 +14,13 @@ function sortExtensions() { const possibleExtensions = sortExtensions(); -export function getInterpretedFile(pathToFile) { +export function getInterpretedFile(pathToFile: string) { return possibleExtensions .map((ext) => (pathToFile.endsWith(ext) ? pathToFile : `${pathToFile}${ext}`)) .find((candidate) => fs.existsSync(candidate)); } -export function getInterpretedFileWithExt(pathToFile) { +export function getInterpretedFileWithExt(pathToFile: string) { return possibleExtensions .map((ext) => ({ path: pathToFile.endsWith(ext) ? pathToFile : `${pathToFile}${ext}`, ext })) .find((candidate) => fs.existsSync(candidate.path)); diff --git a/lib/core/src/server/utils/load-custom-babel-config.js b/lib/core/src/server/utils/load-custom-babel-config.ts similarity index 91% rename from lib/core/src/server/utils/load-custom-babel-config.js rename to lib/core/src/server/utils/load-custom-babel-config.ts index a3940504b94b..2310c902ed72 100644 --- a/lib/core/src/server/utils/load-custom-babel-config.js +++ b/lib/core/src/server/utils/load-custom-babel-config.ts @@ -4,7 +4,7 @@ import JSON5 from 'json5'; import { logger } from '@storybook/node-logger'; -function removeReactHmre(presets) { +function removeReactHmre(presets: string[]) { const index = presets.indexOf('react-hmre'); if (index > -1) { presets.splice(index, 1); @@ -12,9 +12,12 @@ function removeReactHmre(presets) { } // Tries to load a .babelrc and returns the parsed object if successful -function loadFromPath(babelConfigPath) { +function loadFromPath(babelConfigPath: string) { let config; - const error = {}; + const error: { + js?: any; + json?: any; + } = {}; if (fs.existsSync(babelConfigPath)) { const content = fs.readFileSync(babelConfigPath, 'utf-8'); @@ -65,7 +68,7 @@ function loadFromPath(babelConfigPath) { return config; } -export default async function (configDir, getDefaultConfig) { +export default async function (configDir: string, getDefaultConfig: () => unknown) { // Between versions 5.1.0 - 5.1.9 this loaded babel.config.js from the project // root, which was an unintentional breaking change. We can add back project support // in 6.0. diff --git a/lib/core/src/server/utils/load-custom-webpack-config.js b/lib/core/src/server/utils/load-custom-webpack-config.ts similarity index 85% rename from lib/core/src/server/utils/load-custom-webpack-config.js rename to lib/core/src/server/utils/load-custom-webpack-config.ts index d0eabbcf6e12..8551976cbdfd 100644 --- a/lib/core/src/server/utils/load-custom-webpack-config.js +++ b/lib/core/src/server/utils/load-custom-webpack-config.ts @@ -3,5 +3,5 @@ import { serverRequire } from './server-require'; const webpackConfigs = ['webpack.config', 'webpackfile']; -export default (configDir) => +export default (configDir: string) => serverRequire(webpackConfigs.map((configName) => path.resolve(configDir, configName))); diff --git a/lib/core/src/server/utils/load-manager-or-addons-file.js b/lib/core/src/server/utils/load-manager-or-addons-file.ts similarity index 89% rename from lib/core/src/server/utils/load-manager-or-addons-file.js rename to lib/core/src/server/utils/load-manager-or-addons-file.ts index 391864848aa9..e89c8b04ea37 100644 --- a/lib/core/src/server/utils/load-manager-or-addons-file.js +++ b/lib/core/src/server/utils/load-manager-or-addons-file.ts @@ -4,9 +4,7 @@ import dedent from 'ts-dedent'; import { getInterpretedFile } from './interpret-files'; -const toArray = (a) => (a ? [a] : a); - -export function loadManagerOrAddonsFile({ configDir }) { +export function loadManagerOrAddonsFile({ configDir }: { configDir: string }) { const storybookCustomAddonsPath = getInterpretedFile(path.resolve(configDir, 'addons')); const storybookCustomManagerPath = getInterpretedFile(path.resolve(configDir, 'manager')); diff --git a/lib/core/src/server/utils/load-preview-or-config-file.js b/lib/core/src/server/utils/load-preview-or-config-file.ts similarity index 88% rename from lib/core/src/server/utils/load-preview-or-config-file.js rename to lib/core/src/server/utils/load-preview-or-config-file.ts index 8ffa790c1243..b15e3827a053 100644 --- a/lib/core/src/server/utils/load-preview-or-config-file.js +++ b/lib/core/src/server/utils/load-preview-or-config-file.ts @@ -3,7 +3,7 @@ import dedent from 'ts-dedent'; import { getInterpretedFile } from './interpret-files'; -export function loadPreviewOrConfigFile({ configDir }) { +export function loadPreviewOrConfigFile({ configDir }: { configDir: string }) { const storybookConfigPath = getInterpretedFile(path.resolve(configDir, 'config')); const storybookPreviewPath = getInterpretedFile(path.resolve(configDir, 'preview')); diff --git a/lib/core/src/server/utils/merge-webpack-config.test.js b/lib/core/src/server/utils/merge-webpack-config.test.ts similarity index 100% rename from lib/core/src/server/utils/merge-webpack-config.test.js rename to lib/core/src/server/utils/merge-webpack-config.test.ts diff --git a/lib/core/src/server/utils/merge-webpack-config.js b/lib/core/src/server/utils/merge-webpack-config.ts similarity index 51% rename from lib/core/src/server/utils/merge-webpack-config.js rename to lib/core/src/server/utils/merge-webpack-config.ts index 7b259cba86de..6152ce9b0b45 100644 --- a/lib/core/src/server/utils/merge-webpack-config.js +++ b/lib/core/src/server/utils/merge-webpack-config.ts @@ -1,23 +1,38 @@ -function plugins({ plugins: defaultPlugins = [] }, { plugins: customPlugins = [] }) { +function plugins( + { plugins: defaultPlugins = [] }: { plugins?: T[] }, + { plugins: customPlugins = [] }: { plugins?: T[] } +): T[] { return [...defaultPlugins, ...customPlugins]; } -function rules({ rules: defaultRules = [] }, { rules: customRules = [] }) { +function rules( + { rules: defaultRules = [] }: { rules?: T[] }, + { rules: customRules = [] }: { rules?: T[] } +): T[] { return [...defaultRules, ...customRules]; } -function extensions({ extensions: defaultExtensions = [] }, { extensions: customExtensions = [] }) { +function extensions( + { extensions: defaultExtensions = [] }: { extensions?: T[] }, + { extensions: customExtensions = [] }: { extensions?: T[] } +): T[] { return [...defaultExtensions, ...customExtensions]; } -function alias({ alias: defaultAlias = {} }, { alias: customAlias = {} }) { +function alias( + { alias: defaultAlias = {} }: { alias?: any }, + { alias: customAlias = {} }: { alias?: any } +) { return { ...defaultAlias, ...customAlias, }; } -function module({ module: defaultModule = {} }, { module: customModule = {} }) { +function module( + { module: defaultModule = {} }: { module?: any }, + { module: customModule = {} }: { module?: any } +) { return { ...defaultModule, ...customModule, @@ -25,7 +40,10 @@ function module({ module: defaultModule = {} }, { module: customModule = {} }) { }; } -function resolve({ resolve: defaultResolve = {} }, { resolve: customResolve = {} }) { +function resolve( + { resolve: defaultResolve = {} }: { resolve?: any }, + { resolve: customResolve = {} }: { resolve?: any } +) { return { ...defaultResolve, ...customResolve, @@ -35,8 +53,8 @@ function resolve({ resolve: defaultResolve = {} }, { resolve: customResolve = {} } function optimization( - { optimization: defaultOptimization = {} }, - { optimization: customOptimization = {} } + { optimization: defaultOptimization = {} }: { optimization?: any }, + { optimization: customOptimization = {} }: { optimization?: any } ) { return { ...defaultOptimization, @@ -44,7 +62,7 @@ function optimization( }; } -function mergeConfigs(config, customConfig) { +function mergeConfigs(config: any, customConfig: any) { return { // We'll always load our configurations after the custom config. // So, we'll always load the stuff we need. diff --git a/lib/core/src/server/utils/middleware.js b/lib/core/src/server/utils/middleware.ts similarity index 88% rename from lib/core/src/server/utils/middleware.js rename to lib/core/src/server/utils/middleware.ts index 74928bc7a5c8..b0f37bd82e24 100644 --- a/lib/core/src/server/utils/middleware.js +++ b/lib/core/src/server/utils/middleware.ts @@ -1,7 +1,7 @@ import path from 'path'; import fs from 'fs'; -export function getMiddleware(configDir) { +export function getMiddleware(configDir: string) { const middlewarePath = path.resolve(configDir, 'middleware.js'); if (fs.existsSync(middlewarePath)) { let middlewareModule = require(middlewarePath); // eslint-disable-line diff --git a/lib/core/src/server/utils/prebuilt-manager.js b/lib/core/src/server/utils/prebuilt-manager.ts similarity index 88% rename from lib/core/src/server/utils/prebuilt-manager.js rename to lib/core/src/server/utils/prebuilt-manager.ts index cf82feb44b59..d12237967300 100644 --- a/lib/core/src/server/utils/prebuilt-manager.js +++ b/lib/core/src/server/utils/prebuilt-manager.ts @@ -17,7 +17,13 @@ export const IGNORED_ADDONS = [ ...DEFAULT_ADDONS, ]; -export const getPrebuiltDir = async ({ configDir, options }) => { +export const getPrebuiltDir = async ({ + configDir, + options, +}: { + configDir: string; + options: { managerCache?: boolean }; +}) => { if (options.managerCache === false) return false; const prebuiltDir = path.join(__dirname, '../../../prebuilt'); @@ -33,7 +39,7 @@ export const getPrebuiltDir = async ({ configDir, options }) => { const { addons, refs, managerBabel, managerWebpack } = serverRequire(mainConfigFile); if (!addons || refs || managerBabel || managerWebpack) return false; if (DEFAULT_ADDONS.some((addon) => !addons.includes(addon))) return false; - if (addons.some((addon) => !IGNORED_ADDONS.includes(addon))) return false; + if (addons.some((addon: string) => !IGNORED_ADDONS.includes(addon))) return false; // Auto refs will not be listed in the config, so we have to verify there aren't any const autoRefs = await getAutoRefs({ configDir }); diff --git a/lib/core/src/server/utils/resolve-file.js b/lib/core/src/server/utils/resolve-file.ts similarity index 100% rename from lib/core/src/server/utils/resolve-file.js rename to lib/core/src/server/utils/resolve-file.ts diff --git a/lib/core/src/server/utils/resolve-path-in-sb-cache.js b/lib/core/src/server/utils/resolve-path-in-sb-cache.ts similarity index 91% rename from lib/core/src/server/utils/resolve-path-in-sb-cache.js rename to lib/core/src/server/utils/resolve-path-in-sb-cache.ts index c4ea135606fb..70afe8510d05 100644 --- a/lib/core/src/server/utils/resolve-path-in-sb-cache.js +++ b/lib/core/src/server/utils/resolve-path-in-sb-cache.ts @@ -9,7 +9,7 @@ import pkgDir from 'pkg-dir'; * @param fileOrDirectoryName {string} Name of the file or directory * @return {string} Absolute path to the file or directory */ -export function resolvePathInStorybookCache(fileOrDirectoryName) { +export function resolvePathInStorybookCache(fileOrDirectoryName: string) { const cwd = process.cwd(); const projectDir = pkgDir.sync(cwd); diff --git a/lib/core/src/server/utils/server-require.js b/lib/core/src/server/utils/server-require.ts similarity index 90% rename from lib/core/src/server/utils/server-require.js rename to lib/core/src/server/utils/server-require.ts index f87df2364286..7a0cd59f523b 100644 --- a/lib/core/src/server/utils/server-require.js +++ b/lib/core/src/server/utils/server-require.ts @@ -7,7 +7,7 @@ import { getInterpretedFileWithExt } from './interpret-files'; const compilersState = new Map(); -function registerCompiler(moduleDescriptor) { +function registerCompiler(moduleDescriptor: any): number { if (!moduleDescriptor) { return 0; } @@ -47,7 +47,7 @@ function registerCompiler(moduleDescriptor) { return registered; } -function interopRequireDefault(filePath) { +function interopRequireDefault(filePath: string) { // eslint-disable-next-line import/no-dynamic-require,global-require const result = require(filePath); @@ -57,7 +57,7 @@ function interopRequireDefault(filePath) { return isES6DefaultExported ? result.default : result; } -function getCandidate(paths) { +function getCandidate(paths: string[]) { for (let i = 0; i < paths.length; i += 1) { const candidate = getInterpretedFileWithExt(paths[i]); @@ -69,7 +69,7 @@ function getCandidate(paths) { return undefined; } -export function serverRequire(filePath) { +export function serverRequire(filePath: string | string[]) { const candidatePath = serverResolve(filePath); if (!candidatePath) { @@ -90,7 +90,7 @@ export function serverRequire(filePath) { return interopRequireDefault(candidatePath); } -export function serverResolve(filePath) { +export function serverResolve(filePath: string | string[]) { const paths = Array.isArray(filePath) ? filePath : [filePath]; const existingCandidate = getCandidate(paths); diff --git a/lib/core/src/server/utils/template.test.js b/lib/core/src/server/utils/template.test.ts similarity index 100% rename from lib/core/src/server/utils/template.test.js rename to lib/core/src/server/utils/template.test.ts diff --git a/lib/core/src/server/utils/template.js b/lib/core/src/server/utils/template.ts similarity index 76% rename from lib/core/src/server/utils/template.js rename to lib/core/src/server/utils/template.ts index f78e1be3a763..d86fb03ae55f 100644 --- a/lib/core/src/server/utils/template.js +++ b/lib/core/src/server/utils/template.ts @@ -1,10 +1,10 @@ import path from 'path'; import fs from 'fs'; -const interpolate = (string, data = {}) => +const interpolate = (string: string, data: Record = {}) => Object.entries(data).reduce((acc, [k, v]) => acc.replace(new RegExp(`%${k}%`, 'g'), v), string); -export function getPreviewBodyHtml(configDirPath, interpolations) { +export function getPreviewBodyHtml(configDirPath: string, interpolations?: Record) { const base = fs.readFileSync( path.resolve(__dirname, '../templates/base-preview-body.html'), 'utf8' @@ -20,7 +20,7 @@ export function getPreviewBodyHtml(configDirPath, interpolations) { return interpolate(result, interpolations); } -export function getPreviewHeadHtml(configDirPath, interpolations) { +export function getPreviewHeadHtml(configDirPath: string, interpolations?: Record) { const base = fs.readFileSync( path.resolve(__dirname, '../templates/base-preview-head.html'), 'utf8' @@ -36,7 +36,7 @@ export function getPreviewHeadHtml(configDirPath, interpolations) { return interpolate(result, interpolations); } -export function getManagerHeadHtml(configDirPath, interpolations) { +export function getManagerHeadHtml(configDirPath: string, interpolations: Record) { const base = fs.readFileSync( path.resolve(__dirname, '../templates/base-manager-head.html'), 'utf8' diff --git a/lib/core/src/server/utils/validate-configuration-files.js b/lib/core/src/server/utils/validate-configuration-files.ts similarity index 91% rename from lib/core/src/server/utils/validate-configuration-files.js rename to lib/core/src/server/utils/validate-configuration-files.ts index 45429755d1fd..ba19be9b3610 100644 --- a/lib/core/src/server/utils/validate-configuration-files.js +++ b/lib/core/src/server/utils/validate-configuration-files.ts @@ -13,7 +13,7 @@ const warnLegacyConfigurationFiles = deprecate( ` ); -const errorMixingConfigFiles = (first, second, configDir) => { +const errorMixingConfigFiles = (first: string, second: string, configDir: string) => { const firstPath = path.resolve(configDir, first); const secondPath = path.resolve(configDir, second); throw new Error(dedent` @@ -25,9 +25,9 @@ const errorMixingConfigFiles = (first, second, configDir) => { `); }; -export default function validateConfigurationFiles(configDir) { +export default function validateConfigurationFiles(configDir: string) { const extensionsPattern = `{${Array.from(boost).join(',')}}`; - const exists = (file) => + const exists = (file: string) => !!glob.sync(path.resolve(configDir, `${file}${extensionsPattern}`)).length; const main = exists('main'); diff --git a/yarn.lock b/yarn.lock index db553c153ec7..83aed9e79f70 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6113,6 +6113,13 @@ "@types/through" "*" rxjs "^6.4.0" +"@types/interpret@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@types/interpret/-/interpret-1.1.1.tgz#b1bf85b0420e2414b989ce237658ad20dc03719b" + integrity sha512-HZ4d0m2Ebl8DmrOdYZHgYyipj/8Ftq1/ssB/oQR7fqfUrwtTP7IW3BDi2V445nhPBLzZjEkApaPVp83moSCXlA== + dependencies: + "@types/node" "*" + "@types/is-function@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@types/is-function/-/is-function-1.0.0.tgz#1b0b819b1636c7baf0d6785d030d12edf70c3e83" @@ -6238,6 +6245,13 @@ resolved "https://registry.yarnpkg.com/@types/mithril/-/mithril-2.0.3.tgz#f24a764515d9b17095845838b12f2444757d93fa" integrity sha512-cZHOdO2IiXYeyjeDYdbOisSdfaJRzfmRo3zVzgu33IWTMA0KEQObp9fdvqcuYdPz93iJ1yCl19GcEjo/9yv+yA== +"@types/mock-fs@^4.10.0": + version "4.10.0" + resolved "https://registry.yarnpkg.com/@types/mock-fs/-/mock-fs-4.10.0.tgz#460061b186993d76856f669d5317cda8a007c24b" + integrity sha512-FQ5alSzmHMmliqcL36JqIA4Yyn9jyJKvRSGV3mvPh108VFatX7naJDzSG4fnFQNZFq9dIx0Dzoe6ddflMB2Xkg== + dependencies: + "@types/node" "*" + "@types/node-cleanup@^2.1.1": version "2.1.1" resolved "https://registry.yarnpkg.com/@types/node-cleanup/-/node-cleanup-2.1.1.tgz#c8f78a648897d2a40ed10632268ce15d343cc191" From c59c21c0672ee0f14a2883dfa56f7f6831d14fe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Maisse?= Date: Tue, 20 Oct 2020 19:18:38 +0200 Subject: [PATCH 05/21] refactor(core): migrate `common` to TS --- .../common/{babel-cache-preset.js => babel-cache-preset.ts} | 2 +- lib/core/src/server/common/{babel.js => babel.ts} | 0 .../src/server/common/{common-preset.js => common-preset.ts} | 5 +++-- .../server/common/{custom-presets.js => custom-presets.ts} | 2 +- .../src/server/common/{es6Transpiler.js => es6Transpiler.ts} | 0 lib/core/src/server/common/{polyfills.js => polyfills.ts} | 0 6 files changed, 5 insertions(+), 4 deletions(-) rename lib/core/src/server/common/{babel-cache-preset.js => babel-cache-preset.ts} (89%) rename lib/core/src/server/common/{babel.js => babel.ts} (100%) rename lib/core/src/server/common/{common-preset.js => common-preset.ts} (56%) rename lib/core/src/server/common/{custom-presets.js => custom-presets.ts} (84%) rename lib/core/src/server/common/{es6Transpiler.js => es6Transpiler.ts} (100%) rename lib/core/src/server/common/{polyfills.js => polyfills.ts} (100%) diff --git a/lib/core/src/server/common/babel-cache-preset.js b/lib/core/src/server/common/babel-cache-preset.ts similarity index 89% rename from lib/core/src/server/common/babel-cache-preset.js rename to lib/core/src/server/common/babel-cache-preset.ts index 7dc50253e525..847b14d04516 100644 --- a/lib/core/src/server/common/babel-cache-preset.js +++ b/lib/core/src/server/common/babel-cache-preset.ts @@ -1,6 +1,6 @@ import { resolvePathInStorybookCache } from '../utils/resolve-path-in-sb-cache'; -const extend = (babelConfig) => ({ +const extend = (babelConfig: any) => ({ // This is a feature of `babel-loader` for webpack (not Babel itself). // It enables a cache directory for faster-rebuilds cacheDirectory: resolvePathInStorybookCache('babel'), diff --git a/lib/core/src/server/common/babel.js b/lib/core/src/server/common/babel.ts similarity index 100% rename from lib/core/src/server/common/babel.js rename to lib/core/src/server/common/babel.ts diff --git a/lib/core/src/server/common/common-preset.js b/lib/core/src/server/common/common-preset.ts similarity index 56% rename from lib/core/src/server/common/common-preset.js rename to lib/core/src/server/common/common-preset.ts index 8ef5e36fa30f..267d30f1088d 100644 --- a/lib/core/src/server/common/common-preset.js +++ b/lib/core/src/server/common/common-preset.ts @@ -2,7 +2,7 @@ import loadCustomBabelConfig from '../utils/load-custom-babel-config'; import babelConfig from './babel'; -export const babel = async (_, options) => { +export const babel = async (_: unknown, options: { configDir: string; presets: any }) => { const { configDir, presets } = options; return loadCustomBabelConfig(configDir, () => @@ -10,4 +10,5 @@ export const babel = async (_, options) => { ); }; -export const logLevel = (previous, options) => previous || options.loglevel || 'info'; +export const logLevel = (previous: any, options: { loglevel: any }) => + previous || options.loglevel || 'info'; diff --git a/lib/core/src/server/common/custom-presets.js b/lib/core/src/server/common/custom-presets.ts similarity index 84% rename from lib/core/src/server/common/custom-presets.js rename to lib/core/src/server/common/custom-presets.ts index 7d6912d15c28..8abbca4f6ec9 100644 --- a/lib/core/src/server/common/custom-presets.js +++ b/lib/core/src/server/common/custom-presets.ts @@ -2,7 +2,7 @@ import path from 'path'; import { serverRequire, serverResolve } from '../utils/server-require'; import validateConfigurationFiles from '../utils/validate-configuration-files'; -export default function loadCustomPresets({ configDir }) { +export default function loadCustomPresets({ configDir }: { configDir: string }) { validateConfigurationFiles(configDir); const presets = serverRequire(path.resolve(configDir, 'presets')); diff --git a/lib/core/src/server/common/es6Transpiler.js b/lib/core/src/server/common/es6Transpiler.ts similarity index 100% rename from lib/core/src/server/common/es6Transpiler.js rename to lib/core/src/server/common/es6Transpiler.ts diff --git a/lib/core/src/server/common/polyfills.js b/lib/core/src/server/common/polyfills.ts similarity index 100% rename from lib/core/src/server/common/polyfills.js rename to lib/core/src/server/common/polyfills.ts From 8388b19c2bd98d754f89e1f6e9ece137bf2e2816 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Maisse?= Date: Tue, 20 Oct 2020 19:24:24 +0200 Subject: [PATCH 06/21] refactor(core): migrate `config` to TS --- lib/core/src/server/config/{defaults.js => defaults.ts} | 2 +- .../config/{useBaseTsSupport.js => useBaseTsSupport.ts} | 2 +- lib/core/src/server/config/{utils.js => utils.ts} | 6 +++--- lib/core/src/typings.d.ts | 1 + 4 files changed, 6 insertions(+), 5 deletions(-) rename lib/core/src/server/config/{defaults.js => defaults.ts} (69%) rename lib/core/src/server/config/{useBaseTsSupport.js => useBaseTsSupport.ts} (78%) rename lib/core/src/server/config/{utils.js => utils.ts} (92%) diff --git a/lib/core/src/server/config/defaults.js b/lib/core/src/server/config/defaults.ts similarity index 69% rename from lib/core/src/server/config/defaults.js rename to lib/core/src/server/config/defaults.ts index 4e36d0cb8d4b..57e234b4fdac 100644 --- a/lib/core/src/server/config/defaults.js +++ b/lib/core/src/server/config/defaults.ts @@ -4,6 +4,6 @@ export const typeScriptDefaults = { reactDocgenTypescriptOptions: { shouldExtractLiteralValuesFromEnum: true, shouldRemoveUndefinedFromOptional: true, - propFilter: (prop) => (prop.parent ? !/node_modules/.test(prop.parent.fileName) : true), + propFilter: (prop: any) => (prop.parent ? !/node_modules/.test(prop.parent.fileName) : true), }, }; diff --git a/lib/core/src/server/config/useBaseTsSupport.js b/lib/core/src/server/config/useBaseTsSupport.ts similarity index 78% rename from lib/core/src/server/config/useBaseTsSupport.js rename to lib/core/src/server/config/useBaseTsSupport.ts index 0706158ed3e5..9defdcf7d87c 100644 --- a/lib/core/src/server/config/useBaseTsSupport.js +++ b/lib/core/src/server/config/useBaseTsSupport.ts @@ -2,7 +2,7 @@ * Returns true if the framework can use the base TS config. * @param {string} framework */ -export const useBaseTsSupport = (framework) => { +export const useBaseTsSupport = (framework: string) => { // These packages both have their own TS implementation. return !['vue', 'angular'].includes(framework); }; diff --git a/lib/core/src/server/config/utils.js b/lib/core/src/server/config/utils.ts similarity index 92% rename from lib/core/src/server/config/utils.js rename to lib/core/src/server/config/utils.ts index 7fb2db2caa23..354c69afca34 100644 --- a/lib/core/src/server/config/utils.js +++ b/lib/core/src/server/config/utils.ts @@ -26,17 +26,17 @@ const projectRoot = () => { export const includePaths = [projectRoot()]; export const nodeModulesPaths = path.resolve('./node_modules'); -const nodePathsToArray = (nodePath) => +const nodePathsToArray = (nodePath: string) => nodePath .split(process.platform === 'win32' ? ';' : ':') .filter(Boolean) .map((p) => path.resolve('./', p)); // Load environment variables starts with STORYBOOK_ to the client side. -export function loadEnv(options = {}) { +export function loadEnv(options: { production?: boolean } = {}) { const defaultNodeEnv = options.production ? 'production' : 'development'; - const env = { + const env: Record = { NODE_ENV: process.env.NODE_ENV || defaultNodeEnv, NODE_PATH: process.env.NODE_PATH || '', // This is to support CRA's public folder feature. diff --git a/lib/core/src/typings.d.ts b/lib/core/src/typings.d.ts index b26e002ee403..705b99ad0970 100644 --- a/lib/core/src/typings.d.ts +++ b/lib/core/src/typings.d.ts @@ -1,3 +1,4 @@ declare module 'global'; declare module '@storybook/semver'; declare module 'unfetch/dist/unfetch'; +declare module 'lazy-universal-dotenv'; From 9cb48872c0ba5e236fcc985ea787aeab1ff59306 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Maisse?= Date: Tue, 20 Oct 2020 20:06:49 +0200 Subject: [PATCH 07/21] refactor(core): migrate `presets.js` to TS --- .../src/server/{presets.js => presets.ts} | 33 +++++++++++-------- 1 file changed, 20 insertions(+), 13 deletions(-) rename lib/core/src/server/{presets.js => presets.ts} (84%) diff --git a/lib/core/src/server/presets.js b/lib/core/src/server/presets.ts similarity index 84% rename from lib/core/src/server/presets.js rename to lib/core/src/server/presets.ts index 6dd1f52950a4..8700605e1ed3 100644 --- a/lib/core/src/server/presets.js +++ b/lib/core/src/server/presets.ts @@ -3,10 +3,11 @@ import { join } from 'path'; import { logger } from '@storybook/node-logger'; import resolveFrom from 'resolve-from'; -const isObject = (val) => val != null && typeof val === 'object' && Array.isArray(val) === false; -const isFunction = (val) => typeof val === 'function'; +const isObject = (val: unknown): val is Record => + val != null && typeof val === 'object' && Array.isArray(val) === false; +const isFunction = (val: unknown): val is Function => typeof val === 'function'; -const resolvePresetFunction = (input, presetOptions, storybookOptions) => { +const resolvePresetFunction = (input: unknown, presetOptions: any, storybookOptions: any) => { if (isFunction(input)) { return input({ ...storybookOptions, ...presetOptions }); } @@ -33,7 +34,7 @@ const resolvePresetFunction = (input, presetOptions, storybookOptions) => { * - { name: '@storybook/addon-docs(/preset)?', options: { ... } } * => { type: 'presets', item: { name: '@storybook/addon-docs/preset', options } } */ -export const resolveAddonName = (configDir, name) => { +export const resolveAddonName = (configDir: string, name: string) => { let path; if (name.startsWith('.')) { @@ -75,7 +76,7 @@ export const resolveAddonName = (configDir, name) => { }; }; -const map = ({ configDir }) => (item) => { +const map = ({ configDir }: { configDir: string }) => (item: any) => { try { if (isObject(item)) { const { name } = resolveAddonName(configDir, item.name); @@ -98,7 +99,7 @@ const map = ({ configDir }) => (item) => { return undefined; }; -function interopRequireDefault(filePath) { +function interopRequireDefault(filePath: string) { // eslint-disable-next-line global-require,import/no-dynamic-require const result = require(filePath); @@ -108,7 +109,7 @@ function interopRequireDefault(filePath) { return isES6DefaultExported ? result.default : result; } -function getContent(input) { +function getContent(input: any) { if (input.type === 'managerEntries') { const { type, name, ...rest } = input; return rest; @@ -118,7 +119,7 @@ function getContent(input) { return interopRequireDefault(name); } -export function loadPreset(input, level, storybookOptions) { +export function loadPreset(input: any, level: number, storybookOptions: any): any[] { try { const name = input.name ? input.name : input; const presetOptions = input.options ? input.options : {}; @@ -172,7 +173,7 @@ export function loadPreset(input, level, storybookOptions) { } } -function loadPresets(presets, level, storybookOptions) { +function loadPresets(presets: unknown[], level: number, storybookOptions: any) { if (!presets || !Array.isArray(presets) || !presets.length) { return []; } @@ -187,14 +188,20 @@ function loadPresets(presets, level, storybookOptions) { }, []); } -function applyPresets(presets, extension, config, args, storybookOptions) { +function applyPresets( + presets: unknown[], + extension: any, + config: any, + args: any, + storybookOptions: any +) { const presetResult = new Promise((resolve) => resolve(config)); if (!presets.length) { return presetResult; } - return presets.reduce((accumulationPromise, { preset, options }) => { + return presets.reduce((accumulationPromise: Promise, { preset, options }) => { const change = preset[extension]; if (!change) { @@ -226,11 +233,11 @@ function applyPresets(presets, extension, config, args, storybookOptions) { }, presetResult); } -function getPresets(presets, storybookOptions = {}) { +function getPresets(presets: any, storybookOptions: any = {}) { const loadedPresets = loadPresets(presets, 0, storybookOptions); return { - apply: async (extension, config, args = {}) => + apply: async (extension: any, config: any, args = {}) => applyPresets(loadedPresets, extension, config, args, storybookOptions), }; } From 7e0ea97011e9a20e30ccf81c452a23468abd7e8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Maisse?= Date: Tue, 20 Oct 2020 20:07:08 +0200 Subject: [PATCH 08/21] refactor(core): migrate `manager` to TS --- lib/core/package.json | 6 ++- ...der-manager.js => babel-loader-manager.ts} | 0 .../{manager-config.js => manager-config.ts} | 16 +++--- .../{manager-preset.js => manager-preset.ts} | 4 +- ...ck.config.js => manager-webpack.config.ts} | 12 +++-- ...mplate.js => virtualModuleRef.template.ts} | 0 lib/core/src/typings.d.ts | 3 ++ yarn.lock | 54 ++++++++++++++++++- 8 files changed, 77 insertions(+), 18 deletions(-) rename lib/core/src/server/manager/{babel-loader-manager.js => babel-loader-manager.ts} (100%) rename lib/core/src/server/manager/{manager-config.js => manager-config.ts} (90%) rename lib/core/src/server/manager/{manager-preset.js => manager-preset.ts} (79%) rename lib/core/src/server/manager/{manager-webpack.config.js => manager-webpack.config.ts} (95%) rename lib/core/src/server/manager/{virtualModuleRef.template.js => virtualModuleRef.template.ts} (100%) diff --git a/lib/core/package.json b/lib/core/package.json index d1c96d875c44..9526b7356981 100644 --- a/lib/core/package.json +++ b/lib/core/package.json @@ -134,8 +134,12 @@ "webpack-virtual-modules": "^0.2.2" }, "devDependencies": { - "@types/mock-fs": "^4.10.0", + "@types/case-sensitive-paths-webpack-plugin": "^2.1.4", + "@types/dotenv-webpack": "^3.0.0", "@types/interpret": "^1.1.1", + "@types/mock-fs": "^4.10.0", + "@types/terser-webpack-plugin": "^5.0.0", + "@types/webpack-virtual-modules": "^0.1.0", "mock-fs": "^4.12.0" }, "peerDependencies": { diff --git a/lib/core/src/server/manager/babel-loader-manager.js b/lib/core/src/server/manager/babel-loader-manager.ts similarity index 100% rename from lib/core/src/server/manager/babel-loader-manager.js rename to lib/core/src/server/manager/babel-loader-manager.ts diff --git a/lib/core/src/server/manager/manager-config.js b/lib/core/src/server/manager/manager-config.ts similarity index 90% rename from lib/core/src/server/manager/manager-config.js rename to lib/core/src/server/manager/manager-config.ts index 63a51756231a..c71b55c1991a 100644 --- a/lib/core/src/server/manager/manager-config.js +++ b/lib/core/src/server/manager/manager-config.ts @@ -12,7 +12,7 @@ import loadPresets from '../presets'; import loadCustomPresets from '../common/custom-presets'; import { typeScriptDefaults } from '../config/defaults'; -export const getAutoRefs = async (options) => { +export const getAutoRefs = async (options: { configDir: string }) => { const location = await findUp('package.json', { cwd: options.configDir }); const directory = path.dirname(location); @@ -39,15 +39,15 @@ export const getAutoRefs = async (options) => { return list.filter(Boolean); }; -const checkRef = (url) => +const checkRef = (url: string) => fetch(`${url}/iframe.html`).then( ({ ok }) => ok, () => false ); -const stripTrailingSlash = (url) => url.replace(/\/$/, ''); +const stripTrailingSlash = (url: string) => url.replace(/\/$/, ''); -const toTitle = (input) => { +const toTitle = (input: string) => { const result = input .replace(/[A-Z]/g, (f) => ` ${f}`) .replace(/[-_][A-Z]/gi, (f) => ` ${f.toUpperCase()}`) @@ -66,7 +66,7 @@ const deprecatedDefinedRefDisabled = deprecate( ` ); -async function getManagerWebpackConfig(options, presets) { +async function getManagerWebpackConfig(options: any, presets: any) { const typescriptOptions = await presets.apply('typescript', { ...typeScriptDefaults }, options); const babelOptions = await presets.apply('babel', {}, { ...options, typescriptOptions }); @@ -74,7 +74,7 @@ async function getManagerWebpackConfig(options, presets) { const definedRefs = await presets.apply('refs', undefined, options); const entries = await presets.apply('managerEntries', [], options); - const refs = {}; + const refs: Record = {}; if (autoRefs && autoRefs.length) { autoRefs.forEach(({ id, url, title, version }) => { @@ -88,7 +88,7 @@ async function getManagerWebpackConfig(options, presets) { } if (definedRefs) { - Object.entries(definedRefs).forEach(([key, value]) => { + Object.entries(definedRefs).forEach(([key, value]: [string, any]) => { const { disable, disabled } = value; if (disable || disabled) { @@ -130,7 +130,7 @@ async function getManagerWebpackConfig(options, presets) { return presets.apply('managerWebpack', {}, { ...options, babelOptions, entries, refs }); } -export default async (options) => { +export default async (options: any) => { const { corePresets = [], frameworkPresets = [], overridePresets = [], ...restOptions } = options; const presetsConfig = [ diff --git a/lib/core/src/server/manager/manager-preset.js b/lib/core/src/server/manager/manager-preset.ts similarity index 79% rename from lib/core/src/server/manager/manager-preset.js rename to lib/core/src/server/manager/manager-preset.ts index b51924045b3a..60c2ea15da42 100644 --- a/lib/core/src/server/manager/manager-preset.js +++ b/lib/core/src/server/manager/manager-preset.ts @@ -1,11 +1,11 @@ import { loadManagerOrAddonsFile } from '../utils/load-manager-or-addons-file'; import createDevConfig from './manager-webpack.config'; -export async function managerWebpack(_, options) { +export async function managerWebpack(_: unknown, options: any) { return createDevConfig(options); } -export async function managerEntries(installedAddons, options) { +export async function managerEntries(installedAddons: string[] | undefined, options: any) { const { managerEntry = '../../client/manager' } = options; const entries = [require.resolve('../common/polyfills')]; diff --git a/lib/core/src/server/manager/manager-webpack.config.js b/lib/core/src/server/manager/manager-webpack.config.ts similarity index 95% rename from lib/core/src/server/manager/manager-webpack.config.js rename to lib/core/src/server/manager/manager-webpack.config.ts index 5a2539094265..1eade259ecab 100644 --- a/lib/core/src/server/manager/manager-webpack.config.js +++ b/lib/core/src/server/manager/manager-webpack.config.ts @@ -10,8 +10,6 @@ import TerserWebpackPlugin from 'terser-webpack-plugin'; import themingPaths from '@storybook/theming/paths'; import uiPaths from '@storybook/ui/paths'; - -import { version } from '../../../package.json'; import { getManagerHeadHtml } from '../utils/template'; import { loadEnv } from '../config/utils'; @@ -19,6 +17,8 @@ import babelLoader from './babel-loader-manager'; import { resolvePathInStorybookCache } from '../utils/resolve-path-in-sb-cache'; import es6Transpiler from '../common/es6Transpiler'; +const { version } = require('../../../package.json'); + export default async ({ configDir, configType, @@ -31,7 +31,7 @@ export default async ({ versionCheck, releaseNotesData, presets, -}) => { +}: any) => { const { raw, stringified } = loadEnv(); const logLevel = await presets.apply('logLevel', undefined); const isProd = configType === 'PRODUCTION'; @@ -62,7 +62,8 @@ export default async ({ : null, new HtmlWebpackPlugin({ filename: `index.html`, - chunksSortMode: 'none', + // FIXME: `none` isn't a known option + chunksSortMode: 'none' as any, alwaysWriteToDisk: true, inject: false, templateParameters: (compilation, files, options) => ({ @@ -157,7 +158,8 @@ export default async ({ mangle: false, keep_fnames: true, }, - }), + // FIXME: `cache` isn't a known attribute + } as any), ] : [], }, diff --git a/lib/core/src/server/manager/virtualModuleRef.template.js b/lib/core/src/server/manager/virtualModuleRef.template.ts similarity index 100% rename from lib/core/src/server/manager/virtualModuleRef.template.js rename to lib/core/src/server/manager/virtualModuleRef.template.ts diff --git a/lib/core/src/typings.d.ts b/lib/core/src/typings.d.ts index 705b99ad0970..ca918df9ff1e 100644 --- a/lib/core/src/typings.d.ts +++ b/lib/core/src/typings.d.ts @@ -2,3 +2,6 @@ declare module 'global'; declare module '@storybook/semver'; declare module 'unfetch/dist/unfetch'; declare module 'lazy-universal-dotenv'; +declare module 'pnp-webpack-plugin'; +declare module '@storybook/theming/paths'; +declare module '@storybook/ui/paths'; diff --git a/yarn.lock b/yarn.lock index 83aed9e79f70..d24f8aee514b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5943,6 +5943,13 @@ resolved "https://registry.yarnpkg.com/@types/browserslist/-/browserslist-4.8.0.tgz#60489aefdf0fcb56c2d8eb65267ff08dad7a526d" integrity sha512-4PyO9OM08APvxxo1NmQyQKlJdowPCOQIy5D/NLO3aO0vGC57wsMptvGp3b8IbYnupFZr92l1dlVief1JvS6STQ== +"@types/case-sensitive-paths-webpack-plugin@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@types/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.1.4.tgz#11c23e4ef9b5c81e9b4c112ec477690dee950c97" + integrity sha512-/tJtLk60YcY0UHnURl088gObI8cTEj8aevANmIN8/VcFb5vOW39y73RB792x0E4dtTyfy3r7634X+9k39yzv+g== + dependencies: + "@types/webpack" "*" + "@types/chai-as-promised@^7.1.2": version "7.1.2" resolved "https://registry.yarnpkg.com/@types/chai-as-promised/-/chai-as-promised-7.1.2.tgz#2f564420e81eaf8650169e5a3a6b93e096e5068b" @@ -5996,6 +6003,13 @@ resolved "https://registry.yarnpkg.com/@types/doctrine/-/doctrine-0.0.3.tgz#e892d293c92c9c1d3f9af72c15a554fbc7e0895a" integrity sha1-6JLSk8ksnB0/mvcsFaVU+8fgiVo= +"@types/dotenv-webpack@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/dotenv-webpack/-/dotenv-webpack-3.0.0.tgz#9a9156d5b569a61d61f42bf7dbe3903eee8e59b7" + integrity sha512-f3gFAkxOWAjsDemXp8y3gMeSfr8QilpFRt6g808hi5dQGXGU7M53Ty/INwLos7IpeJkt1fHMI+qcZ4QGnGUbGA== + dependencies: + "@types/webpack" "*" + "@types/enzyme@^3.10.3", "@types/enzyme@^3.10.5", "@types/enzyme@^3.9.0": version "3.10.5" resolved "https://registry.yarnpkg.com/@types/enzyme/-/enzyme-3.10.5.tgz#fe7eeba3550369eed20e7fb565bfb74eec44f1f0" @@ -6490,6 +6504,14 @@ resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.5.tgz#9adbc12950582aa65ead76bffdf39fe0c27a3c02" integrity sha512-/gG2M/Imw7cQFp8PGvz/SwocNrmKFjFsm5Pb8HdbHkZ1K8pmuPzOX4VeVoiEecFCVf4CsN1r3/BRvx+6sNqwtQ== +"@types/terser-webpack-plugin@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@types/terser-webpack-plugin/-/terser-webpack-plugin-5.0.0.tgz#7615b46b141b738f27d87b8972f14e9a65b2cf8d" + integrity sha512-9dCbRwnCN8go/WbUEPMMtoVvFqMWQc5E5iP5rzoKLU2qvlUgu3dfrr0/nc23J6iyGqzIDExCFGzZslm3ECydFA== + dependencies: + "@types/webpack" "*" + terser "^5.3.5" + "@types/testing-library__dom@*": version "7.0.2" resolved "https://registry.yarnpkg.com/@types/testing-library__dom/-/testing-library__dom-7.0.2.tgz#2906f8a0dce58b0746c6ab606f786bd06fe6940e" @@ -6566,6 +6588,25 @@ "@types/source-list-map" "*" source-map "^0.6.1" +"@types/webpack-virtual-modules@^0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@types/webpack-virtual-modules/-/webpack-virtual-modules-0.1.0.tgz#6b43e8c71a2d24e4f75e33fe5305573117e0c0e3" + integrity sha512-uVJskUYzUUI1Yjcbu20RbzkWdrVTny0AMoWYpeeL9Y0ii3/bbitlG1/I2Z6vMSL2LB0QDSHf/EBbKtWkeCKJWw== + dependencies: + "@types/webpack" "*" + +"@types/webpack@*": + version "4.41.23" + resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.41.23.tgz#1925f42a7325be4ae0fce38329f1cc27768fcda7" + integrity sha512-ojA4CupZg8RCzVJLugWlvqrHpT59GWhqFxbinlsnvk10MjQCWB+ot7XDACctbWhnhtdhYK7+HOH1JxkVLiZhMg== + dependencies: + "@types/anymatch" "*" + "@types/node" "*" + "@types/tapable" "*" + "@types/uglify-js" "*" + "@types/webpack-sources" "*" + source-map "^0.6.0" + "@types/webpack@^4.41.12", "@types/webpack@^4.41.13", "@types/webpack@^4.41.8", "@types/webpack@^4.41.9": version "4.41.13" resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.41.13.tgz#988d114c8913d039b8a0e0502a7fe4f1f84f3d5e" @@ -31175,7 +31216,7 @@ source-map-support@^0.4.15, source-map-support@~0.4.0: dependencies: source-map "^0.5.6" -source-map-support@^0.5.16, source-map-support@^0.5.17, source-map-support@^0.5.5, source-map-support@^0.5.6, source-map-support@~0.5.10, source-map-support@~0.5.12: +source-map-support@^0.5.16, source-map-support@^0.5.17, source-map-support@^0.5.5, source-map-support@^0.5.6, source-map-support@~0.5.10, source-map-support@~0.5.12, source-map-support@~0.5.19: version "0.5.19" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== @@ -31205,7 +31246,7 @@ source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, sourc resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -source-map@0.7.3, source-map@^0.7.2, source-map@^0.7.3: +source-map@0.7.3, source-map@^0.7.2, source-map@^0.7.3, source-map@~0.7.2: version "0.7.3" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== @@ -32479,6 +32520,15 @@ terser@^4.1.2, terser@^4.3.8, terser@^4.3.9, terser@^4.4.3, terser@^4.6.12, ters source-map "~0.6.1" source-map-support "~0.5.12" +terser@^5.3.5: + version "5.3.7" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.3.7.tgz#798a4ae2e7ff67050c3e99fcc4e00725827d97e2" + integrity sha512-lJbKdfxWvjpV330U4PBZStCT9h3N9A4zZVA5Y4k9sCWXknrpdyxi1oMsRKLmQ/YDMDxSBKIh88v0SkdhdqX06w== + dependencies: + commander "^2.20.0" + source-map "~0.7.2" + source-map-support "~0.5.19" + test-exclude@^5.2.3: version "5.2.3" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-5.2.3.tgz#c3d3e1e311eb7ee405e092dac10aefd09091eac0" From fb9f8010482208a236e4e2ed20dea2678178611a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Maisse?= Date: Tue, 20 Oct 2020 20:17:14 +0200 Subject: [PATCH 09/21] refactor(core): migrate `preview` to TS --- lib/core/package.json | 1 + ...der-preview.js => babel-loader-preview.ts} | 2 +- ...bpack.config.js => base-webpack.config.ts} | 5 +- ...ack-preset.js => custom-webpack-preset.ts} | 4 +- .../{entries.test.js => entries.test.ts} | 0 .../server/preview/{entries.js => entries.ts} | 12 +-- .../server/preview/{globals.js => globals.ts} | 0 ...ack.config.js => iframe-webpack.config.ts} | 16 +-- .../{preview-preset.js => preview-preset.ts} | 6 +- ...ext.test.js => to-require-context.test.ts} | 2 +- yarn.lock | 99 +++++++++++++++++++ 11 files changed, 126 insertions(+), 21 deletions(-) rename lib/core/src/server/preview/{babel-loader-preview.js => babel-loader-preview.ts} (82%) rename lib/core/src/server/preview/{base-webpack.config.js => base-webpack.config.ts} (94%) rename lib/core/src/server/preview/{custom-webpack-preset.js => custom-webpack-preset.ts} (88%) rename lib/core/src/server/preview/{entries.test.js => entries.test.ts} (100%) rename lib/core/src/server/preview/{entries.js => entries.ts} (85%) rename lib/core/src/server/preview/{globals.js => globals.ts} (100%) rename lib/core/src/server/preview/{iframe-webpack.config.js => iframe-webpack.config.ts} (95%) rename lib/core/src/server/preview/{preview-preset.js => preview-preset.ts} (77%) rename lib/core/src/server/preview/{to-require-context.test.js => to-require-context.test.ts} (99%) diff --git a/lib/core/package.json b/lib/core/package.json index 9526b7356981..cfc2a97fcd35 100644 --- a/lib/core/package.json +++ b/lib/core/package.json @@ -138,6 +138,7 @@ "@types/dotenv-webpack": "^3.0.0", "@types/interpret": "^1.1.1", "@types/mock-fs": "^4.10.0", + "@types/react-dev-utils": "^9.0.4", "@types/terser-webpack-plugin": "^5.0.0", "@types/webpack-virtual-modules": "^0.1.0", "mock-fs": "^4.12.0" diff --git a/lib/core/src/server/preview/babel-loader-preview.js b/lib/core/src/server/preview/babel-loader-preview.ts similarity index 82% rename from lib/core/src/server/preview/babel-loader-preview.js rename to lib/core/src/server/preview/babel-loader-preview.ts index e964a1f658a0..b2dcd9fc0989 100644 --- a/lib/core/src/server/preview/babel-loader-preview.js +++ b/lib/core/src/server/preview/babel-loader-preview.ts @@ -1,7 +1,7 @@ import { includePaths } from '../config/utils'; import { useBaseTsSupport } from '../config/useBaseTsSupport'; -export const createBabelLoader = (options, framework) => ({ +export const createBabelLoader = (options: any, framework: string) => ({ test: useBaseTsSupport(framework) ? /\.(mjs|tsx?|jsx?)$/ : /\.(mjs|jsx?)$/, use: [ { diff --git a/lib/core/src/server/preview/base-webpack.config.js b/lib/core/src/server/preview/base-webpack.config.ts similarity index 94% rename from lib/core/src/server/preview/base-webpack.config.js rename to lib/core/src/server/preview/base-webpack.config.ts index 291af29d0b01..e624a0df54bf 100644 --- a/lib/core/src/server/preview/base-webpack.config.js +++ b/lib/core/src/server/preview/base-webpack.config.ts @@ -3,7 +3,10 @@ import findUp from 'find-up'; import path from 'path'; import { logger } from '@storybook/node-logger'; -export async function createDefaultWebpackConfig(storybookBaseConfig, options) { +export async function createDefaultWebpackConfig( + storybookBaseConfig: any, + options: { presetsList: any[] } +) { if ( options.presetsList.some((preset) => /@storybook(\/|\\)preset-create-react-app/.test(preset.name || preset) diff --git a/lib/core/src/server/preview/custom-webpack-preset.js b/lib/core/src/server/preview/custom-webpack-preset.ts similarity index 88% rename from lib/core/src/server/preview/custom-webpack-preset.js rename to lib/core/src/server/preview/custom-webpack-preset.ts index 7679bd99025c..6228cd1b2b54 100644 --- a/lib/core/src/server/preview/custom-webpack-preset.js +++ b/lib/core/src/server/preview/custom-webpack-preset.ts @@ -2,12 +2,12 @@ import { logger } from '@storybook/node-logger'; import loadCustomWebpackConfig from '../utils/load-custom-webpack-config'; import { createDefaultWebpackConfig } from './base-webpack.config'; -async function createFinalDefaultConfig(presets, config, options) { +async function createFinalDefaultConfig(presets: any, config: any, options: any) { const defaultConfig = await createDefaultWebpackConfig(config, options); return presets.apply('webpackFinal', defaultConfig, options); } -export async function webpack(config, options) { +export async function webpack(config: any, options: any) { const { configDir, configType, presets, webpackConfig } = options; const finalDefaultConfig = await createFinalDefaultConfig(presets, config, options); diff --git a/lib/core/src/server/preview/entries.test.js b/lib/core/src/server/preview/entries.test.ts similarity index 100% rename from lib/core/src/server/preview/entries.test.js rename to lib/core/src/server/preview/entries.test.ts diff --git a/lib/core/src/server/preview/entries.js b/lib/core/src/server/preview/entries.ts similarity index 85% rename from lib/core/src/server/preview/entries.js rename to lib/core/src/server/preview/entries.ts index d5003d85e2e2..8b092a5038ad 100644 --- a/lib/core/src/server/preview/entries.js +++ b/lib/core/src/server/preview/entries.ts @@ -5,7 +5,7 @@ import dedent from 'ts-dedent'; import glob from 'glob-promise'; import { loadPreviewOrConfigFile } from '../utils/load-preview-or-config-file'; -export const sortEntries = (entries) => { +export const sortEntries = (entries: string[]) => { const isGenerated = /generated-(config|other)-entry/; const isGeneratedConfig = /(?:preview|config)\..+-generated-config-entry/; @@ -27,12 +27,12 @@ export const sortEntries = (entries) => { }); }; -const getMainConfigs = (options) => { +const getMainConfigs = (options: { configDir: string }) => { const previewPath = loadPreviewOrConfigFile(options); return previewPath ? [previewPath] : []; }; -export async function createPreviewEntry(options) { +export async function createPreviewEntry(options: { configDir: string; presets: any }) { const { configDir, presets } = options; const entries = [ require.resolve('../common/polyfills'), @@ -41,8 +41,8 @@ export async function createPreviewEntry(options) { ]; const configs = getMainConfigs(options); - const other = await presets.apply('config', [], options); - const stories = await presets.apply('stories', [], options); + const other: string[] = await presets.apply('config', [], options); + const stories: string[] = await presets.apply('stories', [], options); if (configs.length > 0) { const noun = configs.length === 1 ? 'file' : 'files'; @@ -53,7 +53,7 @@ export async function createPreviewEntry(options) { if (other && other.length > 0) { const noun = other.length === 1 ? 'file' : 'files'; logger.info(`=> Loading ${other.length} other ${noun} in "${configDir}"`); - entries.push(...other.map((filename) => `${filename}-generated-other-entry.js`)); + entries.push(...other.map((filename: string) => `${filename}-generated-other-entry.js`)); } if (stories && stories.length) { diff --git a/lib/core/src/server/preview/globals.js b/lib/core/src/server/preview/globals.ts similarity index 100% rename from lib/core/src/server/preview/globals.js rename to lib/core/src/server/preview/globals.ts diff --git a/lib/core/src/server/preview/iframe-webpack.config.js b/lib/core/src/server/preview/iframe-webpack.config.ts similarity index 95% rename from lib/core/src/server/preview/iframe-webpack.config.js rename to lib/core/src/server/preview/iframe-webpack.config.ts index 4f23ce715671..4f2454c65f3b 100644 --- a/lib/core/src/server/preview/iframe-webpack.config.js +++ b/lib/core/src/server/preview/iframe-webpack.config.ts @@ -22,9 +22,9 @@ import { getPreviewHeadHtml, getPreviewBodyHtml } from '../utils/template'; import { toRequireContextString } from './to-require-context'; import { useBaseTsSupport } from '../config/useBaseTsSupport'; -const reactPaths = {}; +const reactPaths: Record = {}; -const storybookPaths = [ +const storybookPaths: Record = [ 'addons', 'addons', 'api', @@ -67,7 +67,7 @@ export default async ({ frameworkPath, presets, typescriptOptions, -}) => { +}: any) => { const dlls = await presets.apply('webpackDlls', []); const logLevel = await presets.apply('logLevel', undefined); const frameworkOptions = await presets.apply(`${framework}Options`, {}, {}); @@ -90,7 +90,7 @@ export default async ({ // is loaded. That way our client-apis can assume the existence of the API+store [frameworkInitEntry]: `import '${frameworkImportPath}';`, }; - entries.forEach((entryFilename) => { + entries.forEach((entryFilename: any) => { const match = entryFilename.match(/(.*)-generated-(config|other)-entry.js$/); if (match) { const configFilename = match[1]; @@ -130,7 +130,8 @@ export default async ({ : null, new HtmlWebpackPlugin({ filename: `iframe.html`, - chunksSortMode: 'none', + // FIXME: `none` isn't a known option + chunksSortMode: 'none' as any, alwaysWriteToDisk: true, inject: false, templateParameters: (compilation, files, options) => ({ @@ -213,7 +214,8 @@ export default async ({ mangle: false, keep_fnames: true, }, - }), + // FIXME: `cache` isn't a known attribute + } as any), ] : [], }, @@ -231,7 +233,7 @@ export default async ({ * @param bindings {Object} key-value object use to fill the template, `{{key}}` will be replaced by `escaped(value)` * @returns {String} Filled template */ -const interpolate = (template, bindings) => { +const interpolate = (template: string, bindings: Record) => { return Object.entries(bindings).reduce((acc, [k, v]) => { const escapedString = v.replace(/\\/g, '/').replace(/\$/g, '$$$'); return acc.replace(new RegExp(`{{${k}}}`, 'g'), escapedString); diff --git a/lib/core/src/server/preview/preview-preset.js b/lib/core/src/server/preview/preview-preset.ts similarity index 77% rename from lib/core/src/server/preview/preview-preset.js rename to lib/core/src/server/preview/preview-preset.ts index ae01be2f4da5..e57fa9928aa3 100644 --- a/lib/core/src/server/preview/preview-preset.js +++ b/lib/core/src/server/preview/preview-preset.ts @@ -1,10 +1,10 @@ import webpackConfig from './iframe-webpack.config'; import { createPreviewEntry } from './entries'; -export const webpack = async (_, options) => webpackConfig(options); +export const webpack = async (_: unknown, options: any) => webpackConfig(options); -export const entries = async (_, options) => { - let result = []; +export const entries = async (_: unknown, options: any) => { + let result: string[] = []; result = result.concat(await createPreviewEntry(options)); diff --git a/lib/core/src/server/preview/to-require-context.test.js b/lib/core/src/server/preview/to-require-context.test.ts similarity index 99% rename from lib/core/src/server/preview/to-require-context.test.js rename to lib/core/src/server/preview/to-require-context.test.ts index bd0b64756e92..434df62bc52c 100644 --- a/lib/core/src/server/preview/to-require-context.test.js +++ b/lib/core/src/server/preview/to-require-context.test.ts @@ -178,7 +178,7 @@ describe('toRequireContext', () => { const regex = new RegExp(match); - function isMatched(filePath) { + function isMatched(filePath: string) { const relativePath = `./${path.relative(base, filePath)}`; const baseIncluded = filePath.includes(base); diff --git a/yarn.lock b/yarn.lock index d24f8aee514b..bbe4b87a4343 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5969,11 +5969,26 @@ dependencies: "@types/node" "*" +"@types/clean-css@*": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@types/clean-css/-/clean-css-4.2.2.tgz#99fd79f6939c2b325938a1c569712e07dd97d709" + integrity sha512-xiTJn3bmDh1lA8c6iVJs4ZhHw+pcmxXlJQXOB6G1oULaak8rmarIeFKI4aTJ7849dEhaO612wgIualZfbxTJwA== + dependencies: + "@types/node" "*" + "@types/color-name@^1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== +"@types/connect-history-api-fallback@*": + version "1.3.3" + resolved "https://registry.yarnpkg.com/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.3.tgz#4772b79b8b53185f0f4c9deab09236baf76ee3b4" + integrity sha512-7SxFCd+FLlxCfwVwbyPxbR4khL9aNikJhrorw8nUIOqeuooc9gifBuDQOJw5kzN7i6i3vLn9G8Wde/4QDihpYw== + dependencies: + "@types/express-serve-static-core" "*" + "@types/node" "*" + "@types/connect@*": version "3.4.33" resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.33.tgz#31610c901eca573b8713c3330abc6e6b9f588546" @@ -6033,6 +6048,14 @@ resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag== +"@types/eslint@*": + version "7.2.4" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-7.2.4.tgz#d12eeed7741d2491b69808576ac2d20c14f74c41" + integrity sha512-YCY4kzHMsHoyKspQH+nwSe+70Kep7Vjt2X+dZe5Vs2vkRudqtoFoUIv1RlJmZB8Hbp7McneupoZij4PadxsK5Q== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + "@types/estree@*", "@types/estree@^0.0.44": version "0.0.44" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.44.tgz#980cc5a29a3ef3bea6ff1f7d021047d7ea575e21" @@ -6057,6 +6080,16 @@ "@types/qs" "*" "@types/range-parser" "*" +"@types/express@*": + version "4.17.8" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.8.tgz#3df4293293317e61c60137d273a2e96cd8d5f27a" + integrity sha512-wLhcKh3PMlyA2cNAB9sjM1BntnhPMiM0JOBwPBqttjHev2428MLEB4AYVN+d8s2iyCVZac+o41Pflm/ZH5vLXQ== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "*" + "@types/qs" "*" + "@types/serve-static" "*" + "@types/express@^4.17.2", "@types/express@^4.17.6": version "4.17.6" resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.6.tgz#6bce49e49570507b86ea1b07b806f04697fac45e" @@ -6119,6 +6152,40 @@ resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.0.tgz#551a4589b6ee2cc9c1dff08056128aec29b94880" integrity sha512-iYCgjm1dGPRuo12+BStjd1HiVQqhlRhWDOQigNxn023HcjnhsiFz9pc6CzJj4HwDCSQca9bxTL4PxJDbkdm3PA== +"@types/html-minifier@*": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/html-minifier/-/html-minifier-4.0.0.tgz#2065cb9944f2d1b241146707c6935aa7b947d279" + integrity sha512-eFnGhrKmjWBlnSGNtunetE3UU2Tc/LUl92htFslSSTmpp9EKHQVcYQadCyYfnzUEFB5G/3wLWo/USQS/mEPKrA== + dependencies: + "@types/clean-css" "*" + "@types/relateurl" "*" + "@types/uglify-js" "*" + +"@types/html-webpack-plugin@*": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@types/html-webpack-plugin/-/html-webpack-plugin-3.2.3.tgz#865323e30e82560c0ca898dbf9f6f9d1c541cd7f" + integrity sha512-Y7dsVhTn75IaD4lMIY02UP1L8e0ou8KQu8DKPJAegEFKdJR28/8ejayDG8ykfR0DtYCx3dCEHIkdpN8AOB6txQ== + dependencies: + "@types/html-minifier" "*" + "@types/tapable" "*" + "@types/webpack" "*" + +"@types/http-proxy-middleware@*": + version "0.19.3" + resolved "https://registry.yarnpkg.com/@types/http-proxy-middleware/-/http-proxy-middleware-0.19.3.tgz#b2eb96fbc0f9ac7250b5d9c4c53aade049497d03" + integrity sha512-lnBTx6HCOUeIJMLbI/LaL5EmdKLhczJY5oeXZpX/cXE4rRqb3RmV7VcMpiEfYkmTjipv3h7IAyIINe4plEv7cA== + dependencies: + "@types/connect" "*" + "@types/http-proxy" "*" + "@types/node" "*" + +"@types/http-proxy@*": + version "1.17.4" + resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.4.tgz#e7c92e3dbe3e13aa799440ff42e6d3a17a9d045b" + integrity sha512-IrSHl2u6AWXduUaDLqYpt45tLVCtYv7o4Z0s1KghBCDgIIS9oW5K1H8mZG/A2CfeLdEa7rTd1ACOiHBc1EMT2Q== + dependencies: + "@types/node" "*" + "@types/inquirer@^6.5.0": version "6.5.0" resolved "https://registry.yarnpkg.com/@types/inquirer/-/inquirer-6.5.0.tgz#b83b0bf30b88b8be7246d40e51d32fe9d10e09be" @@ -6198,6 +6265,11 @@ resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-3.12.4.tgz#7d3b534ec35a0585128e2d332db1403ebe057e25" integrity sha512-fYMgzN+9e28R81weVN49inn/u798ruU91En1ZnGvSZzCRc5jXx9B2EDhlRaWmcO1RIxFHL8AajRXzxDuJu93+A== +"@types/json-schema@*": + version "7.0.6" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0" + integrity sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw== + "@types/json-schema@^7.0.3": version "7.0.4" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339" @@ -6385,6 +6457,17 @@ dependencies: "@types/react" "*" +"@types/react-dev-utils@^9.0.4": + version "9.0.4" + resolved "https://registry.yarnpkg.com/@types/react-dev-utils/-/react-dev-utils-9.0.4.tgz#3e4bee79b7536777cef219427ab1d38adc24f3f2" + integrity sha512-8cv9rAeSP1EmyRQAbZ/i6uYtai1VoKHGSBwDyCLM82wCkqoh3WPjJgI1pfi2kiLc0C5hNU7DLo7/c4hylfHLWg== + dependencies: + "@types/eslint" "*" + "@types/express" "*" + "@types/html-webpack-plugin" "*" + "@types/webpack" "*" + "@types/webpack-dev-server" "*" + "@types/react-dom@*", "@types/react-dom@16.9.8", "@types/react-dom@^16.9.8": version "16.9.8" resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.8.tgz#fe4c1e11dfc67155733dfa6aa65108b4971cb423" @@ -6438,6 +6521,11 @@ "@types/prop-types" "*" csstype "^2.2.0" +"@types/relateurl@*": + version "0.2.28" + resolved "https://registry.yarnpkg.com/@types/relateurl/-/relateurl-0.2.28.tgz#6bda7db8653fa62643f5ee69e9f69c11a392e3a6" + integrity sha1-a9p9uGU/piZD9e5p6facEaOS46Y= + "@types/rimraf@^2.0.2": version "2.0.4" resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-2.0.4.tgz#403887b0b53c6100a6c35d2ab24f6ccc042fec46" @@ -6574,6 +6662,17 @@ resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-7.0.4.tgz#00a5749810b4ad80bff73a61f9cc9d0d521feb3c" integrity sha512-WGZCqBZZ0mXN2RxvLHL6/7RCu+OWs28jgQMP04LWfpyJlQUMTR6YU9CNJAKDgbw+EV/u687INXuLUc7FuML/4g== +"@types/webpack-dev-server@*": + version "3.11.0" + resolved "https://registry.yarnpkg.com/@types/webpack-dev-server/-/webpack-dev-server-3.11.0.tgz#bcc3b85e7dc6ac2db25330610513f2228c2fcfb2" + integrity sha512-3+86AgSzl18n5P1iUP9/lz3G3GMztCp+wxdDvVuNhx1sr1jE79GpYfKHL8k+Vht3N74K2n98CuAEw4YPJCYtDA== + dependencies: + "@types/connect-history-api-fallback" "*" + "@types/express" "*" + "@types/http-proxy-middleware" "*" + "@types/serve-static" "*" + "@types/webpack" "*" + "@types/webpack-env@^1.15.1", "@types/webpack-env@^1.15.2": version "1.15.2" resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.15.2.tgz#927997342bb9f4a5185a86e6579a0a18afc33b0a" From 1b8a469471ec93ab9c25b976a80baab0c080ebf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Maisse?= Date: Tue, 20 Oct 2020 20:22:45 +0200 Subject: [PATCH 10/21] refactor(core): migrate `cli` to TS --- lib/core/src/server/cli/{dev.js => dev.ts} | 2 +- lib/core/src/server/cli/{index.js => index.ts} | 0 lib/core/src/server/cli/{prod.js => prod.ts} | 2 +- lib/core/src/server/cli/{utils.js => utils.ts} | 10 +++++++--- 4 files changed, 9 insertions(+), 5 deletions(-) rename lib/core/src/server/cli/{dev.js => dev.ts} (97%) rename lib/core/src/server/cli/{index.js => index.ts} (100%) rename lib/core/src/server/cli/{prod.js => prod.ts} (96%) rename lib/core/src/server/cli/{utils.js => utils.ts} (72%) diff --git a/lib/core/src/server/cli/dev.js b/lib/core/src/server/cli/dev.ts similarity index 97% rename from lib/core/src/server/cli/dev.js rename to lib/core/src/server/cli/dev.ts index f82530cc57bf..0d80aa85cd50 100644 --- a/lib/core/src/server/cli/dev.js +++ b/lib/core/src/server/cli/dev.ts @@ -3,7 +3,7 @@ import chalk from 'chalk'; import { logger } from '@storybook/node-logger'; import { parseList, getEnvConfig, checkDeprecatedFlags } from './utils'; -async function getCLI(packageJson) { +async function getCLI(packageJson: { version: string; name: string }) { process.env.NODE_ENV = process.env.NODE_ENV || 'development'; program diff --git a/lib/core/src/server/cli/index.js b/lib/core/src/server/cli/index.ts similarity index 100% rename from lib/core/src/server/cli/index.js rename to lib/core/src/server/cli/index.ts diff --git a/lib/core/src/server/cli/prod.js b/lib/core/src/server/cli/prod.ts similarity index 96% rename from lib/core/src/server/cli/prod.js rename to lib/core/src/server/cli/prod.ts index d0df8289c286..70a3e7dc9e80 100644 --- a/lib/core/src/server/cli/prod.js +++ b/lib/core/src/server/cli/prod.ts @@ -3,7 +3,7 @@ import chalk from 'chalk'; import { logger } from '@storybook/node-logger'; import { parseList, getEnvConfig, checkDeprecatedFlags } from './utils'; -function getCLI(packageJson) { +function getCLI(packageJson: { version: string; name: string }) { process.env.NODE_ENV = process.env.NODE_ENV || 'production'; program diff --git a/lib/core/src/server/cli/utils.js b/lib/core/src/server/cli/utils.ts similarity index 72% rename from lib/core/src/server/cli/utils.js rename to lib/core/src/server/cli/utils.ts index 0855434d222d..afe9d24947ce 100644 --- a/lib/core/src/server/cli/utils.js +++ b/lib/core/src/server/cli/utils.ts @@ -1,11 +1,11 @@ import deprecate from 'util-deprecate'; import dedent from 'ts-dedent'; -export function parseList(str) { +export function parseList(str: string) { return str.split(','); } -export function getEnvConfig(program, configEnv) { +export function getEnvConfig(program: Record, configEnv: Record) { Object.keys(configEnv).forEach((fieldName) => { const envVarName = configEnv[fieldName]; const envVarValue = process.env[envVarName]; @@ -24,7 +24,11 @@ const warnDLLsDeprecated = deprecate( ` ); -export function checkDeprecatedFlags(options) { +export function checkDeprecatedFlags(options: { + dlls?: boolean; + uiDll?: boolean; + docsDll?: boolean; +}) { if (!options.dlls || options.uiDll || options.docsDll) { warnDLLsDeprecated(); } From 02eb42bdc72ad0a2b51a4541aeda95d52851c8e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Maisse?= Date: Tue, 20 Oct 2020 21:03:19 +0200 Subject: [PATCH 11/21] refactor(core): migrate root `server` directory to TS --- lib/core/package.json | 6 ++ .../{build-dev.test.js => build-dev.test.ts} | 0 .../src/server/{build-dev.js => build-dev.ts} | 42 +++++------ .../{build-static.js => build-static.ts} | 17 ++--- .../server/{config.test.js => config.test.ts} | 0 lib/core/src/server/{config.js => config.ts} | 6 +- .../server/{dev-server.js => dev-server.ts} | 70 ++++++++++++------- .../src/server/{logConfig.js => logConfig.ts} | 2 +- .../{presets.test.js => presets.test.ts} | 18 ++--- .../server/{standalone.js => standalone.ts} | 2 +- lib/core/src/typings.d.ts | 2 + yarn.lock | 55 ++++++++++++++- 12 files changed, 152 insertions(+), 68 deletions(-) rename lib/core/src/server/{build-dev.test.js => build-dev.test.ts} (100%) rename lib/core/src/server/{build-dev.js => build-dev.ts} (87%) rename lib/core/src/server/{build-static.js => build-static.ts} (89%) rename lib/core/src/server/{config.test.js => config.test.ts} (100%) rename lib/core/src/server/{config.js => config.ts} (90%) rename lib/core/src/server/{dev-server.js => dev-server.ts} (84%) rename lib/core/src/server/{logConfig.js => logConfig.ts} (68%) rename lib/core/src/server/{presets.test.js => presets.test.ts} (95%) rename lib/core/src/server/{standalone.js => standalone.ts} (89%) diff --git a/lib/core/package.json b/lib/core/package.json index cfc2a97fcd35..c80160a82995 100644 --- a/lib/core/package.json +++ b/lib/core/package.json @@ -135,11 +135,17 @@ }, "devDependencies": { "@types/case-sensitive-paths-webpack-plugin": "^2.1.4", + "@types/connect": "^3.4.33", + "@types/cpy": "^7.1.3", "@types/dotenv-webpack": "^3.0.0", "@types/interpret": "^1.1.1", + "@types/ip": "^1.1.0", "@types/mock-fs": "^4.10.0", "@types/react-dev-utils": "^9.0.4", + "@types/serve-favicon": "^2.5.0", "@types/terser-webpack-plugin": "^5.0.0", + "@types/webpack-dev-middleware": "^3.7.2", + "@types/webpack-hot-middleware": "^2.25.3", "@types/webpack-virtual-modules": "^0.1.0", "mock-fs": "^4.12.0" }, diff --git a/lib/core/src/server/build-dev.test.js b/lib/core/src/server/build-dev.test.ts similarity index 100% rename from lib/core/src/server/build-dev.test.js rename to lib/core/src/server/build-dev.test.ts diff --git a/lib/core/src/server/build-dev.js b/lib/core/src/server/build-dev.ts similarity index 87% rename from lib/core/src/server/build-dev.js rename to lib/core/src/server/build-dev.ts index 6d58f673c2ab..3f0a2dde9293 100644 --- a/lib/core/src/server/build-dev.js +++ b/lib/core/src/server/build-dev.ts @@ -20,7 +20,7 @@ const cache = Cache({ ns: 'storybook', // Optional. A grouping namespace for items. }); -const writeStats = async (name, stats) => { +const writeStats = async (name: string, stats: any) => { await fs.writeFile( resolvePathInStorybookCache(`public/${name}-stats.json`), JSON.stringify(stats.toJson(), null, 2), @@ -28,13 +28,13 @@ const writeStats = async (name, stats) => { ); }; -const getFreePort = (port) => +const getFreePort = (port: any) => detectFreePort(port).catch((error) => { logger.error(error); process.exit(-1); }); -const updateCheck = async (version) => { +const updateCheck = async (version: string) => { let result; const time = Date.now(); try { @@ -42,7 +42,7 @@ const updateCheck = async (version) => { // if last check was more then 24h ago if (time - 86400000 > fromCache.time) { - const fromFetch = await Promise.race([ + const fromFetch: any = await Promise.race([ fetch(`https://storybook.js.org/versions.json?current=${version}`), // if fetch is too slow, we won't wait for it new Promise((res, rej) => global.setTimeout(rej, 1500)), @@ -63,13 +63,13 @@ const updateCheck = async (version) => { // For this reason, we convert the actual version of the build here so that // every place that relies on this data can reference the version of the // release notes that we expect to use. -const getReleaseNotesVersion = (version) => { +const getReleaseNotesVersion = (version: string) => { const { major, minor } = semver.parse(version); const { version: releaseNotesVersion } = semver.coerce(`${major}.${minor}`); return releaseNotesVersion; }; -const getReleaseNotesFailedState = (version) => { +const getReleaseNotesFailedState = (version: string) => { return { success: false, currentVersion: getReleaseNotesVersion(version), @@ -79,7 +79,7 @@ const getReleaseNotesFailedState = (version) => { export const RELEASE_NOTES_CACHE_KEY = 'releaseNotesData'; -export const getReleaseNotesData = async (currentVersionToParse, fileSystemCache) => { +export const getReleaseNotesData = async (currentVersionToParse: any, fileSystemCache: any) => { let result; try { const fromCache = await fileSystemCache.get('releaseNotesData', []); @@ -119,7 +119,7 @@ export const getReleaseNotesData = async (currentVersionToParse, fileSystemCache return result; }; -function createUpdateMessage(updateInfo, version) { +function createUpdateMessage(updateInfo: any, version: any) { let updateMessage; try { @@ -143,7 +143,7 @@ function createUpdateMessage(updateInfo, version) { return updateMessage; } -function outputStartupInformation(options) { +function outputStartupInformation(options: any) { const { updateInfo, version, @@ -173,6 +173,7 @@ function outputStartupInformation(options) { 'right-mid': '', middle: '', }, + // @ts-ignore paddingLeft: 0, paddingRight: 0, paddingTop: 0, @@ -200,12 +201,12 @@ function outputStartupInformation(options) { ${serveMessage.toString()}${updateMessage ? `\n\n${updateMessage}` : ''} `, - { borderStyle: 'round', padding: 1, borderColor: '#F1618C' } + { borderStyle: 'round', padding: 1, borderColor: '#F1618C' } as any ) ); } -async function outputStats(previewStats, managerStats) { +async function outputStats(previewStats: any, managerStats: any) { if (previewStats) { await writeStats('preview', previewStats); } @@ -215,7 +216,7 @@ async function outputStats(previewStats, managerStats) { ); } -export async function buildDevStandalone(options) { +export async function buildDevStandalone(options: any) { try { const { packageJson, versionUpdates, releaseNotes } = options; const { version } = packageJson; @@ -258,8 +259,9 @@ export async function buildDevStandalone(options) { if (options.smokeTest) { await outputStats(previewStats, managerStats); - const managerWarnings = managerStats.toJson().warnings.length > 0; - const previewWarnings = !options.ignorePreview && previewStats.toJson().warnings.length > 0; + const managerWarnings = (managerStats as any).toJson().warnings.length > 0; + const previewWarnings = + !options.ignorePreview && (previewStats as any).toJson().warnings.length > 0; process.exit(managerWarnings || previewWarnings ? 1 : 0); return; } @@ -277,12 +279,12 @@ export async function buildDevStandalone(options) { npmLog.heading = ''; if (error instanceof Error) { - if (error.error) { - logger.error(error.error); - } else if (error.stats && error.stats.compilation.errors) { - error.stats.compilation.errors.forEach((e) => logger.plain(e)); + if ((error as any).error) { + logger.error((error as any).error); + } else if ((error as any).stats && (error as any).stats.compilation.errors) { + (error as any).stats.compilation.errors.forEach((e: any) => logger.plain(e)); } else { - logger.error(error); + logger.error(error as any); } } logger.line(); @@ -305,7 +307,7 @@ export async function buildDevStandalone(options) { } } -export async function buildDev({ packageJson, ...loadOptions }) { +export async function buildDev({ packageJson, ...loadOptions }: any) { const cliOptions = await getDevCli(packageJson); await buildDevStandalone({ diff --git a/lib/core/src/server/build-static.js b/lib/core/src/server/build-static.ts similarity index 89% rename from lib/core/src/server/build-static.js rename to lib/core/src/server/build-static.ts index 3eb3826ddf58..dd75bc4657a7 100644 --- a/lib/core/src/server/build-static.js +++ b/lib/core/src/server/build-static.ts @@ -13,7 +13,7 @@ import loadManagerConfig from './manager/manager-config'; import { logConfig } from './logConfig'; import { getPrebuiltDir } from './utils/prebuilt-manager'; -async function compileManager(managerConfig, managerStartTime) { +async function compileManager(managerConfig: any, managerStartTime: [number, number]) { logger.info('=> Compiling manager..'); return new Promise((resolve, reject) => { @@ -45,7 +45,7 @@ async function compileManager(managerConfig, managerStartTime) { }); } -async function watchPreview(previewConfig) { +async function watchPreview(previewConfig: any) { logger.info('=> Compiling preview in watch mode..'); return new Promise(() => { @@ -67,7 +67,7 @@ async function watchPreview(previewConfig) { }); } -async function compilePreview(previewConfig, previewStartTime) { +async function compilePreview(previewConfig: any, previewStartTime: [number, number]) { logger.info('=> Compiling preview..'); return new Promise((resolve, reject) => { @@ -100,13 +100,14 @@ async function compilePreview(previewConfig, previewStartTime) { }); } -async function copyAllStaticFiles(staticDir, outputDir) { +async function copyAllStaticFiles(staticDir: any[] | undefined, outputDir: string) { if (staticDir && staticDir.length) { await Promise.all( staticDir.map(async (dir) => { const [currentStaticDir, staticEndpoint] = dir.split(':').concat('/'); const localStaticPath = path.resolve(currentStaticDir); + // @ts-ignore if (await !fs.exists(localStaticPath)) { logger.error(`Error: no such directory to load static files: ${localStaticPath}`); process.exit(-1); @@ -118,7 +119,7 @@ async function copyAllStaticFiles(staticDir, outputDir) { } } -async function buildManager(configType, outputDir, configDir, options) { +async function buildManager(configType: any, outputDir: string, configDir: string, options: any) { logger.info('=> Building manager..'); const managerStartTime = process.hrtime(); @@ -138,7 +139,7 @@ async function buildManager(configType, outputDir, configDir, options) { return compileManager(managerConfig, managerStartTime); } -async function buildPreview(configType, outputDir, packageJson, options) { +async function buildPreview(configType: any, outputDir: string, packageJson: any, options: any) { const { watch, debugWebpack } = options; logger.info('=> Building preview..'); @@ -165,7 +166,7 @@ async function buildPreview(configType, outputDir, packageJson, options) { return compilePreview(previewConfig, previewStartTime); } -export async function buildStaticStandalone(options) { +export async function buildStaticStandalone(options: any) { const { staticDir, configDir, packageJson } = options; const configType = 'PRODUCTION'; @@ -197,7 +198,7 @@ export async function buildStaticStandalone(options) { logger.info(`=> Output directory: ${outputDir}`); } -export function buildStatic({ packageJson, ...loadOptions }) { +export function buildStatic({ packageJson, ...loadOptions }: any) { const cliOptions = getProdCli(packageJson); return buildStaticStandalone({ diff --git a/lib/core/src/server/config.test.js b/lib/core/src/server/config.test.ts similarity index 100% rename from lib/core/src/server/config.test.js rename to lib/core/src/server/config.test.ts diff --git a/lib/core/src/server/config.js b/lib/core/src/server/config.ts similarity index 90% rename from lib/core/src/server/config.js rename to lib/core/src/server/config.ts index aa355bbdcb56..1c61834f757e 100644 --- a/lib/core/src/server/config.js +++ b/lib/core/src/server/config.ts @@ -3,7 +3,7 @@ import loadPresets from './presets'; import loadCustomPresets from './common/custom-presets'; import { typeScriptDefaults } from './config/defaults'; -async function getPreviewWebpackConfig(options, presets) { +async function getPreviewWebpackConfig(options: any, presets: any) { const typescriptOptions = await presets.apply('typescript', { ...typeScriptDefaults }, options); const babelOptions = await presets.apply('babel', {}, { ...options, typescriptOptions }); const entries = await presets.apply('entries', [], options); @@ -24,12 +24,12 @@ async function getPreviewWebpackConfig(options, presets) { ); } -export const filterPresetsConfig = (presetsConfig) => +export const filterPresetsConfig = (presetsConfig: any[]) => presetsConfig.filter( (preset) => !/@storybook[\\\\/]preset-typescript/.test(preset.name || preset) ); -export default async (options) => { +export default async (options: any) => { const { corePresets = [], frameworkPresets = [], overridePresets = [], ...restOptions } = options; const presetsConfig = [ diff --git a/lib/core/src/server/dev-server.js b/lib/core/src/server/dev-server.ts similarity index 84% rename from lib/core/src/server/dev-server.js rename to lib/core/src/server/dev-server.ts index 3d696fcec5e6..b14e266df40d 100644 --- a/lib/core/src/server/dev-server.js +++ b/lib/core/src/server/dev-server.ts @@ -1,6 +1,6 @@ import { logger } from '@storybook/node-logger'; import open from 'better-opn'; -import express, { Router } from 'express'; +import express, { Express, Router } from 'express'; import { pathExists, readFile } from 'fs-extra'; import http from 'http'; import https from 'https'; @@ -10,10 +10,12 @@ import prettyTime from 'pretty-hrtime'; import { stringify } from 'telejson'; import dedent from 'ts-dedent'; import favicon from 'serve-favicon'; -import webpack, { ProgressPlugin } from 'webpack'; -import webpackDevMiddleware from 'webpack-dev-middleware'; +import webpack, { Compiler, ProgressPlugin, Stats } from 'webpack'; +import webpackDevMiddleware, { WebpackDevMiddleware } from 'webpack-dev-middleware'; import webpackHotMiddleware from 'webpack-hot-middleware'; +// eslint-disable-next-line import/no-extraneous-dependencies +import { NextHandleFunction } from 'connect'; import { getMiddleware } from './utils/middleware'; import { logConfig } from './logConfig'; import loadConfig from './config'; @@ -25,10 +27,10 @@ const defaultFavIcon = require.resolve('./public/favicon.ico'); const cache = {}; -let previewProcess; -let previewReject; +let previewProcess: WebpackDevMiddleware & NextHandleFunction; +let previewReject: (reason?: any) => void; -const bailPreview = (e) => { +const bailPreview = (e: Error) => { if (previewReject) previewReject(); if (previewProcess) { try { @@ -41,7 +43,15 @@ const bailPreview = (e) => { throw e; }; -async function getServer(app, options) { +async function getServer( + app: Express, + options: { + https?: boolean; + sslCert?: string; + sslKey?: string; + sslCa?: string[]; + } +) { if (!options.https) { return http.createServer(app); } @@ -65,7 +75,7 @@ async function getServer(app, options) { return https.createServer(sslOptions, app); } -async function useStatics(router, options) { +async function useStatics(router: any, options: { staticDir?: string[] }) { const { staticDir } = options; let hasCustomFavicon = false; @@ -101,7 +111,7 @@ async function useStatics(router, options) { } } -function openInBrowser(address) { +function openInBrowser(address: string) { try { open(address); } catch (error) { @@ -113,18 +123,27 @@ function openInBrowser(address) { } } -const router = new Router(); +// @ts-ignore +const router: Router = new Router(); -const printDuration = (startTime) => +const printDuration = (startTime: [number, number]) => prettyTime(process.hrtime(startTime)) .replace(' ms', ' milliseconds') .replace(' s', ' seconds') .replace(' m', ' minutes'); -const useProgressReporting = async (compiler, options, startTime) => { +const useProgressReporting = async ( + compiler: Compiler, + options: any, + startTime: [number, number] +) => { let value = 0; - let totalModules; - let reportProgress = () => {}; + let totalModules: number; + let reportProgress: (progress?: { + value?: number; + message: string; + modules?: any; + }) => void = () => {}; router.get('/progress', (request, response) => { response.setHeader('Cache-Control', 'no-cache'); @@ -135,14 +154,14 @@ const useProgressReporting = async (compiler, options, startTime) => { const close = () => response.end(); response.on('close', close); - reportProgress = (progress) => { + reportProgress = (progress: any) => { if (response.writableEnded) return; response.write(`data: ${JSON.stringify(progress)}\n\n`); if (progress.value === 1) close(); }; }); - const handler = (newValue, message, arg3) => { + const handler = (newValue: number, message: string, arg3: any) => { value = Math.max(newValue, value); // never go backwards const progress = { value, message: message.charAt(0).toUpperCase() + message.slice(1) }; if (message === 'building') { @@ -150,7 +169,7 @@ const useProgressReporting = async (compiler, options, startTime) => { const complete = parseInt(counts[1], 10); const total = parseInt(counts[2], 10); if (!Number.isNaN(complete) && !Number.isNaN(total)) { - progress.modules = { complete, total }; + (progress as any).modules = { complete, total }; totalModules = total; } } @@ -174,7 +193,7 @@ const startManager = async ({ outputDir, configDir, prebuiltDir, -}) => { +}: any) => { let managerConfig; if (!prebuiltDir) { // this is pretty slow @@ -218,6 +237,7 @@ const startManager = async ({ }, // this actually causes 0 (regular) output from wdm & webpack logLevel: 'warn', + // @ts-ignore clientLogLevel: 'warning', noInfo: true, }); @@ -229,13 +249,13 @@ const startManager = async ({ router.use(middleware); - const managerStats = await new Promise((resolve) => middleware.waitUntilValid(resolve)); + const managerStats: Stats = await new Promise((resolve) => middleware.waitUntilValid(resolve)); if (!managerStats) throw new Error('no stats after building preview'); if (managerStats.hasErrors()) throw managerStats; return { managerStats, managerTotalTime: process.hrtime(startTime) }; }; -const startPreview = async ({ startTime, options, configType, outputDir }) => { +const startPreview = async ({ startTime, options, configType, outputDir }: any) => { if (options.ignorePreview) { return { previewStats: {}, previewTotalTime: 0 }; } @@ -271,10 +291,10 @@ const startPreview = async ({ startTime, options, configType, outputDir }) => { ...previewConfig.devServer, }); - router.use(previewProcess); + router.use(previewProcess as any); router.use(webpackHotMiddleware(compiler)); - const previewStats = await new Promise((resolve, reject) => { + const previewStats: Stats = await new Promise((resolve, reject) => { previewProcess.waitUntilValid(resolve); previewReject = reject; }); @@ -283,7 +303,7 @@ const startPreview = async ({ startTime, options, configType, outputDir }) => { return { previewStats, previewTotalTime: process.hrtime(startTime) }; }; -export async function storybookDevServer(options) { +export async function storybookDevServer(options: any) { const app = express(); const server = await getServer(app, options); @@ -316,7 +336,9 @@ export async function storybookDevServer(options) { const networkAddress = `${proto}://${ip.address()}:${port}/`; await new Promise((resolve, reject) => { - server.listen({ port, host }, (error) => (error ? reject(error) : resolve())); + // FIXME: Following line doesn't match TypeScript signature at all 🤔 + // @ts-ignore + server.listen({ port, host }, (error: Error) => (error ? reject(error) : resolve())); }); const prebuiltDir = await getPrebuiltDir({ configDir, options }); diff --git a/lib/core/src/server/logConfig.js b/lib/core/src/server/logConfig.ts similarity index 68% rename from lib/core/src/server/logConfig.js rename to lib/core/src/server/logConfig.ts index 815fb5beb3e9..26033f9b33d1 100644 --- a/lib/core/src/server/logConfig.js +++ b/lib/core/src/server/logConfig.ts @@ -1,7 +1,7 @@ /* eslint-disable no-console */ import chalk from 'chalk'; -export function logConfig(caption, config) { +export function logConfig(caption: unknown, config: unknown) { console.log(chalk.cyan(caption)); console.dir(config, { depth: null }); } diff --git a/lib/core/src/server/presets.test.js b/lib/core/src/server/presets.test.ts similarity index 95% rename from lib/core/src/server/presets.test.js rename to lib/core/src/server/presets.test.ts index b6564201922f..620b1b73abf7 100644 --- a/lib/core/src/server/presets.test.js +++ b/lib/core/src/server/presets.test.ts @@ -1,11 +1,11 @@ -function wrapPreset(basePresets) { +function wrapPreset(basePresets: any): { babel: Function; webpack: Function } { return { - babel: async (config, args) => basePresets.apply('babel', config, args), - webpack: async (config, args) => basePresets.apply('webpack', config, args), + babel: async (config: any, args: any) => basePresets.apply('babel', config, args), + webpack: async (config: any, args: any) => basePresets.apply('webpack', config, args), }; } -function mockPreset(name, mockPresetObject) { +function mockPreset(name: string, mockPresetObject: any) { jest.mock(name, () => mockPresetObject, { virtual: true }); } @@ -17,7 +17,7 @@ jest.mock('@storybook/node-logger', () => ({ }, })); -jest.mock('resolve-from', () => (l, name) => { +jest.mock('resolve-from', () => (l: any, name: string) => { const KNOWN_FILES = [ '@storybook/addon-actions/register', './local/preset', @@ -83,11 +83,11 @@ describe('presets', () => { it('loads and applies presets when they are combined in another preset', async () => { mockPreset('preset-foo', { - foo: (exec) => exec.concat('foo'), + foo: (exec: string[]) => exec.concat('foo'), }); mockPreset('preset-bar', { - foo: (exec) => exec.concat('bar'), + foo: (exec: string[]) => exec.concat('bar'), }); mockPreset('preset-got', [ @@ -96,11 +96,11 @@ describe('presets', () => { ]); mockPreset('preset-dracarys', { - foo: (exec) => exec.concat('dracarys'), + foo: (exec: string[]) => exec.concat('dracarys'), }); mockPreset('preset-valar', { - foo: (exec, options) => exec.concat(`valar ${options.custom}`), + foo: (exec: string[], options: any) => exec.concat(`valar ${options.custom}`), }); const getPresets = jest.requireActual('./presets').default; diff --git a/lib/core/src/server/standalone.js b/lib/core/src/server/standalone.ts similarity index 89% rename from lib/core/src/server/standalone.js rename to lib/core/src/server/standalone.ts index c7ae111bd752..f3452eb6c6af 100644 --- a/lib/core/src/server/standalone.js +++ b/lib/core/src/server/standalone.ts @@ -1,7 +1,7 @@ import { buildStaticStandalone } from './build-static'; import { buildDevStandalone } from './build-dev'; -async function build(options = {}, frameworkOptions = {}) { +async function build(options: any = {}, frameworkOptions: any = {}) { const { mode = 'dev' } = options; const commonOptions = { diff --git a/lib/core/src/typings.d.ts b/lib/core/src/typings.d.ts index ca918df9ff1e..b727ac7171ae 100644 --- a/lib/core/src/typings.d.ts +++ b/lib/core/src/typings.d.ts @@ -5,3 +5,5 @@ declare module 'lazy-universal-dotenv'; declare module 'pnp-webpack-plugin'; declare module '@storybook/theming/paths'; declare module '@storybook/ui/paths'; +declare module 'file-system-cache'; +declare module 'better-opn'; diff --git a/yarn.lock b/yarn.lock index bbe4b87a4343..1e8aee9171e6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5989,7 +5989,7 @@ "@types/express-serve-static-core" "*" "@types/node" "*" -"@types/connect@*": +"@types/connect@*", "@types/connect@^3.4.33": version "3.4.33" resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.33.tgz#31610c901eca573b8713c3330abc6e6b9f588546" integrity sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A== @@ -6001,6 +6001,13 @@ resolved "https://registry.yarnpkg.com/@types/core-js/-/core-js-2.5.3.tgz#d2f307f708f897f875d312501e3b4a2fd4481d41" integrity sha512-F9RHpjuPSit4dCCRXgi7XcqA01DAjy9QY+v9yICoxXsjXD9cgQpyZyL2eSZnTkBGXGaQnea8waZOZTogLDB+rA== +"@types/cpy@^7.1.3": + version "7.1.3" + resolved "https://registry.yarnpkg.com/@types/cpy/-/cpy-7.1.3.tgz#7a70133886a0feb94f0e9b018122a84b831157ba" + integrity sha512-G0KTGSAi3kwIx63zyI/Lekpftiy9jQ5JvQP8YTFzg3H9TMIz4PMv77kxmomu6m9ugc8Zrfn4THbmmNHL9psN0Q== + dependencies: + cpy "*" + "@types/cross-spawn@^6.0.1": version "6.0.2" resolved "https://registry.yarnpkg.com/@types/cross-spawn/-/cross-spawn-6.0.2.tgz#168309de311cd30a2b8ae720de6475c2fbf33ac7" @@ -6201,6 +6208,13 @@ dependencies: "@types/node" "*" +"@types/ip@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@types/ip/-/ip-1.1.0.tgz#aec4f5bfd49e4a4c53b590d88c36eb078827a7c0" + integrity sha512-dwNe8gOoF70VdL6WJBwVHtQmAX4RMd62M+mAB9HQFjG1/qiCLM/meRy95Pd14FYBbEDwCq7jgJs89cHpLBu4HQ== + dependencies: + "@types/node" "*" + "@types/is-function@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@types/is-function/-/is-function-1.0.0.tgz#1b0b819b1636c7baf0d6785d030d12edf70c3e83" @@ -6299,6 +6313,13 @@ dependencies: "@types/unist" "*" +"@types/memory-fs@*": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@types/memory-fs/-/memory-fs-0.3.2.tgz#5d4753f9b390cb077c8c8af97bc96463399ceccd" + integrity sha512-j5AcZo7dbMxHoOimcHEIh0JZe5e1b8q8AqGSpZJrYc7xOgCIP79cIjTdx5jSDLtySnQDwkDTqwlC7Xw7uXw7qg== + dependencies: + "@types/node" "*" + "@types/micromatch@^4.0.1": version "4.0.1" resolved "https://registry.yarnpkg.com/@types/micromatch/-/micromatch-4.0.1.tgz#9381449dd659fc3823fd2a4190ceacc985083bc7" @@ -6546,6 +6567,13 @@ dependencies: "@types/node" "*" +"@types/serve-favicon@^2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@types/serve-favicon/-/serve-favicon-2.5.0.tgz#21164e61290d577d75e22de1b3119fad70bf52b6" + integrity sha512-APK6i1tJp8XBYCZyU4HqtNZBiwipIBQvpQVLYZezTm4TaKKl0KrsGokQK9k3Ll2CaEGNuehppKhXp/Ki9oWT/w== + dependencies: + "@types/express" "*" + "@types/serve-static@*", "@types/serve-static@^1.13.3": version "1.13.4" resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.4.tgz#6662a93583e5a6cabca1b23592eb91e12fa80e7c" @@ -6662,6 +6690,16 @@ resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-7.0.4.tgz#00a5749810b4ad80bff73a61f9cc9d0d521feb3c" integrity sha512-WGZCqBZZ0mXN2RxvLHL6/7RCu+OWs28jgQMP04LWfpyJlQUMTR6YU9CNJAKDgbw+EV/u687INXuLUc7FuML/4g== +"@types/webpack-dev-middleware@^3.7.2": + version "3.7.2" + resolved "https://registry.yarnpkg.com/@types/webpack-dev-middleware/-/webpack-dev-middleware-3.7.2.tgz#31030c7cca7f98d56debfd859bb57f9040f0d3c5" + integrity sha512-PvETiS//pjVZBK48aJfbxzT7+9LIxanbnk9eXXYUfefGyPdsCkNrMDxRlOVrBvxukXUhD5B6N/pkPMdWrtuFkA== + dependencies: + "@types/connect" "*" + "@types/memory-fs" "*" + "@types/webpack" "*" + loglevel "^1.6.2" + "@types/webpack-dev-server@*": version "3.11.0" resolved "https://registry.yarnpkg.com/@types/webpack-dev-server/-/webpack-dev-server-3.11.0.tgz#bcc3b85e7dc6ac2db25330610513f2228c2fcfb2" @@ -6678,6 +6716,14 @@ resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.15.2.tgz#927997342bb9f4a5185a86e6579a0a18afc33b0a" integrity sha512-67ZgZpAlhIICIdfQrB5fnDvaKFcDxpKibxznfYRVAT4mQE41Dido/3Ty+E3xGBmTogc5+0Qb8tWhna+5B8z1iQ== +"@types/webpack-hot-middleware@^2.25.3": + version "2.25.3" + resolved "https://registry.yarnpkg.com/@types/webpack-hot-middleware/-/webpack-hot-middleware-2.25.3.tgz#ba6265ada359cae4f437d8ac08ac5b8c616f7521" + integrity sha512-zGkTzrwQnhSadIXGYGZLu7tpXQwn4+6y9nGeql+5UeRtW/k54Jp4SnzB0Qw00ednw0ZFoZOvqTFfXSbFXohc5Q== + dependencies: + "@types/connect" "*" + "@types/webpack" "*" + "@types/webpack-sources@*", "@types/webpack-sources@^0.1.5": version "0.1.7" resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-0.1.7.tgz#0a330a9456113410c74a5d64180af0cbca007141" @@ -12749,7 +12795,7 @@ cp-file@^7.0.0: nested-error-stacks "^2.0.0" p-event "^4.1.0" -cpy@^8.1.1: +cpy@*, cpy@^8.1.1: version "8.1.1" resolved "https://registry.yarnpkg.com/cpy/-/cpy-8.1.1.tgz#066ed4c6eaeed9577df96dae4db9438c1a90df62" integrity sha512-vqHT+9o67sMwJ5hUd/BAOYeemkU+MuFRsK2c36Xc3eefQpAsp1kAsyDxEDcc5JS1+y9l/XHPrIsVTcyGGmkUUQ== @@ -23370,6 +23416,11 @@ loglevel@^1.4.1, loglevel@^1.6.4, loglevel@^1.6.6, loglevel@^1.6.8: resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.8.tgz#8a25fb75d092230ecd4457270d80b54e28011171" integrity sha512-bsU7+gc9AJ2SqpzxwU3+1fedl8zAntbtC5XYlt3s2j1hJcn2PsXSmgN8TaLG/J1/2mod4+cE/3vNL70/c1RNCA== +loglevel@^1.6.2: + version "1.7.0" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.0.tgz#728166855a740d59d38db01cf46f042caa041bb0" + integrity sha512-i2sY04nal5jDcagM3FMfG++T69GEEM8CYuOfeOIvmXzOIcwE9a/CJPR0MFM97pYMj/u10lzz7/zd7+qwhrBTqQ== + loglevelnext@^1.0.1: version "1.0.5" resolved "https://registry.yarnpkg.com/loglevelnext/-/loglevelnext-1.0.5.tgz#36fc4f5996d6640f539ff203ba819641680d75a2" From 5e1593544efb2bae29e0f02d06121c39804749f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Maisse?= Date: Tue, 20 Oct 2020 21:22:30 +0200 Subject: [PATCH 12/21] refactor(core): add `@storybook/ui` to typings We need to "fake" `@storybook/ui` types to be able to compile properly `@storybook/core`. This is due to a dependency cycle causing `core` to be build at the same time as `ui`: > lerna WARN ECYCLE Dependency cycles detected, you should fix these! > lerna WARN ECYCLE @storybook/react -> @storybook/core -> @storybook/ui -> @storybook/react --- lib/core/src/typings.d.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/core/src/typings.d.ts b/lib/core/src/typings.d.ts index b727ac7171ae..016867607433 100644 --- a/lib/core/src/typings.d.ts +++ b/lib/core/src/typings.d.ts @@ -7,3 +7,4 @@ declare module '@storybook/theming/paths'; declare module '@storybook/ui/paths'; declare module 'file-system-cache'; declare module 'better-opn'; +declare module '@storybook/ui'; From 784c3212851d5bca0daa008750eda1952b211c89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Maisse?= Date: Wed, 21 Oct 2020 21:03:42 +0200 Subject: [PATCH 13/21] refactor(core): improve typings of `server/utils` --- .../merge-webpack-config.test.ts.snap | 43 ++++++++++----- .../server/utils/load-custom-babel-config.ts | 13 ++--- .../server/utils/merge-webpack-config.test.ts | 25 ++++++--- .../src/server/utils/merge-webpack-config.ts | 52 ++++++++++--------- .../server/utils/resolve-path-in-sb-cache.ts | 2 +- lib/core/src/server/utils/server-require.ts | 8 +-- 6 files changed, 85 insertions(+), 58 deletions(-) diff --git a/lib/core/src/server/utils/__snapshots__/merge-webpack-config.test.ts.snap b/lib/core/src/server/utils/__snapshots__/merge-webpack-config.test.ts.snap index c33eda68bd00..ddc929b507ad 100644 --- a/lib/core/src/server/utils/__snapshots__/merge-webpack-config.test.ts.snap +++ b/lib/core/src/server/utils/__snapshots__/merge-webpack-config.test.ts.snap @@ -2,14 +2,18 @@ exports[`mergeConfigs merges partial custom config 1`] = ` Object { - "devtool": "source-maps", + "devtool": "source-map", "entry": Object { "bundle": "index.js", }, "module": Object { "rules": Array [ - "r1", - "r2", + Object { + "use": "r1", + }, + Object { + "use": "r2", + }, ], }, "optimization": Object { @@ -31,7 +35,7 @@ Object { "A1": "src/B1", "A2": "src/B2", }, - "enforceModuleExtension": true, + "enforceExtension": true, "extensions": Array [ ".js", ".json", @@ -44,14 +48,18 @@ Object { exports[`mergeConfigs merges successfully if custom config is empty 1`] = ` Object { - "devtool": "source-maps", + "devtool": "source-map", "entry": Object { "bundle": "index.js", }, "module": Object { "rules": Array [ - "r1", - "r2", + Object { + "use": "r1", + }, + Object { + "use": "r2", + }, ], }, "optimization": Object { @@ -72,7 +80,7 @@ Object { "A1": "src/B1", "A2": "src/B2", }, - "enforceModuleExtension": true, + "enforceExtension": true, "extensions": Array [ ".js", ".json", @@ -83,17 +91,25 @@ Object { exports[`mergeConfigs merges two full configs in one 1`] = ` Object { - "devtool": "source-maps", + "devtool": "source-map", "entry": Object { "bundle": "index.js", }, "module": Object { "noParse": /jquery\\|lodash/, "rules": Array [ - "r1", - "r2", - "r3", - "r4", + Object { + "use": "r1", + }, + Object { + "use": "r2", + }, + Object { + "use": "r3", + }, + Object { + "use": "r4", + }, ], }, "optimization": Object { @@ -123,7 +139,6 @@ Object { "A4": "src/B4", }, "enforceExtension": false, - "enforceModuleExtension": true, "extensions": Array [ ".js", ".json", diff --git a/lib/core/src/server/utils/load-custom-babel-config.ts b/lib/core/src/server/utils/load-custom-babel-config.ts index 2310c902ed72..0336e13d8150 100644 --- a/lib/core/src/server/utils/load-custom-babel-config.ts +++ b/lib/core/src/server/utils/load-custom-babel-config.ts @@ -3,8 +3,9 @@ import path from 'path'; import JSON5 from 'json5'; import { logger } from '@storybook/node-logger'; +import { TransformOptions } from '@babel/core'; -function removeReactHmre(presets: string[]) { +function removeReactHmre(presets: TransformOptions['presets']) { const index = presets.indexOf('react-hmre'); if (index > -1) { presets.splice(index, 1); @@ -12,11 +13,11 @@ function removeReactHmre(presets: string[]) { } // Tries to load a .babelrc and returns the parsed object if successful -function loadFromPath(babelConfigPath: string) { - let config; +function loadFromPath(babelConfigPath: string): TransformOptions { + let config: TransformOptions; const error: { - js?: any; - json?: any; + js?: Error; + json?: Error; } = {}; if (fs.existsSync(babelConfigPath)) { @@ -68,7 +69,7 @@ function loadFromPath(babelConfigPath: string) { return config; } -export default async function (configDir: string, getDefaultConfig: () => unknown) { +export default async function (configDir: string, getDefaultConfig: () => TransformOptions) { // Between versions 5.1.0 - 5.1.9 this loaded babel.config.js from the project // root, which was an unintentional breaking change. We can add back project support // in 6.0. diff --git a/lib/core/src/server/utils/merge-webpack-config.test.ts b/lib/core/src/server/utils/merge-webpack-config.test.ts index 4a5c78aaf952..c75213f7b641 100644 --- a/lib/core/src/server/utils/merge-webpack-config.test.ts +++ b/lib/core/src/server/utils/merge-webpack-config.test.ts @@ -1,7 +1,8 @@ -import mergeConfigs from './merge-webpack-config'; +import { Configuration } from 'webpack'; +import { mergeConfigs } from './merge-webpack-config'; -const config = { - devtool: 'source-maps', +const config: Configuration = { + devtool: 'source-map', entry: { bundle: 'index.js', }, @@ -9,11 +10,13 @@ const config = { filename: '[name].js', }, module: { - rules: ['r1', 'r2'], + rules: [{ use: 'r1' }, { use: 'r2' }], }, + // For snapshot readability purposes `plugins` attribute doesn't match the correct type + // @ts-expect-errors plugins: ['p1', 'p2'], resolve: { - enforceModuleExtension: true, + enforceExtension: true, extensions: ['.js', '.json'], alias: { A1: 'src/B1', @@ -30,7 +33,7 @@ const config = { describe('mergeConfigs', () => { it('merges two full configs in one', () => { - const customConfig = { + const customConfig: Configuration = { profile: true, entry: { bundle: 'should_not_be_merged.js', @@ -40,8 +43,10 @@ describe('mergeConfigs', () => { }, module: { noParse: /jquery|lodash/, - rules: ['r3', 'r4'], + rules: [{ use: 'r3' }, { use: 'r4' }], }, + // For snapshot readability purposes `plugins` attribute doesn't match the correct type + // @ts-expect-errors plugins: ['p3', 'p4'], resolve: { enforceExtension: false, @@ -52,6 +57,8 @@ describe('mergeConfigs', () => { }, }, optimization: { + // For snapshot readability purposes `minimizer` attribute doesn't match the correct type + // @ts-expect-errors minimizer: ['banana'], }, }; @@ -62,7 +69,9 @@ describe('mergeConfigs', () => { }); it('merges partial custom config', () => { - const customConfig = { + const customConfig: Configuration = { + // For snapshot readability purposes `plugins` attribute doesn't match the correct type + // @ts-expect-errors plugins: ['p3'], resolve: { extensions: ['.ts', '.tsx'], diff --git a/lib/core/src/server/utils/merge-webpack-config.ts b/lib/core/src/server/utils/merge-webpack-config.ts index 6152ce9b0b45..5c8df637e7c2 100644 --- a/lib/core/src/server/utils/merge-webpack-config.ts +++ b/lib/core/src/server/utils/merge-webpack-config.ts @@ -1,28 +1,30 @@ -function plugins( - { plugins: defaultPlugins = [] }: { plugins?: T[] }, - { plugins: customPlugins = [] }: { plugins?: T[] } -): T[] { +import { Configuration, Module, Resolve } from 'webpack'; + +function plugins( + { plugins: defaultPlugins = [] }: Configuration, + { plugins: customPlugins = [] }: Configuration +): Configuration['plugins'] { return [...defaultPlugins, ...customPlugins]; } -function rules( - { rules: defaultRules = [] }: { rules?: T[] }, - { rules: customRules = [] }: { rules?: T[] } -): T[] { +function rules( + { rules: defaultRules = [] }: Module, + { rules: customRules = [] }: Module +): Module['rules'] { return [...defaultRules, ...customRules]; } -function extensions( - { extensions: defaultExtensions = [] }: { extensions?: T[] }, - { extensions: customExtensions = [] }: { extensions?: T[] } -): T[] { +function extensions( + { extensions: defaultExtensions = [] }: Resolve, + { extensions: customExtensions = [] }: Resolve +): Resolve['extensions'] { return [...defaultExtensions, ...customExtensions]; } function alias( - { alias: defaultAlias = {} }: { alias?: any }, - { alias: customAlias = {} }: { alias?: any } -) { + { alias: defaultAlias = {} }: Resolve, + { alias: customAlias = {} }: Resolve +): Resolve['alias'] { return { ...defaultAlias, ...customAlias, @@ -30,9 +32,9 @@ function alias( } function module( - { module: defaultModule = {} }: { module?: any }, - { module: customModule = {} }: { module?: any } -) { + { module: defaultModule = { rules: [] } }: Configuration, + { module: customModule = { rules: [] } }: Configuration +): Configuration['module'] { return { ...defaultModule, ...customModule, @@ -41,9 +43,9 @@ function module( } function resolve( - { resolve: defaultResolve = {} }: { resolve?: any }, - { resolve: customResolve = {} }: { resolve?: any } -) { + { resolve: defaultResolve = {} }: Configuration, + { resolve: customResolve = {} }: Configuration +): Configuration['resolve'] { return { ...defaultResolve, ...customResolve, @@ -53,16 +55,16 @@ function resolve( } function optimization( - { optimization: defaultOptimization = {} }: { optimization?: any }, - { optimization: customOptimization = {} }: { optimization?: any } -) { + { optimization: defaultOptimization = {} }: Configuration, + { optimization: customOptimization = {} }: Configuration +): Configuration['optimization'] { return { ...defaultOptimization, ...customOptimization, }; } -function mergeConfigs(config: any, customConfig: any) { +export function mergeConfigs(config: Configuration, customConfig: Configuration): Configuration { return { // We'll always load our configurations after the custom config. // So, we'll always load the stuff we need. diff --git a/lib/core/src/server/utils/resolve-path-in-sb-cache.ts b/lib/core/src/server/utils/resolve-path-in-sb-cache.ts index 70afe8510d05..7157abdc0257 100644 --- a/lib/core/src/server/utils/resolve-path-in-sb-cache.ts +++ b/lib/core/src/server/utils/resolve-path-in-sb-cache.ts @@ -9,7 +9,7 @@ import pkgDir from 'pkg-dir'; * @param fileOrDirectoryName {string} Name of the file or directory * @return {string} Absolute path to the file or directory */ -export function resolvePathInStorybookCache(fileOrDirectoryName: string) { +export function resolvePathInStorybookCache(fileOrDirectoryName: string): string { const cwd = process.cwd(); const projectDir = pkgDir.sync(cwd); diff --git a/lib/core/src/server/utils/server-require.ts b/lib/core/src/server/utils/server-require.ts index 7a0cd59f523b..9f4c4dd9831c 100644 --- a/lib/core/src/server/utils/server-require.ts +++ b/lib/core/src/server/utils/server-require.ts @@ -1,13 +1,13 @@ -import interpret from 'interpret'; +import interpret, { Extension } from 'interpret'; import path from 'path'; import { logger } from '@storybook/node-logger'; import { getInterpretedFileWithExt } from './interpret-files'; // The code based on https://github.com/webpack/webpack-cli/blob/ca504de8c7c0ea66278021b72fa6a953e3ffa43c/bin/convert-argv -const compilersState = new Map(); +const compilersState = new Map(); -function registerCompiler(moduleDescriptor: any): number { +function registerCompiler(moduleDescriptor: Extension): number { if (!moduleDescriptor) { return 0; } @@ -90,7 +90,7 @@ export function serverRequire(filePath: string | string[]) { return interopRequireDefault(candidatePath); } -export function serverResolve(filePath: string | string[]) { +export function serverResolve(filePath: string | string[]): string | null { const paths = Array.isArray(filePath) ? filePath : [filePath]; const existingCandidate = getCandidate(paths); From 3239d259f1aa73cb556ded32df83f6039751b155 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Maisse?= Date: Mon, 26 Oct 2020 20:23:21 +0100 Subject: [PATCH 14/21] refactor(core): improve typings of `server/common` --- lib/core/src/server/common/babel-cache-preset.ts | 1 + lib/core/src/server/common/babel.ts | 4 +++- lib/core/src/server/common/common-preset.ts | 2 +- lib/core/src/server/common/custom-presets.ts | 2 +- lib/core/src/server/common/es6Transpiler.ts | 5 ++--- lib/core/src/server/manager/babel-loader-manager.ts | 3 ++- lib/core/src/server/manager/manager-webpack.config.ts | 10 ++++++---- lib/core/src/server/preview/iframe-webpack.config.ts | 2 +- 8 files changed, 17 insertions(+), 12 deletions(-) diff --git a/lib/core/src/server/common/babel-cache-preset.ts b/lib/core/src/server/common/babel-cache-preset.ts index 847b14d04516..2cc2f3511aa1 100644 --- a/lib/core/src/server/common/babel-cache-preset.ts +++ b/lib/core/src/server/common/babel-cache-preset.ts @@ -1,5 +1,6 @@ import { resolvePathInStorybookCache } from '../utils/resolve-path-in-sb-cache'; +// FIXME: babelConfig is maybe a TransformOptions? const extend = (babelConfig: any) => ({ // This is a feature of `babel-loader` for webpack (not Babel itself). // It enables a cache directory for faster-rebuilds diff --git a/lib/core/src/server/common/babel.ts b/lib/core/src/server/common/babel.ts index 607de9db24bd..eae844241914 100644 --- a/lib/core/src/server/common/babel.ts +++ b/lib/core/src/server/common/babel.ts @@ -1,3 +1,5 @@ +import { TransformOptions } from '@babel/core'; + export const plugins = [ require.resolve('@babel/plugin-transform-shorthand-properties'), require.resolve('@babel/plugin-transform-block-scoping'), @@ -39,7 +41,7 @@ export const presets = [ require.resolve('@babel/preset-typescript'), ]; -export default () => { +export const babelConfig: () => TransformOptions = () => { return { sourceType: 'unambiguous', presets: [...presets], diff --git a/lib/core/src/server/common/common-preset.ts b/lib/core/src/server/common/common-preset.ts index 267d30f1088d..e1cbc8d6db37 100644 --- a/lib/core/src/server/common/common-preset.ts +++ b/lib/core/src/server/common/common-preset.ts @@ -1,6 +1,6 @@ import loadCustomBabelConfig from '../utils/load-custom-babel-config'; -import babelConfig from './babel'; +import { babelConfig } from './babel'; export const babel = async (_: unknown, options: { configDir: string; presets: any }) => { const { configDir, presets } = options; diff --git a/lib/core/src/server/common/custom-presets.ts b/lib/core/src/server/common/custom-presets.ts index 8abbca4f6ec9..fb817bb7fb43 100644 --- a/lib/core/src/server/common/custom-presets.ts +++ b/lib/core/src/server/common/custom-presets.ts @@ -2,7 +2,7 @@ import path from 'path'; import { serverRequire, serverResolve } from '../utils/server-require'; import validateConfigurationFiles from '../utils/validate-configuration-files'; -export default function loadCustomPresets({ configDir }: { configDir: string }) { +export default function loadCustomPresets({ configDir }: { configDir: string }): string[] { validateConfigurationFiles(configDir); const presets = serverRequire(path.resolve(configDir, 'presets')); diff --git a/lib/core/src/server/common/es6Transpiler.ts b/lib/core/src/server/common/es6Transpiler.ts index b731e992e857..436f97bc1da1 100644 --- a/lib/core/src/server/common/es6Transpiler.ts +++ b/lib/core/src/server/common/es6Transpiler.ts @@ -1,6 +1,7 @@ +import { RuleSetRule } from 'webpack'; import { plugins } from './babel'; -const es6Transpiler = () => { +export const es6Transpiler: () => RuleSetRule = () => { // TODO: generate regexp using are-you-es5 const include = /[\\/]node_modules[\\/](@storybook\/node-logger|are-you-es5|better-opn|boxen|chalk|commander|find-cache-dir|find-up|fs-extra|json5|node-fetch|pkg-dir|resolve-from|semver)/; @@ -25,5 +26,3 @@ const es6Transpiler = () => { include, }; }; - -export default es6Transpiler; diff --git a/lib/core/src/server/manager/babel-loader-manager.ts b/lib/core/src/server/manager/babel-loader-manager.ts index cf5364fe7c86..01597f0044d1 100644 --- a/lib/core/src/server/manager/babel-loader-manager.ts +++ b/lib/core/src/server/manager/babel-loader-manager.ts @@ -1,7 +1,8 @@ +import { RuleSetRule } from 'webpack'; import { includePaths } from '../config/utils'; import { plugins, presets } from '../common/babel'; -export default () => ({ +export const babelLoader: () => RuleSetRule = () => ({ test: /\.(mjs|tsx?|jsx?)$/, use: [ { diff --git a/lib/core/src/server/manager/manager-webpack.config.ts b/lib/core/src/server/manager/manager-webpack.config.ts index 1eade259ecab..0e8dd99ea69a 100644 --- a/lib/core/src/server/manager/manager-webpack.config.ts +++ b/lib/core/src/server/manager/manager-webpack.config.ts @@ -1,6 +1,6 @@ import path from 'path'; import fse from 'fs-extra'; -import { DefinePlugin } from 'webpack'; +import { DefinePlugin, Configuration } from 'webpack'; import Dotenv from 'dotenv-webpack'; import HtmlWebpackPlugin from 'html-webpack-plugin'; import CaseSensitivePathsPlugin from 'case-sensitive-paths-webpack-plugin'; @@ -13,9 +13,9 @@ import uiPaths from '@storybook/ui/paths'; import { getManagerHeadHtml } from '../utils/template'; import { loadEnv } from '../config/utils'; -import babelLoader from './babel-loader-manager'; +import { babelLoader } from './babel-loader-manager'; import { resolvePathInStorybookCache } from '../utils/resolve-path-in-sb-cache'; -import es6Transpiler from '../common/es6Transpiler'; +import { es6Transpiler } from '../common/es6Transpiler'; const { version } = require('../../../package.json'); @@ -31,7 +31,7 @@ export default async ({ versionCheck, releaseNotesData, presets, -}: any) => { +}: any): Promise => { const { raw, stringified } = loadEnv(); const logLevel = await presets.apply('logLevel', undefined); const isProd = configType === 'PRODUCTION'; @@ -43,6 +43,8 @@ export default async ({ name: 'manager', mode: isProd ? 'production' : 'development', bail: isProd, + // FIXME: `none` is not a valid option for devtool + // @ts-ignore devtool: 'none', entry: entries, output: { diff --git a/lib/core/src/server/preview/iframe-webpack.config.ts b/lib/core/src/server/preview/iframe-webpack.config.ts index 4f2454c65f3b..b9895ad6b548 100644 --- a/lib/core/src/server/preview/iframe-webpack.config.ts +++ b/lib/core/src/server/preview/iframe-webpack.config.ts @@ -15,7 +15,7 @@ import resolveFrom from 'resolve-from'; import themingPaths from '@storybook/theming/paths'; import { createBabelLoader } from './babel-loader-preview'; -import es6Transpiler from '../common/es6Transpiler'; +import { es6Transpiler } from '../common/es6Transpiler'; import { nodeModulesPaths, loadEnv } from '../config/utils'; import { getPreviewHeadHtml, getPreviewBodyHtml } from '../utils/template'; From 0d08492ab180385cdb3a5bd6586b132cfef248c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Maisse?= Date: Mon, 26 Oct 2020 21:46:12 +0100 Subject: [PATCH 15/21] refactor(core): introduce a `types.ts` file to centralize some types used across the lib Start typing manager presets and config --- lib/core/src/server/common/custom-presets.ts | 3 +- lib/core/src/server/config.ts | 28 +++++--- lib/core/src/server/config/utils.ts | 6 +- lib/core/src/server/dev-server.ts | 1 + lib/core/src/server/manager/manager-config.ts | 13 +++- lib/core/src/server/manager/manager-preset.ts | 8 ++- .../server/manager/manager-webpack.config.ts | 5 +- lib/core/src/server/presets.ts | 46 ++++++++---- .../server/preview/iframe-webpack.config.ts | 2 +- lib/core/src/server/types.ts | 70 +++++++++++++++++++ 10 files changed, 149 insertions(+), 33 deletions(-) create mode 100644 lib/core/src/server/types.ts diff --git a/lib/core/src/server/common/custom-presets.ts b/lib/core/src/server/common/custom-presets.ts index fb817bb7fb43..c5b0916316d0 100644 --- a/lib/core/src/server/common/custom-presets.ts +++ b/lib/core/src/server/common/custom-presets.ts @@ -1,8 +1,9 @@ import path from 'path'; import { serverRequire, serverResolve } from '../utils/server-require'; import validateConfigurationFiles from '../utils/validate-configuration-files'; +import { PresetConfig } from '../types'; -export default function loadCustomPresets({ configDir }: { configDir: string }): string[] { +export default function loadCustomPresets({ configDir }: { configDir: string }): PresetConfig[] { validateConfigurationFiles(configDir); const presets = serverRequire(path.resolve(configDir, 'presets')); diff --git a/lib/core/src/server/config.ts b/lib/core/src/server/config.ts index 1c61834f757e..533108afabca 100644 --- a/lib/core/src/server/config.ts +++ b/lib/core/src/server/config.ts @@ -1,9 +1,14 @@ import { logger } from '@storybook/node-logger'; +import { Configuration } from 'webpack'; import loadPresets from './presets'; import loadCustomPresets from './common/custom-presets'; import { typeScriptDefaults } from './config/defaults'; +import { PresetConfig, Presets, PresetsOptions, StorybookConfigOptions } from './types'; -async function getPreviewWebpackConfig(options: any, presets: any) { +async function getPreviewWebpackConfig( + options: StorybookConfigOptions & { presets: Presets }, + presets: Presets +): Promise { const typescriptOptions = await presets.apply('typescript', { ...typeScriptDefaults }, options); const babelOptions = await presets.apply('babel', {}, { ...options, typescriptOptions }); const entries = await presets.apply('entries', [], options); @@ -24,17 +29,20 @@ async function getPreviewWebpackConfig(options: any, presets: any) { ); } -export const filterPresetsConfig = (presetsConfig: any[]) => - presetsConfig.filter( - (preset) => !/@storybook[\\\\/]preset-typescript/.test(preset.name || preset) - ); - -export default async (options: any) => { +export function filterPresetsConfig(presetsConfig: PresetConfig[]): PresetConfig[] { + return presetsConfig.filter((preset) => { + const presetName = typeof preset === 'string' ? preset : preset.name; + return !/@storybook[\\\\/]preset-typescript/.test(presetName); + }); +} +const loadConfig: ( + options: PresetsOptions & StorybookConfigOptions +) => Promise = async (options: PresetsOptions & StorybookConfigOptions) => { const { corePresets = [], frameworkPresets = [], overridePresets = [], ...restOptions } = options; - const presetsConfig = [ + const presetsConfig: PresetConfig[] = [ ...corePresets, - require.resolve('./common/babel-cache-preset.js'), + require.resolve('./common/babel-cache-preset'), ...frameworkPresets, ...loadCustomPresets(options), ...overridePresets, @@ -52,3 +60,5 @@ export default async (options: any) => { return getPreviewWebpackConfig({ ...restOptions, presets }, presets); }; + +export default loadConfig; diff --git a/lib/core/src/server/config/utils.ts b/lib/core/src/server/config/utils.ts index 354c69afca34..a2f86e16ac30 100644 --- a/lib/core/src/server/config/utils.ts +++ b/lib/core/src/server/config/utils.ts @@ -33,7 +33,9 @@ const nodePathsToArray = (nodePath: string) => .map((p) => path.resolve('./', p)); // Load environment variables starts with STORYBOOK_ to the client side. -export function loadEnv(options: { production?: boolean } = {}) { +export function loadEnv( + options: { production?: boolean } = {} +): { stringified: Record; raw: Record } { const defaultNodeEnv = options.production ? 'production' : 'development'; const env: Record = { @@ -54,7 +56,7 @@ export function loadEnv(options: { production?: boolean } = {}) { const base = Object.entries(env).reduce( (acc, [k, v]) => Object.assign(acc, { [k]: JSON.stringify(v) }), - {} + {} as Record ); const { stringified, raw } = getEnvironment({ nodeEnv: env.NODE_ENV }); diff --git a/lib/core/src/server/dev-server.ts b/lib/core/src/server/dev-server.ts index b14e266df40d..c4221fcf1c25 100644 --- a/lib/core/src/server/dev-server.ts +++ b/lib/core/src/server/dev-server.ts @@ -288,6 +288,7 @@ const startPreview = async ({ startTime, options, configType, outputDir }: any) logLevel: 'warn', clientLogLevel: 'warning', noInfo: true, + // @ts-ignore ...previewConfig.devServer, }); diff --git a/lib/core/src/server/manager/manager-config.ts b/lib/core/src/server/manager/manager-config.ts index c71b55c1991a..e9fcfe339a77 100644 --- a/lib/core/src/server/manager/manager-config.ts +++ b/lib/core/src/server/manager/manager-config.ts @@ -8,9 +8,11 @@ import dedent from 'ts-dedent'; import { logger } from '@storybook/node-logger'; +import { Configuration } from 'webpack'; import loadPresets from '../presets'; import loadCustomPresets from '../common/custom-presets'; import { typeScriptDefaults } from '../config/defaults'; +import { Presets, PresetsOptions, StorybookConfigOptions } from '../types'; export const getAutoRefs = async (options: { configDir: string }) => { const location = await findUp('package.json', { cwd: options.configDir }); @@ -66,7 +68,10 @@ const deprecatedDefinedRefDisabled = deprecate( ` ); -async function getManagerWebpackConfig(options: any, presets: any) { +async function getManagerWebpackConfig( + options: StorybookConfigOptions & { presets: Presets }, + presets: Presets +): Promise { const typescriptOptions = await presets.apply('typescript', { ...typeScriptDefaults }, options); const babelOptions = await presets.apply('babel', {}, { ...options, typescriptOptions }); @@ -130,7 +135,9 @@ async function getManagerWebpackConfig(options: any, presets: any) { return presets.apply('managerWebpack', {}, { ...options, babelOptions, entries, refs }); } -export default async (options: any) => { +const loadConfig: ( + options: PresetsOptions & StorybookConfigOptions +) => Promise = async (options: PresetsOptions & StorybookConfigOptions) => { const { corePresets = [], frameworkPresets = [], overridePresets = [], ...restOptions } = options; const presetsConfig = [ @@ -145,3 +152,5 @@ export default async (options: any) => { return getManagerWebpackConfig({ ...restOptions, presets }, presets); }; + +export default loadConfig; diff --git a/lib/core/src/server/manager/manager-preset.ts b/lib/core/src/server/manager/manager-preset.ts index 60c2ea15da42..2ffcf5338df4 100644 --- a/lib/core/src/server/manager/manager-preset.ts +++ b/lib/core/src/server/manager/manager-preset.ts @@ -1,11 +1,15 @@ +import { Configuration } from 'webpack'; import { loadManagerOrAddonsFile } from '../utils/load-manager-or-addons-file'; import createDevConfig from './manager-webpack.config'; -export async function managerWebpack(_: unknown, options: any) { +export async function managerWebpack(_: Configuration, options: any): Promise { return createDevConfig(options); } -export async function managerEntries(installedAddons: string[] | undefined, options: any) { +export async function managerEntries( + installedAddons: string[], + options: { managerEntry: string; configDir: string } +): Promise { const { managerEntry = '../../client/manager' } = options; const entries = [require.resolve('../common/polyfills')]; diff --git a/lib/core/src/server/manager/manager-webpack.config.ts b/lib/core/src/server/manager/manager-webpack.config.ts index 0e8dd99ea69a..799ff17f151c 100644 --- a/lib/core/src/server/manager/manager-webpack.config.ts +++ b/lib/core/src/server/manager/manager-webpack.config.ts @@ -16,6 +16,7 @@ import { loadEnv } from '../config/utils'; import { babelLoader } from './babel-loader-manager'; import { resolvePathInStorybookCache } from '../utils/resolve-path-in-sb-cache'; import { es6Transpiler } from '../common/es6Transpiler'; +import { ManagerWebpackOptions } from '../types'; const { version } = require('../../../package.json'); @@ -31,7 +32,7 @@ export default async ({ versionCheck, releaseNotesData, presets, -}: any): Promise => { +}: ManagerWebpackOptions): Promise => { const { raw, stringified } = loadEnv(); const logLevel = await presets.apply('logLevel', undefined); const isProd = configType === 'PRODUCTION'; @@ -128,7 +129,7 @@ export default async ({ }, resolve: { extensions: ['.mjs', '.js', '.jsx', '.json', '.cjs', '.ts', '.tsx'], - modules: ['node_modules'].concat(raw.NODE_PATH || []), + modules: ['node_modules'].concat((raw.NODE_PATH as string[]) || []), alias: { ...themingPaths, ...uiPaths, diff --git a/lib/core/src/server/presets.ts b/lib/core/src/server/presets.ts index 8700605e1ed3..8b778a4a98f9 100644 --- a/lib/core/src/server/presets.ts +++ b/lib/core/src/server/presets.ts @@ -2,12 +2,17 @@ import dedent from 'ts-dedent'; import { join } from 'path'; import { logger } from '@storybook/node-logger'; import resolveFrom from 'resolve-from'; +import { LoadedPreset, PresetConfig, Presets, StorybookConfigOptions } from './types'; const isObject = (val: unknown): val is Record => val != null && typeof val === 'object' && Array.isArray(val) === false; const isFunction = (val: unknown): val is Function => typeof val === 'function'; -const resolvePresetFunction = (input: unknown, presetOptions: any, storybookOptions: any) => { +function resolvePresetFunction( + input: T[] | Function, + presetOptions: any, + storybookOptions: StorybookConfigOptions +): T[] { if (isFunction(input)) { return input({ ...storybookOptions, ...presetOptions }); } @@ -16,7 +21,7 @@ const resolvePresetFunction = (input: unknown, presetOptions: any, storybookOpti } return []; -}; +} /** * Parse an addon into either a managerEntries or a preset. Throw on invalid input. @@ -119,9 +124,15 @@ function getContent(input: any) { return interopRequireDefault(name); } -export function loadPreset(input: any, level: number, storybookOptions: any): any[] { +export function loadPreset( + input: PresetConfig, + level: number, + storybookOptions: StorybookConfigOptions +): LoadedPreset[] { try { - const name = input.name ? input.name : input; + // @ts-ignores + const name: string = input.name ? input.name : input; + // @ts-ignore const presetOptions = input.options ? input.options : {}; let contents = getContent(input); @@ -173,7 +184,11 @@ export function loadPreset(input: any, level: number, storybookOptions: any): an } } -function loadPresets(presets: unknown[], level: number, storybookOptions: any) { +function loadPresets( + presets: PresetConfig[], + level: number, + storybookOptions: StorybookConfigOptions +): LoadedPreset[] { if (!presets || !Array.isArray(presets) || !presets.length) { return []; } @@ -189,12 +204,12 @@ function loadPresets(presets: unknown[], level: number, storybookOptions: any) { } function applyPresets( - presets: unknown[], - extension: any, + presets: LoadedPreset[], + extension: string, config: any, args: any, - storybookOptions: any -) { + storybookOptions: StorybookConfigOptions +): Promise { const presetResult = new Promise((resolve) => resolve(config)); if (!presets.length) { @@ -211,13 +226,12 @@ function applyPresets( if (typeof change === 'function') { const extensionFn = change; const context = { - extensionFn, preset, combinedOptions: { ...storybookOptions, ...args, ...options, presetsList: presets }, }; return accumulationPromise.then((newConfig) => - context.extensionFn.call(context.preset, newConfig, context.combinedOptions) + extensionFn.call(context.preset, newConfig, context.combinedOptions) ); } @@ -233,11 +247,15 @@ function applyPresets( }, presetResult); } -function getPresets(presets: any, storybookOptions: any = {}) { - const loadedPresets = loadPresets(presets, 0, storybookOptions); +function getPresets( + presets: PresetConfig[], + // @ts-ignore + storybookOptions: StorybookConfigOptions = {} +): Presets { + const loadedPresets: LoadedPreset[] = loadPresets(presets, 0, storybookOptions); return { - apply: async (extension: any, config: any, args = {}) => + apply: async (extension: string, config: any, args = {}) => applyPresets(loadedPresets, extension, config, args, storybookOptions), }; } diff --git a/lib/core/src/server/preview/iframe-webpack.config.ts b/lib/core/src/server/preview/iframe-webpack.config.ts index b9895ad6b548..7c62985fa170 100644 --- a/lib/core/src/server/preview/iframe-webpack.config.ts +++ b/lib/core/src/server/preview/iframe-webpack.config.ts @@ -184,7 +184,7 @@ export default async ({ }, resolve: { extensions: ['.mjs', '.js', '.jsx', '.ts', '.tsx', '.json', '.cjs'], - modules: ['node_modules'].concat(raw.NODE_PATH || []), + modules: ['node_modules'].concat((raw.NODE_PATH as string[]) || []), alias: { ...themingPaths, ...storybookPaths, diff --git a/lib/core/src/server/types.ts b/lib/core/src/server/types.ts new file mode 100644 index 000000000000..c5d575520057 --- /dev/null +++ b/lib/core/src/server/types.ts @@ -0,0 +1,70 @@ +import { Configuration } from 'webpack'; +import { TransformOptions } from '@babel/core'; +import { typeScriptDefaults } from './config/defaults'; + +export interface ManagerWebpackOptions { + configDir: any; + configType?: string; + docsMode?: boolean; + entries: string[]; + refs: any; + uiDll: boolean; + dll: any; + outputDir?: string; + cache: any; + previewUrl?: string; + versionCheck: any; + releaseNotesData: any; + presets: any; +} + +export interface Presets { + apply( + extension: 'typescript', + config: typeof typeScriptDefaults, + args: StorybookConfigOptions & { presets: Presets } + ): Promise; + apply(extension: 'babel', config: {}, args: any): Promise; + apply(extension: 'entries', config: [], args: any): Promise; + apply(extension: 'stories', config: [], args: any): Promise; + apply( + extension: 'webpack', + config: {}, + args: { babelOptions?: TransformOptions } & any + ): Promise; + apply(extension: 'managerEntries', config: [], args: any): Promise; + apply(extension: 'refs', config: [], args: any): Promise; + apply( + extension: 'managerWebpack', + config: {}, + args: { babelOptions?: TransformOptions } & ManagerWebpackOptions + ): Promise; + apply(extension: string, config: unknown, args: unknown): Promise; +} + +export interface LoadedPreset { + name: string; + preset: any; + options: any; +} + +export interface StorybookConfigOptions { + configType: 'DEVELOPMENT' | 'PRODUCTION'; + outputDir?: string; + configDir: string; + cache?: any; + framework: string; +} + +export interface PresetsOptions { + corePresets: string[]; + overridePresets: string[]; + frameworkPresets: string[]; +} + +export type PresetConfig = + | string + | { + name: string; + options?: unknown; + }; From 13947884387fec650bab8ebdcd7b11a00cf01607 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Maisse?= Date: Tue, 27 Oct 2020 21:28:31 +0100 Subject: [PATCH 16/21] refactor(core): improve typings of `server/cli` --- lib/core/src/server/cli/dev.ts | 34 +++++++++++++++++++++++++++----- lib/core/src/server/cli/index.ts | 6 ++---- lib/core/src/server/cli/prod.ts | 26 +++++++++++++++++++----- lib/core/src/server/cli/utils.ts | 4 ++-- 4 files changed, 54 insertions(+), 16 deletions(-) diff --git a/lib/core/src/server/cli/dev.ts b/lib/core/src/server/cli/dev.ts index 0d80aa85cd50..a91cf3c656cf 100644 --- a/lib/core/src/server/cli/dev.ts +++ b/lib/core/src/server/cli/dev.ts @@ -1,9 +1,35 @@ -import program from 'commander'; +import program, { CommanderStatic } from 'commander'; import chalk from 'chalk'; import { logger } from '@storybook/node-logger'; import { parseList, getEnvConfig, checkDeprecatedFlags } from './utils'; -async function getCLI(packageJson: { version: string; name: string }) { +export interface DevCliOptions { + port?: number; + host?: number; + staticDir?: string[]; + configDir?: string; + https?: boolean; + sslCa?: string[]; + sslCert?: string; + sslKey?: string; + smokeTest?: boolean; + ci?: boolean; + loglevel?: string; + quiet?: boolean; + versionUpdates?: boolean; + releaseNotes?: boolean; + dll?: boolean; + docs?: boolean; + docsDll?: boolean; + uiDll?: boolean; + debugWebpack?: boolean; + previewUrl?: string; +} + +export async function getDevCli(packageJson: { + version: string; + name: string; +}): Promise { process.env.NODE_ENV = process.env.NODE_ENV || 'development'; program @@ -72,8 +98,6 @@ async function getCLI(packageJson: { version: string; name: string }) { program.port = parseInt(program.port, 10); } - checkDeprecatedFlags(program); + checkDeprecatedFlags(program as DevCliOptions); return { ...program }; } - -export default getCLI; diff --git a/lib/core/src/server/cli/index.ts b/lib/core/src/server/cli/index.ts index 9ff64a635483..825ba73331d0 100644 --- a/lib/core/src/server/cli/index.ts +++ b/lib/core/src/server/cli/index.ts @@ -1,4 +1,2 @@ -import getDevCli from './dev'; -import getProdCli from './prod'; - -export { getDevCli, getProdCli }; +export * from './dev'; +export * from './prod'; diff --git a/lib/core/src/server/cli/prod.ts b/lib/core/src/server/cli/prod.ts index 70a3e7dc9e80..1f7c35b80974 100644 --- a/lib/core/src/server/cli/prod.ts +++ b/lib/core/src/server/cli/prod.ts @@ -1,9 +1,27 @@ -import program from 'commander'; +import program, { CommanderStatic } from 'commander'; import chalk from 'chalk'; import { logger } from '@storybook/node-logger'; import { parseList, getEnvConfig, checkDeprecatedFlags } from './utils'; -function getCLI(packageJson: { version: string; name: string }) { +export interface ProdCliOptions { + staticDir?: string[]; + outputDir?: string; + configDir?: string; + watch?: boolean; + quiet?: boolean; + loglevel?: string; + dll?: boolean; + docsDll?: boolean; + uiDll?: boolean; + debugWebpack?: boolean; + previewUrl?: string; + docs?: boolean; +} + +export function getProdCli(packageJson: { + version: string; + name: string; +}): CommanderStatic & ProdCliOptions { process.env.NODE_ENV = process.env.NODE_ENV || 'production'; program @@ -36,8 +54,6 @@ function getCLI(packageJson: { version: string; name: string }) { configDir: 'SBCONFIG_CONFIG_DIR', }); - checkDeprecatedFlags(program); + checkDeprecatedFlags(program as ProdCliOptions); return { ...program }; } - -export default getCLI; diff --git a/lib/core/src/server/cli/utils.ts b/lib/core/src/server/cli/utils.ts index afe9d24947ce..51ea9e06c186 100644 --- a/lib/core/src/server/cli/utils.ts +++ b/lib/core/src/server/cli/utils.ts @@ -1,11 +1,11 @@ import deprecate from 'util-deprecate'; import dedent from 'ts-dedent'; -export function parseList(str: string) { +export function parseList(str: string): string[] { return str.split(','); } -export function getEnvConfig(program: Record, configEnv: Record) { +export function getEnvConfig(program: Record, configEnv: Record): void { Object.keys(configEnv).forEach((fieldName) => { const envVarName = configEnv[fieldName]; const envVarValue = process.env[envVarName]; From 47863bccf8fe3fc7e0fd26b0f85ea8313228012a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Maisse?= Date: Fri, 30 Oct 2020 21:44:25 +0100 Subject: [PATCH 17/21] refactor(core): improve typings of dev build and dev server --- lib/core/src/server/build-dev.ts | 50 ++++++++++++---- lib/core/src/server/dev-server.ts | 18 ++++-- lib/core/src/server/manager/manager-config.ts | 6 +- lib/core/src/server/manager/manager-preset.ts | 6 +- lib/core/src/server/types.ts | 59 +++++++++++++++++-- lib/core/src/server/utils/prebuilt-manager.ts | 2 +- 6 files changed, 114 insertions(+), 27 deletions(-) diff --git a/lib/core/src/server/build-dev.ts b/lib/core/src/server/build-dev.ts index 3f0a2dde9293..865969588578 100644 --- a/lib/core/src/server/build-dev.ts +++ b/lib/core/src/server/build-dev.ts @@ -11,16 +11,18 @@ import prettyTime from 'pretty-hrtime'; import inquirer from 'inquirer'; import detectFreePort from 'detect-port'; +import { Stats } from 'webpack'; import { storybookDevServer } from './dev-server'; -import { getDevCli } from './cli'; +import { DevCliOptions, getDevCli } from './cli'; import { resolvePathInStorybookCache } from './utils/resolve-path-in-sb-cache'; +import { ReleaseNotesData, VersionCheck, PackageJson, LoadOptions } from './types'; const cache = Cache({ basePath: resolvePathInStorybookCache('dev-server'), ns: 'storybook', // Optional. A grouping namespace for items. }); -const writeStats = async (name: string, stats: any) => { +const writeStats = async (name: string, stats: Stats) => { await fs.writeFile( resolvePathInStorybookCache(`public/${name}-stats.json`), JSON.stringify(stats.toJson(), null, 2), @@ -28,13 +30,13 @@ const writeStats = async (name: string, stats: any) => { ); }; -const getFreePort = (port: any) => +const getFreePort = (port: number) => detectFreePort(port).catch((error) => { logger.error(error); process.exit(-1); }); -const updateCheck = async (version: string) => { +const updateCheck = async (version: string): Promise => { let result; const time = Date.now(); try { @@ -63,7 +65,7 @@ const updateCheck = async (version: string) => { // For this reason, we convert the actual version of the build here so that // every place that relies on this data can reference the version of the // release notes that we expect to use. -const getReleaseNotesVersion = (version: string) => { +const getReleaseNotesVersion = (version: string): string => { const { major, minor } = semver.parse(version); const { version: releaseNotesVersion } = semver.coerce(`${major}.${minor}`); return releaseNotesVersion; @@ -79,7 +81,10 @@ const getReleaseNotesFailedState = (version: string) => { export const RELEASE_NOTES_CACHE_KEY = 'releaseNotesData'; -export const getReleaseNotesData = async (currentVersionToParse: any, fileSystemCache: any) => { +export const getReleaseNotesData = async ( + currentVersionToParse: string, + fileSystemCache: any +): Promise => { let result; try { const fromCache = await fileSystemCache.get('releaseNotesData', []); @@ -119,7 +124,7 @@ export const getReleaseNotesData = async (currentVersionToParse: any, fileSystem return result; }; -function createUpdateMessage(updateInfo: any, version: any) { +function createUpdateMessage(updateInfo: VersionCheck, version: string): string { let updateMessage; try { @@ -143,7 +148,14 @@ function createUpdateMessage(updateInfo: any, version: any) { return updateMessage; } -function outputStartupInformation(options: any) { +function outputStartupInformation(options: { + updateInfo: VersionCheck; + version: string; + address: string; + networkAddress: string; + managerTotalTime: [number, number]; + previewTotalTime: [number, number]; +}) { const { updateInfo, version, @@ -206,7 +218,7 @@ function outputStartupInformation(options: any) { ); } -async function outputStats(previewStats: any, managerStats: any) { +async function outputStats(previewStats: Stats, managerStats: Stats) { if (previewStats) { await writeStats('preview', previewStats); } @@ -216,7 +228,16 @@ async function outputStats(previewStats: any, managerStats: any) { ); } -export async function buildDevStandalone(options: any) { +export async function buildDevStandalone( + options: DevCliOptions & + LoadOptions & { + packageJson: PackageJson; + ignorePreview: boolean; + docsMode: boolean; + configDir: string; + cache: any; + } +) { try { const { packageJson, versionUpdates, releaseNotes } = options; const { version } = packageJson; @@ -244,7 +265,9 @@ export async function buildDevStandalone(options: any) { /* eslint-disable no-param-reassign */ options.port = port; + // @ts-ignore options.versionCheck = updateInfo; + // @ts-ignore options.releaseNotesData = releaseNotesData; /* eslint-enable no-param-reassign */ @@ -307,14 +330,17 @@ export async function buildDevStandalone(options: any) { } } -export async function buildDev({ packageJson, ...loadOptions }: any) { +export async function buildDev({ + packageJson, + ...loadOptions +}: { packageJson: PackageJson } & LoadOptions) { const cliOptions = await getDevCli(packageJson); await buildDevStandalone({ ...cliOptions, ...loadOptions, packageJson, - configDir: loadOptions.configDir || cliOptions.configDir || './.storybook', + configDir: (loadOptions as any).configDir || cliOptions.configDir || './.storybook', ignorePreview: !!cliOptions.previewUrl, docsMode: !!cliOptions.docs, cache, diff --git a/lib/core/src/server/dev-server.ts b/lib/core/src/server/dev-server.ts index c4221fcf1c25..a764361554a8 100644 --- a/lib/core/src/server/dev-server.ts +++ b/lib/core/src/server/dev-server.ts @@ -22,6 +22,7 @@ import loadConfig from './config'; import loadManagerConfig from './manager/manager-config'; import { resolvePathInStorybookCache } from './utils/resolve-path-in-sb-cache'; import { getPrebuiltDir } from './utils/prebuilt-manager'; +import { ManagerResult, PreviewResult } from './types'; const defaultFavIcon = require.resolve('./public/favicon.ico'); @@ -193,7 +194,7 @@ const startManager = async ({ outputDir, configDir, prebuiltDir, -}: any) => { +}: any): Promise => { let managerConfig; if (!prebuiltDir) { // this is pretty slow @@ -224,7 +225,9 @@ const startManager = async ({ } if (!managerConfig) { - return { managerStats: {}, managerTotalTime: 0 }; + // FIXME: This object containing default values should match ManagerResult + // @ts-ignore + return { managerStats: {}, managerTotalTime: 0 } as ManagerResult; } const compiler = webpack(managerConfig); @@ -255,9 +258,16 @@ const startManager = async ({ return { managerStats, managerTotalTime: process.hrtime(startTime) }; }; -const startPreview = async ({ startTime, options, configType, outputDir }: any) => { +const startPreview = async ({ + startTime, + options, + configType, + outputDir, +}: any): Promise => { if (options.ignorePreview) { - return { previewStats: {}, previewTotalTime: 0 }; + // FIXME: This object containing default values should match PreviewResult + // @ts-ignore + return { previewStats: {}, previewTotalTime: 0 } as PreviewResult; } const previewConfig = await loadConfig({ diff --git a/lib/core/src/server/manager/manager-config.ts b/lib/core/src/server/manager/manager-config.ts index e9fcfe339a77..4bd92676115a 100644 --- a/lib/core/src/server/manager/manager-config.ts +++ b/lib/core/src/server/manager/manager-config.ts @@ -12,9 +12,9 @@ import { Configuration } from 'webpack'; import loadPresets from '../presets'; import loadCustomPresets from '../common/custom-presets'; import { typeScriptDefaults } from '../config/defaults'; -import { Presets, PresetsOptions, StorybookConfigOptions } from '../types'; +import { Presets, PresetsOptions, Ref, StorybookConfigOptions } from '../types'; -export const getAutoRefs = async (options: { configDir: string }) => { +export const getAutoRefs = async (options: { configDir: string }): Promise => { const location = await findUp('package.json', { cwd: options.configDir }); const directory = path.dirname(location); @@ -79,7 +79,7 @@ async function getManagerWebpackConfig( const definedRefs = await presets.apply('refs', undefined, options); const entries = await presets.apply('managerEntries', [], options); - const refs: Record = {}; + const refs: Record = {}; if (autoRefs && autoRefs.length) { autoRefs.forEach(({ id, url, title, version }) => { diff --git a/lib/core/src/server/manager/manager-preset.ts b/lib/core/src/server/manager/manager-preset.ts index 2ffcf5338df4..6124094642f7 100644 --- a/lib/core/src/server/manager/manager-preset.ts +++ b/lib/core/src/server/manager/manager-preset.ts @@ -1,8 +1,12 @@ import { Configuration } from 'webpack'; import { loadManagerOrAddonsFile } from '../utils/load-manager-or-addons-file'; import createDevConfig from './manager-webpack.config'; +import { ManagerWebpackOptions } from '../types'; -export async function managerWebpack(_: Configuration, options: any): Promise { +export async function managerWebpack( + _: Configuration, + options: ManagerWebpackOptions +): Promise { return createDevConfig(options); } diff --git a/lib/core/src/server/types.ts b/lib/core/src/server/types.ts index c5d575520057..8081f094daf8 100644 --- a/lib/core/src/server/types.ts +++ b/lib/core/src/server/types.ts @@ -1,4 +1,4 @@ -import { Configuration } from 'webpack'; +import { Configuration, Stats } from 'webpack'; import { TransformOptions } from '@babel/core'; import { typeScriptDefaults } from './config/defaults'; @@ -7,14 +7,14 @@ export interface ManagerWebpackOptions { configType?: string; docsMode?: boolean; entries: string[]; - refs: any; + refs: Record; uiDll: boolean; - dll: any; + dll: boolean; outputDir?: string; - cache: any; + cache: boolean; previewUrl?: string; - versionCheck: any; - releaseNotesData: any; + versionCheck: VersionCheck; + releaseNotesData: ReleaseNotesData; presets: any; } @@ -68,3 +68,50 @@ export type PresetConfig = name: string; options?: unknown; }; + +export interface Ref { + id: string; + url: string; + title: string; + version: string; + type?: string; +} + +export interface VersionCheck { + success: boolean; + data?: any; + error?: any; + time: number; +} + +export interface ReleaseNotesData { + success: boolean; + currentVersion: string; + showOnFirstLaunch: boolean; +} + +export interface PreviewResult { + previewStats: Stats; + previewTotalTime: [number, number]; +} + +export interface ManagerResult { + managerStats: Stats; + managerTotalTime: [number, number]; +} + +// TODO: this is a generic interface that we can share across multiple SB packages (like @storybook/cli) +export interface PackageJson { + name: string; + version: string; + dependencies?: Record; + devDependencies?: Record; +} + +// TODO: This could be exported to the outside world and used in `options.ts` file of each `@storybook/APP` +// like it's described in docs/api/new-frameworks.md +export interface LoadOptions { + packageJson: PackageJson; + framework: string; + frameworkPresets: string[]; +} diff --git a/lib/core/src/server/utils/prebuilt-manager.ts b/lib/core/src/server/utils/prebuilt-manager.ts index d12237967300..2e527b2ea831 100644 --- a/lib/core/src/server/utils/prebuilt-manager.ts +++ b/lib/core/src/server/utils/prebuilt-manager.ts @@ -23,7 +23,7 @@ export const getPrebuiltDir = async ({ }: { configDir: string; options: { managerCache?: boolean }; -}) => { +}): Promise => { if (options.managerCache === false) return false; const prebuiltDir = path.join(__dirname, '../../../prebuilt'); From 87da256b17a9fb1b816ebcdb3fa35f9553a593c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Maisse?= Date: Tue, 3 Nov 2020 19:25:03 +0100 Subject: [PATCH 18/21] docs(core): add a note about internal WIP types that must not be exported --- lib/core/src/server/types.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/core/src/server/types.ts b/lib/core/src/server/types.ts index 8081f094daf8..6993a9dd0dbf 100644 --- a/lib/core/src/server/types.ts +++ b/lib/core/src/server/types.ts @@ -2,6 +2,9 @@ import { Configuration, Stats } from 'webpack'; import { TransformOptions } from '@babel/core'; import { typeScriptDefaults } from './config/defaults'; +/** + * ⚠️ This file contains internal WIP types they MUST NOT be exported outside this package for now! + */ export interface ManagerWebpackOptions { configDir: any; configType?: string; From f85e88808f4d8b2bdd223dd58aab43ff6e73de40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Maisse?= Date: Tue, 3 Nov 2020 20:17:19 +0100 Subject: [PATCH 19/21] fix(core): fix type of `addons` property in StorybookConfig --- lib/core/types/index.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/core/types/index.ts b/lib/core/types/index.ts index afc126a01fcc..ab0efa010b1f 100644 --- a/lib/core/types/index.ts +++ b/lib/core/types/index.ts @@ -11,9 +11,15 @@ export interface StorybookConfig { /** * Sets the addons you want to use with Storybook. * - * @example `['@storybook/addon-essentials']` + * @example `['@storybook/addon-essentials']` or `[{ name: '@storybook/addon-essentials', options: { backgrounds: false } }]` */ - addons?: string[]; + addons?: Array< + | string + | { + name: string; + options?: any; + } + >; /** * Tells Storybook where to find stories. * @@ -50,7 +56,7 @@ export interface TypescriptOptions { /** * Enables type checking within Storybook. * - * @defalt `false` + * @default `false` */ check: boolean; /** From 6a01f37a7d4f709a2248ed3ad970bc2e255e697f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Maisse?= Date: Tue, 3 Nov 2020 21:11:30 +0100 Subject: [PATCH 20/21] chore: add a log to know the level of concurrency in publishing task --- scripts/run-registry.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/run-registry.ts b/scripts/run-registry.ts index e5b0ab1e321e..f860e3c4e163 100755 --- a/scripts/run-registry.ts +++ b/scripts/run-registry.ts @@ -108,6 +108,8 @@ const currentVersion = async () => { }; const publish = (packages: { name: string; location: string }[], url: string) => { + logger.log(`Publishing packages with a concurrency of ${maxConcurrentTasks}`); + const limit = pLimit(maxConcurrentTasks); let i = 0; From d2cbbb7c7876b6a5d582633cbc52d475b999cc8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Maisse?= Date: Tue, 3 Nov 2020 21:27:10 +0100 Subject: [PATCH 21/21] ci: try to fix `publish` job by limiting the number of concurrent tasks --- scripts/utils/concurrency.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/utils/concurrency.js b/scripts/utils/concurrency.js index e76be81992cc..6745f3649014 100644 --- a/scripts/utils/concurrency.js +++ b/scripts/utils/concurrency.js @@ -2,10 +2,10 @@ const os = require('os'); /** * The maximum number of concurrent tasks we want to have on some CLI and CI tasks. - * The amount of CPUS minus one. + * The amount of CPUS minus one, arbitrary limited to 15 to not overload CI executors. * @type {number} */ -const maxConcurrentTasks = Math.max(1, os.cpus().length - 1); +const maxConcurrentTasks = Math.min(Math.max(1, os.cpus().length - 1), 15); /** * Use a simple round robin to filter input data according to the CI node currently running the script