vite-pwa / vite-plugin-pwa

Zero-config PWA for Vite

Home Page:https://vite-pwa-org.netlify.app/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

`injectManifest` doesn't include enough plugins

keithlayne opened this issue · comments

See #229 for an example of this - this plugin has a whitelist of allowed plugins when using injectManifest:

https://github.com/antfu/vite-plugin-pwa/blob/main/src/modules.ts#L41-L50

That issue needed at least vite:asset for it to work, possibly more.

I actually remember now debugging this about a year ago before abandoning this plugin and rolling my own to support my service worker setup. Your plugin is way, way, way better than mine 😸 so I wanna get it working.

This works for me for the moment:

  const includedPluginNames = [
+   "commonjs",
+   "vite:asset",
+   "vite:json",
    "alias",
    "vite:resolve",
    "vite:esbuild",
    "replace",
    "vite:define",
    "rollup-plugin-dynamic-import-variables",
    "vite:esbuild-transpile",
    "vite:terser"
  ];

Honestly I am confused about this approach - I'm assuming there was a good reason to whitelist the plugins at some point, but I'm not seeing it. I'm also not that familiar with vite and rollup, so I don't really know the implications. In my hand-rolled plugin I just blacklisted my own plugin, and that worked fine.

I see a few options really to solve this:

  1. Just filter out vite-plugin-pwa*
  2. Option 1 plus filtering out any known problem plugins from vite's default set.
  3. Add a config option to easily add back plugins by name when needed.

I'd probably order them the same way as far as my preference of solution, I just don't know if the first one is feasible...although it's the easiest too.

In general though, users can use whatever plugins they want, and the whitelist feels like a pretty hostile approach - if you rely on any particular plugin for your service worker than you're out of luck here.

Update:

Replacing the whitelist thing with this simple thing works, at least for my current project - it allows me to do a successful production build. Can't deploy yet to test but will update if there are any issues.

const plugins = viteOptions.plugins.filter((p) => !p.name.startsWith('vite-plugin-pwa'));

@keithlayne we have a PR to add commonjs and json plugins, we need to merge and release, maybe we can include also assets before merge to main.

Sorry i missed that, but any thoughts on the last paragraph? I'm going to have to carry a patch if you're going to insist on a plugin list.

Does anyone even remember why it's like this?

@keithlayne avoid infinite recursion, if we include a plugin that is building using vite plugins will not work, for example, in this plugin we need to exclude itself from the rollup build.

Maybe we can review it and apply similar approach for web worker build on vite.

Or just expose the default plugin list and allow configure that list on inject manifest options.

@keithlayne avoid infinite recursion, if we include a plugin that is building using vite plugins will not work, for example, in this plugin we need to exclude itself from the rollup build.

Yeah this is the basis for my (working) one-liner above. I meant why the allow-list vs. a disallow-list, or the simple thing in my example. For my project, the plugins that aren't added my me are (via uniq | sort):

alias
commonjs
rollup-plugin-dynamic-import-variables
vite:asset
vite:asset-import-meta-url
vite:build-html
vite:build-import-analysis
vite:build-metadata
vite:css
vite:css-post
vite:data-uri
vite:define
vite:esbuild
vite:esbuild-transpile
vite:html-inline-proxy
vite:json
vite:load-fallback
vite:load-fallbackvite:build-metadata
vite:manifest
vite:modulepreload-polyfill
vite:reporter
vite:resolve
vite:terser
vite:wasm
vite:watch-package-data
vite:worker
vite:worker-import-meta-url

That's...a lot of plugins. And everyone that's not on the allowed list is vite's default feature set that this plugin is gimping, in this specific case. The current approach is IMO bad (please don't take this the wrong way!) and makes this really good plugin much less usable in this specific case. I still don't see any real rationale for the current approach. Maybe I should dig into the git history? The fact that the one-liner works for me implies that (for at least many cases) the current approach is suboptimal.

If this must be configurable, I'd make it a disallow list of plugins, that gets merged with vite-plugin-pwa's plugin names. By default, users expect all their configured plugins to run, and this shouldn't be an exception. This still allows the flexibility to filter out bad-behaving plugins (if there is such a thing).

Okay, you're talking about #215. Wow, that's pretty disheartening how long it's taken to get a 2-liner approved, and still not merged.

In regards to the webworker plugins: this plugin shouldn't omit them. If you use them in a service worker, you will get runtime errors. That is user error. However, the code is essentially valid JS, and should build anyway. Lots of other things with heinous runtime errors are valid JS, and vite should not (and does not) refuse to build them.

Maybe in an ideal world you'd protect users at build time from using those things, but honestly, it's not any of the plugin's business. The only valid reason to omit plugins is because they cause a build to fail or generate incorrect output. So: go with the one-liner probably, and be done with it.

@keithlayne maybe you can make a pr, then we can check the best solution.

👍 will do

@keithlayne we need to exclude also vite:build-html and vite:html, since them will transform the html again, we should prevent that. I have this on the original PR:
https://github.com/antfu/vite-plugin-pwa/pull/43/files#diff-6c92cdf875e851bf289c6c86c2f48382289c8aa490fc1651ce8c0f12a967dd1aR29

I'll change the PR adding some new configuration stuff and so you will be able to provide the plugin list. The plugin order ids doesn't matter, we don't change the original plugins from vite, we just filter them.

@keithlayne my PR will allow you to do what you want, using the approach on your PR: just use the new option vitePlugins on injectManifest plugin option using the same filter function. And so we don't need to change the original behavior.

import { VitePWA } from 'vite-plugin-pwa'
VitePWA({
  ...
  injectManifest: {
    ...
    vitePlugins: ids => ids.filter(id => !id.startsWith('vite-plugin-pwa'))
  }
}),

You can also import defaultInjectManifestVitePlugins and add vite:asset to it:commonjs and vite:json also added to the default Vite plugins:

import { VitePWA, defaultInjectManifestVitePlugins } from 'vite-plugin-pwa'
VitePWA({
  ...
  injectManifest: {
    ...
    vitePlugins: [...defaultInjectManifestVitePlugins, 'vite:asset']
  }
}),

@keithlayne we need to exclude also vite:build-html and vite:html, since them will transform the html again, we should prevent that.

What HTML? You're running rollup directly against swSrc.

@keithlayne since your are providing the plugins to the rollup build, vite:html will be applied again and so will rebuild/transform the html entry point.

@userquin injectManifest.vitePlugins option is ignored when in dev mode.

  • in other words, when devOptions.enabled is set to true

After looking deeper into it, seems like vite plugins are not applied in the dev mode at all.
In my case, I need vite:define to be applied in dev mode

@keithlayne the plugins are filtered

@userquin please let me know, if I could assist you in any way.
It's very opinionated how the dev mode should look like, maybe you might like how vite-plugin-native-sw handled it in this commit.


vite-plugin-native-sw works great btw in dev mode; I believe rewriting src/plugins/dev.ts in this repo based on vite-plugin-native-sw plugin's dev plugin would simplify code a lot

@userquin could you please clarify your opinion on this issue?

@o-alexandrov if you're using vite:define, cannot just use import.meta.env.VITE_XXX in the sw?

@userquin the problem is not only with vite:define, none of the plugins are applied in the dev mode.

Based on the above, vite-plugin-pwa can produce a completely different output in dev and prod modes, resulting in a DX that you can't trust while developing.


Only the dev mode is broken; In prod, all defaultInjectManifestVitePlugins are applied

@o-alexandrov vite-plugin-pwa in dev just delegates the build to Vite/esbuild, the difference with build is just the final build using rollup to remove static imports. You cannot use ESM in sw yet (only on chromium based browsers).

If you use define, include the corresponding entries, you can use import.meta.env.VITE_XXX in dev and build.

@o-alexandrov can you provide a minimal repro what you're trying to add to your custom sw?

EDIT: maybe we can just allow add a list of plugins, as an advanced option: if the build is broken...

@userquin

vite-plugin-pwa in dev just delegates the build to Vite/esbuild, the difference with build is just the final build using rollup to remove static imports.

It's not true, the difference related to this ticket is:

  • defaultInjectManifestVitePlugins is not applied in dev, but applied in prod

@o-alexandrov here an example using define (the same result with build + preview):

imagen

imagen

imagen

@userquin I have no idea why are you so fixed on vite:define.
We shouldn't attempt to mask the bug with an alternative way of value replacement.

The bug is:

  • defaultInjectManifestVitePlugins is not applied in dev, but applied in prod

@o-alexandrov ok: defaultInjectManifestVitePlugins will be only applied on build, we're not building the sw on dev, the dev plugin just read the sw content file and return it (vite/esbuild just remove the typescript annotations and types if using typescript).

Check jsdoc (applied on rollup build, on dev we don't build the sw, there is nothing we can do here): https://github.com/vite-pwa/vite-plugin-pwa/blob/main/src/types.ts#L14

By not applying any vite plugins, the service worker cannot reuse all these plugins' configurations, for example:

  • define w/ variables replacement (using import.meta.env.* is not a sufficient alternative, as you can't replace values from the code you don't manage by using import.meta.env.*)
  • esbuild plugin's target setting, or jsx
  • resolve w/ pointers for different libraries, ex. lodash & lodash-es

Do you really think, it's fine to not apply any vite's plugins configuration to the service worker in dev?

  • this plugin, vite-plugin-pwa, should NOT have vite- prefix for dev mode, as it doesn't use vite's features

@o-alexandrov have you read this comment, the EDIT comment #260 (comment) ?

You already know vite-plugin-pwa doesn't use any vite's plugins in the dev mode, what would a repro help you with?
This comment in this same issue provided a link to vite-plugin-native-sw that has a working dev & prod modes

  • it's just less popular and doesn't have other features vite-plugin-pwa has

Realized this is not exactly matching the OP's issue, so added a new one in #425.
And added a reproducible example there.

I would like to also bring another use-case with plugins, which currently forces me to not build with this plugin but as a separate rollup build step.
Basically I need to stub some modules for service worker build only, which means that resolve.alias in vite config file would not work as it will also stub the modules in the main app which will break the app.

So basically I would need to have something similar to what injectManifest.vitePlugins gives but instead of just being a filtering logic based on strigs it should accept an array of vite/rollup plugins that would apply just to the service worker build.

Do you think this is something that could be supported by this plugin?
Should I create another issue for this feature?

@o-alexandrov @gund @keithlayne We're switching injetManifest to build the service worker using a new custom Vite build, adding a new option to injectManifest to configure plugins?: Plugin | Plugin[], you only need to configure plugins in vite config file and pwa options, I'll ping you again when PR in the repo, I need to do some tests.

We're also including original define entries in the new build configuration.