html-webpack-plugin: overriding publicPath (or, how to set the path for scripts when app is not at server root)?

I have a base, dev and dist webpack config. dev and dist extend base with some custom setup for developing locally vs. deploying to our server. When I run dist it bundles all my code into a folder with the following structure:

dist/
    assets/
        app.js
        vendors.js
    index.html
    favicon.ico

the scripts in index.html get the following structure:

<script type="text/javascript" src="/assets/vendors.js?4aaf64703d2dfe86cedc"></script>
  <script type="text/javascript" src="/assets/app.js?4aaf64703d2dfe86cedc"></script>

… which is fine when I am developing locally, as the project exists at the “root” of my local server, however the project lives in a deeply nested sub directory on my server – /assets/ maps to the root /assets/ directory, when I really need it to be more like assets/vendors.js or even ./assets/vendors.js

Is there a way I can specify this for this plugin? I believe it would require overriding publicPath. Not sure if that’s doable/possible.

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 5
  • Comments: 16 (7 by maintainers)

Most upvoted comments

@jantimon publicPath is applied to both href/src for <link>/<script> and for url() in CSS. If you specify a relative publicPath (e.g. assets/), then the url()s in CSS files will be incorrectly rewritten (foo.png to assets/foo.png, which means the browser tries to load assets/assets/foo.png). Having this configuration option in this plugin lets you use relative publicPaths just for <link>/<script> tags.

It’s entirely possible that I’m configuring webpack wrong, but that’s the reason I want this configuration option.

No problem it takes a lot of time to understand all the webpack configuration options

There’s still no explicit way to solve this problem, though I did also find a workaround for the limitation I was encountering. You are expecting people to be deploying 1-page apps for this; and some of us will have serverside rendering behind it for preloading and SEO.

You’re rendering the link and script tags based on the filename attributes set in the webpack config. This isn’t enough:

  • I hit my app at /index.html and it requests main.js, which resolves to /main.js and we’re fine.
  • I hit my app at /login/ and we’re also fine.
  • I hit my app at /my-coolest-blog/my-bestest-post and main.js (or .css) nor resolves to /my-coolest-blog/main.js and we get a 404 instead of our application code.

The workaround: specify your filenames with a leading / in your webpack config. This will be ignored by your system’s path resolution (// is just changed to /) and also cause the output to have a root-relative URL in it. This only works for apps hosted at the domain root, however, so I think the problem still necessitates the option @tomshen has implemented above?

Setting publicPath: "" for CSS loaders fixed my issue. Thanks for the help! I’ll close my PR.

what about

// Modules
{
   test: /\.s?css$/,
   loader: ExtractTextPlugin.extract('style', '!css?-minimize!postcss!sass', {publicPath: '../../'})
}
// ...
plugins: [
    new ExtractTextPlugin('assets/css/[name].css', {
      allChunks: true
    })