Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React: Inline CSS modules in JSX with Webpack

I have a minimal React component which consists of two files: button.jsx and button.less. The styles are imported and the class names are appended with a hash to make all styles local to the component.

This is great, but i'd like to have all component code in one file. Is it possible to inline the styles in jsx file without losing css modularity?

Current Code

button.jsx

import React from 'react';
import styles from './button.less'

export default class Button extends React.Component {
    render() {
        return <button className={styles.primary}>{this.props.text}</button>;
    }
}

button.less

@import '~semantic-ui/src/definitions/elements/button.less';

.common {
    composes: ui button;
}

.primary {
    composes: common primary;
}

webpack.config.js (relevant bits)

module: {
    loaders: [
        {
            test: /\.jsx$/,
            loader: 'babel'
        },

        {
            test: /\.less$/,
            loader: "style!css?modules&importLoaders=1!less"
        }
    ]
},

What i'd like to write instead

button.jsx

<style lang="less" modules>
    @import '~semantic-ui/src/definitions/elements/button.less';

    .common {
        composes: ui button;
    }

    .primary {
        composes: common primary;
    }
</style>

import React from 'react';

export default class Button extends React.Component {
    render() {
        return <button className={styles.primary}>{this.props.text}</button>;
    }
}

Inspired by vue.js and vue-loader.

I believe this is a duplicate of this unanswered question: Using css-loader inline with Webpack + React

like image 925
Alp Avatar asked Jan 16 '16 20:01

Alp


2 Answers

I wrote a Webpack loader for this very purpose:

https://github.com/chrisdavies/stylextract-loader

It allows you to write a single style tag per JSX file and it supports webpack CSS modules, too, if you want.

At build time, it extracts the rules from your style tag and moves them out to an external CSS file.

I should note that because it simply extracts your rules out to an external CSS file, it plays nice with SASS, autoprefixer, etc

like image 164
Christopher Davies Avatar answered Oct 19 '22 13:10

Christopher Davies


You can use callback-loader for this. This is actualy a workaround, but it do the trick. Just implement a callback which will extract your css-code and replace it with appropriate import. For example:

webpack.config.js

var fs = require('fs');
var cssIndex = 0;
// Do not forget to create and clean temporary folder "cssTemp" before
var webpackConfig = {
    ...
    resolve: {
        alias: {
            cssTemp: path.resolve('./cssTemp')
        }
    },
    module: {
        loaders: [
            { test: /\.jsx$/, loader: "callback!babel" }
        ]
    },
    callbackLoader: {
        cssCallback: function(code) {
            var filename = cssIndex + '.less';
            cssIndex++;
            // Save the css code from the callback argument
            fs.writeFileSync('./cssTemp/' + filename, code);
            // Return the import statement which will replace the callback statement
            return 'import styles from "cssTemp/' + filename + '";';
        }
    }
    ...
};

button.jsx

import React from 'react';
cssCallback(`
    @import '~semantic-ui/src/definitions/elements/button.less';

    .common {
        composes: ui button;
    }

    .primary {
        composes: common primary;
    }
`);

export default class Button extends React.Component {
    render() {
        return <button className={styles.primary}>{this.props.text}</button>;
    }
}
like image 44
Kreozot Avatar answered Oct 19 '22 15:10

Kreozot