SSR SCSS的Webpack配置

时间:2019-05-26 23:18:59

标签: reactjs webpack sass ssr

我有一个React-TypeScript SSR应用程序,在其中我使用SCSS文件进行样式设计。我需要在Webpack中编写一条规则来加载SCSS,但我还无法做到这一点。

我在网上找到了各种解决方案,所有这些解决方案都非常复杂,并且使用诸如mini-css-extract-plugin之类的东西。我无法让他们工作。

我目前有两个webpack配置文件,一个用于客户端(网络),一个用于服务器(节点),这两个文件都这样加载SCSS:

{
    test: /\.scss$/,
    use: ["css-loader", "sass-loader"]
}

我还遇到了另一个问题,因为它引发有关窗口对象的错误,所以我不能使用样式加载器。有没有人有在Webpack中加载SCSS的可行示例(最好是简单的示例)?

2 个答案:

答案 0 :(得分:1)

您在正确的2个Web配置文件上可以使用

https://gist.github.com/mburakerman/629783c16acf5e5f03de60528d3139af

但是不要在project.json中设置任何其他配置文件,例如babel.rc .yaml等或其他定义

尝试

        test: /\.scss$/,
        use: [
            MiniCssExtractPlugin.loader,
            'css-loader',
            'postcss-loader',
            'sass-loader'
        ]

// ..

plugins: [
    new MiniCssExtractPlugin({
        filename: 'assets/css/bundle-[contenthash].css',
        chunkFilename: 'assets/css/bundle-[contenthash].css'
    })
],

查看完整示例https://github.com/dewelloper/pzone/blob/master/webpack.config.store.js

答案 1 :(得分:0)

使用 reactwebpackSass 的服务器端渲染样板 (对于 css 模块和纯 sass)

webpack.config.js

const path = require('path');
const isDevelopment = true;

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

开发依赖:

npm i -D @babel/cli @babel/preset-es2015  @babel/core @babel/plugin-proposal-class-properties @babel/preset-env @babel/preset-react babel-core babel-loader babel-plugin-lodash babel-plugin-react-transform babel-preset-env babel-preset-es2015 babel-preset-react babel-preset-stage-0 css-loader express isomorphic-style-loader node-sass sass-loader style-loader webpack webpack-dev-middleware webpack-hot-middleware webpack-hot-server-middleware

和依赖项:

npm i react react-dom react-helmet react-router-dom

sever.jsx:

import React from 'react';
import ReactDOMServer from 'react-dom/server';
import { StaticRouter } from 'react-router-dom';
import {Helmet} from "react-helmet";
import Template from './template';
import App from './App';

export default function serverRenderer({ clientStats, serverStats }) {
    return (req, res, next) => {
        const context = {};
        const markup = ReactDOMServer.renderToString(
            <StaticRouter location={ req.url } context={ context }>
                <App />
            </StaticRouter>
        );
        const helmet = Helmet.renderStatic();

        res.status(200).send(Template({
            markup: markup,
            helmet: helmet,
        }));
    };
}

App.jsx:

import React, { Component } from 'react';
import { Switch, Route } from 'react-router-dom';
import Menu from './Menu'
import Helmet from "react-helmet";
import homepageStyles from './homepage.scss';

class Homepage extends Component {
    render() {
        return (
            <div className={ homepageStyles.component }>
                <Helmet
                    title="Welcome to our Homepage"
                />
                <Menu />
                <h1>Homepage</h1>
            </div>
        );
    }
}


class About extends Component {
    render() {
        return (
            <div>
                <h1>About</h1>
            </div>
        );
    }
}

class Contact extends Component {
    render() {
        return (
            <div>
                <h1>Contact</h1>
            </div>
        );
    }
}


export default class App extends Component {
    constructor(props) {
        super(props);
    }

    render() {
        return (
            <div>
                <Helmet
                    htmlAttributes={{lang: "en", amp: undefined}} // amp takes no value
                    titleTemplate="%s | React App"
                    titleAttributes={{itemprop: "name", lang: "en"}}
                    meta={[
                        {name: "description", content: "Server side rendering example"},
                        {name: "viewport", content: "width=device-width, initial-scale=1"},
                    ]}
                />
                <Switch>
                    <Route exact path='/' component={ Homepage } />
                    <Route path="/about" component={ About } />
                    <Route path="/contact" component={ Contact } />
                </Switch>
            </div>
        );
    }
}

模板.jsx

export default ({ markup, helmet }) => {
    return `<!doctype html>
<html ${helmet.htmlAttributes.toString()}>
<head>
    ${helmet.title.toString()}
    ${helmet.meta.toString()}
    ${helmet.link.toString()}
</head>
<body ${helmet.bodyAttributes.toString()}>
    <div id="root">${markup}</div>
    <div>Heeeeeeeeeeeeeeeeeeeelmet</div>
    <script src="/static/client.js" async></script>
</body>
</html>`;
};

menu.jsx:

import { Link } from 'react-router-dom';
import React, { Component } from 'react';
import './menu.scss';

class Menu extends Component {
    render() {
        return (
            <div>
                <ul>
                    <li>
                        <Link to={'/'}>Homepage</Link>
                    </li>
                    <li>
                        <Link to={'/about'}>About</Link>
                    </li>
                    <li>
                        <Link to={'/contact'}>Contact</Link>
                    </li>
                </ul>
            </div>
        );
    }
}

export default Menu;

.babelrc:

{
 "presets": [
   "@babel/react",
   "@babel/preset-env"
 ],
 "plugins": [
   "@babel/proposal-class-properties"
 ]
}

主页.sccs

.component {
    color: blue;
}

menu.scss:


li {
  background-color: yellow;
}

我使用了这篇文章:

https://blog.digitalkwarts.com/server-side-rendering-with-reactjs-react-router-v4-react-helmet-and-css-modules/