sveltejs / kit

web development, streamlined
https://svelte.dev/docs/kit
MIT License
18.75k stars 1.96k forks source link

Vite Plugin: emitted files don't show up in the build output #5346

Open leonhma opened 2 years ago

leonhma commented 2 years ago

Describe the bug

I am currently writing a plugin that is supposed to generate the manifest and images needed for a pwa, and the user can bring their own service worker, in order to be as customisable as possible. The icons are resized into a bunch of different variants and then emitted using emitFiles. Prior function doesn't give any errors and returns an resolveId that resolves to a valid URL. Everything seems to work, but in the end, nothing turns up in the build output, and when requesting _app/manifest.webmanifest or any of the images the server responds with the 404 page.

I have also tested this using a plain vue3 app, and it works flawlessly.

Reproduction

Since I don't have the plugin published, you will have to also clone https://github.com/leonhma/vite-plugin-webmanifest.git and use yarn link. Here is the original relevant plugin code:

import { Plugin } from 'vite'
import { PluginOptions } from './types.js'
import { readFileSync, existsSync } from 'fs'
import { generateIcon } from './utils.js';
import sharp from 'sharp'

export default (options: PluginOptions): Plugin => {
  const purposes: ('any' | 'maskable')[] = ['maskable', 'any']
  const formats: ('webp' | 'png')[] = ['webp', 'png']

  let manifestUrl: string = ''

  return {
    name: 'vite-plugin-webmanifest',
    async buildStart() {
      const imageSrc = options.image?.src || './icon.png'

      const icon = sharp(readFileSync(imageSrc))

      let icons: object[] = []

      for (const resolution of (options.image?.resolutions || [180, 192, 270, 512])) {
        for (const purpose of purposes) {
          for (const format of formats) {
            icons.push({
              // <-------- snip -------->
            })
          }
        }
      }

      const manifest = {
        // <-------- snip --------->
        ...options.manifest || {},
        icons
      };

      manifestUrl = this.getFileName(
        this.emitFile({
          type: 'asset',
          fileName: 'manifest.webmanifest',
          source: Buffer.from(JSON.stringify(manifest))
        })
      )
    },
    async transformIndexHtml() {
      return [
        {
          tag: 'link',
          attrs: {
            rel: 'manifest',
            href: manifestUrl
          },
          injectTo: 'head'
        }
      ]
    }
  }
}

Here's a URL to the repo for reproduction: https://github.com/leonhma/repro-sveltekit-vite-emitfiles.git

Logs

leonhardmasche@penguin:~/imani$ yarn build && yarn start
yarn run v1.22.19
$ svelte-kit build
vite v2.9.12 building for production...
✓ 17 modules transformed.
  Client build completed. Wrote 6 chunks and 2 assets
  Building server
.svelte-kit/output/client/_app/immutable/manifest.json                               1.45 KiB
.svelte-kit/output/client/_app/immutable/pages/__layout.svelte-3c05abc6.js           1.07 KiB / gzip: 0.65 KiB
.svelte-kit/output/client/_app/immutable/error.svelte-9fc3965b.js                    1.56 KiB / gzip: 0.75 KiB
.svelte-kit/output/client/_app/immutable/pages/dashboard/index.svelte-3d01a1bf.js    0.84 KiB / gzip: 0.52 KiB
.svelte-kit/output/client/_app/immutable/pages/index.svelte-b547958d.js              0.68 KiB / gzip: 0.45 KiB
.svelte-kit/output/client/_app/immutable/chunks/index-69850b26.js                    6.92 KiB / gzip: 2.82 KiB
.svelte-kit/output/client/_app/immutable/assets/pages/__layout.svelte-2ccc8da3.css   0.13 KiB / gzip: 0.13 KiB
.svelte-kit/output/client/_app/immutable/start-61eed66d.js                           23.26 KiB / gzip: 8.79 KiB
vite v2.9.12 building SSR bundle for production...
✓ 15 modules transformed.
Generated an empty chunk: "hooks"
.svelte-kit/output/server/manifest.json                             1.48 KiB
.svelte-kit/output/server/index.js                                  73.21 KiB
.svelte-kit/output/server/entries/endpoints/index.ts.js             0.31 KiB
.svelte-kit/output/server/entries/pages/__layout.svelte.js          0.70 KiB
.svelte-kit/output/server/entries/fallbacks/error.svelte.js         0.72 KiB
.svelte-kit/output/server/entries/pages/dashboard/index.svelte.js   0.42 KiB
.svelte-kit/output/server/entries/pages/index.svelte.js             0.38 KiB
.svelte-kit/output/server/chunks/index-5f038599.js                  2.31 KiB
.svelte-kit/output/server/chunks/hooks-1c45ba0b.js                  0.00 KiB
  Prerendering
(node:6457) ExperimentalWarning: buffer.Blob is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)

Run npm run preview to preview your production build locally.

> Using @sveltejs/adapter-cloudflare
  ✔ done
Done in 5.47s.
yarn run v1.22.19

System Info

System:
    OS: Linux 5.10 Debian GNU/Linux 11 (bullseye) 11 (bullseye)
    CPU: (8) arm64 unknown
    Memory: 3.09 GB / 3.10 GB
    Container: Yes
    Shell: 5.1.4 - /bin/bash
  Binaries:
    Node: 16.14.2 - ~/.config/versions/node/v16.14.2/bin/node
    Yarn: 1.22.19 - ~/.yarn/bin/yarn
    npm: 8.5.0 - ~/.config/versions/node/v16.14.2/bin/npm
  npmPackages:
    @sveltejs/adapter-cloudflare: next => 1.0.0-next.24 
    @sveltejs/kit: next => 1.0.0-next.357 
    svelte: ^3.46.0 => 3.48.0

Severity

blocking an upgrade

Additional Information

No response

benmccann commented 2 years ago

@userquin has been working to make https://github.com/antfu/vite-plugin-pwa work with SvelteKit and has it pretty well figured out. There are two known issues: https://github.com/sveltejs/kit/issues/5308 and https://github.com/sveltejs/kit/issues/5306. I have a PR out to fix the first one already

Is there a reason you don't just contribute to vite-plugin-pwa instead of writing your own plugin?

leonhma commented 2 years ago

Thank you. I'll take a look at vite-plugin-pwa. Originally, when looking for how to make my project into a pwa, if found this too, but as far as I understand, this generates a service worker for you. I want to have a bit more control over the service worker, so my idea was to handle the manifest and the icons and apple splash screens via the plugin, and use sveltekit's sw.ts as the service worker. Also, it tries to be zero-config for sveltekit specifically.

leonhma commented 2 years ago

I just took some time to look at antfu's repo, and the strategy they are using, is just copying the service worker and manifest into the build output. IMO it would be much better to make use of vite's/rollup's emitFile in order to somewhat reliably inject those files (for different adapters).

As I see it, vite plugins at the moment are kinda broken, which #5306 seeks to fix.

userquin commented 2 years ago

@leonhma we've changed it since the sveltekit plugin was setting the webmanifest file into the immutable folder, originally we had the output pointing to the .sveltekit folder, check the history

jacob-8 commented 2 years ago

@leonhma I'm digging into why UnoCSS doesn't scan app.html in a SvelteKit project but it does just fine in a vite-svelte project. I've made minimal repros of the transformIndexHtml vite plugin hook working in a vite-svelte project and not working in SvelteKit project.

Somehow vite-pwa is using this hook in SvelteKit though so it looks like there is some way to get a Vite plugin to recognize app.html as the file to pass to transformIndexHtml. I suspect this is happening somewhere in the @vite-pwa/sveltekit config.ts file but haven't had a chance to fully understand that code.

Is there a maintainer who can help explain how to point Vite's transformIndexHtml hook to process SvelteKit's app.html file?

winston0410 commented 1 year ago

@leonhma I have the exact same issue with you, and trying this.emitFile in buildStart now seems to work