Skip to content

Commit

Permalink
Merge pull request #4405 from chadfawcett/css-modules
Browse files Browse the repository at this point in the history
Support css-modules
  • Loading branch information
igor-dv committed Oct 22, 2018
2 parents 5b10bd2 + f42fb81 commit d704510
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 11 deletions.
5 changes: 4 additions & 1 deletion app/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,15 @@
"@babel/runtime": "^7.1.2",
"@emotion/styled": "^0.10.6",
"@storybook/core": "4.0.0-rc.1",
"@storybook/node-logger": "^3.4.11",
"babel-plugin-react-docgen": "^2.0.0",
"common-tags": "^1.8.0",
"global": "^4.3.2",
"lodash": "^4.17.11",
"prop-types": "^15.6.2",
"react-dev-utils": "^6.0.5"
"react-dev-utils": "^6.0.5",
"semver": "^5.6.0",
"webpack": "^4.21.0"
},
"peerDependencies": {
"babel-loader": "^7.0.0 || ^8.0.0",
Expand Down
85 changes: 85 additions & 0 deletions app/react/src/server/cra_config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import semver from 'semver';
import { normalizeCondition } from 'webpack/lib/RuleSet';

export function isReactScriptsInstalled() {
try {
// eslint-disable-next-line global-require, import/no-extraneous-dependencies
const reactScriptsJson = require('react-scripts/package.json');
if (semver.lt(reactScriptsJson.version, '2.0.0')) return false;
return true;
} catch (e) {
return false;
}
}

export function getStyleRules(rules) {
// Extensions of style rules we're interested in
const extensions = ['.css', '.scss', '.sass', '.module.css', '.module.scss', '.module.sass'];

return rules.reduce((styleRules, rule) => {
// If at least one style extension satisfies the rule test, the rule is one
// we want to extract
if (rule.test && extensions.some(normalizeCondition(rule.test))) {
// If the base test is for styles, return early
return styleRules.concat(rule);
}

// Get any style rules contained in rule.oneOf
if (!rule.test && rule.oneOf) {
styleRules.push(...getStyleRules(rule.oneOf));
}

// Get any style rules contained in rule.rules
if (!rule.test && rule.rules) {
styleRules.push(...getStyleRules(rule.rules));
}

return styleRules;
}, []);
}

export function getCraWebpackConfig(mode) {
if (mode === 'production') {
// eslint-disable-next-line global-require, import/no-extraneous-dependencies
return require('react-scripts/config/webpack.config.prod');
}

// eslint-disable-next-line global-require, import/no-extraneous-dependencies
return require('react-scripts/config/webpack.config.dev');
}

export function applyCRAWebpackConfig(baseConfig) {
// Remove any rules from baseConfig that test true for any one of the extensions
const baseRulesExcludingStyles = baseConfig.module.rules.filter(
rule => !rule.test || !['.css', '.scss', '.sass'].some(normalizeCondition(rule.test))
);

// Load create-react-app config
const craWebpackConfig = getCraWebpackConfig(baseConfig.mode);

const craStyleRules = getStyleRules(craWebpackConfig.module.rules);

// Add css minification for production
const plugins = [...baseConfig.plugins];
if (baseConfig.mode === 'production') {
// eslint-disable-next-line global-require, import/no-extraneous-dependencies
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
plugins.push(
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
filename: 'static/css/[name].[contenthash:8].css',
chunkFilename: 'static/css/[name].[contenthash:8].chunk.css',
})
);
}

return {
...baseConfig,
module: {
...baseConfig.module,
rules: [...baseRulesExcludingStyles, ...craStyleRules],
},
plugins,
};
}
13 changes: 13 additions & 0 deletions app/react/src/server/framework-preset-cra-styles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { logger } from '@storybook/node-logger';
import { applyCRAWebpackConfig, isReactScriptsInstalled } from './cra_config';

export function webpackFinal(config) {
if (!isReactScriptsInstalled()) {
logger.info('=> Using base config because react-scripts is not installed.');
return config;
}

logger.info('=> Loading create-react-app config.');

return applyCRAWebpackConfig(config);
}
1 change: 1 addition & 0 deletions app/react/src/server/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ export default {
frameworkPresets: [
require.resolve('./framework-preset-react.js'),
require.resolve('./framework-preset-react-docgen.js'),
require.resolve('./framework-preset-cra-styles.js'),
],
};
5 changes: 1 addition & 4 deletions lib/core/src/server/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ function wrapCorePresets(presets) {
return {
babel: async (config, args) => presets.apply('babel', config, args),
webpack: async (config, args) => presets.apply('webpack', config, args),
webpackFinal: async (config, args) => presets.apply('webpackFinal', config, args),
preview: async (config, args) => presets.apply('preview', config, args),
manager: async (config, args) => presets.apply('manager', config, args),
};
Expand Down Expand Up @@ -35,9 +34,7 @@ async function getWebpackConfig(options, presets) {
manager: await presets.manager([], options),
};

const webpackConfig = await presets.webpack({}, { ...options, babelOptions, entries });

return presets.webpackFinal(webpackConfig, options);
return presets.webpack({}, { ...options, babelOptions, entries });
}

export default async options => {
Expand Down
23 changes: 19 additions & 4 deletions lib/core/src/server/core-preset-webpack-custom.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,39 @@ function informAboutCustomConfig(defaultConfigName) {
logger.info(`=> Using default webpack setup based on "${defaultConfigName}".`);
}

export function webpack(config, { configDir, configType, defaultConfigName }) {
function wrapPresets(presets) {
return {
webpackFinal: async (config, args) => presets.apply('webpackFinal', config, args),
};
}

async function createFinalDefaultConfig(presets, config, options) {
const defaultConfig = createDefaultWebpackConfig(config);
return presets.webpackFinal(defaultConfig, options);
}

export async function webpack(config, options) {
const { configDir, configType, defaultConfigName } = options;
const presets = wrapPresets(options.presets);

const finalConfig = await presets.webpackFinal(config, options);

// Check whether user has a custom webpack config file and
// return the (extended) base configuration if it's not available.
const customConfig = loadCustomWebpackConfig(configDir);

if (customConfig === null) {
informAboutCustomConfig(defaultConfigName);
return defaultConfig;
return createFinalDefaultConfig(presets, config, options);
}

if (typeof customConfig === 'function') {
logger.info('=> Loading custom webpack config (full-control mode).');
return customConfig(config, configType, defaultConfig);
const finalDefaultConfig = await createFinalDefaultConfig(presets, config, options);
return customConfig(finalConfig, configType, finalDefaultConfig);
}

logger.info('=> Loading custom webpack config (extending mode).');

return mergeConfigs(config, customConfig);
return mergeConfigs(finalConfig, customConfig);
}
11 changes: 9 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1880,6 +1880,13 @@
"@storybook/react-simple-di" "^1.2.1"
babel-runtime "6.x.x"

"@storybook/node-logger@^3.4.11":
version "3.4.11"
resolved "https://registry.yarnpkg.com/@storybook/node-logger/-/node-logger-3.4.11.tgz#a6684a4c21f74dae937cd9f202deec0932d3f3b5"
integrity sha512-eCjvZsCwZTcjDOeG7JDEVs5bugyybpAFu/4+X3hfikxGBBjnx2NtjJIfIsriUKa1O559+aFGUG73wogYAjudhg==
dependencies:
npmlog "^4.1.2"

"@storybook/podda@^1.2.3":
version "1.2.3"
resolved "https://registry.yarnpkg.com/@storybook/podda/-/podda-1.2.3.tgz#53c4a1a3f8c7bbd5755dff5c34576fd1af9d38ba"
Expand Down Expand Up @@ -5753,12 +5760,12 @@ caniuse-api@^3.0.0:
lodash.memoize "^4.1.2"
lodash.uniq "^4.5.0"

caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000844, caniuse-lite@^1.0.30000864, caniuse-lite@^1.0.30000884, caniuse-lite@^1.0.30000887, caniuse-lite@^1.0.30000889, caniuse-lite@^1.0.30000890:
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000844, caniuse-lite@^1.0.30000864, caniuse-lite@^1.0.30000884, caniuse-lite@^1.0.30000887, caniuse-lite@^1.0.30000889:
version "1.0.30000890"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000890.tgz#86a18ffcc65d79ec6a437e985761b8bf1c4efeaf"
integrity sha512-4NI3s4Y6ROm+SgZN5sLUG4k7nVWQnedis3c/RWkynV5G6cHSY7+a8fwFyn2yoBDE3E6VswhTNNwR3PvzGqlTkg==

caniuse-lite@^1.0.30000892:
caniuse-lite@^1.0.30000890, caniuse-lite@^1.0.30000892:
version "1.0.30000892"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000892.tgz#344d2b51ee3ff5977537da4aa449c90eec40b759"
integrity sha512-X9rxMaWZNbJB5qjkDqPtNv/yfViTeUL6ILk0QJNxLV3OhKC5Acn5vxsuUvllR6B48mog8lmS+whwHq/QIYSL9w==
Expand Down

0 comments on commit d704510

Please sign in to comment.