NekR / offline-plugin

Offline plugin (ServiceWorker, AppCache) for webpack (https://webpack.js.org/)
MIT License
4.52k stars 295 forks source link

Does it work with 2 HtmlWebpackPlugin instances? #403

Closed poteirard closed 3 weeks ago

poteirard commented 6 years ago

Hi,

First of all thanks for your work. This is amazing 💯 !!

I'm new into service workers and I would like to have all the chunks served from the service worker but I can't :(

I have 2 instances of HtmlWebpackPlugin and I thought that maybe that's the problem. Because I get the assets from one (the one used for session management) but not the other one (the app itself).

deposits

Here is my webpack client config
const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const { clientPath, staticPath, currentWorkingDirectory } = require('../../paths');
var OfflinePlugin = require('offline-plugin');

module.exports = {
  entry: {
    RPZopaCheckSession: path.resolve(currentWorkingDirectory, 'src', 'RPZopaCheckSession', 'index.ts'),
    client: path.resolve(clientPath, 'client.tsx'),
  },
  output: {
    filename: '[name].bundle.js',
    chunkFilename: '[name].chunk.js',
    path: path.resolve(currentWorkingDirectory, 'build', 'client'),
    publicPath: '/assets/',
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          {
            loader: 'style-loader',
          },
          {
            loader: 'css-loader',
            options: {
              localIdentName: '[path][name]__[local]--[hash:base64:5]',
            },
          },
        ],
      },
      {
        test: /\.(jpg|png|svg)$/,
        use: {
          loader: 'url-loader',
          options: {
            limit: 25000,
          },
        },
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, 'templates', 'index.ejs'),
      chunks: ['client'],
      //TODO: remove this patch for webpack 4 https://github.com/jantimon/html-webpack-plugin/issues/870
      chunksSortMode: 'none',
    }),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, 'templates', 'RPZopaCheckSession.ejs'),
      filename: 'RPZopaCheckSession.html',
      chunks: ['RPZopaCheckSession'],
      //TODO: remove this patch for webpack 4 https://github.com/jantimon/html-webpack-plugin/issues/870
      chunksSortMode: 'none',
    }),
    // Useful for optimizing de external dependencies. Uncomment to activate
    // new BundleAnalyzerPlugin(),

    // More info: https://github.com/NekR/offline-plugin
    new OfflinePlugin({
      autoUpdate: 1000 * 60 * 2, // 2 minutes
    }),
  ],
  resolve: {
    alias: {
      Redux: path.resolve(clientPath, 'redux'),
      Hoc: path.resolve(clientPath, 'hoc'),
      Components: path.resolve(clientPath, 'components'),
      Form: path.resolve(clientPath, 'form'),
      Services: path.resolve(clientPath, 'services'),
      Constants: path.resolve(clientPath, 'constants'),
      Scenes: path.resolve(clientPath, 'scenes'),
      APIs: path.resolve(clientPath, 'apis'),
      Types: path.resolve(clientPath, 'types'),
      ClientTypes: path.resolve(clientPath, 'types'),
      Helpers: path.resolve(clientPath, 'helpers'),
      Styles: path.resolve(clientPath, 'styles'),
      Static: staticPath,
      Assets: staticPath, // alias for static
      Data: path.resolve(clientPath, 'data'),

      // lightweight react compatibility library.
      // Comment this if we have compatibility problems.
      // 'react': 'preact-compat',
      // 'react-dom': 'preact-compat',
    },
    // Default setting: `[".js", ".json"]`. Augmented to allow for JSX, and
    // TypeScript when leaving off module filename extension. The last item in
    // the array, `"*"`, is to allow for proper module resolution for modules
    // that are imported using an extension.
    extensions: ['.js', '.jsx', '.ts', '.tsx', '.json', '*'],

    // When leaving `target` unspecified in the config, it defaults to `"web"`.
    // Web's default is `mainFields: ["browser", "module", "main"]`, so the
    // array is augmented to include support for TypeScript
    mainFields: ['browser', 'module', 'main', 'types'],
  },
};
This is the response of `sw.js`
var __wpo = {
    "assets": {
        "main": ["/assets/vendors~LandingPage.chunk.js", "/assets/UserDebugDashboard.chunk.js", "/assets/Holding.chunk.js", "/assets/Reconciliation.chunk.js", "/assets/Onboarding.chunk.js", "/assets/Dashboard.chunk.js", "/assets/LandingPage.chunk.js", "/assets/Matured.chunk.js", "/assets/Extended.chunk.js", "/assets/Extendable.chunk.js", "/assets/SuccessTermStarted.chunk.js", "/assets/PeriodOpenNoFunds.chunk.js", "/assets/OpenSufficientFunds.chunk.js", "/assets/OpenInsufficientFunds.chunk.js", "/assets/FailureInsufficientFunds.chunk.js", "/assets/client.bundle.js", "/assets/RPZopaCheckSession.bundle.js", "/assets/", "/assets/RPZopaCheckSession.html"],
        "additional": [],
        "optional": []
    },
    "externals": [],
    "hashesMap": {
        "b26ed730c4d746027ecf8ed45e9ac5155f2fe9b8": "/assets/vendors~LandingPage.chunk.js",
        "80dde33288e336f02eef00eaedc65f10c5e547fe": "/assets/UserDebugDashboard.chunk.js",
        "797c34956adc7bfcfd8d8a26bd64d9a671e34c78": "/assets/Holding.chunk.js",
        "09b5668dd10bb852e2b6dd40a43d006e66eed7f3": "/assets/Reconciliation.chunk.js",
        "63279e4e5133ea2b35f7ff2c43d6b9c95e3b170d": "/assets/Onboarding.chunk.js",
        "006ead839ead716e71e46295d26e4701540e86a1": "/assets/Dashboard.chunk.js",
        "c7d14756a60c74264d990682838e1287cd43c830": "/assets/LandingPage.chunk.js",
        "dfb0d8e983a1711e1d7f52fedefcbd3c2bf96aa2": "/assets/Matured.chunk.js",
        "62e5956fd553ac5607ae41d7b1a0c7019cf763bd": "/assets/Extended.chunk.js",
        "650555e4bfccc8d7ebf75d409a8e88834f82f8e5": "/assets/Extendable.chunk.js",
        "b8a8aa9f735e16d64216875486b5863a53368358": "/assets/SuccessTermStarted.chunk.js",
        "3e8e59a88c0e29f089e73ed09ace19413a98f3ad": "/assets/PeriodOpenNoFunds.chunk.js",
        "6203b6f9ec48da9085159b3d94558045544ffb0e": "/assets/OpenSufficientFunds.chunk.js",
        "47806f72c18d51153720e5780d4e1bf5e2e2f2dd": "/assets/OpenInsufficientFunds.chunk.js",
        "60706eb310642b9e09a2a73597d1187af593ee43": "/assets/FailureInsufficientFunds.chunk.js",
        "15d44fb182d79f8305d277e231dc96bf92cecbeb": "/assets/client.bundle.js",
        "5c047781010f9ee91c30d5898c0168cc61d46fc8": "/assets/RPZopaCheckSession.bundle.js",
        "e4af508908b8cf38040f319a3a64bb793fde8655": "/assets/",
        "36714bad7c524d7645ffbd92498d4d3ff798c9f8": "/assets/RPZopaCheckSession.html"
    },
    "strategy": "changed",
    "responseStrategy": "cache-first",
    "version": "2018-7-25 12:29:52",
    "name": "webpack-offline",
    "pluginVersion": "5.0.5",
    "relativePaths": false
};

! function(e) {
    var n = {};

    function t(r) {
        if (n[r]) return n[r].exports;
        var o = n[r] = {
            i: r,
            l: !1,
            exports: {}
        };
        return e[r].call(o.exports, o, o.exports, t), o.l = !0, o.exports
    }
    t.m = e, t.c = n, t.d = function(e, n, r) {
        t.o(e, n) || Object.defineProperty(e, n, {
            enumerable: !0,
            get: r
        })
    }, t.r = function(e) {
        "undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, {
            value: "Module"
        }), Object.defineProperty(e, "__esModule", {
            value: !0
        })
    }, t.t = function(e, n) {
        if (1 & n && (e = t(e)), 8 & n) return e;
        if (4 & n && "object" == typeof e && e && e.__esModule) return e;
        var r = Object.create(null);
        if (t.r(r), Object.defineProperty(r, "default", {
                enumerable: !0,
                value: e
            }), 2 & n && "string" != typeof e)
            for (var o in e) t.d(r, o, function(n) {
                return e[n]
            }.bind(null, o));
        return r
    }, t.n = function(e) {
        var n = e && e.__esModule ? function() {
            return e.default
        } : function() {
            return e
        };
        return t.d(n, "a", n), n
    }, t.o = function(e, n) {
        return Object.prototype.hasOwnProperty.call(e, n)
    }, t.p = "/assets/", t(t.s = 1)
}([function(e, n) {}, function(e, n, t) {
    "use strict";
    if (function() {
            var e = ExtendableEvent.prototype.waitUntil,
                n = FetchEvent.prototype.respondWith,
                t = new WeakMap;
            ExtendableEvent.prototype.waitUntil = function(n) {
                var r = this,
                    o = t.get(r);
                if (!o) return o = [Promise.resolve(n)], t.set(r, o), e.call(r, Promise.resolve().then(function e() {
                    var n = o.length;
                    return Promise.all(o.map(function(e) {
                        return e.catch(function() {})
                    })).then(function() {
                        return o.length != n ? e() : (t.delete(r), Promise.all(o))
                    })
                }));
                o.push(Promise.resolve(n))
            }, FetchEvent.prototype.respondWith = function(e) {
                return this.waitUntil(e), n.call(this, e)
            }
        }(), void 0 === r) var r = !1;

    function o(e, n) {
        var t = n.cacheMaps,
            o = n.navigationPreload,
            u = e.strategy,
            l = e.responseStrategy,
            h = e.assets,
            d = e.hashesMap,
            p = e.externals,
            v = e.prefetchRequest || {
                credentials: "same-origin",
                mode: "cors"
            },
            m = e.name,
            g = e.version,
            w = m + ":" + g,
            y = m + "$preload",
            b = "__offline_webpack__data";
        C();
        var P = [].concat(h.main, h.additional, h.optional);

        function O() {
            if (!h.additional.length) return Promise.resolve();
            r && console.log("[SW]:", "Caching additional");
            return ("changed" === u ? U("additional") : S("additional")).catch(function(e) {
                console.error("[SW]:", "Cache section `additional` failed to load")
            })
        }

        function S(n) {
            var t = h[n];
            return caches.open(w).then(function(r) {
                return A(r, t, {
                    bust: e.version,
                    request: v,
                    failAll: "main" === n
                })
            }).then(function() {
                f("Cached assets: " + n, t)
            }).catch(function(e) {
                throw console.error(e), e
            })
        }

        function U(n) {
            return x().then(function(t) {
                if (!t) return S(n);
                var r = t[0],
                    o = t[1],
                    i = t[2],
                    a = i.hashmap,
                    c = i.version;
                if (!i.hashmap || c === e.version) return S(n);
                var u = Object.keys(a).map(function(e) {
                        return a[e]
                    }),
                    s = o.map(function(e) {
                        var n = new URL(e.url);
                        return n.search = "", n.hash = "", n.toString()
                    }),
                    l = h[n],
                    p = [],
                    m = l.filter(function(e) {
                        return -1 === s.indexOf(e) || -1 === u.indexOf(e)
                    });
                Object.keys(d).forEach(function(e) {
                    var n = d[e];
                    if (-1 !== l.indexOf(n) && -1 === m.indexOf(n) && -1 === p.indexOf(n)) {
                        var t = a[e];
                        t && -1 !== s.indexOf(t) ? p.push([t, n]) : m.push(n)
                    }
                }), f("Changed assets: " + n, m), f("Moved assets: " + n, p);
                var g = Promise.all(p.map(function(e) {
                    return r.match(e[0]).then(function(n) {
                        return [e[1], n]
                    })
                }));
                return caches.open(w).then(function(t) {
                    var r = g.then(function(e) {
                        return Promise.all(e.map(function(e) {
                            return t.put(e[0], e[1])
                        }))
                    });
                    return Promise.all([r, A(t, m, {
                        bust: e.version,
                        request: v,
                        failAll: "main" === n,
                        deleteFirst: "main" !== n
                    })])
                })
            })
        }

        function R() {
            return caches.keys().then(function(e) {
                var n = e.map(function(e) {
                    if (0 === e.indexOf(m) && 0 !== e.indexOf(w)) return console.log("[SW]:", "Delete cache:", e), caches.delete(e)
                });
                return Promise.all(n)
            })
        }

        function x() {
            return caches.keys().then(function(e) {
                for (var n = e.length, t = void 0; n-- && 0 !== (t = e[n]).indexOf(m););
                if (t) {
                    var r = void 0;
                    return caches.open(t).then(function(e) {
                        return r = e, e.match(new URL(b, location).toString())
                    }).then(function(e) {
                        if (e) return Promise.all([r, r.keys(), e.json()])
                    })
                }
            })
        }

        function q() {
            return caches.open(w).then(function(n) {
                var t = new Response(JSON.stringify({
                    version: e.version,
                    hashmap: d
                }));
                return n.put(new URL(b, location).toString(), t)
            })
        }

        function W(e, n, t) {
            return k(e), i(t, w).then(function(o) {
                return o ? (r && console.log("[SW]:", "URL [" + t + "](" + n + ") from cache"), o) : fetch(e.request).then(function(o) {
                    return o.ok ? (r && console.log("[SW]:", "URL [" + n + "] from network"), t === n && function() {
                        var t = o.clone(),
                            r = caches.open(w).then(function(e) {
                                return e.put(n, t)
                            }).then(function() {
                                console.log("[SW]:", "Cache asset: " + n)
                            });
                        e.waitUntil(r)
                    }(), o) : (r && console.log("[SW]:", "URL [" + n + "] wrong response: [" + o.status + "] " + o.type), o)
                })
            })
        }

        function L(e, n, t) {
            return F(e).then(function(e) {
                if (e.ok) return r && console.log("[SW]:", "URL [" + n + "] from network"), e;
                throw e
            }).catch(function(e) {
                return r && console.log("[SW]:", "URL [" + n + "] from cache if possible"), i(t, w).then(function(n) {
                    if (n) return n;
                    if (e instanceof Response) return e;
                    throw e
                })
            })
        }

        function k(e) {
            if (o && "function" == typeof o.map && e.preloadResponse && "navigate" === e.request.mode) {
                var n = o.map(new URL(e.request.url), e.request);
                n && _(n, e)
            }
        }
        self.addEventListener("install", function(e) {
            console.log("[SW]:", "Install event");
            var n = void 0;
            n = "changed" === u ? U("main") : S("main"), e.waitUntil(n)
        }), self.addEventListener("activate", function(e) {
            console.log("[SW]:", "Activate event");
            var n = O();
            n = (n = (n = n.then(q)).then(R)).then(function() {
                if (self.clients && self.clients.claim) return self.clients.claim()
            }), o && self.registration.navigationPreload && (n = Promise.all([n, self.registration.navigationPreload.enable()])), e.waitUntil(n)
        }), self.addEventListener("fetch", function(e) {
            if ("GET" === e.request.method && ("only-if-cached" !== e.request.cache || "same-origin" === e.request.mode)) {
                var n = new URL(e.request.url);
                n.hash = "";
                var t = n.toString(); - 1 === p.indexOf(t) && (n.search = "", t = n.toString());
                var r = -1 !== P.indexOf(t),
                    i = t;
                if (!r) {
                    var a = T(e.request);
                    a && (i = a, r = !0)
                }
                if (r) {
                    var c = void 0;
                    c = "network-first" === l ? L(e, t, i) : W(e, t, i), e.respondWith(c)
                } else {
                    if ("navigate" === e.request.mode && !0 === o) return void e.respondWith(F(e));
                    if (o) {
                        var u = M(e);
                        if (u) return void e.respondWith(u)
                    }
                }
            }
        }), self.addEventListener("message", function(e) {
            var n = e.data;
            if (n) switch (n.action) {
                case "skipWaiting":
                    self.skipWaiting && self.skipWaiting()
            }
        });
        var E = new Map;

        function _(e, n) {
            var t = new URL(e, location),
                r = n.preloadResponse;
            E.set(r, {
                url: t,
                response: r
            });
            var o = function() {
                    return E.has(r)
                },
                i = r.then(function(e) {
                    if (e && o()) {
                        var n = e.clone();
                        return caches.open(y).then(function(e) {
                            if (o()) return e.put(t, n).then(function() {
                                if (!o()) return caches.open(y).then(function(e) {
                                    return e.delete(t)
                                })
                            })
                        })
                    }
                });
            n.waitUntil(i)
        }

        function j(e) {
            if (E) {
                var n = void 0,
                    t = void 0;
                return E.forEach(function(r, o) {
                    r.url.href === e.href && (n = r.response, t = o)
                }), n ? (E.delete(t), n) : void 0
            }
        }

        function M(e) {
            var n = new URL(e.request.url);
            if (self.registration.navigationPreload && o && o.test && o.test(n, e.request)) {
                var t = j(n),
                    r = e.request;
                return t ? (e.waitUntil(caches.open(y).then(function(e) {
                    return e.delete(r)
                })), t) : i(r, y).then(function(n) {
                    return n && e.waitUntil(caches.open(y).then(function(e) {
                        return e.delete(r)
                    })), n || fetch(e.request)
                })
            }
        }

        function C() {
            Object.keys(h).forEach(function(e) {
                h[e] = h[e].map(function(e) {
                    var n = new URL(e, location);
                    return n.hash = "", -1 === p.indexOf(e) && (n.search = ""), n.toString()
                })
            }), d = Object.keys(d).reduce(function(e, n) {
                var t = new URL(d[n], location);
                return t.search = "", t.hash = "", e[n] = t.toString(), e
            }, {}), p = p.map(function(e) {
                var n = new URL(e, location);
                return n.hash = "", n.toString()
            })
        }

        function A(e, n, t) {
            var r = t.bust,
                o = !1 !== t.failAll,
                i = !0 === t.deleteFirst,
                c = t.request || {
                    credentials: "omit",
                    mode: "cors"
                },
                u = Promise.resolve();
            return i && (u = Promise.all(n.map(function(n) {
                return e.delete(n).catch(function() {})
            }))), Promise.all(n.map(function(e) {
                return r && (e = a(e, r)), fetch(e, c).then(s).then(function(e) {
                    return e.ok ? {
                        response: e
                    } : {
                        error: !0
                    }
                }, function() {
                    return {
                        error: !0
                    }
                })
            })).then(function(t) {
                return o && t.some(function(e) {
                    return e.error
                }) ? Promise.reject(new Error("Wrong response status")) : (o || (t = t.filter(function(e) {
                    return !e.error
                })), u.then(function() {
                    var r = t.map(function(t, r) {
                        var o = t.response;
                        return e.put(n[r], o)
                    });
                    return Promise.all(r)
                }))
            })
        }

        function T(e) {
            var n = e.url,
                r = new URL(n),
                o = void 0;
            o = c(e) ? "navigate" : r.origin === location.origin ? "same-origin" : "cross-origin";
            for (var i = 0; i < t.length; i++) {
                var a = t[i];
                if (a && (!a.requestTypes || -1 !== a.requestTypes.indexOf(o))) {
                    var u = void 0;
                    if ((u = "function" == typeof a.match ? a.match(r, e) : n.replace(a.match, a.to)) && u !== n) return u
                }
            }
        }

        function F(e) {
            return e.preloadResponse && !0 === o ? e.preloadResponse.then(function(n) {
                return n || fetch(e.request)
            }) : fetch(e.request)
        }
    }

    function i(e, n) {
        return caches.match(e, {
            cacheName: n
        }).then(function(t) {
            return u(t) ? t : s(t).then(function(t) {
                return caches.open(n).then(function(n) {
                    return n.put(e, t)
                }).then(function() {
                    return t
                })
            })
        }).catch(function() {})
    }

    function a(e, n) {
        return e + (-1 !== e.indexOf("?") ? "&" : "?") + "__uncache=" + encodeURIComponent(n)
    }

    function c(e) {
        return "navigate" === e.mode || e.headers.get("Upgrade-Insecure-Requests") || -1 !== (e.headers.get("Accept") || "").indexOf("text/html")
    }

    function u(e) {
        return !e || !e.redirected || !e.ok || "opaqueredirect" === e.type
    }

    function s(e) {
        return u(e) ? Promise.resolve(e) : ("body" in e ? Promise.resolve(e.body) : e.blob()).then(function(n) {
            return new Response(n, {
                headers: e.headers,
                status: e.status
            })
        })
    }

    function f(e, n) {
        console.groupCollapsed("[SW]:", e), n.forEach(function(e) {
            console.log("Asset:", e)
        }), console.groupEnd()
    }
    o(__wpo, {
        loaders: {},
        cacheMaps: [],
        navigationPreload: !1
    }), e.exports = t(0)
}]);

Thanks again :)

poteirard commented 6 years ago

I tried to remove RPZopaCheckSession and then nothing gets served from the SW :(