viteaws-amplifyvite-plugin-pwa

Cannot find service worker script after deployment of Vite-built React app to Amplify environment


After successfully testing my React app locally via vite and vite preview, I have deployed my app to an AWS Amplify environment via git integration. However, in that environment the app cannot find the service worker script at /service-worker.js and I am totally stumped as to why. I am using Vite with vite-plugin-pwa and Workbox.

The service-worker script is located in the root of my build output directory and other files next to it can be found. All the other files the app tries to load for the first time, including the minified script file for the project is located at /assets/index-randomgibberish.js, correctly load.

I know that vite preview runs a dev server using the final build outputs and when I delete build files while previewing, it begins giving 404s as expected, so the same build command being run in the cloud should be generating identical outputs.

During builds, I can see src/service-worker.js being built and public/service-worker.mjs is printed into the console

PWA v0.21.1
Building src/service-worker.js service worker ("es" format)...
[...]
public/service-worker.mjs

However, I never see any file with the .mjs extension.

Trying to GET mywebsite.com/service-worker.js, mywebsite.com/service-worker.mjs, mywebsite.com/assets/service-worker.js and mywebsite.com/assets/service-worker.mjs via both the browser and cURL all fail. Trying to configure redirects/rewrites in Amplify between all of these urls does nothing. Turning off all redirects/rewrites doesn't do anything useful.

As far as I can tell, all of the CloudFront and S3 infrastructure (I see headers that mention both S3 and CloudFront with the requests) and any build infrastructure used is managed by AWS and not accessible to me to examine any build artifacts or lower-level configurations.

I am using a custom domain and both it and the generated Amplify url have identical behavior.

This is my amplify.yaml

version: 1
frontend:
  phases:
    preBuild:
      commands:
        - npm ci --cache .npm --prefer-offline
    build:
      commands:
        - npx ampx pipeline-deploy --branch $AWS_BRANCH --app-id $AWS_APP_ID
        - npm run build
  artifacts:
    baseDirectory: dist
    files:
      - '**/*'
      - 'service-worker.js'

Solution

  • The issue was an inexplicable difference with how the build was being done locally vs in the ci environment.

    In my local environment, the service-worker.js script was being placed in the /public directory and copied (somehow) into the /dist production built output. I assumed since vite copies the /public contents into the build output as-is, this was an expected result.

    When the same build was being done in the ci pipeline, the script was going into the /public directory as before yet NOT being copied into /dist, so the build artifacts given to Amplify didn't have it.

    I have updated my vite.config.ts to move it directly into dist when building for prod.

    export default defineConfig(({mode}) => {
        return ({
            base: '/',
            plugins: [
                react(),
                VitePWA({
                    injectManifest: {
                        injectionPoint: undefined,
                        globDirectory: './dist',
                        globPatterns: ['**/*.{js,css,html,png,svg}'],
                    },
                    srcDir: "src",
                    outDir: mode === "production" ? "dist" : "public",
                    strategies: "injectManifest",
                    filename: "service-worker.js",
                    registerType: "autoUpdate"
                })
            ],
            build: {
                sourcemap: true
            }
        })
    });
    

    I have no idea why these same commands work one way in one place and another way in the other.