未定义窗口服务器端渲染(反应+表达)

时间:2020-07-26 19:52:57

标签: javascript node.js reactjs express webpack

如果请求了浏览器URL,则路由正常工作。

顺便说一句,location = $ {path}; 调用react renderToString函数时,表示组件错误的部分。

我正在查看Web Pack设置或其他内容,但找不到原因。救命!

// App.js

import React, {useState, useEffect} from 'react';
import moment from "moment";
import Header from "./components/header/Header";
import Footer from "./components/footer/Footer";

export default function App() {

    const [time, setTime] = useState(null);

    useEffect(() => {
        console.log('use effect..');
        setTime(moment().format('hh:mm:ss a'));
    }, []);

    return (
        <div style={{height:'100%'}}>
            <Header/>
            <div style={{height:'100%'}}>
                <h1>Sample App</h1>
                <p>Current time is {time}</p>
            </div>
            <Footer/>
        </div>
    )

}

// Header.js

import React from 'react';

export default function Header() {

    function goPage(path) {
        console.log(`goPage..`);
        console.log(window.location); // error
        // window.location = path;
    }

    return (
        <header style={{width: '100%', border: '1px dotted black'}}>
            <div>
                <span style={{padding: '4px'}}>My App |</span>
                <span style={{padding: '4px', cursor: 'pointer'}}>Home</span>
                <span style={{padding: '4px', cursor: 'pointer'}} onClick={goPage('/about')}>About</span>
            </div>
        </header>
    )
}


server.js

const express = require('express');
const path = require('path');
import React from 'react';
import ReactDOMServer from 'react-dom/server';

const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');
const config = require('../webpack.config.js');
const compiler = webpack(config);

import Router from '../routes/index';

import App from '../src/App';
import Html from "../src/Html";

const expressApp = express();
const port = process.env.PORT || 3000;

if (process.env.NODE_ENV != 'production') {
    expressApp.use(webpackDevMiddleware(compiler, {
        publicPath: '/'
    }));
}
expressApp.use(express.static(path.join(__dirname, '')));

expressApp.get('*', (request, response) => {

    console.log('request.. in express');
    console.log(Router.match(request));
    const component = ReactDOMServer.renderToString(Router.match(request));

    const html = ReactDOMServer.renderToStaticMarkup(<Html
        title="Sample Title"
        description="Isomorphic web application sample"
        body={component}
    />);

    response.send(`<!DOCTYPE html>` + html);

});


expressApp.listen(port, () => {
    console.log(`App is listening at http://localhost:${port}/`);
});


// Router

import React from 'react';

import App from "../src/App";
import NotFound from "../src/components/error/NotFound";
import Error from "../src/components/error/Error";
import About from "../src/components/about/About";

const routes = [
    {name : 'home', path : '/', action : () => <App/>},
    {name : 'about', path : '/about', action : () => <About/>},
    {name : '404', path : '/404', action : () => <NotFound/>},
    {name : '500', path : '/500', action : () => <Error/>},
];


export default {
    match(location) {
        console.log(location.path);
        const route = routes.find(x => x.path === location.path);

        if (route) {
            try {
                return route.action();
            } catch (err) {
                console.log('err');
                return routes.find(x => x.path === '/500').action();
            }
        } else {
            console.log('404');
            return routes.find(x => x.path === '/404').action();
        }
    }
}

// webpack config

const path = require('path');

// plugin
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const MomentLocalesPlugin = require('moment-locales-webpack-plugin');
const nodeExternals = require('webpack-node-externals');


// SSR
const ssr = {
    mode : 'development',
    entry: './server/server.js',
    output: {
        path: path.join(__dirname, '/build'),
        filename: "server.js",
    },
    target: 'node',
    node: false,
    externals: [nodeExternals()],
    resolve: {
        modules: ['node_modules']
    },
    module: {
        rules: [
            {
                test: /(.js|.jsx)/,
                exclude: /node_modules/,
                include: [
                    path.join(__dirname, '/src'),
                    path.join(__dirname, '/routes/index.js'),
                    path.join(__dirname, '/server/server.js'),
                ],
                use: {
                    loader: 'babel-loader'
                }
            },
        ]
    },

    plugins: [
        new CleanWebpackPlugin({
            cleanAfterEveryBuildPatterns: ['build']
        })
    ],
};

// CSR
const csr = {
    mode : 'development',
    entry:'./client/client.js',
    output: {
        publicPath: '/',
        path: path.join(__dirname, '/build'),
        filename: 'client.js'
    },
    target: 'web',
    module: {
        rules: [
            {
                test: /(.js|.jsx)/,
                exclude: /node_modules/,
                include: [
                    path.join(__dirname, '/src'),
                    path.join(__dirname, '/routes/index.js'),
                    path.join(__dirname, '/client/client.js'),
                ],
                use: {
                    loader: 'babel-loader'
                }
            },
        ]
    },
    // devtool: 'source-map',
    plugins: [
        new MomentLocalesPlugin({
            localesToKeep: ['es-us', 'ru'],
        }),
    ]
};


module.exports = [ssr, csr];

该服务器由express组成,并设置为babel7和webpack4。 如果查看server.js部分,则会在请求URL中获得相应的react组件。 如果在获取的组件上调用renderToString(),则未定义window错误。 我真的很想解决。请帮忙。

1 个答案:

答案 0 :(得分:0)

为什么未在SSR中定义window

在ssr上没有窗口的定义。因为window是基于浏览器的属性。

您需要采取一些措施来避免这种情况。例如

function goPage(path) {
        console.log(`goPage..`);
        if (window) {
           console.log(window.location);
        }
    }

在服务器端,您可以通过此方法获取网址

req.url
// or
app.get('/users/:userId/books/:bookId', function (req, res) {
  console.log(req.params)
}