buildviteprogressive-web-apps

How to get build assets during build in Vite?


I am using service worker for my project. For some time I did not need code-splitting and the web app was working offline without extra configuration, but now I need to tell the service worker about my assets (paths and names of different chunks) for it to handle it in background while the network is available.

To build a service worker file I assembled custom Vite plugin like this:

import * as child from "child_process";
import { build } from "esbuild";
import { replace } from "esbuild-plugin-replace";
import { join } from "node:path";

import type { PluginOption } from "vite";

/**
 * Returns the hash of the latest git commit
 */
export function getCommitHash(short = false) {
    return child
        .execSync(`git rev-parse ${short ? "--short" : ""} HEAD`)
        .toString()
        .trim();
}

export const compileServiceWorker: PluginOption = {
    apply: "build",
    enforce: "post",
    name: "compile-service-worker",
    transformIndexHtml() {
        void build({
            bundle: true,
            entryPoints: [ join(process.cwd(), "src", "service-worker.js") ],
            minify: true,
            outfile: join(process.cwd(), "dist", "service-worker.js"),
            plugins: [
                replace({
                    values: {
                        "__COMMIT_HASH__": () => getCommitHash()
                    }
                })
            ],
            target: "es2021"
        });
    }
};

Here I minify the service worker and put some sort of hash based on latest commit for service worker to update.

I can write up some script that will get all assets paths and names after build, but I feel there is a better way of doing it via Vite itself. Can somebody point me to some direction?

I am aware of the vite-pwa plugin, but I want to do this myself and learn how to do it.

I have the example of something similar in squoosh app here, but that project is built using Rollup.


Solution

  • I found a solution for my problem.

    There is a hook generateBundle, here the generated bundle information as an object is passed via bundle argument:

    generateBundle(this, options, bundle) {
      console.log(Object.keys(bundle));
    }