May 12, 2020

Properly serving static files Magento PWA Studio

Yireo Blog Post

This is a big topic, but important nonetheless. When building a Magento PWA Studio, most tutorials out there tell you to either implement things using a Node server or without. But often this includes steps to route requests for static files to UPWARD. Why not use the webserver for this directly?

Brief summary of a setup with UPWARD

So this story is maybe meant for those of you that are already playing with Magento PWA Studio. For those new to this topic, here's a brief summary: Magento PWA Studio allows you to build a PWA, which connects to Magento. This connection is made easier (which is open for discussion though) to handle both static files (HTML, JavaScript, CSS, images) and dynamic calls (dynamic URLs, GraphQL, REST) on the same domain name by adding a proxy-thing called UPWARD.

UPWARD definitely has its usage and the scope of this blog does not include a discussion of how useful UPWARD is (or not). However, as soon as you would follow the default tutorials, UPWARD is setup to receive all PWA requests (mixing both static and dynamic requests) and serving them as needed. This counts for the UPWARD-setup within Node and the UPWARD-connector written in PHP (which is integrated in Magento as a regular Magento 2 module).

The point of this blog is that this kind of setup routes all PWA requests through UPWARD. While actually the webserver (Nginx) should be perfectly capable of serving static files itself.

The webserver that runs UPWARD

The basic thing to remember is that the two ways to run UPWARD (PHP or Node) still require a webserver (like Nginx). With the Node variation, a proxy configuration forwards requests to an Express middleware that includes UPWARD logic. With the PHP variation, Nginx simply forwards PHP calls to something like PHP-FPM which then calls upon the Magento codebase.

Every request is still sent from a regular client (like a browser) towards the webserver and then the webserver routes things further. The faster we can serve certain content, the better. So why not use the webserver to serve static contents.

The PWA as part of Magento

I've now helped setting up a couple of Magento-PWA-Studio-based projects where the React app (so, the PWA) was run on the same server as Magento itself. This has the benefits of a single server instance, a single domain, a single SSL certificate, a single deployment chain.

The PWA is then served in a subfolder of Magento, public/pwa. Now, the UPWARD choice for either Node or PWA leads to a specific Nginx configuration that forwards the main requests (URLs like venia-dress.html) to either the original Magento index.php or a separate Node instance:

location / {
    proxy_redirect off;
    add_header Access-Control-Allow-Origin *;

This is working fine. However, with either approach, you do want to make sure that static files are served without Node or PHP being involved.

Serving static files directly

While the PWA is hosted in a public/pwa subfolder, the React source is still compiled with / as the homepage, so that the browser requests all files as if they are placed in public directly, not public/pwa. When UPWARD is right there to intercept those calls, this is working perfectly fine.

But there is a performance loss, because UPWARD is in the middle. By removing UPWARD, or put differently, by simply routing static files directly to the public/pwa subfolder, files are served quicker. This could look the following block:

location ~* \.(js|json|svg|png|jpg|css|ico)$ {
    try_files /pwa/$uri /$uri $uri/ =404;

Bypassing Node when it

With the Node variation, there is another block that you could benefit from. Dynamic requests (dynamic URLs, GraphQL, REST) are still routed via the Node server (Express plus UPWARD). But in the case of GraphQL or REST requests, these are simply forwarded to Magento again. So why not route those directly to Magento as well:

location ~ ^/(graphql|api) {
    try_files $uri $uri/ /index.php?$args;

Thanks to these two modifications, only dynamic URL requests (like venia-dresses.html) should end up with UPWARD so that UPWARD only focuses on those parts that are important. Theoreticaly, you don't even need UPWARD for that.

ElasticSearch stuff as well

As soon as the stack of PWA, Magento and possibly Node middleware is extended with a search engine like ElasticSearch, the same trick applies. Instead of forward a search request via Nginx to Magento or Node, why not forward it directly to ElasticSearch. A word of warning needs to be given on properly configuring things with security in mind (for instance, only allowing GET requests to be forwarded), but other than that, the same performance benefit lies there.

Posted on May 12, 2020

About the author

Author Jisse Reitsma

Jisse Reitsma is the founder of Yireo, extension developer, developer trainer and 3x Magento Master. His passion is for technology and open source. And he loves talking as well.

Sponsor Yireo

Looking for a training in-house?

Let's get to it!

We don't write too commercial stuff, we focus on the technology (which we love) and we regularly come up with innovative solutions. Via our newsletter, you can keep yourself up to date on all of this coolness. Subscribing only takes seconds.

Do not miss out on what we say

This will be the most interesting spam you have ever read

We don't write too commercial stuff, we focus on the technology (which we love) and we regularly come up with innovative solutions. Via our newsletter, you can keep yourself up to date on all of this coolness. Subscribing only takes seconds.