Any route to implementing root service workers?

Solved
ask_the_bird
Excursionist
12 0 9

Hello!

We are wrapping up a performance-oriented total rewrite of our main store. One feature we've wanted for years, a root service worker, does not seem possible.

This requires the serving the SW file from the root domain level. We can easily serve one via assets/files, but then this only has permissions over assets/files.

Our cart & collection pages are generated with 0 liquid (content is rendered by JS, similar to react). This has gotten us to speeds we're really happy with, but 50-70% of the remaining load time is TTFB *document load. If we had root SW access, we could define the caching policy for these documents and pre-fetch them. This could (theoretically) get our first-visit DCL < 100ms. That would really be something!!!

It seems like we could do this by putting a CDN in front of Shopify, but that sounds both silly and questionable performance-wise.

My actual questions:

  • Does anyone know of any "tricks" for deploying a root SW on Shopify?
  • Any methods of client-side cache policy modification that I might have overlooked?
Accepted Solution (1)

Accepted Solutions
jameskosh
Excursionist
10 4 14

This is an accepted solution.

It used to be possible to use a root-level service worker with Shopify via an App Proxy. Shopify made that impossible around the start of the year for "security reasons" while granting a few lucky Shopify Partners a monopoly on this capability. I've asked about this multiple times to different staff within Shopify and the best response I got was a vague answer that Shopify is working on a "longer term fix" for this.

Like many others, I would like this capability too since it's a modern approach to address many web performance issues. If this is something you need, I would recommend requesting it from your MSM if you have one or via a support request. Perhaps if enough voices are heard, Shopify will do something about it more urgently.

View solution in original post

Replies 15 (15)
jameskosh
Excursionist
10 4 14

This is an accepted solution.

It used to be possible to use a root-level service worker with Shopify via an App Proxy. Shopify made that impossible around the start of the year for "security reasons" while granting a few lucky Shopify Partners a monopoly on this capability. I've asked about this multiple times to different staff within Shopify and the best response I got was a vague answer that Shopify is working on a "longer term fix" for this.

Like many others, I would like this capability too since it's a modern approach to address many web performance issues. If this is something you need, I would recommend requesting it from your MSM if you have one or via a support request. Perhaps if enough voices are heard, Shopify will do something about it more urgently.

ask_the_bird
Excursionist
12 0 9

Thank you for the reply. I'm disappointed in my Googling! Hours of research never turned up that staff post; thank you for sharing it. 

I'll set a meeting with our MSM.

ejb503
Shopify Partner
19 3 2

There are ways to set the scope of service workers without having root access (Service worker access scope headers) https://medium.com/dev-channel/two-http-headers-related-to-service-workers-you-never-may-have-heard-... This isn't as well documented as it should be. 

I'm not sure how your hosting setup is but if you can control the headers there are ways to implement SW without root access. 

YownIt: Welcome to the eCommerce marketplace with one click install, integrated video, audio and chat. Engage with your customers online and offline with multi-channel conversion tools. Available in the App store: https://apps.shopify.com/the-shop-front
ask_the_bird
Excursionist
12 0 9

Vanilla Plus hosting precludes modifying headers. Regardless of implementation logistics, Shopify is sensible to restrict it. I seriously would not want app developers to have the ability to register service workers beyond their app page scope. That header would allow that.

I did find a way to implement get a root SW (and more) via Cloudflare Enterprise. I'm running tests on it this week via our dev store. 

ask_the_bird
Excursionist
12 0 9

Confirming for posterity's sake - root service workers are possible with Shopify-hosted stores via an O2O proxy with Cloudflare Enterprise.

I am running a Cloudflare edge worker that intercepts the "domain.com/sw.js" route and returns the contents of a JS file it reads from an s3 bucket.

junichiokamura
Community Manager
Community Manager
1160 272 475

Hi. folks,  just FYI. I am not sure if this helps you, guys, but if you want to load SW JS on the top of store themes,  the combination of app proxies and app embedded blocks will work fine which is adapted by this app for their browser push notification feature.
https://apps.shopify.com/pushcode

Technical Partner Manager, Japan
aditodkar
Shopify Partner
13 0 2

Hi @junichiokamura I am trying similar thing. So what I understood is that I can load scripts (external JS file) using theme app extension but if I want to load SW JS file on top of store themes then I will have to make use of app proxies is this correct understanding?

junichiokamura
Community Manager
Community Manager
1160 272 475

Hi,  as you understand, you can provide your SW files like xxx.myshopify.com/apps/YOUR_PATH/xxxx.js with app proxies and if you provide an app embedded extension with your JS code rendering the JS above and merchants enable it in their theme index page,   the code like  <div><script>//registering your SW code using the app proxy hosted file</script></div> gets inserted to the top page. 

Technical Partner Manager, Japan
aditodkar
Shopify Partner
13 0 2

@junichiokamura  I am trying to load service worker file using theme app extension but getting 404 error message in console: `TypeError: Failed to register a ServiceWorker for scope ('https://samplestore.myshopify.com/') with script ('https://samplestore.myshopify.com/sw.js'): A bad HTTP response code (404) was received when fetching the script.` What I have tried:
I have used theme app extension to load JavaScript file which is used for requesting permission and registering service worker.
```
navigator.serviceWorker
.register('/sw.js', {
scope: '/'
})
```
And in app embed liquid file I have added script tag which contains service worker code
```<script defer src="https://ighqcdqaodklrntrxmro.supabase.co/storage/v1/object/public/serviceworker/sw.js"></script>
``` any idea what I am doing wrong am I missing something from my side because service worker registeration is failing

junichiokamura
Community Manager
Community Manager
1160 272 475

Hi,  you cannot put sw.js to your Shopify shop root or include the external domain ones directly. 

Could you read this app proxies docs? 
https://shopify.dev/apps/online-store/app-proxies

This is my test shop to register desktop notification using the app above.
https://junichiokamurasp.myshopify.com/

Once you view the browser source,  you'll see the following code.
<div id="shopify-block-13741660719313883354" class="shopify-block shopify-app-block"><script defer src="/apps/pushcode/pushcode_shopify.js"></script>

/apps/pushcode/pushcode_shopify.js is an app proxies file which rendering script tag dynamically to load their service worker files (You can dive into the code from the source view).



 

 

 

Technical Partner Manager, Japan
suchapleasantdx
Shopify Partner
4 0 0

These methods are exactly what Shopify has disabled.

suchapleasantdx
Shopify Partner
4 0 0

What problem does this approach solve? If I understand correctly, it still doesn't allow service workers to be registered with root scope.

junichiokamura
Community Manager
Community Manager
1160 272 475

Hi,  thank you for your response.

 

Could you give me more derails to clarify some? 

 

These methods are exactly what Shopify has disabled.

What does "disabled" means?   Does Shopify reject your public app submission or block your code running in some ways? 

If I understand correctly, it still doesn't allow service workers to be registered with root scope.

I don't catch up all you want to do with "root scope", but at least push notification from store top page with service workers seem to work in this approach.

 

Technical Partner Manager, Japan
aditodkar
Shopify Partner
13 0 2

I had one doubt: 

 

I have created 2 files sw_register.js and sw.js both these files are served from nginx server. I have add theme app proxy configuration. Now I am using theme app extension to load both these files like this:
app-embed.liquid:
```
const jsFiles = ["/apps/myapp/sw.js", "/apps/myapp/sw_register.js"]
for (let file of mrloadjs) {
let s = document.createElement("script");
s.type = "text/javascript";
s.async = true;
s.src=file;
var x = document.getElementsByTagName("script")[0];
x.parentNode.insertBefore(s, x);
}

{% schema %}
{
"name": "Myapp",
"target": "head",
"settings": []
}
{% endschema %}
```
But I am getting this error: `The script has an unsupported MIME type ('text/html')` service worker registeration failed.

 

One more issue which I am facing is with this error:
```
The path of the provided scope ('/') is not under the max scope allowed ('/apps/myapp/'). Adjust the scope, move the Service Worker script, or use the Service-Worker-Allowed HTTP header to allow the scope.
```

junichiokamura
Community Manager
Community Manager
1160 272 475

Hi,

 

The script has an unsupported MIME type ('text/html')

Seems app proxies returns your JS as html contents?  You can set HTTP response header text/javascript in the app proxies code. 

As I mentioned above,  the app I introduced did some hacky way and you can see it from my store browser source. (as I checked again, they seem to register SW in their app proxy hosted JS which is loaded dynamically)


Technical Partner Manager, Japan