-
Notifications
You must be signed in to change notification settings - Fork 683
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support for express server compression middleware. #2980
Conversation
|
This project used shrink-ray-current in the past |
@fooman
This PR ideally solves both of those problems; use a very simple gzip compression middleware and make it opt-in. Paired with this we will also be working on documentation around compression best practices at the web server layer, focusing on AWS/nginx and Magento Cloud (Fastly on Pro/Stage branches, nginx config on Integration branches). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Logic is sound, I think it just needs moved. Potential to remove unnecessary middleware too. Nice work!
if (env.ENABLE_EXPRESS_SERVER_COMPRESSION === 'true') { | ||
app.use( | ||
compression({ | ||
threshold: 0 | ||
}) | ||
); | ||
app.use(gzipValidationMiddleware(env)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We've already implemented inversion of control here with the before
prop, so let's just use that. Move this logic to PWADevServer
, and follow the same pattern as addImgOptMiddleware
. With the environment variable being defined in buildpack, it would also make more sense for buildpack to be the one to use it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having it in the PWADevServer
will only run this as part of the Dev mode. If someone wants to have compression in other modes/environments as well, that wouldn't be possible with it being in PWADevServer
. That's the reason why I have left this in the serve
module.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me rephrase; we cannot add API to upward-js
without also updating the upward-spec
and upward-php
implementations. If I had confidence UPWARD was going to remain in the stack, this would be an option, but it would likely be better to use upward.yml
config as opposed to an environment variable.
Given this, please move the middleware to PWADevServer
and utilities/serve
in buildpack. Sorry I didn't specify to also put it in the serve
utility as well, was just pointing out where to find an example of the IOC pattern.
|
||
if (contentEncoding !== 'gzip') { | ||
log( | ||
'\nGzip compression is supported by the Client. For better performance please enable gzip compression.\n' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not a fan of this getting logged on every request. Oddly enough though, when I switched to this branch compression was enabled, even though I have nothing set in my .env
. If this was working as intended, it also doesn't make sense this middleware is only injected alongside compression
with that flag set.
I propose removing this middleware entirely, and we focus on adding a blurb to the getting started docs that highlights the real purpose of this middleware.
If you want to run performance metrics on a local development instance, it is suggested that you replicate your production environment as closely as possible to get more accurate measurements. To simulate web server layer compression, you can pass this flag to enable an Express middleware that performs gzip compression of assets.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should not if you haven't set the ENV variable. Can you check?
Also, I have added a check to not render this warning in a production environment but there is a known bug in the serve module that does not let it work if NODE_ENV
is production. I have created a ticket in our backlog to handle this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Checked again, always compresses with yarn watch:venia
, while yarn stage:venia
seems to work as intended. Regardless, I would still get rid of the warning. If someone is purposely not using compression or using a different algorithm, there's no reason to annoy them.
} | ||
} | ||
); | ||
|
||
let envPort; | ||
if (process.env.PORT) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This has been a false-positive all along. Since we dint have tests, we never found it. I have added covering tests for this change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion for test improvement but not a blocker to send this to QA. Awesome work covering this with tests too 👌
test('should create upward server', async () => { | ||
const server = await serve('pwa-buildpack'); | ||
|
||
expect(createUpwardServer.mock.calls).toMatchSnapshot(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This assertion looks fragile; has a lot of cruft in it that I'm not sure we need to check (eg. some devDependency stuff). Can we slim this down?
* null and undefined are represented as strings in the env | ||
* so we have to match using strings instead. | ||
*/ | ||
if (process.env.PORT !== 'null' && process.env.PORT !== 'undefined') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was going to propose parseInt
here, but I guess 0 is a valid port number. I'm fine with this, but a little type checking wouldn't hurt.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah you are right, 0 is a valid port number.
@revanth0212 Condition update to port validation is failing. When you run
|
QA Approved. |
@@ -16,4 +16,4 @@ UPWARD_JS_LOG_URL=1 | |||
CHECKOUT_BRAINTREE_TOKEN=redacted | |||
GOOGLE_MAPS_API_KEY=redacted | |||
MAGENTO_BACKEND_EDITION=EE | |||
ENABLE_EXPRESS_SERVER_COMPRESSION=false | |||
ENABLE_EXPRESS_SERVER_COMPRESSION=true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Our official guidance should be to do compression at the web server or proxy layer, not the application layer. Any reason you opted for this config instead of adding compression to nginx?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dev wanted to test it out and have it enabled on our AWS instances which are not served by Nginx (I presume).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right @tjwiebell. Our app is served using nginx but the compression is not enabled.
For instance, this is a PR instance without
And here is the same network req from this PR instance with compression enabled,
@dpatil-magento do you know if we can enable compression at nginx level, if so, how long does it take. Till then this can be a stop-gap solution.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given this change I'm assuming we just deploy these Docker images directly to EBS, so nginx is involved. It sounds like this isn't as straight forward as it should be with the jwilder/nginx-proxy
container, but is possible. Not going to block this PR, but we should consider doing this at the correct layer if our goal is performance.
Where to add config: https://github.com/nginx-proxy/nginx-proxy#proxy-wide
Sample of config needed: https://github.com/h5bp/server-configs-nginx/blob/master/h5bp/web_performance/compression.conf
Description
The
express
server that serves the app provides a middleware that applies GZIP compression if not applied already on the responses requested by the storefront. Compression is a very important but sensitive feature to manage because it can be applied at different layers of a system. One can apply it at the proxy layer or application layer and overdoing it can cause performance degradation. Hence the express server compression will be controlled by an environment variable. If someone wants to apply compression at the express layer, they have to set the value ofENABLE_EXPRESS_SERVER_COMPRESSION
totrue
. By default, it will be set tofalse
.ENABLE_EXPRESS_SERVER_COMPRESSION
in a sample project's.env
file created using thecreate-pwa
scafolding tool:Related Issue
Closes PWA-1108.
Acceptance
Should apply GZIP compression on responses if
ENABLE_EXPRESS_SERVER_COMPRESSION
totrue
.Verification Stakeholders
@jimbo
@dpatil-magento
Verification Steps
ENABLE_EXPRESS_SERVER_COMPRESSION=true
yarn watch:venia
andyarn build && yarn stage:venia
Content-Encoding: gzip
.ENABLE_EXPRESS_SERVER_COMPRESSION
tofalse
.Content-Encoding: gzip
.Screenshots / Screen Captures (if appropriate)
When
ENABLE_EXPRESS_SERVER_COMPRESSION=true
When
ENABLE_EXPRESS_SERVER_COMPRESSION=false
Checklist