Library Affected:
workbox-webpack-plugin v5.0.0
Issue or Feature Request Description:
My goal: I use the micro-front-end architecture in my project, and use navigator.serviceWorker in the main application. Now I need to generate the preaceche manifest file in the sub-application, and then read the main application's InjectManifest manifestTransforms parameter to finally generate the preaceche manifest.
But the question comes, how can I use workbox-webpack-plugin to generate a preaceche manifest JSON file in the sub-app project
In v5, the webpack plugin's InjectManifest mode does (roughly) two things:
self.__WB_MANIFEST somewhere in the swSrc file, and replaces it with the array of objects that makes up the precache manifest based on your configuration and the webpack asset pipeline.swSrc file.If you created a swSrc file that consisted of:
module.exports = self.__WB_MANIFEST;
I think you'd get the behavior you want. (Not JSON, but as CJS module that you could then read from another node script.)
thank you for your reply! @jeffposnick
module.exports = self.__WB_MANIFEST;
the generated code should be an Entry, not a module.
(function(e) {
var t = {}
function r(n) {
if (t[n]) return t[n].exports
var o = t[n] = { i: n, l: !1, exports: {} }
return e[n].call(o.exports, o, o.exports, r), o.l = !0, o.exports
}
r.m = e, r.c = t, r.d = function(e, t, n) {
r.o(e, t) || Object.defineProperty(e, t, { enumerable: !0, get: n })
}, r.r = function(e) {
"undefined" !== typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, { value: "Module" }), Object.defineProperty(e, "__esModule", { value: !0 })
}, r.t = function(e, t) {
if (1 & t && (e = r(e)), 8 & t) return e
if (4 & t && "object" === typeof e && e && e.__esModule) return e
var n = Object.create(null)
if (r.r(n), Object.defineProperty(n, "default", {
enumerable: !0,
value: e,
}), 2 & t && "string" != typeof e) for (var o in e) r.d(n, o, function(t) {
return e[t]
}.bind(null, o))
return n
}, r.n = function(e) {
var t = e && e.__esModule ? function() {
return e["default"]
} : function() {
return e
}
return r.d(t, "a", t), t
}, r.o = function(e, t) {
return Object.prototype.hasOwnProperty.call(e, t)
}, r.p = "/", r(r.s = "249e")
})({
"249e": function(e, t, r) {
"use strict"
r.r(t), console.log(111), t["default"] = [{
"revision": "e012c7685e0f83ceeb2edff8e047a5c7",
"url": "/icons/icon_128x128.e012c7685e0f83ceeb2edff8e047a5c7.png",
}]
},
})
My ability is limited,I tried to change the code, but did't work, still an Entry not a module.
maybe I need to write a plugin based on workbox-build.
I hope the official can provide this feature, thanks
node_modules/workbox-webpack-plugin/build/inject-manifest.js

@jeffposnick
Hello i am here again
I hope the official can provide this function, if the official agrees, I will make a pull request.
If the official can't agree, I will release an npm package
The approximate code is as follows. based on workbox-webpack-plugin
const getManifestEntriesFromCompilation = require("workbox-webpack-plugin/build/lib/get-manifest-entries-from-compilation")
const relativeToOutputPath = require("workbox-webpack-plugin/build/lib/relative-to-output-path")
const { RawSource } = require("webpack-sources")
class ManifestWorkboxWebpackPlugin {
constructor(config = {}) {
this.config = config
}
apply(compiler) {
compiler.hooks.emit.tapPromise(
"ManifestWorkboxWebpackPlugin",
async compilation => {
const dest = relativeToOutputPath(compilation, this.config.dest)
const manifestEntries = await getManifestEntriesFromCompilation(
compilation,
this.config,
)
compilation.assets[dest] = new RawSource(
JSON.stringify(manifestEntries),
)
},
)
}
}
module.exports = ManifestWorkboxWebpackPlugin
Oh, hmm, I guess webpack does end up putting in quite a bit of boilerplate during compilation even if the source file just has a simple module.exports = ... statement. Sorry about that.
We don't offer any guarantees that the getManifestEntriesFromCompilation() and relativeToOutputPath() functions will continue to behave exactly like they do right now—they're not meant as part of the external interface—so while you could package that up into a plugin that you release on npm, it might end up only being compatible with specific versions of workbox-webpack-plugin.
But for your own use, sure, that should accomplish most of what you want.
@jeffposnick Hello, is the official considering this feature built-in? Named GenerateManifest exists like GenerateSW, InjectManifest.
const { GenerateManifest } = require("workbox-webpack-plugin")
const webpackConfig = {
plugins: [new GenerateManifest(options)]
}
I think I can create a new pull request
I'd rather not add this in as an official mode unless I hear strongly from more users who have the same requirement.
We currently have trouble explaining to developers what the difference is between GenerateSW and InjectManifest (maybe this guide helps, but I do see folks get confused all of the time) and I think the negative consequences of creating an additional "official" mode that developers have to choice from would outweigh the benefits.
Apologies, but again, if you're able to solve your use case via that approach, please feel free to do so. And you could publish things as a standalone module on npm with the caveat that you'd need to keep it up to date if something changes in the (internal to workbox-webpack-plugin) getManifestEntriesFromCompilation() and relativeToOutputPath() methods.
@jeffposnick Hello, is the official considering this feature built-in? Named GenerateManifest exists like GenerateSW, InjectManifest.
const { GenerateManifest } = require("workbox-webpack-plugin") const webpackConfig = { plugins: [new GenerateManifest(options)] }I think I can create a new pull request
Wow~ awesome, I need this plugin too!
Okay, so based on https://github.com/GoogleChrome/workbox/issues/2401 and other comments here, it sounds like there is in fact demand for this sort of thing.
As I said, I would rather not create a brand new workbox-webpack-plugin class for this use case.
Here's an idea, though: we could add in a new configuration parameter to InjectManifest called compileSrc, which defaults to true. If it's explicitly set to false, then instead of starting up a child compilation, InjectManifest will just generate the manifest entries and do a string replacement of self.__WB_MANIFEST in the swSrc file. We can make sure that the manifest replacement uses valid JSON.
I believe that would allow you to use swSrc files that contain either
self.__WB_MANIFEST
if you wanted a standalone JSON file containing the manifest, or
module.exports = self.__WB_MANIFEST;
if you wanted a CJS module that exported it.
How would folks feel about that approach?
I think that's awesome.
My current implementation is like this:
I create a variable in the top of the webpack file. let manifest = [];
then, in the manifestTransform function parameter of InjectManifest, I have manifest = manifestEntry;
Then, After the InjectManifest plugin, I have another plugin, but not via class such as new PluginNewOne(), but directly { apply(compiler){} } . In that function I register emit hook, so that when it executes, my manifest variable is already set to whatever manifestTransform did. Now, what I do, is get the specific file from compilation.assets and if that file contains const manifest = WB_MANIFEST line, I replace WB_MANIFEST with my manifest variable.
The idea was that I needed to have manifest entries in other file such as app.js and not only in my built service-worker.js file. The last question I have is do you think this solution is pretty good from the perspective of workbox at this stage?
I didn't _think_ that so many folks would need to have manifest entries in another file, outside of their service-worker.js, but if you feel like it's a legitimate use case and we can enable it via one additional configuration option, I'm willing to do so.
(It's hard for me to say whether a specific use case is "valid" or not.)
Actually, yes, I feel like It's a good thing. I have a use case where I need to loop through all the files outside of service worker and make requests for them. I don't want to write something that gives me the array of the files, since InjectManifest already does that. So, why not? I agree that this mightn't be necessary for lots of folks, it all comes down to how much effort you gotta put. If it's not too much, That would be great from your side.
Most helpful comment
@jeffposnick Hello, is the official considering this feature built-in? Named GenerateManifest exists like GenerateSW, InjectManifest.
I think I can create a new pull request