0

I hava got a FOUC issue with react server side rendering. I used React+ReactRouter+Redux Here is main tech stacks I think it necessary to list:

  • CSS Module deal with component style
  • extract-text-webpack-plugin for generating separate css file
  • css-modules-require-hook & asset-require-hook for dealing assets in server side

and my webpack config:

module.exports = {
   entry: [
   APP_PATH,
 ],

  output: {
     path: BUILD_PATH,
     filename: 'client.bundle.js',
     publicPath: '/JdBus/',
  },
 resolve: {
  extensions: ['.js', '.jsx'],
 },
 module: {
 rules: [
   {
    test: /\.(js|jsx)$/,
    exclude: /node_modules/,
    use: [
      'babel-loader',
    ],
  },

  {
    test: /\.css$/,
    use: ExtractTextPlugin.extract({
      fallback: 'style-loader',
      use: [
        {
          loader: 'css-loader',
          options: {
            modules: true, // 开启CSS Module
            localIdentName: '[name]__[local]-[hash:base64:5]',
          },
        },
        {
          loader: 'postcss-loader',
          options: {
            plugins() { // 这里配置postcss的插件
              return [autoprefixer];
            },
          },
        },
      ],
    }),
  },
  { // 处理图片
    test: /\.(png|jpg|gif|webp')$/,
    // include:path.resolve(__dirname,'/client/assets'),
    use: [{
      loader: 'url-loader',
      options: {
        limit: 10000,
        // 这个是输出的图片文件,跟output一致,生成的是bundleImg目录下的图片文件
        name: 'bundleImg/[hash:8].[name].[ext]',
      },
    }],
  },

  { // 处理文字
    test: /\.(woff|ttf|svg|eot|woff2)$/,
    // include:path.resolve(__dirname,'/client/assets'),
    use: [{
      loader: 'url-loader',
       options: {
        limit: 10000,
        name: 'bundleFonts/[hash:8]-[name].[ext]',
       },
     }],
    },
  ],
},
 plugins: [
    new webpack.DefinePlugin({
      'process.env': {
       NODE_ENV: JSON.stringify('production'),
      WEBPACK: true,
    },
   }),
   new webpack.optimize.UglifyJsPlugin({
     compressor: {
       warnings: false,
     },
   }),
  new ExtractTextPlugin('bundle.css'),
  new webpack.optimize.CommonsChunkPlugin({ 
    name: 'commons',
    filename: 'commons.js',
    minChunks: 2,
  }),
};

ExtractTextPlugin will generate all CSS styles in bundle.css.

my server side handle by express:

match({ routes: AppRoutes, location: `/jdbus${req.url}` }, (err, redirectLocation, renderProps) => {
    if (err) {
      res.status(500).send(err.message);
    } else if (redirectLocation) {
      res.redirect(302, redirectLocation.pathname + redirectLocation.search);
    } else if (renderProps) {

      const store = configureStore({ user: {
        name: 'ddd',
        avatar: 'ddd',
      } });
      // console.log(renderProps);
      const marked = renderToStaticMarkup(
        <Provider store={store}>
            <RouterContext {...renderProps} />
        </Provider>
      );
      const initHtml = renderFullPage(marked, store.getState(), process.env.NODE_ENV);
      res.status(200).end(initHtml);
    } else {
      res.status(404).end('404 not');
    }
  });

renderFullPage() is a function to generate html from veiw.js:

function renderFullPage (html, initiaState, env) {
    // 根据生产和开发环境配置不同的页面
if (env === 'development') {
  return `
    <!DOCTYPE html>
      <html lang="en">
      <head>
      <title>开发测试页面</title>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-
      scale=1.0, user-scalable=no"/>
          <style>
          body{
              margin:0px;    
          }
          </style>
      </head>

      <body>
        <div id="root"></div>
        <script>
          window.__INITIAL_STATE__ = ${JSON.stringify(initiaState)};
        </script>
        <script src='/devClient.bundle.js'></script>
      </body>     
   </html>
   `;
  } else if (env === 'production') {
    return `
       <!DOCTYPE html>
       <html lang="en">
       <head>
       <meta charset="UTF-8">
       <title>十二棵橡树</title>
      <meta name="viewport" content="width=device-width, initial-scale=1.0, 
    user-scalable=no"/>
      <link rel="stylesheet" type="text/css" href="/JdBus/bundle.css">
      <style>
      body{
          margin:0px;
          scroll:no
      }
      </style>

    </head>
    <body>
      <div id="root">
          ${html}
      </div>
      <script>
        window.__INITIAL_STATE__ = ${JSON.stringify(initiaState)};
      </script>

    </body>
    </html>
  `;
   }
  }
 module.exports = renderFullPage;

my server.js is where program start:

// 各种钩子
     require('babel-polyfill');
     require('css-modules-require-hook')({
         extensions: ['.css'],
         generateScopedName: '[name]__[local]-[hash:base64:8]',
    });

    require('asset-require-hook')({
        extensions: ['jpg', 'png', 'gif', 'webp'],
        limit: 10000,
    });
    // 处理字体
   require('asset-require-hook')({
      extensions: ['ttf', 'woff', 'svg', 'eot', 'woff2'],
      limit: 10000,
   });

const app = require('./app');

app.listen(PORT, () => {
  console.log('Node app is running on port:', PORT);

  // 注册全局未捕获异常处理器
  process.on('uncaughtException', (e) => {
    console.error(`Caught exception:, ${e.stack}`);
  });
  process.on('unhandledRejection', (reason, p) => {
    console.error(`Unhandled Rejection at: Promise , ${p},  reason: , ${reason.stack}`);
  });
});

asset-require-hookand css-modules-require-hook handle assets that server side can not deal.

Everything is OK except...FOUC! My server side would generate html normally while no css in a moment every time I tried.

this is my screenshot: enter image description here

1 Answer 1

0

Below is a snippet from my webpack.config file. I fixed the FOUC issue in my React Server-side Rendering Example. I think it was using the HtmlWebpackHarddiskPlugin setting the alwaysWriteToDisk to true in the HtmlWebpackPlugin.

new ExtractTextPlugin({
    filename: isDevelopment
        ? 'assets/styles/main.css'
        : 'assets/styles/[name].[chunkhash].css',
}),

new HtmlWebpackPlugin({
    template: path.resolve(__dirname, 'src/index.html'),
    minify: isProduction ? {collapseWhitespace: true, collapseInlineTagWhitespace: true} : false,
    alwaysWriteToDisk: true,
}),
new HtmlWebpackHarddiskPlugin(),
Sign up to request clarification or add additional context in comments.

1 Comment

OK I will have a try ,Thks😃

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.