向 React SSR 组件添加 CSS

3
我正在尝试为使用SSR构建的React组件添加CSS,但是我无法做到。 我查看了以下内容: 但是在这些内容中,其中没有一个过程是简单的或明确说明的。我尝试了很多次的一个是同构加载器,它看起来很有希望,但设置在我的CSS文件中后,它给出了一些模糊的错误:

Unexpected token (1:0) You may need an appropriate loader to handle this file type.

这是我的样板包 - https://github.com/alexnm/react-ssr 如何将样式添加到我的React SSR代码中。 更新
const dev = process.env.NODE_ENV !== "production";
const path = require( "path" );
const { BundleAnalyzerPlugin } = require( "webpack-bundle-analyzer" );
const FriendlyErrorsWebpackPlugin = require( "friendly-errors-webpack-plugin" );

const plugins = [
    new FriendlyErrorsWebpackPlugin(),
];

if ( !dev ) {
    plugins.push( new BundleAnalyzerPlugin( {
        analyzerMode: "static",
        reportFilename: "webpack-report.html",
        openAnalyzer: false,
    } ) );
}

module.exports = {
    mode: dev ? "development" : "production",
    context: path.join( __dirname, "src" ),
    devtool: dev ? "none" : "source-map",
    entry: {
        app: "./client.js",
    },
    resolve: {
        modules: [
            path.resolve( "./src" ),
            "node_modules",
        ],
    },
    module: {
        rules: [
            {
                test: /\.jsx?$/,
                exclude: /(node_modules|bower_components)/,
                loader: "babel-loader",
            },
        ],
    },
    output: {
        path: path.resolve( __dirname, "dist" ),
        filename: "[name].bundle.js",
    },
    plugins,
};

你能分享一下你的webpack配置吗? - Ajay Varghese
@AjayVarghese,我刚刚做了,但我之前已经添加了所有的加载器,但我希望它能与你的解决方案一起工作。 - Rahul Singh
webpack配置中缺少CSS加载器。 - Ajay Varghese
@AjayVarghese 我已经添加了它,但是在它无法工作后我将其删除了,如果您检查同构链接,它具有weboackconfig。 - Rahul Singh
我尝试了@Ajay的建议,但没有效果。程序在启动时崩溃,仍然是同样的错误。 - Rahul Singh
显示剩余6条评论
2个回答

4
以下配置使CSS工作:
安装的软件包:
babel-plugin-dynamic-import-node、babel-plugin-css-modules-transform、mini-css-extract-plugin、css-loader、style-loader

index.js
require( "babel-register" )( {
presets: [ "env" ],
plugins: [
    [
        "css-modules-transform",
        {
            camelCase: true,
            extensions: [ ".css", ".scss" ],
        }
    ],
    "dynamic-import-node"
],
} );
require( "./src/server" );

webpack.config.js

rules: [
        {
            test: /\.jsx?$/,
            exclude: /(node_modules|bower_components)/,
            loader: "babel-loader",
        },{
            test: /\.css$/,
            use: [
                {
                    loader: MiniCssExtractPlugin.loader,
                },
                'css-loader'
            ],
        },
    ]

在webpack配置文件中,添加以下插件:
new MiniCssExtractPlugin({
    filename: "styles.css",
}),

在 server.js 中,将以下代码添加到 htmlTemplate 的 head 中。

<link rel="stylesheet" type="text/css" href="./styles.css" />

使用方法

import  "./../App.css";

<h2 className="wrapper">F1 2018 Season Calendar</h2>

嘿@AjayVarghese,它有效了,谢谢你提供的好方法,救了我的一天。你能解释一下这里发生了什么以及它是如何工作的吗?因为我只是按照你提到的步骤进行操作,但没有得到任何见解,如果你能分享一些见解,那将会很有帮助。此外,我无法使用scss,我认为我需要scss loader来实现它,而且模块概念也不起作用,比如React的css模块。如果你能添加这个,它将成为其他使用这个库的人的完整解决方案...谢谢。 - Rahul Singh
对于SSR,渲染会在服务器和客户端各进行一次。在服务器上,普通的CSS加载器不起作用。css-modules-transform将处理此部分,这就是我在index.js中编写的内容。这是一个非常基本的CSS设置。对于sass或CSS模块,您可以在webpack.config.js中添加配置。希望这能起作用。 - Ajay Varghese

0

我已经疯了,尝试按照所有提到的方法自己设置它,但没有运气。在我的情况下,我正在使用css-loader创建css模块语法和SSR用于React模块,这些模块并不是太大。

正如有人提到的那样,因为webpack将运行两次,您最终会得到不同的类名,这将在控制台上弹出一些错误,指出您的服务器和客户端标记不同。为了缓解这种情况,您可以创建自己的加载器。

想法是存储一个webpack编译中css-loader的输出值,并将其用于下一个编译。这可能不是加载器设计的目的,但它能胜任工作。

 /**
 * @typedef {Object} LoaderOptions
 * @property {"client" | "server"} type
 */

const mapContent = new Map();

/**
 * @param {LoaderOptions} options
 * @returns boolean
 */
const optionsValidator = (options) => {
  return (
    typeof options === 'object' &&
    'type' in options &&
    typeof options.type === 'string' &&
    (options.type === 'client' || options.type === 'server')
  );
};

module.exports = function (source) {
  /**
    @type import('./node_modules/webpack/types').LoaderContext<LoaderOptions>
   */
  const loader = this;
  const options = loader.getOptions();
  const logger = loader.getLogger();

  if (!optionsValidator(options)) {
    logger.error('css-ssr-replacer-loader. Only valid props are "type" with values of "client" or "server"');
  }

  const isClient = options.type === 'client';

  if (isClient) {
    mapContent.set(loader.resourcePath, Buffer.from(source));
  }

  return isClient ? source : mapContent.get(loader.resourcePath);
};

然后在您的Webpack配置中,需要添加类似以下的内容。
const webpackConfig = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          {
            loader: 'howEverYouWantToCallTheLoader',
            options: {
              type: 'client' || 'server'
            }
          },
          {
            loader: 'css-loader',
            options: {
              modules: {
                exportLocalsConvention: 'camelCase',
                localIdentName: '[local]_[hash:base64:8]',
                mode: 'local'
              }
            }
          }
        ]
      }
    ]
  },
  resolveLoader: {
    alias: {
      howEverYouWantToCallTheLoader: path.resolve(__dirname, 'pathToYourLoader.js')
    }
  }
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接