gajus / babel-plugin-react-css-modules

Transforms styleName to className using compile time CSS module resolution.
Other
2.05k stars 162 forks source link

Is `composes` supposed to work? #192

Closed bitttttten closed 5 years ago

bitttttten commented 6 years ago
/* PageTitle.css */
.root {
    composes: h2 from '../../theme/type.css';
    color: #147C3F;
    padding: 1.6rem 0;
}
/* theme/type.css */
.heading {
    line-height: 1.2em;
    text-align: center;
    font-weight: bold;
    letter-spacing: 0.8px;
    text-transform: uppercase;
}

.h2 {
    composes: heading;
    font-size: 2.4rem;
}

My class name is correct: <h2 class="PageTitle_root theme_h2 theme_heading">Shopping</h2>. However the CSS is not:

/* theme/type.css */
._2mTJYElVgbS7n2ZX_6poxK{line-height:1.2em;text-align:center;font-weight:700;letter-spacing:.8px;text-transform:uppercase}
.euz7EGBHQkfc-E5dtLq7b{font-size:38.4px;font-size:2.4rem}

/* PageTitle.css */
.PageTitle_root{color:#147c3f;padding:25.6px 0;padding:1.6rem 0}

As you can see, the PageTitle CSS is generating the class name correctly, but the theme/type.css file is not. What's up with that?

My config is this:

// Process JS with Babel.
{
    test: /\.(js|jsx|mjs)$/,
    include: paths.appSrc,
    loader: require.resolve('babel-loader'),
    options: {
        // This is a feature of `babel-loader` for webpack (not Babel itself).
        // It enables caching results in ./node_modules/.cache/babel-loader/
        // directory for faster rebuilds.
        cacheDirectory: false,
        plugins: [
            'transform-decorators-legacy',
            'react-loadable/babel',
            ['react-css-modules', {
                context: paths.appSrc,
                generateScopedName,
                webpackHotModuleReloading: false,
                attributeNames: {
                    activeStyleName: 'activeClassName'
                }
            }]
        ]
    },
},
gajus commented 6 years ago

Whats the definition of generateScopedName?

bitttttten commented 6 years ago

Oh sorry, I tried to include as much as I can. I took this function from this medium article and changed it slightly.

const incstr = require('incstr')
const path = require('path')

const createUniqueIdGenerator = () => {
    const index = {}

    const generateNextId = incstr.idGenerator({
        alphabet: 'abcdefghijklmnopqrstuvwxyz0123456789'
    })

    return (name) => {

        if (index[name]) {
            return index[name]
        }

        let nextId

        // class name cannot start with a number
        // and it cannot start with 'ad' otherwise adblocks will hide the element
        do {
            nextId = generateNextId()
        } while (/^[0-9]/.test(nextId) || /^ad/.test(nextId))

        index[name] = process.env.NODE_ENV === 'development'
            ? `${name}-${nextId}`
            : nextId

        return index[name]
    }
}

const uniqueIdGenerator = createUniqueIdGenerator()

const generateScopedName = (localName, resourcePath) => {
    let componentName = resourcePath.split(path.sep).slice(-2, -1)

    if (componentName === "theme") {
        componentName = `${componentName}.${resourcePath.split(path.sep).slice(-1, -1)}`
    }

    return `${uniqueIdGenerator(componentName)}_${uniqueIdGenerator(localName)}`
}

and my .babelrc

{
    "presets": [
        ["env", {
            "modules": false,
            "targets": {
                "browsers": ["> 0.5%"]
            }
        }],
        "stage-2",
        "react"
    ],
    "env": {
        "server": {
            "presets": [["env", {
                "targets": {
                    "node": "8.9.1"
                }
            }], "react"],
            "plugins": [
                "transform-decorators-legacy",
                "transform-class-properties",
                "react-loadable/babel"
            ]
        }
    }
}
bitttttten commented 6 years ago

And also my css-loader config:

{
    test: /\.css$/,
    use: [
        {
            loader: require.resolve('style-loader'),
            options: {
                insertInto: 'body',
            },
        },              
        {
            loader: require.resolve('css-loader'),
            options: {
                importLoaders: 1,
                modules: true,
                getLocalIdent: (context, localIdentName, localName) => {
                    return generateScopedName(localName, context.resourcePath)
                },
            },
        },
        {
            loader: require.resolve('postcss-loader'),
        },
    ],
},
bitttttten commented 6 years ago

Perhaps it is my local set up that is incorrect. If I remove getLocalIdent from the css-loader and generateScopedName from react-css-modules config composes is still not working.

I see in the DOM:

<h2 class="components-PageTitle-___PageTitle__root___3fA2n theme-___type__h2___266vk theme-___type__heading___1anDN">Shopping</h2>

But in the CSS I see:

/* PageTitle.css */._3fA2nPANa1DNO1QapNXW1v{color:#147c3f;padding:25.6px 0;padding:1.6rem 0} /* theme/type.css */._1anDNxYVFvlSql6C1Bryx5{...}

If you are still interested, I can give you a repo to check out?

Edit: I see you need to match them so I understand why this doesn't work lol. Although my first question and the offer to share a reproduceable repo still stands.

gajus commented 5 years ago

Probably duplicate of: