Thanks for your awesome tool.
parcel document gives a brief introduction to CSS Modules but I stuck at my first try to use it:
// Import a CSS file with CSS modules
import classNames from './test.css';
I quickly cloned a demo project, add node-sass
, import index.scss
as CSS Modules and want to see how it works but unfortunately it doesn't work.
Minimal example to reproduce: https://github.com/micooz/react-parcel-example/commit/44e8c2bdb6181476af308f66397cfc3b715fee2a
Why
I guess require
does a wrong thing when interpret scss or css file as CSS Modules, it just returns an empty object here:
// bundle.js
var _index = require("./index.scss"); // {}
var _index2 = _interopRequireDefault(_index); // {default: {}}
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var App = function App() {
return _react2.default.createElement(
"div",
{ className: _index2.default.app },
"Hello Parcel x React"
);
};
Currently, you need to install postcss-modules
in your app, and add this to your .postcssrc
file:
{
"modules": true
}
This is documented briefly at https://parceljs.org/transforms.html#postcss. It's necessary to do this because we don't want to include the classes in the JS bundle by default for people that aren't using CSS modules.
Perhaps there is a better way we could detect CSS modules so we don't need to require that configuration (e.g. based on import statements maybe), so open to suggestions there.
Thanks for your help, problem resolved.
@micooz I tried it too but it didn't work, even after cloning your repo and adding the postCss. Do you mind creating a commit with the working version and post here the hash so I can clone it and see it working? Thx
@meiriko Here it is: https://github.com/micooz/react-parcel-example/commit/77d495992645733881156c276b56cd53f50b0187
You may need to upgrade parcel-bundler
to v1.0.3 to make it work.
Using the example provided by @micooz (and in my own testing), the styles seem to be removed as soon as the module hot reloads, and are not re-applied even on refresh.
Almost the same as @Jayphen here, global styles are applied when the module hot-reloads, local ones do not, but when I refresh the page they are applied normally.
I am getting the same results as @Jayphen and @thomasfortes, except I am using Stylus.
module.exports = {
modules: true,
}
import React from 'react'
import {render} from 'react-dom'
import styles from './index.styl'
console.log(styles)
const App = () => <div className={styles.app}>Hello from React!</div>
render(<App />, document.getElementById('root'))
.app {
font-family: sans-serif;
}
When I run parcel src/index.html
, the app logs an empty object: {}
. However when I produce the production bundle with parcel bundle src/index.html
, it loads the styles correctly.
I am using [email protected].
Hi, I meet @jrop same problem here but seems it is a problem with hot reload. When I start with parcel --no-hmr src/index.html, it works as expected.
I've noticed that when the --no-hmr flag is set that the css classes are transpiled correctly, and without the flag, the class names are the same as they are in source.
With hot modules: .root
WIthout: hot modules ._root_17swk_1
Thanks @g33kChris. That piece of knowledge did it for me. Just use the name of the class itself, not the imported classname. That confused me a bit, especially since my IDE was complaining about the unused import statement for the css file.
Is there a way to tell postcss to only transform ".css" files to css modules and not e.g. ".scss" files? Like an "input": "src/**/*.css"
property in the .postcssrc
file?
@devongovett not sure it's the same. But I'm still getting similar error saying:
even after adding "postcss-modules" along with suggested postcss settings, everything things worked before with the same setup (without postcss-modules & relative settings).
node v9.5.0
parcel v1.6.2
It turned out its caused by less
, getting back to v2 from v3 help solved the issue.
Is there a way to tell the Bundler
to disable HMR? Trying to use the fix @azzgo suggested, but I'm using Parcel as middleware with express so that I can proxy API calls.
In the long term, I assume fixing HMR mode so that it respects CSS Modules naming is the fix...
UPDATE:
The API docs for Bundler
don't seem to show it, but it looks like there is an hmr
parameter within options that does the trick:
import ParcelBundler from 'parcel-bundler'
import express from 'express'
import proxy from 'http-proxy-middleware'
const parcel = new ParcelBundler('./static/index.html', { hmr: false })
const app = express()
app.use('/api', proxy({ target: 'http://localhost:8000' }))
app.use(parcel.middleware())
app.listen(Number(process.env.UI_PORT || 1234))
Again, this is a temporary fix until HMR with CSS Modules is fixed.
Currently, you need to install
postcss-modules
in your app, and add this to your.postcssrc
file:{ "modules": true }
This is documented briefly at https://parceljs.org/transforms.html#postcss. It's necessary to do this because we don't want to include the classes in the JS bundle by default for people that aren't using CSS modules.
Perhaps there is a better way we could detect CSS modules so we don't need to require that configuration (e.g. based on import statements maybe), so open to suggestions there.
It seems like you are implying that there's a significant overhead when importing classNames, in terms of bundle size and processing time. What other reason might be there not to make it a default? I love Parcel it offers great defaults and I'm sure I'm not the only one. CSS Modules are great default imo.
@devongovett
Perhaps there is a better way we could detect CSS modules so we don't need to require that configuration (e.g. based on import statements maybe), so open to suggestions there.
You could do it the way https://poi.js.org/ does it, *.module.(css|scss|less)
. That way it's not an all or nothing approach.
Parcel just works... unless you use something basic like CSS, then it requires complex configurations
I landed on this question too after thinking that CSS Modules was broken somehow. I think my confusion stemmed from the fact that on the docs page for CSS, it says up top that:
CSS assets can be imported from a JavaScript or HTML file:
import './index.css';
But then it's clarified below that you need to install PostCSS if you want it to work.
On my first read-through, it seemed like I only needed to install PostCSS if I wanted to use plugins like autoprefixer. I assumed based on the info at the top that if I just wanted to import a plain CSS file in Javascript, it would 'just work'.
Also, even after installing PostCSS and creating a postcssrc file, my modules didn't work. I had to find another closed Github issue which told me to clear the .cache
directory, and then it worked. Can we clarify the documentation a bit to make that step more explicit?
@DeMoorJasper Is .postcssrc even being handled like .babelrc regarding cache invalidation?
Not to undermine the purpose of this issue... I recommend a css-in-js solution instead of a style sheet. I use typestyle but there are others. Just a friendly tip. For most new app development cases.
Managed to succeed thanks to @micooz
Guys, css modules in parcel for some reason don't work without autoprefixer installed and added to .postcssrc
is using the --no-hmr
flag still the only way to make css modules behave correctly?
My bad, installing autoprefixer
and postcss-modules
into the correct package.json does indeed resolve it, even with hot reload
Most helpful comment
Currently, you need to install
postcss-modules
in your app, and add this to your.postcssrc
file:This is documented briefly at https://parceljs.org/transforms.html#postcss. It's necessary to do this because we don't want to include the classes in the JS bundle by default for people that aren't using CSS modules.
Perhaps there is a better way we could detect CSS modules so we don't need to require that configuration (e.g. based on import statements maybe), so open to suggestions there.