-
-
Notifications
You must be signed in to change notification settings - Fork 9.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support css-modules #4405
Support css-modules #4405
Changes from all commits
7594e87
3ccf2bb
535d2b6
0441fc5
fefd86a
4a6fd1b
f40b98c
b12ffae
3f88f74
da0ad40
76a668f
39e2c3e
980f394
9719566
53004c4
41826b6
1753127
e1b73c7
5949b40
b2f9e66
950e2a6
2873911
cf34baa
6297d48
5f00d84
e2cf993
f42fb81
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🤔 I wonder if we could make Webpack 4+ a peer dep instead? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
}, | ||
"peerDependencies": { | ||
"babel-loader": "^7.0.0 || ^8.0.0", | ||
|
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) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd love to get some comments throughout this function. Not certain what's occurring. It looks like a way to concatenate across the subset of style loading possibilities given the array of file suffixes we're sifting? |
||
// 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( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Very nice 👏 |
||
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'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On a second thought, I think this can make problems if 'mini-css-extract-plugin' is not installed as the root package in node_modules 🤔 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we need to do something like this instead ? const miniCssExtractPlugin = craWebpackConfig.plugins.find(plugin => plugin.constructor.name === 'MiniCssExtractPlugin'); There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you were right initially. Since we check to make sure There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we want to use it, we have to depend on it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There's no guarantee that it's available in root There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like #4524 is broken now because of this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Created #4534 to hopefully resolve this |
||
plugins.push( | ||
new MiniCssExtractPlugin({ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we really need this, though? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nope! I just thought minification would be good for production. Also, if we don't want to include this plugin, then we have to filter out the related rule from all of the style rules. Adding the plugin was less work than removing it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this exclude interop for CRAv1? I don't really care about that, but it could be something to consider. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FWIW we dont really need autoprefixer in the default ruleset either 🤷♂️ I'm a fan of good defaults 👍 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @kylemh This preset checks for |
||
// 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, | ||
}; | ||
} |
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) { | ||
igor-dv marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
} | ||
|
||
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); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be
"4.0.0-rc.3"