1

I am building an isomorphic react-redux app on top of NodeJS. I am rendering my homePage from the server. However, my styles are not reflected in my rendered view. I would like to import stylesheets just how I do it on the client side. I tried this article and this too, but neither of them actually got me what I want to achieve.

Here are more details on the project.

.babelrc

{
 "presets": [ "es2015", "react", "stage-0"],
 "plugins": ["transform-decorators-legacy", ["transform-assets", {
            "extensions": ["scss"],
            "name": "[name].[ext]?[sha512:hash:base64:7]",
          }]]
 }

webpack.config.js

const path = require('path');
module.exports = [
    {
      name: 'client',
      target: 'web',
      entry: './routes/client.jsx',
      output: {
        path: path.join(__dirname, 'assets'),
        filename: 'client.js',
        publicPath: '/assets/',
      },
      resolve: {
        extensions: ['.js', '.jsx']
      },
      devtool: 'source-map',
      module: {
        rules: [
            {
                test: /\.(js|jsx)$/,
                exclude: /(node_modules\/)/,
                use: [{ loader: 'babel-loader'}]
            },
            {
                test: /\.scss$/,
                use: [
                    { loader: 'isomorphic-style-loader' },
                    {
                        loader: 'css-loader',
                        options: {
                            modules: true,
                            importLoaders: 1,
                            localIdentName: '[name]__[local]___[hash:base64:5]',
                            sourceMap: true
                        }
                    },
                    { loader: 'sass-loader'}
                ]
            }
        ],
    },
}];

server.js

import express from 'express'
import React from 'react'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import MainStore from './views/store/MainStore'
import { StaticRouter } from 'react-router-dom';
import Routes from './routes/routes';
import Template from './views/templates/template';
import { Helmet } from 'react-helmet';
import { renderToString } from 'react-dom/server'
import ReactDOMServer from 'react-dom/server';
import ContextProvider from './routes/contextProvider'

const webpackDevMiddleware = require('webpack-dev-middleware')
const config = require('./webpack/webpack.development.config.js')
const webpack = require('webpack')
const app = express()
const port = 3000
const compiler = webpack(config);

let preloadedState = { shipper: {view: "from_server"} }

app.use('/assets', express.static('./assets'))
app.use(webpackDevMiddleware(compiler, {
   publicPath: "/assets/",
}));

app.use(handleRender);

function handleRender(req, res) {
   // Create a new Redux store instance
   const store = createStore(MainStore, preloadedState)
   const css = new Set(); // CSS for all rendered React components
   const context = { insertCss: (...styles) => styles.forEach(style =>   
   css.add(style._getCss())) }

   const html = renderToString(
     <Provider store={store}>
        <StaticRouter context={context}>
            <ContextProvider context={context}>
            <Routes />
        </ContextProvider>
        </StaticRouter>
     </Provider>
  )
  const finalState = store.getState()
  const helmet = Helmet.renderStatic();
  const preloadedState = store.getState()
  res.send(renderFullPage(html, preloadedState));
 }

 function renderFullPage(html, finalState) {
    return `
      <!doctype html>
      <html>
         <head>
            <title>Redux Universal Example</title>
            <style type="text/css">${[...css].join('')}</style>
         </head>
         <body>
             <div id="root">${html}</div>
             <script>
                window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState).replace(/</g, '\\u003c')}
             </script>
             <script src="./assets/client.js"></script>
         </body>
    </html>
    `
  }

app.listen(port)

contextProvider.js

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Routes from './routes.jsx';

export default class ContextProvider extends Component {
   static childContextTypes = {
   insertCss: PropTypes.func,
}

 getChildContext() {
    return { ...this.props.context }
  }

 render() {
    const { children, ...props } = this.props
    return React.cloneElement(children, props)
  }
}

I am importing it in my homePresenter as

import homePageStyle from './home.scss';

and using it in my div in the same component as

<div className="component">

If I change this to

<div className={homePageStyle.component}>

I get an error on the browser

TypeError: style._getCss is not a function at server.js:52:84

On the browser, I could see that the div has class name as 'component'; it;'s just it is not inheriting the styles.

Any suggestions on what I am missing here?

2
  • 1
    did you use import withStyles from 'isomorphic-style-loader/lib/withStyles'; in your react component? Commented Dec 1, 2017 at 3:13
  • @Umesh Thank you for the lead. I inserted, but I am now running into a different issue. I followed the process here github.com/kriasoft/isomorphic-style-loader/issues/110 and github.com/kriasoft/react-starter-kit/issues/378 and according to the documentation of isomorphic-style-loader, isomorphic-style-loader provides two helper methods on to the styles object - ._insertCss() (injects CSS into the DOM) and ._getCss() (returns a CSS string). I am however getting the error "TypeError: style._getCss is not a function at server.js:52:84" Commented Dec 1, 2017 at 15:54

1 Answer 1

-1

TypeError: style._getCss is not a function at server.js:52:84

Most likely that server-side rendering is not configured properly. If you are not using webpack for compiling server-side bundle, of course, appropriate styles will not loaded, since isomorphic-style-loader had not processed files on server-side.
Check how application is started and ensure, that webpack had been applied for server-bundle and configuration was like this: https://webpack.js.org/configuration/node/
Also you can try ready isomorphic solution with frontend+backend bundling and includes css support, like resolve-app.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.