diff --git a/lib/builder-webpack4/src/index.ts b/lib/builder-webpack4/src/index.ts index de78a2803471..5d9b131b778b 100644 --- a/lib/builder-webpack4/src/index.ts +++ b/lib/builder-webpack4/src/index.ts @@ -4,7 +4,7 @@ import webpack4, { Stats, Configuration } from '@types/webpack'; import webpackDevMiddleware from 'webpack-dev-middleware'; import webpackHotMiddleware from 'webpack-hot-middleware'; import { logger } from '@storybook/node-logger'; -import { Builder, useProgressReporting } from '@storybook/core-common'; +import { Builder, useProgressReporting, checkWebpackVersion } from '@storybook/core-common'; let compilation: ReturnType; let reject: (reason?: any) => void; @@ -13,6 +13,9 @@ type WebpackBuilder = Builder; const webpack = (webpackReal as any) as typeof webpack4; +const checkWebpackVersion4 = (webpackInstance: { version?: string }) => + checkWebpackVersion(webpackInstance, '4.x', 'builder-webpack4'); + export const getConfig: WebpackBuilder['getConfig'] = async (options) => { const { presets } = options; const typescriptOptions = await presets.apply('typescript', {}, options); @@ -47,6 +50,8 @@ export const makeStatsFromError: (err: string) => Stats = (err) => } as any); export const start: WebpackBuilder['start'] = async ({ startTime, options, router }) => { + checkWebpackVersion4(executor.get); + const config = await getConfig(options); const compiler = executor.get(config); if (!compiler) { @@ -113,6 +118,8 @@ export const bail: WebpackBuilder['bail'] = (e: Error) => { }; export const build: WebpackBuilder['build'] = async ({ options, startTime }) => { + checkWebpackVersion4(executor.get); + logger.info('=> Compiling preview..'); const config = await getConfig(options); diff --git a/lib/builder-webpack5/src/index.ts b/lib/builder-webpack5/src/index.ts index c71525b879a1..6bc723267fe0 100644 --- a/lib/builder-webpack5/src/index.ts +++ b/lib/builder-webpack5/src/index.ts @@ -2,13 +2,16 @@ import webpack, { Stats, Configuration, ProgressPlugin } from 'webpack'; import webpackDevMiddleware from 'webpack-dev-middleware'; import webpackHotMiddleware from 'webpack-hot-middleware'; import { logger } from '@storybook/node-logger'; -import { Builder, useProgressReporting } from '@storybook/core-common'; +import { Builder, useProgressReporting, checkWebpackVersion } from '@storybook/core-common'; let compilation: ReturnType; let reject: (reason?: any) => void; type WebpackBuilder = Builder; +const checkWebpackVersion5 = (webpackInstance: { version?: string }) => + checkWebpackVersion(webpackInstance, '5.x', 'builder-webpack5'); + export const getConfig: WebpackBuilder['getConfig'] = async (options) => { const { presets } = options; const typescriptOptions = await presets.apply('typescript', {}, options); @@ -36,6 +39,8 @@ export const executor = { }; export const start: WebpackBuilder['start'] = async ({ startTime, options, router }) => { + checkWebpackVersion5(executor.get); + const config = await getConfig(options); const compiler = executor.get(config); if (!compiler) { @@ -101,6 +106,8 @@ export const bail: WebpackBuilder['bail'] = (e: Error) => { }; export const build: WebpackBuilder['build'] = async ({ options, startTime }) => { + checkWebpackVersion5(executor.get); + logger.info('=> Compiling preview..'); const config = await getConfig(options); diff --git a/lib/core-common/package.json b/lib/core-common/package.json index 2920dc5cf503..f4d9d90d73f9 100644 --- a/lib/core-common/package.json +++ b/lib/core-common/package.json @@ -58,6 +58,7 @@ "@babel/preset-typescript": "^7.12.7", "@babel/register": "^7.12.1", "@storybook/node-logger": "6.2.0-rc.1", + "@storybook/semver": "^7.3.2", "@types/glob-base": "^0.3.0", "@types/micromatch": "^4.0.1", "@types/node": "^14.0.10", diff --git a/lib/core-common/src/index.ts b/lib/core-common/src/index.ts index 57fae368279e..9a3d73d7e929 100644 --- a/lib/core-common/src/index.ts +++ b/lib/core-common/src/index.ts @@ -1,6 +1,7 @@ export * from './presets'; export * from './utils/babel'; +export * from './utils/check-webpack-version'; export * from './utils/envs'; export * from './utils/es6Transpiler'; export * from './utils/interpret-files'; diff --git a/lib/core-common/src/utils/check-webpack-version.ts b/lib/core-common/src/utils/check-webpack-version.ts new file mode 100644 index 000000000000..46cbac2ca540 --- /dev/null +++ b/lib/core-common/src/utils/check-webpack-version.ts @@ -0,0 +1,23 @@ +import semver from '@storybook/semver'; +import { logger } from '@storybook/node-logger'; +import dedent from 'ts-dedent'; + +export const checkWebpackVersion = ( + webpack: { version?: string }, + specifier: string, + caption: string +) => { + if (!webpack.version) { + logger.info('Skipping webpack version check, no version available'); + return; + } + if (!semver.satisfies(webpack.version, specifier)) { + logger.warn(dedent` + Unexpected webpack version in ${caption} + - Received: ${webpack.version} + - Expected: ${specifier} + + For more info: https://gist.github.com/shilman/8856ea1786dcd247139b47b270912324#troubleshooting + `); + } +}; diff --git a/lib/core-common/typings.d.ts b/lib/core-common/typings.d.ts index 4affaba85be5..4a7f19019bcc 100644 --- a/lib/core-common/typings.d.ts +++ b/lib/core-common/typings.d.ts @@ -1,6 +1,6 @@ declare module 'lazy-universal-dotenv'; declare module 'pnp-webpack-plugin'; - +declare module '@storybook/semver'; declare module 'file-system-cache' { export interface Options { basePath?: string; @@ -15,12 +15,12 @@ declare module 'file-system-cache' { ensureBasePath(): Promise; get(key: string, defaultValue?: any): Promise; getSync(key: string, defaultValue?: any): any | typeof defaultValue; - set(key: string, value: any): Promise<{ path: string }> + set(key: string, value: any): Promise<{ path: string }>; setSync(key: string, value: any): this; remove(key: string): Promise; clear(): Promise; save(): Promise<{ paths: string[] }>; - load(): Promise<{ files: Array<{ path: string, value: any }> }>; + load(): Promise<{ files: Array<{ path: string; value: any }> }>; } function create(options: Options): FileSystemCache; diff --git a/lib/core-server/src/manager/builder.ts b/lib/core-server/src/manager/builder.ts index 9cab145a172c..96e28564491a 100644 --- a/lib/core-server/src/manager/builder.ts +++ b/lib/core-server/src/manager/builder.ts @@ -1,7 +1,7 @@ import webpack, { Stats, Configuration, ProgressPlugin } from 'webpack'; import webpackDevMiddleware from 'webpack-dev-middleware'; import { logger } from '@storybook/node-logger'; -import { Builder, useProgressReporting } from '@storybook/core-common'; +import { Builder, useProgressReporting, checkWebpackVersion } from '@storybook/core-common'; import { pathExists } from 'fs-extra'; import express from 'express'; import { getManagerWebpackConfig } from './manager-config'; @@ -13,6 +13,9 @@ let reject: (reason?: any) => void; type WebpackBuilder = Builder; +const checkWebpackVersion4 = (webpackInstance: { version?: string }) => + checkWebpackVersion(webpackInstance, '4.x', 'manager-builder'); + export const getConfig: WebpackBuilder['getConfig'] = getManagerWebpackConfig; export const executor = { @@ -27,6 +30,8 @@ export const makeStatsFromError = (err: string) => } as any) as Stats); export const start: WebpackBuilder['start'] = async ({ startTime, options, router }) => { + checkWebpackVersion4(executor.get); + const prebuiltDir = await getPrebuiltDir(options); const config = await getConfig(options); @@ -108,6 +113,8 @@ export const bail: WebpackBuilder['bail'] = (e: Error) => { export const build: WebpackBuilder['build'] = async ({ options, startTime }) => { logger.info('=> Compiling manager..'); + checkWebpackVersion4(executor.get); + const config = await getConfig(options); const statsOptions = typeof config.stats === 'boolean' ? 'minimal' : config.stats;