diff --git a/packages/storybook/.storybook/main.js b/packages/storybook/.storybook/main.js index c187dc5f56..12b9c34435 100644 --- a/packages/storybook/.storybook/main.js +++ b/packages/storybook/.storybook/main.js @@ -1,4 +1,5 @@ const path = require('path'); +const WebpackPluginFailBuildOnWarning = require('./webpack-plugin-fail-build-on-warning'); module.exports = { stories: [ @@ -53,6 +54,11 @@ module.exports = { ({ constructor }) => constructor.name !== 'ProgressPlugin', ); + // Fail storybook build on CI if there are webpack warnings. + if (process.env.CI) { + config.plugins.push(new WebpackPluginFailBuildOnWarning()) + } + return config; }, }; diff --git a/packages/storybook/.storybook/webpack-plugin-fail-build-on-warning.js b/packages/storybook/.storybook/webpack-plugin-fail-build-on-warning.js new file mode 100644 index 0000000000..1ccf825839 --- /dev/null +++ b/packages/storybook/.storybook/webpack-plugin-fail-build-on-warning.js @@ -0,0 +1,68 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * When building storybook, we can have warnings which may cause issues in the future. One of the example case is + * https://github.com/spotify/backstage/issues/718. To make sure new warnings are not introduced with new PRs, we + * want to fail CI builds if there are warnings when building storybook. + * + * This webpack plugin makes sure the CI builds fail on Webpack warnings. We also have a whitelist of warnings here + * which we think are non-critical. + * + * Note that this implementation will not detect other warnings emitted by storybook build that are separate from + * Webpack. A better solution over this plugin should be preferred, possibly on Storybook level (CLI options etc.) + * + * The case with #718 is caused because we are using `ts-loader` for `webpack` to load all our JS/TS files, but we + * have disabled type checking during build. This is done by setting `transpileOnly` to `true` in storybook/main.js + * and it improves the Storybook build speed. Because of this, Webpack emits warnings when we try to re-export types. + * Reference: https://github.com/TypeStrong/ts-loader#transpileonly + */ +class WebpackPluginFailBuildOnWarning { + // Ignore the following warnings in the Webpack build. + warningsWhitelist = new Set([ + 'AssetsOverSizeLimitWarning', + 'EntrypointsOverSizeLimitWarning', + 'NoAsyncChunksWarning', + ]); + + /* Entry point for the Webpack plugin. */ + apply(compiler) { + // Invoke plugin logic when Webpack build is 'done'. + compiler.hooks.done.tap('FailBuildOnWarning', this.execute.bind(this)); + } + + execute(stats) { + // All the compilation warnings are stored in stats.compilation.warnings + let warnings = stats.compilation.warnings; + if (warnings.length > 0) { + // Throw error if there are unexpected warnings. + for (let warning of warnings) { + if (!this.warningsWhitelist.has(warning.name)) { + process.on('beforeExit', () => { + console.log( + `You have some unexpected warning(s) in your webpack build. Exiting process as error.`, + ); + process.exit(1); + }); + // No need to go over the rest of warnings from here. + break; + } + } + } + } +} + +module.exports = WebpackPluginFailBuildOnWarning;