0

I have a node express server. This has a file called server.js that has a route called home that responds to the client with html.

The content of the main div in the HTML is a react component (i.e root component for my App) that has been converted to HTML string.

I have created a renderMarkup function in a separate module to my server module. This contains the code for converting my root component to a HTML string using the renderToString Method. My react component is written in JSX and uses es6 imports so I have converted the renderMarkup module into a node compatible module using Webpack and babel.

The outputted bundle is required inside my server.js file. The renderMarkup function is called inside of my route and inserted into a HTML string using template literal. The entire HTML is returned by my route.

Is there a way in development to dynamically update my server rendered components and see the updates without refreshing the page?

I have tried using webpack-dev-middleware but this only updates my client side bundles not server side bundle. Also even after this is achieved not sure how i would achieve hot reloading

I have an array export in my Webpack config that exports my client side and server side config. My code is below

server.js

const express = require("express");
const app = express();
const path = require("path");

const renderMarkup = require("./react-bundles/home.bundle.js").default;

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

const port = 3000;

const __DEV__ = process.env.NODE_ENV === "development";

if (__DEV__) {
  app.use(middleware(compiler, { serverSideRender: true }));

} else {
  app.use(express.static(path.resolve(__dirname, "../../public")));
}

app.get("/", (req, res) => {
  const { html, styleTags } = renderMarkup();

  const templateMarkup = `<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Experiment Page</title>
  ${styleTags}
  <!-- Your other meta tags, stylesheets, and scripts go here -->
  <script defer src="/js/shared.bundle.js"></script>
  <script defer src="/js/home.bundle.js"></script>
</head>
  
<body>
  <div id="app">${html}</div>
</body>

</html>`;

  res.send(templateMarkup);
});

app.listen(port, () => {
  console.log(`Server listening on port ${port}`);
});

render markup function

import React from "react";
import App from "../components/home";
import { renderToString } from "react-dom/server";
import { ServerStyleSheet } from "styled-components";

const renderMarkup = () => {
  let html = "";
  let styleTags = "";
  const sheet = new ServerStyleSheet();

  try {
    html = renderToString(sheet.collectStyles(<App />));
    styleTags = sheet.getStyleTags();
  } catch (err) {
    console.log(err);
  } finally {
    sheet.seal();
  }

  return { html, styleTags };
};

export default renderMarkup;

webpack config

const path = require("path");
const { merge } = require("webpack-merge");
const serverConfig = require("./webpack.server.config.js");

const pagesFolder = path.resolve(__dirname, "src/pages");

const __DEV__ = process.env.NODE_ENV === "development";

const commonConf = {
  name: "client",
  entry: {
    home: path.resolve(pagesFolder, "home", "entry", "home.js"),
    about: path.resolve(pagesFolder, "about", "entry", "about.js"),
  },
  output: {
    filename: "js/[name].bundle.js",
    path: path.resolve(__dirname, "public"),
    publicPath: "/",
  },
  optimization: {
    splitChunks: {
      chunks: "all",
      cacheGroups: {
        shared: {
          name: "shared",
          chunks: "all",
          filename: "js/shared.bundle.js",
        },
      },
    },
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader",
          options: {
            presets: ["@babel/preset-react"],
          },
        },
      },
    ],
  },
};

const devConf = merge(commonConf, {
  mode: "development", //dev
  devtool: "inline-source-map", //dev
  devServer: {
    hot: true, //dev
    static: path.resolve(__dirname, "public"), //dev
  },
});

const prodConf = merge(commonConf, {
  mode: "production",
});

const getConf = () => {
  if (__DEV__) {
    return devConf;
  }
  return prodConf;
};

module.exports = [getConf(), serverConfig];
jweston
  • 1
  • 1

0 Answers0