Daphne Smit
Daphne Smit

Reputation: 21

How to implement a serviceworker in SFCC (Demandware)

I was wondering if anyone here has experience with implementing a service worker in SFCC/Demandware.

I generate a service worker with Webpack with sw-precache-webpack-plugin

The problem is: a service worker should be available from the root of the domain. so site.com/sw.js. JS files will come normally in the static/ folder. Anyone an idea how to serve this JS file from the root of the project in Demandware/SFCC?

Upvotes: 2

Views: 1294

Answers (2)

Miroslav Genev
Miroslav Genev

Reputation: 415

Unfortunately, registering a service worker under an scope that is in an upper path than the service worker file itself does not work (as stated in MDN):

  • The service worker will only catch requests from clients under the service worker's scope.
  • The max scope for a service worker is the location of the worker.

(Source: https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers)

Solution

Here is a suggestion for a working approach for serving "/sw.js" in Demandware (Sales Force):

  • Create a new controller (or pipeline), e.g. "ServiceWorker-GetFile"; the response should be a file content, which can be read from whatever source you wish:
    • Content asset (dw.content.ContentMgr.getContent());
    • Library file (dw.content.ContentMgr.getContent() or directly reading a file with dw.io.File / dw.io.FileReader);
    • even Site preference (although I wouldn't recommend it);
  • Create an entry in Business Manager / Merchant Tools / SEO / Aliases to route "/sw.js" to "ServiceWorker-GetFile", i.e. use something along:
{
  ...
  "your-host" : [
    ...,
    {
      "if-site-path": "/sw.js",
      "pipeline": "ServiceWorker-GetFile"
    }
  ]
}

This may seem like an unnecessary overhead, but it was the only way I could findfor serving files with root path in the URI.

Serving other root files as well

By expanding the controller (renaming it to, say, "Content-GetFile" and adding GET/POST parameters like "name" and/or "source") this could be conveniently used for other files as well ("/manifest.json", "/.well-known/assetlinks.json" etc.). In the next example of Business Manager / ... / Aliases, let Content-GetFile accept two parameters: "name" (which would be a file name in the content library or a content asset ID) and "source" (which would be "file" or "asset"):

...
{
  "if-site-path": "/sw.js",
  "pipeline": "Content-GetFile",
  "params": {
    "name": "/ServiceWorker/sw.js",
    "source": "file"
  }
},
{
  "if-site-path": "/manifest.json",
  "pipeline": "Content-GetFile",
  "params": {
    "name": "MANIFEST_JSON",
    "source": "asset"
  }
}

Note that your code should handle appropriately the base paths of the resources (e.g. "/ServiceWorker/sw.js" from the above example does not speak much; you should know whether this is a path in a content library or a path relative to "cartridges//static/default/js/").

Dynamic content

Since the suggested approach uses a controller, you can dynamically process the content before serving it to the user (e.g. if you need to add/remove the "/v12435145145/" part from DMW links). Sky is your limits. :)

Upvotes: 2

Suso
Suso

Reputation: 11

I'm currently messing around with the service workers on DW as well. In my case I have directly added the script inside a footer.isml file like this:

<script>
  //init service worker
  if ('serviceWorker' in navigator) {
    window.addEventListener('load', () => {     
      navigator.serviceWorker
        .register("${URLUtils.staticURL('/lib/sw/sw.js')}")
        .then(registration => {
          console.log(
            `Service Worker registered! Scope: ${registration.scope}`
          );
        })
        .catch(err => {
          console.log(`Service Worker registration failed: ${err}`);
        });
    });
  }
</script>

This works for me, well at least I can see the Service Worker registered message.

I also had some issues due to the SSL certificate since my development environment doesn't have a proper SSL but it's using HTTPs routes, so chrome was complaining about it, I needed to run chrome via terminal using this command:

/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --user-data-dir=/tmp/foo --ignore-certificate-errors --unsafely-treat-insecure-origin-as-secure=[YOUR DOMAIN]

Unfortunately I'm not able to make work any line of code inside that service worker file, even I tried on Safari, since it has a Service Workers option in the develop menu, but it's not showing any service worker running.

I Hope it will helps you.

Upvotes: 1

Related Questions