0

I am build an isomorphic app using react, react-router, express and webpack. Now I want to use css modules to import css.

I use import './index.css' in index.jsx, it works fine on client, but doesn't work on server rendering. The error is Error: Cannot find module './index.css'.

components/index.jsx

import React, {Component, PropTypes} from 'react';
import style from './index.css';

class App extends Component {
    constructor(props, context) {
        super(props, context);
    }

    render() {
        return (
            <div id="login">
                 // ...
            </div>
        );
    }
};

export default App;

server/router/index.js

import url from 'url';
import express from 'express';
import swig from 'swig';
import React from 'react';
import {renderToString} from 'react-dom/server';
import {match, RouterContext} from 'react-router';

import routes from '../../client/routes/routes';
import DataWrapper from '../../client/container/DataWrapper';
import data from '../module/data';

const router = express.Router();

router.get('*', async(req, res) => {
  match({
    routes,
    location: req.url
  }, async(error, redirectLocation, props) => {
    if (error) {
      res.status(500).send(error.message);
    } else if (redirectLocation) {
      res.status(302).redirect(redirectLocation.pathname + redirectLocation.search);
    } else if (props) {
      let content = renderToString(
        <DataWrapper data={data}><RouterContext {...props}/></DataWrapper>
      );
      let html = swig.renderFile('views/index.html', {
        content,
        env: process.env.NODE_ENV
      });
      res.status(200).send(html);
    } else {
      res.status(404).send('Not found');
    }
  });
});

export default router;

webpack.config.dev.js(for webpack-dev-server)

var webpack = require('webpack');
var config = require('./config');

module.exports = {
    devtool: 'inline-source-map',
    entry: [
        'webpack-dev-server/client?http://localhost:' + config.webpackPort,
        'webpack/hot/only-dev-server',
        './src/client/entry',
    ],
    output: {
        path: __dirname + '/public/js',
        filename: 'app.js',
        publicPath: 'http://localhost:' + config.webpackPort + '/public/js',
    },
    plugins: [
        new webpack.HotModuleReplacementPlugin(),
        new webpack.NoErrorsPlugin(),
        new webpack.DefinePlugin({
            "process.env": {
                NODE_ENV: JSON.stringify('development')
            }
        })
    ],
    resolve: {
        extensions: ['', '.js', '.jsx', '.css']
    },
    module: {
        loaders: [{
            test: /\.jsx?$/,
            loader: 'react-hot',
            exclude: /node_modules/
        }, {
            test: /\.jsx?$/,
            loader: 'babel-loader',
            exclude: /node_modules/
        }, {
            test: /\.css$/,
            loader: 'style-loader!css-loader?modules',
            exclude: /node_modules/
        }, {
            test: /\.(png|woff|woff2|svg|ttf|eot)$/,
            loader: 'url-loader',
            exclude: /node_modules/
        }]
    }
}
4
  • 1
    I'm using the Isomorphic CSS style loader for Webpack in this case to render critical path CSS during server-side rendering. Commented Aug 14, 2016 at 10:50
  • @HiDeo Do you use react-router? Could you show me a demo maybe? I tried this loader but I have no idea how to handle the server side code. Commented Aug 14, 2016 at 10:52
  • Yes and there are many examples / starter, for example the React Isomorphic Starterkit use isomorphic-style-loader, react-router alongside server-side React rendering. Commented Aug 14, 2016 at 10:56
  • Since you are using css modules you should take a look on isomorphic css style loader - it's step to ultimate isomorphic boosted app. But be prepared for bundling node server code with webpack Commented Aug 14, 2016 at 14:59

2 Answers 2

1

I'd recommend using webpack to compile UI code for both client and server side in that case. Just set target: "node" in webpack config to produce bundle which can executed in Node environment.

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

Comments

0

That article might help for compiling your server side code with Webpack: http://jlongster.com/Backend-Apps-with-Webpack--Part-I Especially on how to exclude node_modules with the externals key.

A very bare config might look like:

'use strict';

const path = require('path');
const fs = require('fs');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

const rootDir = path.resolve(__dirname, '..');
const distDir = path.join(rootDir, 'dist');
const srcDir = path.join(rootDir, 'src');

const localStyles = new ExtractTextPlugin('local.css', { allChunks: true });

const nodeModules = fs.readdirSync('node_modules')
  .filter(dir => !dir.startsWith('.'))
  .reduce((acc, prop) => {
    acc[prop] = 'commonjs ' + prop;
    return acc;
  }, {});

const loaders = [
  {
    test: /\.(js|jsx)$/,
    include: srcDir,
    exclude: /node_modules/,
    loader: 'babel',
    query: {
      cacheDirectory: true,
    },
  },
  {
    test: /\.css$/,
    include: srcDir,
    loader: localStyles.extract(
      'style',
      'css?modules&localIdentName=[name]-[local]_[hash:base64:5]'
    ),
  },
  {
    test: /\.json$/,
    loader: 'json',
  },
];


module.exports = {

  target: 'node',

  entry: {
    server: ['server/index'],
  },

  output: {
    path: distDir,
    filename: '[name].bundle.js',
  },

  externals: nodeModules,

  module: {
    loaders,
  },

  plugins: [
    localStyles,
  ],

};

Another solution (Webpack free) could be to use babel-plugin-css-modules-transform .

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.