isomorphic-style-loader icon indicating copy to clipboard operation
isomorphic-style-loader copied to clipboard

TypeError: style._getCss is not a function

Open monarajhans opened this issue 7 years ago • 4 comments

Hi, 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 am getting "TypeError: style._getCss is not a function on server.js:52:84". What did I miss?

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)
      }
    }

Any suggestions on what I am missing here?

monarajhans avatar Dec 01 '17 15:12 monarajhans

Do you compile server-side code by webpack?

frenzzy avatar Dec 02 '17 14:12 frenzzy

@frenzzy Compiling it now, made the change to the script in my package.json as follows: "start": "webpack --config ./webpack/webpack.development.config.js && babel-node server.js" Still getting the same error.

monarajhans avatar Dec 02 '17 15:12 monarajhans

@frenzzy In server.js, on line

const context = { insertCss: (...styles) => styles.forEach(style => css.add(style._getCss()))

style is undefined, and hence ._getCss is returning not a function error.

monarajhans avatar Dec 04 '17 05:12 monarajhans

I guess you do not have configuration for server.js entry point in webpack.development.config.js, and you should run with node compiled script not the original one.

frenzzy avatar Dec 04 '17 08:12 frenzzy