css-modules / css-modules-require-hook

A require hook to compile CSS Modules in runtime
MIT License
484 stars 44 forks source link

Usage in production and includePaths #69

Open tmaximini opened 8 years ago

tmaximini commented 8 years ago

Hey! I have two questions:

First I have a hard time thinking about if and how to use this hook in production. I am using webpack with css modules for the client side and this require hook on the server side when doing server side rendering of react components. In my production environment I am planning to use ExtractTextPlugin to extract all the css. Currently we are still in development.

What I notice so far is that the require hook is setting the correct classes but it does not include any generated css in the server rendered templates. So I actually get flashes of unstyled content until client side (webpack) picks up, which then inlines the styles into the html. Is this expected behaviour? Also are there any performance hogs to be expected in production (compiling scss in runtime sounds like it). What is best practice here for setting up this hook for both development and production?

second question:

I have lots of components and lots of scss files. In these files I am importing most of the times other .scss files such as variables and mixins from a shared folder. Webpack allows a configuration for modulesDirectories, similar to this hook's includePaths.

The problem is, that with webpack I have to prepend imports from these custom directories with a tilde. e.g.: @import '~styles/variables'; instead of @import '../../../../styles/variables';

The tilde prefix breaks this require hook, here it would work with just @import 'styles/variables'; Any idea how to solve this?

Here is my current setup:

const cssRequireHook = require('css-modules-require-hook');
const sass = require('node-sass');
const path = require('path');
const nameScope = process.env.NODE_ENV === 'test' ? '[local]' : '[name]__[local]___[hash:base64:5]';

cssRequireHook({
    generateScopedName: nameScope,
    extensions: ['.scss', '.css'],
    preprocessCss: (data, filename) => sass.renderSync({
        data,
        file: filename,
        includePaths: [path.resolve(__dirname, '../../client')]
    }).css
});
wuct commented 8 years ago

I have same questions and still try to figure out the best solution.

In addition to modulesDirectories, I also want to know how to handle the reslove.alias of webpack's config.

tmaximini commented 8 years ago

From my experience so far:

1) It is definitely okay to use this hook in production. You can check the actual compile times when you run your server with DEBUG=css-modules:*. This shows that the first render is actually pretty slow as all the css modules are compiled in run-time but all subsequent requests are being served from cache and so we decided it is feasable to run this in production.

2) As modulesDirectories is a webpack feature I found it to be not possible to do server-side rendering of css-modules using this feature, and so our team decided to always use relative paths for requiring styles.

Hope that helps.

wuct commented 8 years ago

@tmaximini Thanks for answering. There are useful information.

mightyaleksey commented 8 years ago

@tmaximini @wuct sorry guys for the late call. I'll try to answer according to my experience.

I don't see any problem to use it in production, since it extends the default require function. By default Node.js caches all the require calls, so it will be slow on the start (since you need to extract tokens from all the require calls). I think, I can boost it a little better in future by caching all the calls betweens sessions.

What I notice so far is that the require hook is setting the correct classes but it does not include any generated css in the server rendered templates. So I actually get flashes of unstyled content until client side (webpack) picks up, which then inlines the styles into the html. Is this expected behaviour?

Can you describe the problem a bit more detailed?

Talking about second question. Currently, there is no support for ~ in paths, as you mentioned, but if all such calls take place in CSS it should be possible to support. I'm not familiar with sass, but with postcss it can be solve easily. Unfortunately in that case you'll have to preprocess all the files three times — with postcss, sass and postcss again. Presumably that problem can be solved with sass also. Looks like importer option provides possibility to add some heuristic to the path resolving mechanic. Have you tried it?

Talking about webpack resolve.alias — I do see any good possibility to add it currently. Still you may checked the NODE_PATH global variable. It doesn't provide any possibility to rename modules, but it allows you to add the custom folders in which modules will be looked for.

tmaximini commented 8 years ago

thanks @sullenor Regarding that comment that you quoted, the unstyled content came from different generated hashs on webpack compilation and require-hook compilation, due to different folder structure (transpiled server code into a /dist subfolder for production). I fixed this by using rootDir in the hook and context in the css-loader. This issue can be closed from my side if you wish.

mightyaleksey commented 8 years ago

@tmaximini yeah, I got it, thank you.

I wonder if I add any adapter to support sass, will it be useful for you? And what kind of configuration would you like to see in it?

Jezternz commented 7 years ago

Regarding the flashes, I was able to solve this by following the directions in https://github.com/css-modules/css-modules-require-hook/issues/53.

figalex commented 7 years ago

@tmaximini @Jezternz I'm having the same problem with unstyled server side rendered content. I did not understand what was your solution to that problem and the small example provided on this repo uses ExtractTextPlugin on webpack config but I don't want to use this plugin on development.

Could you please show me what is your webpack configuration? Are you using webpack for both server and client side code?

Jezternz commented 7 years ago

@figalex Not sure if this will help you, but this is what I use (for my universal react app - used for both development/production)

figalex commented 7 years ago

@Jezternz Thanks! with this setup are you able to automatically reload styles when you change a css file?

Jezternz commented 7 years ago

@figalex Just checked and I apologise, it does not seem to be doing that. Strangely it registers the change and even sends a notification to client, but the style doesn't update.