具有服务器端渲染的样式化组件,代码拆分(不是next.js)

时间:2020-05-15 16:30:21

标签: reactjs server-side styled-components code-splitting

在我的应用程序的第一次展示中,我的样式组件未应用,仅看到纯HTML标签。

我该如何处理?我想从服务器端渲染中应用基本样式。

我检查了样式化组件的官方文档,但是 ServerStyleSheet 不起作用。

我在这里获取我的应用预览和代码

enter image description here

server.tsx

import express from 'express';
import path from 'path';
import React from 'react';
import { renderToString } from 'react-dom/server';
import { StaticRouter } from 'react-router-dom';
import { Helmet } from 'react-helmet';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import { ChunkExtractor } from '@loadable/server';
import { ServerStyleSheet, StyleSheetManager } from 'styled-components';

const app = express();

if (process.env.NODE_ENV !== 'production') {
  const webpack = require('webpack');
  const webpackConfig = require('../webpack.client.js').map((config: any) => {
    config.output.path = config.output.path.replace('dist/dist/', 'dist/');
    return config;
  });

  const webpackDevMiddleware = require('webpack-dev-middleware');
  const webpackHotMiddleware = require('webpack-hot-middleware');

  const compiler = webpack(webpackConfig);

  app.use(
    webpackDevMiddleware(compiler, {
      logLevel: 'silent',
      publicPath: webpackConfig[0].output.publicPath,
      writeToDisk: true,
    }),
  );

  app.use(webpackHotMiddleware(compiler));
}

app.use(express.static(path.resolve(__dirname)));

app.get('*', (req, res) => {
  const sheet = new ServerStyleSheet(); 
  const styleTags = sheet.getStyleTags(); 
  const nodeStats = path.resolve(__dirname, './node/loadable-stats.json');
  const webStats = path.resolve(__dirname, './web/loadable-stats.json');
  const nodeExtractor = new ChunkExtractor({ statsFile: nodeStats });
  const { default: App } = nodeExtractor.requireEntrypoint();
  const webExtractor = new ChunkExtractor({ statsFile: webStats });

  const context = {};


  try {
    const styledHtml = sheet.collectStyles(
      <StaticRouter location={req.url} context={context}>
        <App />
      </StaticRouter>
    )
    const jsx = webExtractor.collectChunks(styledHtml);
    const html = renderToString(jsx);

    const helmet = Helmet.renderStatic();

    res.set('content-type', 'text/html');
    res.send(`
      <!DOCTYPE html>
        <html lang="en">
          <head>
            <meta name="viewport" content="width=device-width, user-scalable=no">
            <meta name="google" content="notranslate">
            ${helmet.title.toString()}
            ${webExtractor.getLinkTags()}
            ${webExtractor.getStyleTags()}
          </head>
          <body>
            <div id="root">${html}</div>
            ${webExtractor.getScriptTags()}
          </body>
        </html>
    `);

    } catch(error){
      console.log(error);
    } finally{
      sheet.seal(); 
  }
});

app.listen(5000, () => console.log('Server started http://localhost:5000'));

1 个答案:

答案 0 :(得分:1)

我通过使用 ServerStyleSheet

注入适当的样式来解决此问题

请参见下面的代码

  /// server.tsx  using express 
  import { ServerStyleSheet } from 'styled-components';
  import { ChunkExtractor } from '@loadable/server'; 
  ... 
  const sheet = new ServerStyleSheet();
  const webStats = path.resolve(__dirname, './loadable-stats.json');
  const webExtractor = new ChunkExtractor({statsFile: webStats}); 

  const jsx = webExtractor.collectChunks(<App/>);
  const html = renderToString(sheet.collectStyles(jsx));
  const styles = sheet.getStyleTags(); 

  res.send(`
      ... 

      <head>
       ${webExtractor.getStyleTags() + styles }
      </head> 
      ...  `)

我缺少的关键点放在 webExtractor.getStyleTags()之后的样式

完成这些操作后,我发现一切正常