Building server part of (React) isomorphic webapp with webpack including style-loader for CSS

試著忘記壹切 提交于 2019-12-19 10:39:22

问题


I am attempting to make a React application that I am developing isomorphic. One of the known problems with doing this is that webpack loaders allow import/require of non-javascript assets such as CSS files. e.g.

// ExampleComponent.jsx
import Select from 'react-select';
import 'react-select/dist/react-select.css';

If building an application with Express then node will get to this import and fail because it can not process a CSS file, it is expecting javascript only (and thanks to babel-register JSX).

One of the ways around this is to use the target: 'node' option in webpack when building the server application (which includes all the common parts such as the components as it is an isomorphic app) to build the server side code. This should result in a server.js being built that can then be run by node.

Note: I know that there are other ways around this particular problem (such as not using import/require to include anything that isn't javascript, but that isn't practical at this stage of development in this application.

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

module.exports = [
  // Client build
  {
    entry: {
      'bundle.min': [
        'bootstrap-webpack!./bootstrap.config.js',
        'babel-polyfill',
        './client/index.jsx'
      ],
      'bundle': [
        'bootstrap-webpack!./bootstrap.config.js',
        'babel-polyfill',
        './client/index.jsx'
      ]
    },
    output: {
      path: './dist',
      filename: '[name].js'
    },
    plugins: [
      new webpack.optimize.UglifyJsPlugin({
        include: /\.min\.js$/,
        minimize: true
      })
    ],
    module: {
      loaders: [
        {
          test: /\.jsx$/,
          loader: 'babel-loader',
          exclude: /node_modules/,
          query: {
            plugins: ['transform-runtime'],
            presets: ['react', 'es2015', 'stage-0']
          }
        },
        {
          test: /\.js$/,
          loader: 'babel-loader',
          exclude: /node_modules/,
          query: {
            plugins: ['transform-runtime'],
            presets: ['es2015', 'stage-0']
          }
        },
        {
          test: /\.css$/,
          loader: 'style-loader!css-loader'
        },
        { test: /\.png$/,
          loader: "url-loader?limit=100000"
        },

        // Bootstrap
        {
          test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/,
          loader: 'url?limit=10000&mimetype=application/font-woff'},
        {
          test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
          loader: 'url?limit=10000&mimetype=application/octet-stream'
        },
        {
          test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
          loader: 'file'
        },
        {
          test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
          loader: 'url?limit=10000&mimetype=image/svg+xml'
        }
      ]
    },
    resolve: {
      extensions: ['', '.js', '.jsx', '.json']
    }
  },

  // Server build
  {
    entry: './server/server.jsx',
    target: 'node',
    node: {
      console: false,
      global: false,
      process: false,
      Buffer: false,
      __filename: false,
      __dirname: false,
    },
    output: {
      path: './dist',
      filename: 'server.js',
    },
    module: {
      loaders: [
        {
          test: /\.jsx$/,
          loader: 'babel-loader',
          exclude: /node_modules/,
          query: {
            plugins: ['transform-runtime'],
            presets: ['react', 'es2015', 'stage-0']
          }
        },
        {
          test: /\.js$/,
          loader: 'babel-loader',
          exclude: /node_modules/,
          query: {
            plugins: ['transform-runtime'],
            presets: ['es2015', 'stage-0']
          }
        },
        {
          test: /\.json$/,
          loader: 'json-loader'
        },
        {
          test: /\.css$/,
          loader: 'style-loader!css-loader'
        },
        { test: /\.png$/,
          loader: "url-loader?limit=100000"
        },

        // Bootstrap
        {
          test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/,
          loader: 'url?limit=10000&mimetype=application/font-woff'},
        {
          test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
          loader: 'url?limit=10000&mimetype=application/octet-stream'
        },
        {
          test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
          loader: 'file'
        },
        {
          test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
          loader: 'url?limit=10000&mimetype=image/svg+xml'
        }
      ]
    },
    resolve: {
      extensions: ['', '.js', '.jsx', '.json']
    }
  }
];

The problem is then that the style-loader makes use of window which obviously does not exist in the node environment.

$ node dist/server.js
/Users/dpwrussell/Checkout/ExampleApp/dist/server.js:25925
            return /msie [6-9]\b/.test(window.navigator.userAgent.toLowerCase());
                                       ^

ReferenceError: window is not defined

From here in style-loader.

It feels like I am very close to making this work so any thoughts would be welcome.


回答1:


The answer is not to use style-loader in your server build: its sole purpose is to take CSS, turn it into a <style> element, and insert it into the DOM. Most people seem to use the ExtractTextPlugin to collect their CSS for inclusion on the server side.



来源:https://stackoverflow.com/questions/36020514/building-server-part-of-react-isomorphic-webapp-with-webpack-including-style-l

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!