catamphetamine / webpack-isomorphic-tools

Server-side rendering for your Webpack-built applications (e.g. React)
MIT License
1.25k stars 48 forks source link

Is it possible to have _style property in production using ExtractTextPlugin loader #146

Closed rolele closed 7 years ago

rolele commented 7 years ago

I want to have the _style property in production mode (with ExtractTextPlugin) This will allow me to compute the minimal css to inline on my page and move the <link async src> tag in the body of my page. I do not want my backend to do an http request to get the css on another server while doing the rendering. I would like to have all the necessary information in my webpack-assets.json but I did not find a way to have the _styleproperty with the ExtractTextPlugin (in production mode)

(I am doing all my tests using this boilerplate: https://github.com/bertho-zero/react-redux-universal-hot-example )

I use a basic isomorphic config such as: https://github.com/bertho-zero/react-redux-universal-hot-example/blob/2eb667b13f407b7770ba525158f8253f74171369/webpack/webpack-isomorphic-tools.js

If I display the assets property of the webpack-asset object in DEV mode (notice the _style property):

 console.log(assets.assets)
>>>
   './src/components/InfoBar/InfoBar.scss':
    { infoBar: 'infoBar___3d8nt',
      time: 'time___3yoCl',
      _style: '.infoBar___3d8nt {\n  font-variant: italics;\n}\n\n.time___3yoCl {\n  margin: 0 30px;\n}\n' },
   './src/containers/App/App.scss':
    { app: 'app___1CDKx',
      brand: 'brand___2_gfF',
      appContent: 'appContent___2DqeY',
      notifs: 'notifs___3IABw',
      _style: '.app___1CDKx .brand___2_gfF {\n  position: absolute;\n  top: 5px;\n  left: 5px;\n  display: inline-block;\n  background: #2d2d2d url(...)

In production mode, because we use the ExtractTextPlugin and not the style-loader the object will look like this:

"./src/components/InfoBar/InfoBar.scss":
{"infoBar":"_3d8ntS2imXIVxEC2yKiwag","time":"_3yoClH_zzzxTCuZQR68tjo"},
"./src/containers/App/App.scss":
{"app":"_1CDKxYcBPvNzbxt05cMe_M","brand":"_2_gfFF2uRFcQMbLWyVPrQt","appContent":"_2DqeYkGZpzEPRwi6pHnoBY","notifs":"_3IABwkRcS1Uc2Pn0vx7p25"},

I lost the _style property because the config is:

parser: function (module, options, log) {
        if (options.development) {
          return WebpackIsomorphicToolsPlugin.css_modules_loader_parser(module, options, log);
        } else {
          // in production mode there's Extract Text Loader which extracts CSS text away
          return module.source;
        }
      }

If I remove the conditional like this:

parser: function (module, options, log) {
          return WebpackIsomorphicToolsPlugin.css_modules_loader_parser(module, options, log);
      }

and re-run a build I will get something like this:

"./src/components/InfoBar/InfoBar.scss":{"_style":"[object Object]"},
"./src/containers/App/App.scss":{"_style":"[object Object]"},

probably because webpack isomorphic tools expect style-loader to run at that stage.

Basicaly, what config do I need to save the styles on the webpack-assets.json while using ExtractTextPlugin ?

catamphetamine commented 7 years ago

Yeah, I guess you'll have to make up your own parser for your use case.

The original function is

// a sample module source parser for webpack css-loader
// (with css-loader "modules" feature support)
Webpack_isomorphic_tools_plugin.css_modules_loader_parser = function(module, options, log)
{
    return module.source + '\n module.exports = exports.locals || {}; module.exports._style = exports.toString();'
}

Play with the module variable to see if the raw styles are available (could be module.exports.~~something~~). Anyway the thing you're doing is not so relevant since HTTP v2 uses the same single connection for multiple HTTP requests to the server so bundling is becoming outdated nowadays.

catamphetamine commented 7 years ago

You could also try something like return 'module.exports = JSON.stringify(exports)'. exports is a runtime Webpack variable and parser uses exports to obtain the data from it.