iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
📘

Public Path Configuration is No Longer Required in webpack and Vite

に公開

*Except for IE

The Problem

One of the long-standing headaches in frontend development was the configuration of publicPath. This required explicitly specifying the host to resolve chunks when building an application that includes them.

For example, when placing static files at https://cdn.example.test/assets/module.js, it was necessary to specify https://cdn.example.test/assets/ as the publicPath. This was because, in legacy browser environments, module.js didn't know the path from which it was being executed, and since there was no way to know the path of files relative to itself, it had to be specified at build time.

The Solution

Nowadays, with ESM, you can use import.meta.url, and when called via <script src="..."></script>, you can determine the execution path using document.currentScript.src.

There should be a way to solve this using these, and looking at it now, both webpack and vite have solutions available.

vite: library mode

For standalone builds that have an index.html, you can just distribute your own asset paths as-is. This time, I will explain the solution when creating a build in library mode.

import { defineConfig } from "vite";
import path from "path";

export default defineConfig({
  base: "./",
  build: {
    target: "esnext",
    lib: {
      fileName: "mod",
      formats: ["es"],
      entry: path.join(__dirname, "src/mod.ts"),
    },
  },
});

This generates dist/mod.es.js. You can load it as ESM from any environment.

In this configuration, the part to note is base: "./", which attempts to resolve modules as paths relative to the file itself.

If you deploy this to any location, it will function correctly, including the split chunks.

<script type="module" src="<deploy path>/mod.es.js"></script>

(To be precise, when a relative path starting with ./ is requested, the static asset server needs to resolve the relative path from the requester. Modern CDNs are usually fine, but with self-hosted servers, there might be cases where it fails due to directory traversal protections, etc.)

webpack

// https://webpack.js.org/guides/public-path/#automatic-publicpath
module.exports = {
  output: {
    publicPath: 'auto',
  },
};

I haven't tested this with webpack myself, but the mechanism is the same. If you want to run it on IE, a currentScript polyfill is required.

amiller-gh/currentScript-polyfill: An exceptionally slim polyfill for document.currentScript in IE9+

This polyfill has had some issues for a long time, so I don't really trust it much...

Conclusion

It feels like a method for easily distributing complex frontends has finally been established.

Discussion