pcb icon indicating copy to clipboard operation
pcb copied to clipboard

Add 'publicPath' option to runtime 'install' method

Open alfeg opened this issue 8 years ago • 21 comments

Is it possible to update runtime_template.js to contain a publicPath option. So that I can register SW in runtime using custom publicPath - not the one provided by webPack, i.e.

require("offline-plugin/runtime").install({
    publicPath: '/myOwnPublicPathTo/sw.js'
})

When my app is deployed to asp.net mvc app it can run from any subfolder - so asp.net provide proper base path in runtime.

alfeg avatar Feb 14 '17 08:02 alfeg

I'm realized that sw.js itself contains a lot of build time path variables...

alfeg avatar Feb 14 '17 08:02 alfeg

Don't give up on it so fast :-) Yes, sw.js has a lot of things generated on build time, but in general everything there could be used relatively to publicPath.

There is a relative paths option in offline-plugin, if you set it to true then it don't use webpack's publicPath, but rather everything relative to page which requested the sw.js. Give it a try :-)

NekR avatar Feb 14 '17 09:02 NekR

Thanks. I've hacked a bit runtime_template.js and make it works as expected. So yeah. I want custom path option in runtime.install

alfeg avatar Feb 14 '17 10:02 alfeg

@alfeg can you show to me what exactly you changed there?

NekR avatar Feb 14 '17 12:02 NekR

@NekR, sure. Something like:

    var registration = navigator.serviceWorker
        .register(
          <%- JSON.stringify(ServiceWorker.location) %>
          <% if (ServiceWorker.scope) { %>
            , { scope: <%- JSON.stringify(ServiceWorker.scope) %> }
          <% } %>
        );

to

    var registration = navigator.serviceWorker
        .register(
          options.publicPath || <%- JSON.stringify(ServiceWorker.location) %>
          <% if (ServiceWorker.scope) { %>
            , { scope: <%- JSON.stringify(ServiceWorker.scope) %> }
          <% } %>
        );

This works for me.

alfeg avatar Feb 14 '17 12:02 alfeg

@alfeg okay, that makes sense. I'll need some other things from your. In generated sw.js there is a __wpo variable at the top. Would be good if you could provide here its content and if possible your webpack config. If you don't want it to be public, you can send it to my email (it's on github profile). This will help me understand the whole picture. Thank you!

NekR avatar Feb 14 '17 14:02 NekR

It's a combination of problems.

We using webpack builded application inside of older Asp.Net MVC application - this cause us to use publicPath with server side includes - ~\WebPackApp\path\to\app. Those URI's are resolved in runtime with ASP.NET engine. Essentialy our app is just a single View. Actually this problem with webpack.publicPath reuse is my main problem with a lot of external libs. Maybe we need to find time to solve it on our side, but's it's very tricky.

Due to our deployment processes I cannot identify correct public path during build, and don't want to do anything with package during deploy.

I cannot provide code - it's already deleted. I've done with research, and find out that we are able to seamlessly integrate Service Workers caching with a very little amount of code. offline-plugin works as expected, relative paths hint helped a lot. Only issue is lack of ability to provide path to sw.js in runtime.

alfeg avatar Feb 14 '17 15:02 alfeg

@alfeg I see, thank you for the additional information. I think I can fix that. Thanks for reporting this issue 👍

NekR avatar Feb 14 '17 22:02 NekR

I'm also experiencing a similar issue.

I need the sw.js file served from / so that it can cache my top level index.html, but all my assets from Webpack are served under /static/. I need a way to have the registration call that gets added by offline-plugin to my bundle to load /sw.js, and for sw.js itself to cache my webpack assets using a /static path.

Currently if I specify publicPath on the options for OfflinePlugin() (or as a key on it's ServiceWorker option) the registration code will, in addition to the expected behaviour of prepending that path to my assets in the sw.js __wpo.assets.main object, try to also use that path when registering the sw.js file which I believe to be a bug.

I should be able to specify something like (perhaps with the publicPath properties swapped around):

new OfflinePlugin({
      externals: ['/'],
      publicPath: '/',
      ServiceWorker: {
        publicPath: '/static'
      }
    })

To have the registration code load the ServiceWorker from /sw.js, which should append /static to the assets paths in __wpo.

Also it's very unclear in the docs how this library actually uses the publicPath options. One would assume the top level and ServiceWorker option would have different effects but it appears both get used as both the path to register the sw.js from and the path to prepend to your bundle assets in sw.js itself. I think one of the options (probably the top level one) should be removed, and a registerPath option which is used as the path to register the ServiceWorker from added instead.

wyqydsyq avatar Feb 23 '17 23:02 wyqydsyq

@wyqydsyq This works for me:

new OfflinePlugin({
  externals: ['/'],
  publicPath: '/static',
  ServiceWorker: {
    publicPath: '/sw.js'
  },
  AppCache: {
    publicPath: '/appcache'
  }
})

Although you'll need to generated correct structure of assets too because specified publicPaths do not affect how assets are generated to the file system.

If you think something isn't clear, please make it clearer. All that is welcome.

NekR avatar Feb 24 '17 12:02 NekR

@alfeg will __webpack_public_path__ work for you in your case? If you have to prefix SW/AppCache paths then I guess you have to prefix all other assets paths and the correct way to do so in webpack is by assigning to __webpack_public_path__:

__webpack_public_path__ = '/dynamic-path/'

NekR avatar Feb 24 '17 12:02 NekR

@wyqydsyq ping @alfeg ping

NekR avatar Feb 28 '17 22:02 NekR

@NekR , nope It's already set to proper path.

alfeg avatar Mar 01 '17 09:03 alfeg

I am also facing the similar issue, we want to make our client-side code host domain agnostic and serve from CDN, without building multiple times.

in short __webpack_public_path__ = '/dynamic-path/' this would work if offline-plugin supports it. Anything similar which would allow to set publicPath at runtime or set it automatically as well.

fusionstrings avatar Mar 12 '17 01:03 fusionstrings

Yeah, I see a point it. Would be good to add it.

NekR avatar Mar 12 '17 02:03 NekR

@NekR I tried your example and you're right that it works, I must have had the publicPath properties the wrong way around, which leads me to what I believe to be an actionable here; the publicPath property under the ServiceWorker option needs to be renamed to make a clear distinction between the behaviour of it and the top level option.

Something like this would make more sense:

new OfflinePlugin({
  externals: ['/'],
  publicPath: '/static',
  ServiceWorker: {
    installPath: '/sw.js'
  }
})

Since publicPath refers to the publicPath used in building your assets, installPath is the path that the ServiceWorker loader will try to install sw.js from.

wyqydsyq avatar Mar 13 '17 02:03 wyqydsyq

@wyqydsyq Yes, I think renaming it to registerPath makes sense. PR is welcome if you want to do so.

Also if someone wants to help with adding "dynamic public path support" it's welcome too 👍

NekR avatar Mar 22 '17 15:03 NekR

I want to use offline-plugin with CDN, so I am interested to take a look if I can get a working PR.

Bobgy avatar Oct 11 '18 07:10 Bobgy

hold on... it seems that I am thinking about a different thing from previous discussion. For my use case, my sw.js still lives on my website, but my scripts generated by webpack are hosted on cdn. So I want my sw.js to cache the scripts from cdn instead during install.

actually I wasn't even sure if that's possible, because serviceWorker.register(...) doesn't allow passing any value to the service worker. https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/register

Bobgy avatar Oct 11 '18 09:10 Bobgy

after some investigation, I am thinking about storing the dynamic publicPath to IndexedDB before calling serviceWorker.register, and let service worker read from IndexedDB and override publicPath if it exists.

Bobgy avatar Oct 11 '18 09:10 Bobgy

@NekR indexedDB's API is too complex, I want to import a small module (only 500b) 'idb-keyval' to take care of it. So it will be a dependency in generated code.

ask beforehand if you have any concerns. I think I can make a proof of concept PR soon. If the solution sounds good. I can keep polishing it up to support all cases.

Bobgy avatar Oct 12 '18 06:10 Bobgy