`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:
- Just filter out
vite-plugin-pwa*
- Option 1 plus filtering out any known problem plugins from vite's default set.
- 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
andvite: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?
- as described in the previous message, currently vite plugins are not applied in dev
@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...
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 indev
, but applied inprod
@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 indev
, but applied inprod
@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 (usingimport.meta.env.*
is not a sufficient alternative, as you can't replace values from the code you don't manage by usingimport.meta.env.*
)esbuild
plugin'starget
setting, orjsx
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 havevite-
prefix for dev mode, as it doesn't usevite
'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.