简体   繁体   中英

Prerender React app as static HTML

I have an interactive landing page (single page - no react router). This landing page will need to be uploaded to a CMS where you just paste in the HTML - meaning I do not need <html> <head> <body> tags and the JavaScript file is uploaded separately. Currently I can just paste <div id="react-root"></div> into the CMS and upload my bundled JavaScript file and the page works.

However, the feedback is that this page now needs be be crawlable on all search engines. This means I need to basically render the initial HTML generated by react to paste into the CMS and have the page still all work as expected.

I am trying to make my build command output the rendered HTML to an index.html file where I can copy and paste the code into the CMS. (I have got my bundle.js file working fine).

webpack.common.js

const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          'css-loader',
        ]
      },
      {
        test: /\.(png|svg|jpg|gif)$/,
        use: [
          'file-loader'
        ]
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/,
        use: [
          'file-loader'
        ]
      },
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: "babel-loader"
      },
    ]
  },
  plugins: [
    new CleanWebpackPlugin(['dist'])
  ],
};

webpack.prod.js

const webpack = require('webpack');
const merge = require('webpack-merge');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const common = require('./webpack.common.js');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = merge(common, {
  plugins: [
    new UglifyJSPlugin(),
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('production')
    }),
    new HtmlWebpackPlugin({
      inject: false,
      template: require('./src/template.js'),
    })
  ]
});

template.js

const React = require('react');
const ReactDOMServer = require('react-dom/server');
const LandingPage = require('./App.js');
const html = ReactDOMServer.renderToString(LandingPage);

module.exports = function () {
  return ReactDOM.hydrate(html, document.getElementById('lp-root'));
};

So I have used react-dom-server to renderToString. Is this the best way to do this? If so, this way isn't working as HtmlWebpackPlugin cannot process the ES6 syntax used in the landing pages (import and exports) - anyway around this?

The approach seems correct.
However, you might need babel transpiler to convert your code from ES6 syntax.
Try adding a new rule in the webpack config for the js/jsx files.
Something like this:

  {
    test: /js$/,
    exclude: /(node_modules)/,
    loader: "babel-loader",
    query: { presets: ["react", "es2016", "es2015"], plugins: ["transform-class-properties"] },
  },

It will transpile your code properly before using.

Hope it helps. Please revert for any doubts.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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