Merge remote-tracking branch 'origin/master' into css-modules

This commit is contained in:
igor-dv 2018-10-19 15:12:31 +03:00
commit 950e2a62e5
47 changed files with 220 additions and 158 deletions

View File

@ -28,6 +28,26 @@
"@babel/preset-env", "@babel/preset-env",
"babel-preset-vue" "babel-preset-vue"
] ]
},
{
"test": [
"./lib/core/src/server",
"./lib/node-logger",
"./lib/codemod",
"./addons/storyshots",
"./addons/storysource/src/loader",
"./app/**/src/server/**"
],
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": "8.11"
}
}
]
]
} }
] ]
} }

View File

@ -173,7 +173,7 @@ If you're using `start-storybook` on CI, you may need to opt out of this using t
We've deprecated the `getstorybook` CLI in 4.0. The new way to install storybook is `sb init`. We recommend using `npx` for convenience and to make sure you're always using the latest version of the CLI: We've deprecated the `getstorybook` CLI in 4.0. The new way to install storybook is `sb init`. We recommend using `npx` for convenience and to make sure you're always using the latest version of the CLI:
``` ```
npx -p @storybook/cli@alpha sb init npx -p @storybook/cli@rc sb init
``` ```
## From version 3.3.x to 3.4.x ## From version 3.3.x to 3.4.x

View File

@ -55,7 +55,7 @@ First install storybook:
```sh ```sh
cd my-react-app cd my-react-app
npx -p @storybook/cli@alpha sb init npx -p @storybook/cli@rc sb init
``` ```
If you'd rather set up your project manually, take a look at our [Slow Start Guide](https://storybook.js.org/basics/slow-start-guide/). If you'd rather set up your project manually, take a look at our [Slow Start Guide](https://storybook.js.org/basics/slow-start-guide/).
@ -66,7 +66,7 @@ Once it's installed, you can `npm run storybook` and it will run the development
```sh ```sh
cd my-storybook-v2-app cd my-storybook-v2-app
npx -p @storybook/cli@alpha sb init npx -p @storybook/cli@rc sb init
``` ```
It runs a codemod to update all package names. Read all migration details in our [Migration Guide](MIGRATION.md) It runs a codemod to update all package names. Read all migration details in our [Migration Guide](MIGRATION.md)

View File

@ -12,7 +12,7 @@ So you can develop UI components in isolation without worrying about app specifi
```sh ```sh
cd my-angular-app cd my-angular-app
npx -p @storybook/cli@alpha sb init npx -p @storybook/cli@rc sb init
``` ```
For more information visit: [storybook.js.org](https://storybook.js.org) For more information visit: [storybook.js.org](https://storybook.js.org)

View File

@ -40,7 +40,7 @@
"sass-loader": "^7.1.0", "sass-loader": "^7.1.0",
"ts-loader": "^5.2.2", "ts-loader": "^5.2.2",
"tsconfig-paths-webpack-plugin": "^3.2.0", "tsconfig-paths-webpack-plugin": "^3.2.0",
"webpack": "^4.20.2", "webpack": "^4.21.0",
"zone.js": "^0.8.26" "zone.js": "^0.8.26"
}, },
"peerDependencies": { "peerDependencies": {

View File

@ -2,7 +2,12 @@ import path from 'path';
import fs from 'fs'; import fs from 'fs';
import { logger } from '@storybook/node-logger'; import { logger } from '@storybook/node-logger';
import { TsconfigPathsPlugin } from 'tsconfig-paths-webpack-plugin'; import { TsconfigPathsPlugin } from 'tsconfig-paths-webpack-plugin';
import { isBuildAngularInstalled, normalizeAssetPatterns } from './angular-cli_utils'; import {
isBuildAngularInstalled,
normalizeAssetPatterns,
filterOutStylingRules,
getAngularCliParts,
} from './angular-cli_utils';
function getTsConfigOptions(tsConfigPath) { function getTsConfigOptions(tsConfigPath) {
const basicOptions = { const basicOptions = {
@ -27,20 +32,6 @@ function getTsConfigOptions(tsConfigPath) {
return basicOptions; return basicOptions;
} }
function getAngularCliParts(cliWebpackConfigOptions) {
// eslint-disable-next-line global-require, import/no-extraneous-dependencies
const ngCliConfigFactory = require('@angular-devkit/build-angular/src/angular-cli-files/models/webpack-configs');
try {
return {
cliCommonConfig: ngCliConfigFactory.getCommonConfig(cliWebpackConfigOptions),
cliStyleConfig: ngCliConfigFactory.getStylesConfig(cliWebpackConfigOptions),
};
} catch (e) {
return null;
}
}
export function getAngularCliWebpackConfigOptions(dirToSearch) { export function getAngularCliWebpackConfigOptions(dirToSearch) {
const fname = path.join(dirToSearch, 'angular.json'); const fname = path.join(dirToSearch, 'angular.json');
@ -107,12 +98,9 @@ export function applyAngularCliWebpackConfig(baseConfig, cliWebpackConfigOptions
const { cliCommonConfig, cliStyleConfig } = cliParts; const { cliCommonConfig, cliStyleConfig } = cliParts;
// Don't use storybooks .css/.scss rules because we have to use rules created by @angular-devkit/build-angular // Don't use storybooks styling rules because we have to use rules created by @angular-devkit/build-angular
// because @angular-devkit/build-angular created rules have include/exclude for global style files. // because @angular-devkit/build-angular created rules have include/exclude for global style files.
const rulesExcludingStyles = baseConfig.module.rules.filter( const rulesExcludingStyles = filterOutStylingRules(baseConfig);
rule =>
!rule.test || (rule.test.toString() !== '/\\.css$/' && rule.test.toString() !== '/\\.scss$/')
);
// cliStyleConfig.entry adds global style files to the webpack context // cliStyleConfig.entry adds global style files to the webpack context
const entry = { const entry = {

View File

@ -23,6 +23,24 @@ function getAssetsParts(resolvedAssetPath, assetPath) {
}; };
} }
function isStylingRule(rule) {
const { test } = rule;
if (!test) {
return false;
}
if (!(test instanceof RegExp)) {
return false;
}
return test.test('.css') || test.test('.scss') || test.test('.sass');
}
export function filterOutStylingRules(config) {
return config.module.rules.filter(rule => !isStylingRule(rule));
}
export function isBuildAngularInstalled() { export function isBuildAngularInstalled() {
try { try {
require.resolve('@angular-devkit/build-angular'); require.resolve('@angular-devkit/build-angular');
@ -32,6 +50,20 @@ export function isBuildAngularInstalled() {
} }
} }
export function getAngularCliParts(cliWebpackConfigOptions) {
// eslint-disable-next-line global-require, import/no-extraneous-dependencies
const ngCliConfigFactory = require('@angular-devkit/build-angular/src/angular-cli-files/models/webpack-configs');
try {
return {
cliCommonConfig: ngCliConfigFactory.getCommonConfig(cliWebpackConfigOptions),
cliStyleConfig: ngCliConfigFactory.getStylesConfig(cliWebpackConfigOptions),
};
} catch (e) {
return null;
}
}
export function normalizeAssetPatterns(assetPatterns, dirToSearch, sourceRoot) { export function normalizeAssetPatterns(assetPatterns, dirToSearch, sourceRoot) {
if (!assetPatterns || !assetPatterns.length) { if (!assetPatterns || !assetPatterns.length) {
return []; return [];

View File

@ -31,7 +31,7 @@ export function webpack(config, { configDir }) {
exclude: /\.async\.html$/, exclude: /\.async\.html$/,
}, },
{ {
test: /\.scss$/, test: /\.s(c|a)ss$/,
use: [require.resolve('raw-loader'), require.resolve('sass-loader')], use: [require.resolve('raw-loader'), require.resolve('sass-loader')],
}, },
], ],

View File

@ -12,7 +12,7 @@ So you can develop UI components in isolation without worrying about app specifi
```sh ```sh
cd my-ember-app cd my-ember-app
npx -p @storybook/cli@alpha sb init npx -p @storybook/cli@rc sb init
``` ```
For more information visit: [storybook.js.org](https://storybook.js.org) For more information visit: [storybook.js.org](https://storybook.js.org)

View File

@ -14,7 +14,7 @@ So you can develop UI components in isolation without worrying about app specifi
```sh ```sh
cd my-app cd my-app
npx -p @storybook/cli@alpha sb init -t html npx -p @storybook/cli@rc sb init -t html
``` ```
For more information visit: [storybook.js.org](https://storybook.js.org) For more information visit: [storybook.js.org](https://storybook.js.org)

View File

@ -12,7 +12,7 @@ So you can develop UI components in isolation without worrying about app specifi
```sh ```sh
cd my-marko-app cd my-marko-app
npx -p @storybook/cli@alpha sb init npx -p @storybook/cli@rc sb init
``` ```
For more information visit: [storybook.js.org](https://storybook.js.org) For more information visit: [storybook.js.org](https://storybook.js.org)

View File

@ -12,7 +12,7 @@ So you can develop UI components in isolation without worrying about app specifi
```sh ```sh
cd my-mithril-app cd my-mithril-app
npx -p @storybook/cli@alpha sb init npx -p @storybook/cli@rc sb init
``` ```
For more information visit: [storybook.js.org](https://storybook.js.org) For more information visit: [storybook.js.org](https://storybook.js.org)

View File

@ -14,7 +14,7 @@ So you can develop UI components in isolation without worrying about app specifi
```sh ```sh
cd my-polymer-app cd my-polymer-app
npx -p @storybook/cli@alpha sb init npx -p @storybook/cli@rc sb init
``` ```
For more information visit: [storybook.js.org](https://storybook.js.org) For more information visit: [storybook.js.org](https://storybook.js.org)

View File

@ -35,7 +35,7 @@
"global": "^4.3.2", "global": "^4.3.2",
"react": "^16.5.2", "react": "^16.5.2",
"react-dom": "^16.5.2", "react-dom": "^16.5.2",
"webpack": "^4.20.2" "webpack": "^4.21.0"
}, },
"devDependencies": { "devDependencies": {
"lit-html": "^0.12.0", "lit-html": "^0.12.0",

View File

@ -63,7 +63,7 @@
"shelljs": "^0.8.2", "shelljs": "^0.8.2",
"url-parse": "^1.4.3", "url-parse": "^1.4.3",
"uuid": "^3.3.2", "uuid": "^3.3.2",
"webpack": "^4.20.2", "webpack": "^4.21.0",
"webpack-dev-middleware": "^3.4.0", "webpack-dev-middleware": "^3.4.0",
"webpack-hot-middleware": "^2.24.3", "webpack-hot-middleware": "^2.24.3",
"ws": "^6.1.0" "ws": "^6.1.0"

View File

@ -12,7 +12,7 @@ The `storybook` CLI tool can be used to add Storybook to your React Native app.
```shell ```shell
cd my-rn-app cd my-rn-app
npx -p @storybook/cli@alpha sb init npx -p @storybook/cli@rc sb init
``` ```
The next thing you need to do is make Storybook UI visible in your app. The next thing you need to do is make Storybook UI visible in your app.

View File

@ -12,7 +12,7 @@ So you can develop UI components in isolation without worrying about app specifi
```sh ```sh
cd my-react-app cd my-react-app
npx -p @storybook/cli@alpha sb init npx -p @storybook/cli@rc sb init
``` ```
For more information visit: [storybook.js.org](https://storybook.js.org) For more information visit: [storybook.js.org](https://storybook.js.org)

View File

@ -14,7 +14,7 @@ So you can develop UI components in isolation without worrying about app specifi
```sh ```sh
cd my-riot-app cd my-riot-app
npx -p @storybook/cli@alpha sb init npx -p @storybook/cli@rc sb init
``` ```
For more information visit: [storybook.js.org](https://storybook.js.org) For more information visit: [storybook.js.org](https://storybook.js.org)

View File

@ -12,7 +12,7 @@ So you can develop UI components in isolation without worrying about app specifi
```sh ```sh
cd my-svelte-app cd my-svelte-app
npx -p @storybook/cli@alpha sb init npx -p @storybook/cli@rc sb init
``` ```
For more information visit: [storybook.js.org](https://storybook.js.org) For more information visit: [storybook.js.org](https://storybook.js.org)

View File

@ -12,7 +12,7 @@ So you can develop UI components in isolation without worrying about app specifi
```sh ```sh
cd my-vue-app cd my-vue-app
npx -p @storybook/cli@alpha sb init npx -p @storybook/cli@rc sb init
``` ```
For more information visit: [storybook.js.org](https://storybook.js.org) For more information visit: [storybook.js.org](https://storybook.js.org)

View File

@ -1,8 +1,7 @@
* * * ---
id: 'faq' id: 'faq'
title: 'Frequently Asked Questions'
## title: 'Frequently Asked Questions' ---
Here are some answers to frequently asked questions. If you have a question, you can ask it by opening an issue on the [Storybook Repository](https://github.com/storybooks/storybook/). Here are some answers to frequently asked questions. If you have a question, you can ask it by opening an issue on the [Storybook Repository](https://github.com/storybooks/storybook/).

View File

@ -10,13 +10,13 @@ Get started using the automated command line tool. This command adds a set of bo
```sh ```sh
cd my-project-directory cd my-project-directory
npx -p @storybook/cli@alpha sb init npx -p @storybook/cli@rc sb init
``` ```
The tool inspects your `package.json` to determine which view layer you're using. If you want to develop HTML snippets in storybook, we can't determine that automatically. So to install storybook for HTML, use the `--type` flag to force that the HTML project type: The tool inspects your `package.json` to determine which view layer you're using. If you want to develop HTML snippets in storybook, we can't determine that automatically. So to install storybook for HTML, use the `--type` flag to force that the HTML project type:
``` ```
npx -p @storybook/cli@alpha sb init --type html npx -p @storybook/cli@rc sb init --type html
``` ```
To setup a project manually, take a look at the [Slow Start Guide](/basics/slow-start-guide/). To setup a project manually, take a look at the [Slow Start Guide](/basics/slow-start-guide/).

View File

@ -39,7 +39,7 @@
"ember-resolver": "^5.0.1", "ember-resolver": "^5.0.1",
"ember-source": "~3.5.0", "ember-source": "~3.5.0",
"loader.js": "^4.2.3", "loader.js": "^4.2.3",
"webpack": "^4.17.1", "webpack": "^4.21.0",
"webpack-cli": "^3.1.2" "webpack-cli": "^3.1.2"
}, },
"engines": { "engines": {

View File

@ -29,6 +29,6 @@
"@storybook/addons": "4.0.0-rc.1", "@storybook/addons": "4.0.0-rc.1",
"@storybook/marko": "4.0.0-rc.1", "@storybook/marko": "4.0.0-rc.1",
"prettier": "^1.14.3", "prettier": "^1.14.3",
"webpack": "^4.20.2" "webpack": "^4.21.0"
} }
} }

View File

@ -22,6 +22,6 @@
"@storybook/addon-viewport": "4.0.0-rc.1", "@storybook/addon-viewport": "4.0.0-rc.1",
"@storybook/addons": "4.0.0-rc.1", "@storybook/addons": "4.0.0-rc.1",
"@storybook/mithril": "4.0.0-rc.1", "@storybook/mithril": "4.0.0-rc.1",
"webpack": "^4.20.2" "webpack": "^4.21.0"
} }
} }

View File

@ -9,7 +9,7 @@
"generate-addon-jest-testresults": "jest --config=tests/addon-jest.config.json --json --outputFile=stories/addon-jest.testresults.json", "generate-addon-jest-testresults": "jest --config=tests/addon-jest.config.json --json --outputFile=stories/addon-jest.testresults.json",
"graphql": "node ./graphql-server/index.js", "graphql": "node ./graphql-server/index.js",
"image-snapshots": "yarn run build-storybook && yarn run do-image-snapshots", "image-snapshots": "yarn run build-storybook && yarn run do-image-snapshots",
"storybook": "STORYBOOK_DISPLAY_WARNING=true DISPLAY_WARNING=true start-storybook -p 9011 -c ./ -s built-storybooks" "storybook": "cross-env STORYBOOK_DISPLAY_WARNING=true DISPLAY_WARNING=true start-storybook -p 9011 -c ./ -s built-storybooks"
}, },
"devDependencies": { "devDependencies": {
"@emotion/core": "^0.13.1", "@emotion/core": "^0.13.1",
@ -37,6 +37,7 @@
"@storybook/node-logger": "4.0.0-rc.1", "@storybook/node-logger": "4.0.0-rc.1",
"@storybook/react": "4.0.0-rc.1", "@storybook/react": "4.0.0-rc.1",
"cors": "^2.8.4", "cors": "^2.8.4",
"cross-env": "^5.2.0",
"enzyme-to-json": "^3.3.4", "enzyme-to-json": "^3.3.4",
"eventemitter3": "^3.1.0", "eventemitter3": "^3.1.0",
"express": "^4.16.3", "express": "^4.16.3",
@ -50,6 +51,6 @@
"react-chromatic": "^0.8.4", "react-chromatic": "^0.8.4",
"react-dom": "^16.5.2", "react-dom": "^16.5.2",
"uuid": "^3.3.2", "uuid": "^3.3.2",
"webpack": "^4.20.2" "webpack": "^4.21.0"
} }
} }

View File

@ -1,7 +1,7 @@
const path = require('path'); const path = require('path');
const { DefinePlugin, ContextReplacementPlugin } = require('webpack'); const { DefinePlugin, ContextReplacementPlugin } = require('webpack');
module.exports = (baseConfig, env, defaultConfig) => ({ module.exports = async (baseConfig, env, defaultConfig) => ({
...defaultConfig, ...defaultConfig,
module: { module: {
...defaultConfig.module, ...defaultConfig.module,

View File

@ -22,7 +22,7 @@
"global": "^4.3.2", "global": "^4.3.2",
"lit-html": "^0.12.0", "lit-html": "^0.12.0",
"polymer-webpack-loader": "^2.0.3", "polymer-webpack-loader": "^2.0.3",
"webpack": "^4.20.2" "webpack": "^4.21.0"
}, },
"devDependencies": { "devDependencies": {
"copy-webpack-plugin": "^4.5.3", "copy-webpack-plugin": "^4.5.3",

View File

@ -33,7 +33,7 @@
"raw-loader": "^0.5.1", "raw-loader": "^0.5.1",
"riot-tag-loader": "^2.1.0", "riot-tag-loader": "^2.1.0",
"svg-url-loader": "^2.3.2", "svg-url-loader": "^2.3.2",
"webpack": "^4.20.2", "webpack": "^4.21.0",
"webpack-dev-server": "^3.1.9" "webpack-dev-server": "^3.1.9"
} }
} }

View File

@ -32,7 +32,7 @@
"file-loader": "^2.0.0", "file-loader": "^2.0.0",
"svg-url-loader": "^2.3.2", "svg-url-loader": "^2.3.2",
"vue-loader": "^15.4.2", "vue-loader": "^15.4.2",
"webpack": "^4.20.2", "webpack": "^4.21.0",
"webpack-dev-server": "^3.1.9" "webpack-dev-server": "^3.1.9"
} }
} }

View File

@ -10,7 +10,7 @@ Just go to your project and run:
```sh ```sh
cd my-app cd my-app
npx -p @storybook/cli@alpha sb init npx -p @storybook/cli@rc sb init
``` ```
That's all you've to do. That's all you've to do.
@ -24,7 +24,7 @@ The CLI supports yarn. If you have installed yarn in your system, it'll detect i
If you don't want to use `yarn` always you can use the `--use-npm` option like this: If you don't want to use `yarn` always you can use the `--use-npm` option like this:
```sh ```sh
npx -p @storybook/cli@alpha sb init --use-npm npx -p @storybook/cli@rc sb init --use-npm
``` ```
--- ---
@ -34,7 +34,7 @@ npx -p @storybook/cli@alpha sb init --use-npm
It also supports flow files. By default, [jscodeshift](https://github.com/facebook/jscodeshift), the tool used to transform the source files, uses babel to read the files. To be able to transform any flow annotated file, you need to use the flow parser. It also supports flow files. By default, [jscodeshift](https://github.com/facebook/jscodeshift), the tool used to transform the source files, uses babel to read the files. To be able to transform any flow annotated file, you need to use the flow parser.
```sh ```sh
npx -p @storybook/cli@alpha sb init --parser flow npx -p @storybook/cli@rc sb init --parser flow
``` ```
For more information visit: [storybook.js.org](https://storybook.js.org) For more information visit: [storybook.js.org](https://storybook.js.org)
@ -46,7 +46,7 @@ For more information visit: [storybook.js.org](https://storybook.js.org)
If the CLI cannot detect your project type, it will ask you. You can also force it to use a particular project type: If the CLI cannot detect your project type, it will ask you. You can also force it to use a particular project type:
```sh ```sh
npx -p @storybook/cli@alpha sb init --type <type> npx -p @storybook/cli@rc sb init --type <type>
``` ```
Where type is one of the project types defined in [project_types.js](https://github.com/storybooks/storybook/blob/master/lib/cli/lib/project_types.js) Where type is one of the project types defined in [project_types.js](https://github.com/storybooks/storybook/blob/master/lib/cli/lib/project_types.js)

View File

@ -1509,7 +1509,7 @@ Then, run the following command inside your apps directory:
```sh ```sh
cd my-react-app cd my-react-app
npx -p @storybook/cli@alpha sb init npx -p @storybook/cli@rc sb init
``` ```
After that, follow the instructions on the screen. After that, follow the instructions on the screen.

View File

@ -1178,7 +1178,7 @@ You can also deploy your Storybook as a static app. This way, everyone in your t
Then, run the following command inside your apps directory: Then, run the following command inside your apps directory:
```sh ```sh
npx -p @storybook/cli@alpha sb init npx -p @storybook/cli@rc sb init
``` ```
After that, follow the instructions on the screen. After that, follow the instructions on the screen.

View File

@ -78,7 +78,7 @@
"style-loader": "^0.23.1", "style-loader": "^0.23.1",
"svg-url-loader": "^2.3.2", "svg-url-loader": "^2.3.2",
"url-loader": "^1.1.2", "url-loader": "^1.1.2",
"webpack": "^4.20.2", "webpack": "^4.21.0",
"webpack-dev-middleware": "^3.4.0", "webpack-dev-middleware": "^3.4.0",
"webpack-hot-middleware": "^2.24.3" "webpack-hot-middleware": "^2.24.3"
}, },

View File

@ -134,7 +134,9 @@ export async function buildDevStandalone(options) {
applyStatic(app, options); applyStatic(app, options);
app.use(storybook(options)); const storybookMiddleware = await storybook(options);
app.use(storybookMiddleware);
const serverListening = listenToServer(server, listenAddr); const serverListening = listenToServer(server, listenAddr);

View File

@ -8,7 +8,7 @@ import loadConfig from './config';
const defaultFavIcon = require.resolve('./public/favicon.ico'); const defaultFavIcon = require.resolve('./public/favicon.ico');
export function buildStaticStandalone(options) { export async function buildStaticStandalone(options) {
const { outputDir, staticDir, watch } = options; const { outputDir, staticDir, watch } = options;
// create output directory if not exists // create output directory if not exists
@ -20,7 +20,7 @@ export function buildStaticStandalone(options) {
// Build the webpack configuration using the `baseConfig` // Build the webpack configuration using the `baseConfig`
// custom `.babelrc` file and `webpack.config.js` files // custom `.babelrc` file and `webpack.config.js` files
// NOTE changes to env should be done before calling `getBaseConfig` // NOTE changes to env should be done before calling `getBaseConfig`
const config = loadConfig({ const config = await loadConfig({
configType: 'PRODUCTION', configType: 'PRODUCTION',
corePresets: [require.resolve('./core-preset-prod.js')], corePresets: [require.resolve('./core-preset-prod.js')],
...options, ...options,
@ -63,10 +63,10 @@ export function buildStaticStandalone(options) {
} }
} }
export function buildStatic({ packageJson, ...loadOptions }) { export async function buildStatic({ packageJson, ...loadOptions }) {
const cliOptions = getProdCli(packageJson); const cliOptions = getProdCli(packageJson);
buildStaticStandalone({ await buildStaticStandalone({
...cliOptions, ...cliOptions,
...loadOptions, ...loadOptions,
configDir: cliOptions.configDir || './.storybook', configDir: cliOptions.configDir || './.storybook',

View File

@ -5,11 +5,11 @@ import serverRequire from './serverRequire';
function wrapCorePresets(presets) { function wrapCorePresets(presets) {
return { return {
babel: (config, args) => presets.apply('babel', config, args), babel: async (config, args) => presets.apply('babel', config, args),
webpack: (config, args) => presets.apply('webpack', config, args), webpack: async (config, args) => presets.apply('webpack', config, args),
webpackFinal: (config, args) => presets.apply('webpackFinal', config, args), webpackFinal: async (config, args) => presets.apply('webpackFinal', config, args),
preview: (config, args) => presets.apply('preview', config, args), preview: async (config, args) => presets.apply('preview', config, args),
manager: (config, args) => presets.apply('manager', config, args), manager: async (config, args) => presets.apply('manager', config, args),
}; };
} }
@ -27,20 +27,20 @@ function customPreset({ configDir }) {
return []; return [];
} }
function getWebpackConfig(options, presets) { async function getWebpackConfig(options, presets) {
const babelOptions = presets.babel({}, options); const babelOptions = await presets.babel({}, options);
const entries = { const entries = {
iframe: presets.preview([], options), iframe: await presets.preview([], options),
manager: presets.manager([], options), manager: await presets.manager([], options),
}; };
const webpackConfig = presets.webpack({}, { ...options, babelOptions, entries }); const webpackConfig = await presets.webpack({}, { ...options, babelOptions, entries });
return presets.webpackFinal(webpackConfig, options); return presets.webpackFinal(webpackConfig, options);
} }
export default options => { export default async options => {
const { corePresets = [], frameworkPresets = [], ...restOptions } = options; const { corePresets = [], frameworkPresets = [], ...restOptions } = options;
const presetsConfig = [ const presetsConfig = [

View File

@ -1,8 +1,8 @@
export function createPreviewEntry(options) { export async function createPreviewEntry(options) {
const { configDir, presets } = options; const { configDir, presets } = options;
const preview = [require.resolve('./polyfills'), require.resolve('./globals')]; const preview = [require.resolve('./polyfills'), require.resolve('./globals')];
const configs = presets.apply('config', [], options); const configs = await presets.apply('config', [], options);
if (!configs || !configs.length) { if (!configs || !configs.length) {
throw new Error(`=> Create a storybook config file in "${configDir}/config.{ext}".`); throw new Error(`=> Create a storybook config file in "${configDir}/config.{ext}".`);
@ -13,11 +13,11 @@ export function createPreviewEntry(options) {
return preview; return preview;
} }
export function createManagerEntry(options) { export async function createManagerEntry(options) {
const { presets } = options; const { presets } = options;
const manager = [require.resolve('./polyfills')]; const manager = [require.resolve('./polyfills')];
const addons = presets.apply('addons', [], options); const addons = await presets.apply('addons', [], options);
if (addons && addons.length) { if (addons && addons.length) {
manager.push(...addons); manager.push(...addons);

View File

@ -71,7 +71,7 @@ export default ({ configDir, quiet, babelOptions, entries }) => {
module: { module: {
rules: [ rules: [
{ {
test: /\.jsx?$/, test: /\.(mjs|jsx?)$/,
use: [ use: [
{ {
loader: 'babel-loader', loader: 'babel-loader',
@ -94,7 +94,7 @@ export default ({ configDir, quiet, babelOptions, entries }) => {
resolve: { resolve: {
// Since we ship with json-loader always, it's better to move extensions to here // Since we ship with json-loader always, it's better to move extensions to here
// from the default config. // from the default config.
extensions: ['.js', '.jsx', '.json'], extensions: ['.js', '.jsx', '.json', '.mjs'],
// Add support to NODE_PATH. With this we could avoid relative path imports. // Add support to NODE_PATH. With this we could avoid relative path imports.
// Based on this CRA feature: https://github.com/facebookincubator/create-react-app/issues/253 // Based on this CRA feature: https://github.com/facebookincubator/create-react-app/issues/253
modules: ['node_modules'].concat(nodePaths), modules: ['node_modules'].concat(nodePaths),

View File

@ -57,7 +57,7 @@ export default ({ configDir, babelOptions, entries }) => {
module: { module: {
rules: [ rules: [
{ {
test: /\.jsx?$/, test: /\.(mjs|jsx?)$/,
use: [ use: [
{ {
loader: 'babel-loader', loader: 'babel-loader',
@ -80,7 +80,7 @@ export default ({ configDir, babelOptions, entries }) => {
resolve: { resolve: {
// Since we ship with json-loader always, it's better to move extensions to here // Since we ship with json-loader always, it's better to move extensions to here
// from the default config. // from the default config.
extensions: ['.js', '.jsx', '.json'], extensions: ['.js', '.jsx', '.json', '.mjs'],
// Add support to NODE_PATH. With this we could avoid relative path imports. // Add support to NODE_PATH. With this we could avoid relative path imports.
// Based on this CRA feature: https://github.com/facebookincubator/create-react-app/issues/253 // Based on this CRA feature: https://github.com/facebookincubator/create-react-app/issues/253
modules: ['node_modules'].concat(nodePaths), modules: ['node_modules'].concat(nodePaths),

View File

@ -5,11 +5,11 @@ import createDevConfig from './config/webpack.config.dev';
import defaultBabelConfig from './config/babel.dev'; import defaultBabelConfig from './config/babel.dev';
import { createManagerEntry, createPreviewEntry } from './config/entries'; import { createManagerEntry, createPreviewEntry } from './config/entries';
export function webpack(_, options) { export async function webpack(_, options) {
return createDevConfig(options); return createDevConfig(options);
} }
export function babel(_, options) { export async function babel(_, options) {
const { configDir, presets } = options; const { configDir, presets } = options;
return loadCustomBabelConfig(configDir, () => return loadCustomBabelConfig(configDir, () =>
@ -17,21 +17,20 @@ export function babel(_, options) {
); );
} }
export function manager(_, options) { export async function manager(_, options) {
return createManagerEntry(options); return createManagerEntry(options);
} }
export function preview(_, options) { export async function preview(_, options) {
return [ const entry = await createPreviewEntry(options);
...createPreviewEntry(options),
`${require.resolve('webpack-hot-middleware/client')}?reload=true`, return [...entry, `${require.resolve('webpack-hot-middleware/client')}?reload=true`];
];
} }
export function addons(_, options) { export async function addons(_, options) {
return loadCustomAddons(options); return loadCustomAddons(options);
} }
export function config(_, options) { export async function config(_, options) {
return loadCustomConfig(options); return loadCustomConfig(options);
} }

View File

@ -5,11 +5,11 @@ import createProdConfig from './config/webpack.config.prod';
import defaultBabelConfig from './config/babel.prod'; import defaultBabelConfig from './config/babel.prod';
import { createManagerEntry, createPreviewEntry } from './config/entries'; import { createManagerEntry, createPreviewEntry } from './config/entries';
export function webpack(_, options) { export async function webpack(_, options) {
return createProdConfig(options); return createProdConfig(options);
} }
export function babel(_, options) { export async function babel(_, options) {
const { configDir, presets } = options; const { configDir, presets } = options;
return loadCustomBabelConfig(configDir, () => return loadCustomBabelConfig(configDir, () =>
@ -17,18 +17,18 @@ export function babel(_, options) {
); );
} }
export function manager(_, options) { export async function manager(_, options) {
return createManagerEntry(options); return createManagerEntry(options);
} }
export function preview(_, options) { export async function preview(_, options) {
return createPreviewEntry(options); return createPreviewEntry(options);
} }
export function addons(_, options) { export async function addons(_, options) {
return loadCustomAddons(options); return loadCustomAddons(options);
} }
export function config(_, options) { export async function config(_, options) {
return loadCustomConfig(options); return loadCustomConfig(options);
} }

View File

@ -53,7 +53,7 @@ function isBabelLoader8() {
return satisfies(babelLoaderPkg.version, '>=8.0.0-0'); return satisfies(babelLoaderPkg.version, '>=8.0.0-0');
} }
export default function(configDir, getDefaultConfig) { export default async function(configDir, getDefaultConfig) {
const babelConfig = loadFromPath(path.resolve(configDir, '.babelrc')); const babelConfig = loadFromPath(path.resolve(configDir, '.babelrc'));
if (babelConfig) { if (babelConfig) {

View File

@ -14,12 +14,12 @@ export const webpackValid = new Promise((resolve, reject) => {
webpackReject = reject; webpackReject = reject;
}); });
export default function(options) { export default async function(options) {
const { configDir } = options; const { configDir } = options;
// Build the webpack configuration using the `getBaseConfig` // Build the webpack configuration using the `getBaseConfig`
// custom `.babelrc` file and `webpack.config.js` files // custom `.babelrc` file and `webpack.config.js` files
const config = loadConfig({ const config = await loadConfig({
configType: 'DEVELOPMENT', configType: 'DEVELOPMENT',
corePresets: [require.resolve('./core-preset-dev.js')], corePresets: [require.resolve('./core-preset-dev.js')],
...options, ...options,

View File

@ -42,31 +42,36 @@ function loadPresets(presets) {
} }
function applyPresets(presets, config, args = {}, extension) { function applyPresets(presets, config, args = {}, extension) {
const presetResult = new Promise(resolve => resolve(config));
if (!presets.length) { if (!presets.length) {
return config; return presetResult;
} }
return presets.reduce((accumulatedConfig, { preset, options }) => { return presets.reduce((accumulationPromise, { preset, options }) => {
const extensionFn = preset[extension]; const extensionFn = preset[extension];
if (extensionFn && typeof extensionFn === 'function') { if (extensionFn && typeof extensionFn === 'function') {
const combinedOptions = { const context = {
...args, extensionFn,
...options, preset,
combinedOptions: { ...args, ...options },
}; };
return extensionFn.call(preset, accumulatedConfig, combinedOptions); return accumulationPromise.then(newConfig =>
context.extensionFn.call(context.preset, newConfig, context.combinedOptions)
);
} }
return accumulatedConfig; return accumulationPromise;
}, config); }, presetResult);
} }
function getPresets(presets) { function getPresets(presets) {
const loadedPresets = loadPresets(presets); const loadedPresets = loadPresets(presets);
return { return {
apply: (extension, config, args) => applyPresets(loadedPresets, config, args, extension), apply: async (extension, config, args) => applyPresets(loadedPresets, config, args, extension),
}; };
} }

View File

@ -1,7 +1,7 @@
function wrapPreset(basePresets) { function wrapPreset(basePresets) {
return { return {
babel: (config, args) => basePresets.apply('babel', config, args), babel: async (config, args) => basePresets.apply('babel', config, args),
webpack: (config, args) => basePresets.apply('webpack', config, args), webpack: async (config, args) => basePresets.apply('webpack', config, args),
}; };
} }
@ -10,40 +10,46 @@ function mockPreset(name, mockPresetObject) {
} }
describe('presets', () => { describe('presets', () => {
it('does not throw when there is no preset file', () => { it('does not throw when there is no preset file', async () => {
const loadPresets = require.requireActual('./presets').default; const loadPresets = require.requireActual('./presets').default;
let presets; let presets;
expect(() => { async function testPresets() {
presets = wrapPreset(loadPresets()); presets = wrapPreset(loadPresets());
presets.webpack(); await presets.webpack();
presets.babel(); await presets.babel();
}).not.toThrow(); }
await expect(testPresets()).resolves.toBeUndefined();
expect(presets).toBeDefined(); expect(presets).toBeDefined();
}); });
it('does not throw when presets are empty', () => { it('does not throw when presets are empty', async () => {
const loadPresets = require.requireActual('./presets').default; const loadPresets = require.requireActual('./presets').default;
const presets = wrapPreset(loadPresets([])); const presets = wrapPreset(loadPresets([]));
expect(() => { async function testPresets() {
presets.webpack(); await presets.webpack();
presets.babel(); await presets.babel();
}).not.toThrow(); }
await expect(testPresets()).resolves.toBeUndefined();
}); });
it('does not throw when preset can not be loaded', () => { it('does not throw when preset can not be loaded', async () => {
const loadPresets = require.requireActual('./presets').default; const loadPresets = require.requireActual('./presets').default;
const presets = wrapPreset(loadPresets(['preset-foo'])); const presets = wrapPreset(loadPresets(['preset-foo']));
expect(() => { async function testPresets() {
presets.webpack({}); await presets.webpack();
presets.babel(); await presets.babel();
}).not.toThrow(); }
await expect(testPresets()).resolves.toBeUndefined();
}); });
it('loads and applies presets when they are declared as a string', () => { it('loads and applies presets when they are declared as a string', async () => {
const mockPresetFooExtendWebpack = jest.fn(); const mockPresetFooExtendWebpack = jest.fn();
const mockPresetBarExtendBabel = jest.fn(); const mockPresetBarExtendBabel = jest.fn();
@ -58,16 +64,18 @@ describe('presets', () => {
const loadPresets = require.requireActual('./presets').default; const loadPresets = require.requireActual('./presets').default;
const presets = wrapPreset(loadPresets(['preset-foo', 'preset-bar'])); const presets = wrapPreset(loadPresets(['preset-foo', 'preset-bar']));
expect(() => { async function testPresets() {
presets.webpack(); await presets.webpack();
presets.babel(); await presets.babel();
}).not.toThrow(); }
await expect(testPresets()).resolves.toBeUndefined();
expect(mockPresetFooExtendWebpack).toBeCalled(); expect(mockPresetFooExtendWebpack).toBeCalled();
expect(mockPresetBarExtendBabel).toBeCalled(); expect(mockPresetBarExtendBabel).toBeCalled();
}); });
it('loads and applies presets when they are declared as an object without props', () => { it('loads and applies presets when they are declared as an object without props', async () => {
const mockPresetFooExtendWebpack = jest.fn(); const mockPresetFooExtendWebpack = jest.fn();
const mockPresetBarExtendBabel = jest.fn(); const mockPresetBarExtendBabel = jest.fn();
@ -82,16 +90,18 @@ describe('presets', () => {
const loadPresets = require.requireActual('./presets').default; const loadPresets = require.requireActual('./presets').default;
const presets = wrapPreset(loadPresets([{ name: 'preset-foo' }, { name: 'preset-bar' }])); const presets = wrapPreset(loadPresets([{ name: 'preset-foo' }, { name: 'preset-bar' }]));
expect(() => { async function testPresets() {
presets.webpack(); await presets.webpack();
presets.babel(); await presets.babel();
}).not.toThrow(); }
await expect(testPresets()).resolves.toBeUndefined();
expect(mockPresetFooExtendWebpack).toBeCalled(); expect(mockPresetFooExtendWebpack).toBeCalled();
expect(mockPresetBarExtendBabel).toBeCalled(); expect(mockPresetBarExtendBabel).toBeCalled();
}); });
it('loads and applies presets when they are declared as an object with props', () => { it('loads and applies presets when they are declared as an object with props', async () => {
const mockPresetFooExtendWebpack = jest.fn(); const mockPresetFooExtendWebpack = jest.fn();
const mockPresetBarExtendBabel = jest.fn(); const mockPresetBarExtendBabel = jest.fn();
@ -111,16 +121,18 @@ describe('presets', () => {
]) ])
); );
expect(() => { async function testPresets() {
presets.webpack({}); await presets.webpack({});
presets.babel({}); await presets.babel({});
}).not.toThrow(); }
await expect(testPresets()).resolves.toBeUndefined();
expect(mockPresetFooExtendWebpack).toBeCalledWith(expect.anything(), { foo: 1 }); expect(mockPresetFooExtendWebpack).toBeCalledWith(expect.anything(), { foo: 1 });
expect(mockPresetBarExtendBabel).toBeCalledWith(expect.anything(), { bar: 'a' }); expect(mockPresetBarExtendBabel).toBeCalledWith(expect.anything(), { bar: 'a' });
}); });
it('loads and applies presets when they are declared as a string and as an object', () => { it('loads and applies presets when they are declared as a string and as an object', async () => {
const mockPresetFooExtendWebpack = jest.fn(); const mockPresetFooExtendWebpack = jest.fn();
const mockPresetBarExtendBabel = jest.fn(); const mockPresetBarExtendBabel = jest.fn();
@ -137,16 +149,18 @@ describe('presets', () => {
loadPresets(['preset-foo', { name: 'preset-bar', options: { bar: 'a' } }]) loadPresets(['preset-foo', { name: 'preset-bar', options: { bar: 'a' } }])
); );
expect(() => { async function testPresets() {
presets.webpack({}); await presets.webpack({});
presets.babel({}); await presets.babel({});
}).not.toThrow(); }
await expect(testPresets()).resolves.toBeUndefined();
expect(mockPresetFooExtendWebpack).toBeCalled(); expect(mockPresetFooExtendWebpack).toBeCalled();
expect(mockPresetBarExtendBabel).toBeCalledWith(expect.anything(), { bar: 'a' }); expect(mockPresetBarExtendBabel).toBeCalledWith(expect.anything(), { bar: 'a' });
}); });
it('applies presets in chain', () => { it('applies presets in chain', async () => {
const mockPresetFooExtendWebpack = jest.fn(() => ({})); const mockPresetFooExtendWebpack = jest.fn(() => ({}));
const mockPresetBarExtendWebpack = jest.fn(() => ({})); const mockPresetBarExtendWebpack = jest.fn(() => ({}));
@ -163,10 +177,12 @@ describe('presets', () => {
loadPresets(['preset-foo', { name: 'preset-bar', options: { bar: 'a' } }]) loadPresets(['preset-foo', { name: 'preset-bar', options: { bar: 'a' } }])
); );
expect(() => { async function testPresets() {
presets.webpack({}); await presets.webpack();
presets.babel(); await presets.babel();
}).not.toThrow(); }
await expect(testPresets()).resolves.toBeUndefined();
expect(mockPresetFooExtendWebpack).toBeCalled(); expect(mockPresetFooExtendWebpack).toBeCalled();
expect(mockPresetBarExtendWebpack).toBeCalledWith(expect.anything(), { bar: 'a' }); expect(mockPresetBarExtendWebpack).toBeCalledWith(expect.anything(), { bar: 'a' });

View File

@ -22750,10 +22750,10 @@ webpack@4.19.1:
watchpack "^1.5.0" watchpack "^1.5.0"
webpack-sources "^1.2.0" webpack-sources "^1.2.0"
webpack@^4.15.1, webpack@^4.17.1, webpack@^4.20.2: webpack@^4.15.1, webpack@^4.21.0:
version "4.20.2" version "4.21.0"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.20.2.tgz#89f6486b6bb276a91b0823453d377501fc625b5a" resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.21.0.tgz#bd03605c0f48c0d4aaaef78ead2769485e5afd92"
integrity sha512-75WFUMblcWYcocjSLlXCb71QuGyH7egdBZu50FtBGl2Nso8CK3Ej+J7bTZz2FPFq5l6fzCisD9modB7t30ikuA== integrity sha512-CGBeop4AYR0dcmk9Afl33qQULwTHQCXQPAIBTHMJoy9DpY8FPUDna/NUlAGTr5o5y9QC901Ww3wCY4wNo1X9Lw==
dependencies: dependencies:
"@webassemblyjs/ast" "1.7.8" "@webassemblyjs/ast" "1.7.8"
"@webassemblyjs/helper-module-context" "1.7.8" "@webassemblyjs/helper-module-context" "1.7.8"