Skip to content

Commit

Permalink
Add CSS Module support. (#1248)
Browse files Browse the repository at this point in the history
  • Loading branch information
tai2 authored and gauravtiwari committed Feb 24, 2018
1 parent 49022f2 commit 88ff79c
Show file tree
Hide file tree
Showing 10 changed files with 133 additions and 50 deletions.
32 changes: 31 additions & 1 deletion docs/css.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
Webpacker supports importing CSS, Sass and SCSS files directly into your JavaScript files.


## Import styles into your JS app
## Import global styles into your JS app

```sass
// app/javascript/hello_react/styles/hello-react.sass
Expand All @@ -30,6 +30,36 @@ const Hello = props => (
)
```

## Import scoped styles into your JS app

Stylesheets end with '.modules.*' is treated as [CSS Modules](https://github.com/css-modules/css-modules).

```sass
// app/javascript/hello_react/styles/hello-react.module.sass
.helloReact
padding: 20px
font-size: 12px
```

```js
// React component example
// app/javascripts/packs/hello_react.jsx

import React from 'react'
import helloIcon from '../hello_react/images/icon.png'
import styles from '../hello_react/styles/hello-react'

const Hello = props => (
<div className={styles.helloReact}>
<img src={helloIcon} alt="hello-icon" />
<p>Hello {props.name}!</p>
</div>
)
```

**Note:** Declared class is referenced as object property in JavaScript.


## Link styles from your Rails views

Expand Down
3 changes: 3 additions & 0 deletions lib/install/config/webpacker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ default: &default
- .sass
- .scss
- .css
- .module.sass
- .module.scss
- .module.css
- .png
- .svg
- .gif
Expand Down
3 changes: 3 additions & 0 deletions package/__tests__/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ describe('Webpacker.yml config', () => {
'.sass',
'.scss',
'.css',
'.module.sass',
'.module.scss',
'.module.css',
'.png',
'.svg',
'.gif',
Expand Down
44 changes: 6 additions & 38 deletions package/rules/css.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,7 @@
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const path = require('path')
const { dev_server: devServer } = require('../config')
const styleRuleFactory = require('./style_rule_factory')

const postcssConfigPath = path.resolve(process.cwd(), '.postcssrc.yml')
const isProduction = process.env.NODE_ENV === 'production'
const inDevServer = process.argv.find(v => v.includes('webpack-dev-server'))
const isHMR = inDevServer && (devServer && devServer.hmr)
const extractCSS = !(isHMR) || isProduction

const styleLoader = {
loader: 'style-loader',
options: {
hmr: isHMR,
sourceMap: true
}
}

const extractOptions = {
fallback: styleLoader,
use: [
{ loader: 'css-loader', options: { minimize: isProduction, sourceMap: true, importLoaders: 2 } },
{ loader: 'postcss-loader', options: { sourceMap: true, config: { path: postcssConfigPath } } }
]
}

// For production extract styles to a separate bundle
const extractCSSLoader = {
test: /\.(css)$/i,
use: ExtractTextPlugin.extract(extractOptions)
}

// For hot-reloading use regular loaders
const inlineCSSLoader = {
test: /\.(css)$/i,
use: [styleLoader].concat(extractOptions.use)
}

module.exports = extractCSS ? extractCSSLoader : inlineCSSLoader
module.exports = styleRuleFactory(
/\.(css)$/i,
false,
[]
)
4 changes: 4 additions & 0 deletions package/rules/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ const babel = require('./babel')
const file = require('./file')
const css = require('./css')
const sass = require('./sass')
const moduleCss = require('./module.css')
const moduleSass = require('./module.sass')

module.exports = {
babel,
css,
sass,
moduleCss,
moduleSass,
file
}
7 changes: 7 additions & 0 deletions package/rules/module.css.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const styleRuleFactory = require('./style_rule_factory')

module.exports = styleRuleFactory(
/\.(css)$/i,
true,
[]
)
10 changes: 10 additions & 0 deletions package/rules/module.sass.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const styleRuleFactory = require('./style_rule_factory')

module.exports = styleRuleFactory(
/\.(scss|sass)$/i,
true,
[{
loader: 'sass-loader',
options: { sourceMap: true }
}]
)
17 changes: 6 additions & 11 deletions package/rules/sass.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
const cssLoader = require('./css')
const deepMerge = require('../utils/deep_merge')
const styleRuleFactory = require('./style_rule_factory')

// Duplicate and remove css loader object reference
let sassLoader = JSON.parse(JSON.stringify(cssLoader))

sassLoader = deepMerge(sassLoader, {
test: /\.(scss|sass)$/i,
use: [{
module.exports = styleRuleFactory(
/\.(scss|sass)$/i,
false,
[{
loader: 'sass-loader',
options: { sourceMap: true }
}]
})

module.exports = sassLoader
)
60 changes: 60 additions & 0 deletions package/rules/style_rule_factory.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const path = require('path')
const { dev_server: devServer } = require('../config')

const postcssConfigPath = path.resolve(process.cwd(), '.postcssrc.yml')
const isProduction = process.env.NODE_ENV === 'production'
const inDevServer = process.argv.find(v => v.includes('webpack-dev-server'))
const isHMR = inDevServer && (devServer && devServer.hmr)
const extractCSS = !(isHMR) || isProduction

const styleRuleFactory = (test, modules, preprocessors) => {
const styleLoader = {
loader: 'style-loader',
options: {
hmr: isHMR,
sourceMap: true
}
}

const extractOptions = {
fallback: styleLoader,
use: [
{
loader: 'css-loader',
options: {
minimize: isProduction, sourceMap: true, importLoaders: 2, modules
}
},
{
loader: 'postcss-loader',
options: {
sourceMap: true, config: { path: postcssConfigPath }
}
},
...preprocessors
]
}

const modulesCondition = modules
? { include: /\.module\.[a-z]+$/ }
: { exclude: /\.module\.[a-z]+$/ }

// For production extract styles to a separate bundle
const extractCSSLoader = Object.assign(
{},
{ test, use: ExtractTextPlugin.extract(extractOptions) },
modulesCondition
)

// For hot-reloading use regular loaders
const inlineCSSLoader = Object.assign(
{},
{ test, use: [styleLoader].concat(extractOptions.use) },
modulesCondition
)

return extractCSS ? extractCSSLoader : inlineCSSLoader
}

module.exports = styleRuleFactory
3 changes: 3 additions & 0 deletions test/test_app/config/webpacker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ default: &default
- .sass
- .scss
- .css
- .module.sass
- .module.scss
- .module.css
- .png
- .svg
- .gif
Expand Down

0 comments on commit 88ff79c

Please sign in to comment.