Webpack-React with server-side-rendering: linking to css file in server template with hash name
Asked Answered
C

2

6

I'm preparing a starter for react from scratch, here is the code: https://github.com/antondc/react-starter

I managed to set up bundling for client and server, with css modules and less, and now I'm with server side rendering. I'm doing that with a js template:

// src/server/views/index.ejs
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>INDEX.EJS</title>
    <link rel="stylesheet" type="text/css" href="assets/index.css">
</head>
<body>
    <div id="app"></div>
    <script src="/assets/bundle.js"></script>
</body>
</html>

As you see, the link to the css file is harcoded there. But in my Webpack configuration I have this file name hashed, because I want to prevent caching from browsers when I update the code on development.

I am wondering how can I link the css file there. Now in the template I have href="assets/index.css, but the css file is in /dist/assets/d47e.css.

It would be great if would be possible to do something like href="assets/*.css, but is not possible, so what is the common approach for a problem like this one?

Thanks!

Curl answered 22/4, 2018 at 17:22 Comment(1)
any solution yet ?Works
H
3

It depends.

Step 1: Get the current asset name

To get the current name of the generated webpack css/js files, you can use the assets-webpack-plugin. This will (with default config) generate an assets.json file in your output folder with essentially this structure:

{
    "bundle_name": {
        "asset_kind": "/public/path/to/asset"
    }
}

Step 2a: Your html is rendered from a template (pug/jade/what ever)

// in your render code

const assets = require('<webpack-output-folder>/assets.json');

// ...

res.render('template', {
 scripts: [{src: `${WEBPACK_PUBLIC_PATH}/${assets.myEntryPointName.js}` }],
 links: [{href: `${WEBPACK_PUBLIC_PATH}/${assets.myEntryPointName.css}` rel: 'stylesheet' }],
});

// in your template (example for pug)

// ...

each link in links
  link(rel=link.rel href=link.href)

// ...

each script in scripts
  script(src=script.src)

// ...

Step 2b: Your html is static

You need to update the html (using a script) with the information from the asset.json file. This script needs to be run after webpack. Something like

const assets = require('<webpack-output-folder>/assets.json');
const fs = require('fs');

const css = /assets\/[a-z0-9]*\.css/i;
const js = /assets\/[a-z0-9]*\.js/i;

fs.readFile('<yourhtml>.html', (err, data) => {

  // ... (error handling)

  const updatedCss = data.replace(css, assets.myEntryPointName.css);
  const updatedJs = updatedCss.replace(js, assets.myEntryPointName.js);

  fs.writeFile('<yourhtml>.html', updated, (err) => {

    // ... (error handling)

  });

});
Hopscotch answered 9/3, 2019 at 10:7 Comment(0)
H
-1

You can use HTMLWebpackPlugin to generate an HTML file that will have your JS and CSS output inserted.

Hate answered 22/4, 2018 at 21:29 Comment(2)
Don't understand why you propose doing that with Webpack, if you read the question you will notice that HTMLWebpackPlugin is not a viable solution.Curl
html webpack plugin is not a good solution for this use case, we generate our template by a function and return the result of it and use it to inject the result of react 's most top components render to string to it to create our file, so it should not be a good solution in this case , if you know any better solution to implement with html webpack plugin , please dont hesitate to share it with us...Works

© 2022 - 2024 — McMap. All rights reserved.