简体   繁体   English

路由导入的服务器端渲染问题

[英]Server side rendering issue with routes importing

I found a lot of information about SSR with React and all of them with completely different approach. 我发现了很多有关带有React的SSR的信息,并且所有信息都以完全不同的方式来使用。 So I found one example which looks more useful in my case (web-app on React/graphQL/Apollo/Express/Webpack), but I stuck on one issue. 因此,我发现了一个在我的案例中看起来更有用的示例(React / graphQL / Apollo / Express / Webpack上的Web应用程序),但我坚持了一个问题。 Below some examples: 下面是一些示例:

server.js

    ...
    import {router} from './client/App';
    import React from 'react';
    import { renderToString } from 'react-dom/server';
    import { match, RoutingContext, Route } from 'react-router';
    ...
    function renderApp(props, res) {
        const markup = renderToString(<RoutingContext {...props}/>);
        const html = createPage(markup);
        write(html, 'text/html', res);
    }

    app.get('*', (req, res, next) => {
            const location = hist.createLocation(req.path);
            match({routes: router, location: location}, (err, redirectLocation, renderProps) => {
                if (err) {
                    writeError('ERROR!', res);
                    next(err);
                } else if (redirectLocation) {
                    redirect(redirectLocation, res);
                } else if (renderProps) {
                    renderApp(renderProps, res);
                } else {
                    writeNotFound(res);
                }
            });
        });
    ...

and App.js from where we import router: 和从路由器导入位置的App.js

...

import Login from './components/Login';
import Register from './components/Register';
...
let routes = (
    <Route>
        <Route path="login" component={Login}/>
        <Route path="register" component={Register}/>
        ...
    </Route>
);

export let router = [{
    path: '/',
    component: Layout,
    indexRoute: {
        component: View
    },
    getChildRoutes(location, cb) {
        require.ensure([], () => cb(null, routes));
    }
}];

match({router, location}, () => {
    render(
        <ApolloProvider client={client}>
            <div>
                <Router routes={router} onUpdate={() => window.scrollTo(0, 0)} history={browserHistory}/>
            </div>
        </ApolloProvider>,
        document.getElementById('root')
    );
});

I tried do everything like in this example but issue is when in server.js I try to import router from App.js server doesn't run and give me error related with React component (styles importing and etc. everything what we can do on client but can't on server). 我试图做这个例子中的所有事情,但是问题是当我在server.js尝试从App.js导入router ,服务器未运行,并给我与React组件相关的错误(样式导入等),我们可以做的所有事情客户端,但不能在服务器上)。

So question is, what am I doing wrong? 问题是,我在做什么错? How else can I import routes without having this issue? 没有这个问题,我还能如何导入路线? It's really annoying that I already waist that much time on this small task. 我已经花了这么多时间完成这项小任务真是令人讨厌。

I'll be grateful for any help, thanks! 我将不胜感激,谢谢!

As you know, server side render is render your react component in your node server. 如您所知,服务器端渲染是在节点服务器中渲染您的react组件。 but Node server doesn't support import css/png files. 但节点服务器不支持导入css / png文件。

And if you don't want to change your client code, you can try user webpack-isomorphic-tools , it will help you generate a assert.json file, which can make require('*.css') calls return a json objects and generated CSS class names maps like they do in webpack css-loader . 而且,如果您不想更改客户端代码,可以尝试使用用户webpack-isomorphic-tools ,它将帮助您生成一个assert.json文件,该文件可以使require('*。css')调用返回一个json对象并生成CSS类名称映射,就像在webpack css-loader

if you are interested, you can look this demo . 如果您有兴趣,可以查看此演示

here is your webpack-isomorphic-tools.js 这是您的webpack-isomorphic-tools.js

var WebpackIsomorphicToolsPlugin = require('webpack-isomorphic-tools/plugin');


module.exports = {


  assets: {
    images: {
      extensions: [
        'jpeg',
        'jpg',
        'png',
        'gif'
      ],
      parser: WebpackIsomorphicToolsPlugin.url_loader_parser
    },
    fonts: {
      extensions: [
        'woff',
        'woff2',
        'ttf',
        'eot'
      ],
      parser: WebpackIsomorphicToolsPlugin.url_loader_parser
    },
    svg: {
      extension: 'svg',
      parser: WebpackIsomorphicToolsPlugin.url_loader_parser
    },

    bootstrap: {
      extension: 'js',
      include: ['./src/theme/bootstrap.config.js'],
      filter: function(module, regex, options, log) {
        function is_bootstrap_style(name) {
          return name.indexOf('./src/theme/bootstrap.config.js') >= 0;
        }
        if (options.development) {
          return is_bootstrap_style(module.name) && WebpackIsomorphicToolsPlugin.style_loader_filter(module, regex, options, log);
        }

      },

      path: WebpackIsomorphicToolsPlugin.style_loader_path_extractor,
      parser: WebpackIsomorphicToolsPlugin.css_loader_parser
    },
    style_modules: {
      extensions: ['less','scss'],
      filter: function(module, regex, options, log) {
        if (options.development) {
                      return WebpackIsomorphicToolsPlugin.style_loader_filter(module, regex, options, log);
        } else {
                      return regex.test(module.name);
        }
      },
      path: function(module, options, log) {
        if (options.development) {
                      return WebpackIsomorphicToolsPlugin.style_loader_path_extractor(module, options, log);
        } else {
                      return module.name;
        }
      },
      parser: function(module, options, log) {
        if (options.development) {
          return WebpackIsomorphicToolsPlugin.css_modules_loader_parser(module, options, log);
        } else {
              return module.source;
        }
      }
    }
  }
}

and your server.js should look like this 和您的server.js应该看起来像这样

function renderFullPage (title, css, html, initialState) {
    return `
        <!DOCTYPE html>
            <html>
              <head>
                <title>${title}</title>
                <style type="text/css">${css}</style>
              </head>
              <body>
                <div id="app">${html}</div>

                <script>
                    window.__INITIAL_STATE__ = ${JSON.stringify(initialState)};
                </script>
                <script src="/assets/scripts/app.bundle.js"></script>
              </body>
            </html>
    `;
}

const asyncStore = (store, renderProps) => {
    let promise = Promise.all([
        store.dispatch(queryArtistList()),
        store.dispatch(queryAuth())
    ]);
    return promise;
}

const HomeCtrl = {
    index: async (req, res) => {
        // 补全同构应用运行时缺失的全局对象
        global.window = {
            navigator: {
                userAgent: req.get('User-Agent'),
            },
            location: {
                protocol: req.protocol + ':',
                hostname: req.hostname,
            },
        };  
        match({ routes, location: req.url }, async (err, redirectLocation, renderProps) => {
            if (err) {
                res.status(500).end(`Internal Server Error ${err}`);
            } else if (redirectLocation) {
                res.redirect(redirectLocation.pathname + redirectLocation.search + '/');
            } else if (renderProps) {
                let store   = configureStore();
                const state = store.getState();
                await asyncStore(store, renderProps);
                const components = (<Provider store={store}>
                                            <RouterContext {...renderProps} />
                                        </Provider>);
                const html = renderToStaticMarkup(components);

                res.end(renderFullPage('tokyo Artist', '', html, store.getState()));

            } else {
              res.status(404).end('Not found');
            }
        })
    }
}

and please make sure, start your server after you have generate your webpack-asserts.json ; 并请确保在生成webpack-asserts.json之后启动服务器;

so your app.js should look like this: 因此您的app.js应该如下所示:

#!/usr/bin/env node
const path = require('path');
const rootDir = path.resolve(__dirname, '..');
const fs = require('fs');

const babelrc = fs.readFileSync(rootDir + '/.babelrc', 'utf-8');
var config;

try {
    config = JSON.parse(babelrc);
} catch (err) {
    console.error('==>     ERROR: Error parsing your .babelrc.');
    console.error(err);
}

require('babel-register')(config);

/**
 * Define isomorphic constants.
 */
global.__CLIENT__ = false;
global.__SERVER__ = true;
global.__DEVELOPMENT__ = process.env.NODE_ENV !== 'production';
global.__DEVTOOLS__ = __DEVELOPMENT__;


const WebpackIsomorphicTools = require('webpack-isomorphic-tools');
global.webpackIsomorphicTools = new WebpackIsomorphicTools(require('../webpack/webpack.isomorphic-tools'))
    .development(__DEVELOPMENT__)
    .server(__DEVELOPMENT__ ? __dirname : rootDir, function() {
        require('../server/app.js');
    });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM