反应服务器端渲染 - webpack的“样式加载器”失败

Posted

技术标签:

【中文标题】反应服务器端渲染 - webpack的“样式加载器”失败【英文标题】:React server side rendering - failure on `style-loader` of webpack 【发布时间】:2020-12-05 18:26:11 【问题描述】:

我有一个使用React 和服务器端渲染的项目。对于开发,我使用webpack -w && nodemon server.js。它将构建文件监视任何更改以构建和监视服务器的任何更改。但这是我在运行nodemon server.js 时遇到的错误:

ReferenceError: document is not defined
at insertStyleElement (webpack:///./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js?:93:15)
at addStyle (webpack:///./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js?:208:13)
at modulesToDom (webpack:///./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js?:81:18)
at module.exports (webpack:///./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js?:239:25)
at eval (webpack:///./src/shared/css/home-style.css?:15:14)

如您所见,该错误与我使用的 webpack style-loader 有关。事实上,当我从webpack.config.js 中删除style-loader 时,错误就消失了。但是,如果您想捆绑您的反应 <App/ > 引用的 css,这种方法并不理想。如何解决此错误?

以下是我的文件:

index.js(将由 webpack 构建到 server.js 中,由它进行服务器端渲染)

import React from 'react';
import express from 'express';
import cors from 'cors';
import  renderToString  from 'react-dom/server';
import App from '../shared/Components/App';
import serialize from 'serialize-javascript';

const app = express();

app.use(cors());

app.use(express.static('public'));

app.get('*', (req, res, next) => 
    const markup = renderToString(
        
            <App />
        
    );

    res.status(200).send(
        `<!DOCTYPE html>
        <html lang="">
        <head>
            <meta http-equiv="X-UA-Compatible" content="IE=edge" />
            <meta charset="utf-8" />
            <title>Welcome to Banding-Bandingz</title>
            <meta name="viewport" content="width=device-width, initial-scale=1">
            <script src='/bundle.js' defer></script>

        </head>
        <body>
            <div id="app">$markup</div>
        </body>
        </html>`
    );
);

app.listen(3000, () => 
    console.log('server is listening on port 3000...');
);

package.json

"scripts": 
    "start": "webpack -w && node server.js",
    "watch:server": "nodemon server.js",
    "watch:build": "webpack -w",
    "test": "echo \"Error: no test specified\" && exit 1"
,
"babel": 
    "presets": [
        "@babel/preset-env",
        "@babel/preset-react"
    ],
    "plugins": [
        "@babel/plugin-proposal-object-rest-spread",
        "@babel/plugin-proposal-class-properties"
    ]
,
"devDependencies": 
    "@babel/core": "^7.3.4",
    "@babel/plugin-proposal-class-properties": "^7.10.4",
    "@babel/plugin-proposal-object-rest-spread": "^7.9.0",
    "@babel/preset-env": "^7.3.4",
    "@babel/preset-react": "^7.0.0",
    "babel-loader": "^8.1.0",
    "concurrently": "^5.3.0",
    "css-loader": "^4.2.1",
    "file-loader": "^6.0.0",
    "nodemon": "^2.0.4",
    "style-loader": "^1.2.1",
    "url-loader": "^4.1.0",
    "webpack": "^4.42.1",
    "webpack-cli": "^3.3.11",
    "webpack-node-externals": "^1.7.2"
,
"dependencies": 
    "cors": "^2.8.5",
    "express": "^4.17.1",
    "isomorphic-fetch": "^2.2.1",
    "jsdom": "^16.4.0",
    "npm-run-all": "^4.1.5",
    "pure-react-carousel": "^1.27.1",
    "react": "^16.13.1",
    "react-dom": "^16.13.1",
    "react-router-dom": "4.4.0-beta.8",
    "serialize-javascript": "^3.0.0"

webpack.config.js

var path = require('path');
var webpack = require('webpack');
var nodeExternals = require('webpack-node-externals');

var browserConfig = 
    entry: './src/browser/index.js',
    output: 
        path: path.resolve(__dirname, 'public'),
        filename: 'bundle.js',
        publicPath: '/',
    ,
    module: 
        rules: [
             test: /\.(js)$/, use: 'babel-loader' ,
            
                test: /\.css$/,
                use: ['style-loader', 'css-loader'],
            ,
            
                test: /\.(jpg|png|PNG|svg|jpe?g)$/,
                use: [
                    
                        loader: 'file-loader',
                        options: 
                            outputPath: 'img/',
                            publicPath: 'img/',
                        ,
                    ,
                ],
            ,
        ],
    ,
    mode: 'production',
    plugins: [
        new webpack.DefinePlugin(
            __isBrowser__: 'true',
        ),
    ],
    performance: 
        maxEntrypointSize: 512000,
        maxAssetSize: 512000,
    ,
;

var serverConfig = 
    entry: './src/server/index.js',
    target: 'node',
    externals: [nodeExternals()],
    output: 
        path: __dirname,
        filename: 'server.js',
        publicPath: '/',
    ,
    module: 
        rules: [
             test: /\.(js)$/, use: 'babel-loader' ,
            
                test: /\.css$/,
                use: ['style-loader', 'css-loader'],
            ,
            
                test: /\.(jpg|png|PNG|svg|jpe?g)$/,
                use: [
                    
                        loader: 'file-loader',
                        options: 
                            outputPath: 'img/',
                            publicPath: 'img/',
                        ,
                    ,
                ],
            ,
        ],
    ,
    mode: 'development',
    plugins: [
        new webpack.DefinePlugin(
            __isBrowser__: 'false',
        ),
    ],
    performance: 
        maxEntrypointSize: 512000,
        maxAssetSize: 512000,
    ,
;

module.exports = [browserConfig, serverConfig];

【问题讨论】:

这能回答你的问题吗? How can I use style-loader in react s-s-r (Server Side Rendering)? 还是这个? 'window is not defined' error when using style-loader with webpack 嘿@segFault 你建议的页面将我引导到一个同构样式加载器库,当包含该库时,它会修复错误消息。所以谢谢你!我一直在寻找解决方案。你知道我是否应该配置其他东西吗?因为在请求时我仍然看不到页面上的样式.. 我会检查the documentation for that plugin here,我对这个库不太熟悉。 【参考方案1】:

我会检查样式加载器是否可以在服务器端使用。我不相信,因为您得到的错误通常是您的脚本试图找到一个“文档”以在其中注入一个“样式”标签

【讨论】:

以上是关于反应服务器端渲染 - webpack的“样式加载器”失败的主要内容,如果未能解决你的问题,请参考以下文章

使用 Sass 反应服务器端渲染

Webpack 样式加载器未将样式注入 DOM

Webpack 4 - 样式加载器/url 不起作用

webpack 样式加载器是不是意味着加载所有 css?或者只是应用程序特定的css?

Webpack 样式加载器与 mini-css-extract-plugin

错误:无法解析模块“样式加载器”