HtmlWebpackPlugin injects relative path files which breaks when loading non-root website paths
Asked Answered
L

3

156

I am using webpack and the HtmlWebpackPlugin to inject bundled js and css into an html template file.

new HtmlWebpackPlugin({
   template: 'client/index.tpl.html',
   inject: 'body',
   filename: 'index.html'
}),

And it produces the following html file.

<!doctype html>
<html lang="en">
  <head>
    ...
    <link href="main-295c5189923694ec44ac.min.css" rel="stylesheet">
  </head>
  <body>
    <div id="app"></div>
    <script src="main-295c5189923694ec44ac.min.js"></script>
  </body>
</html>

This works fine when visiting the root of the app localhost:3000/, but fails when I try to visit the app from another URL, for example, localhost:3000/items/1 because the bundled files are not injected with an absolute path. When the html file is loaded, it will look for the js file inside the non-exist /items directory because react-router hasn't loaded yet.

How can I get HtmlWebpackPlugin to inject the files with an absolute path, so express will look for them at the root of my /dist directory and not at /dist/items/main-...min.js? Or maybe I can change my express server to work around the issue?

app.use(express.static(__dirname + '/../dist'));

app.get('*', function response(req, res) {
  res.sendFile(path.join(__dirname, '../dist/index.html'));
});

Essentially, I just need to get the line:

<script src="main...js"></script>

to have a slash at the start of the source.

<script src="/main...js></script>
Langan answered 5/1, 2016 at 20:27 Comment(0)
W
259

Try setting the publicPath in your webpack config:

output.publicPath = '/'

HtmlWebpackPlugin use the publicPath to prepend the urls of the injects.

Another option is to set the base href in the <head> of your html template, to specify the base url of all relative urls in your document.

<base href="http://localhost:3000/">
Wat answered 6/1, 2016 at 7:47 Comment(5)
Thank you, adding output.publicPath = '/' was the solution.Langan
This will not work if you're running behind reverse proxy.Alburg
You could also use simply <base href="/"> to avoid having to hardcode the host name in the HTML template, or having to interpolate variables.Tephrite
I had to set publicPath = '' and add <base href="~/dist/"> since my site is a ASP.Net MVC project using IIS and a virtual directory.Classieclassification
Lead me in the right direction. Setting publicPath to "" (an empty string) worked to fix my problem.Harned
C
22

In fact, I had to put :

output.publicPath: './';

in order to have it working in a non-ROOT path. At the same time I was injecting :

   baseUrl: './'

into

<base href="<%= htmlWebpackPlugin.options.metadata.baseUrl %>">

With both parameter set, it worked like a charm.

Coeval answered 1/12, 2016 at 9:26 Comment(5)
This shows the URL on browser as https://localhost/myproject/%3C%=%20htmlWebpackPlugin.options.baseUrl%20%%3E#/project/1. Is there any way to solve this?Lowermost
Where are you setting baseUrl: '.' is it in the HtmlWebpackPlugin options? { meta: { baseUrl: './' } }?Elutriate
@Elutriate I don't have this webpack project on hand right now, and I think a lot of things have changed since I posted this answer (including default value). So yes, this is certainly where it should be set, but './' is the correct value.Coeval
Now It can inject base tag directly. inject base tagDistraught
Dumb but really effective 2nd approach. Thanks!Susan
K
9

in webpack config

config.output.publicPath = ''

in your index.html

<base href="/someurl/" />

this should do it.

Kristoforo answered 23/7, 2018 at 13:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.