Performance¶
Key Points¶
- Regularly run Lighthouse audits to ensure the site is performant.
- Strive for the best possible Lighthouse scores.
- Ideally in the 80-100 range, but definitely above 50.
- Learn & apply the most performant methods available:
- Ensure Miva's TTFBs are below or near 500ms
KPIs & Standards¶
Name | Code | Definition | Good | Average | Poor |
---|---|---|---|---|---|
Time to First Byte | TTFB | Measures the duration from the user or client making an HTTP request to the first byte of the page being received by the client's browser. It is a measurement used as an indication of the responsiveness of a webserver or other network resources. | < 500 ms. | 500 ms. to 1500 ms. | >= 1500 ms. |
First Contentful Paint | FCP | The time when the browser first rendered any text, image (including background images){target=_blank}, non-white canvas or SVG. This includes text with pending webfonts. This is the first time users could start consuming page content | < 1800 ms. | 1800 ms. to 3000 ms. | >= 3000 ms. |
Largest Contentful Paint | LCP | A user-centric metric for measuring perceived load speed because it marks the point in the page load timeline when the page's main content has likely loaded---a fast LCP helps reassure the user that the page is useful. | < 2500 ms. | 2500 ms. to 4000 ms. | >= 4000 ms. |
First Input Delay | FID | A user-centric metric for measuring load responsiveness because it quantifies the experience users feel when trying to interact with unresponsive pages---a low FID helps ensure that the page is usable. | < 100 ms. | 100 ms. to 300 ms. | >= 300 ms. |
Cumulative Layout Shift | CLS | A user-centric metric for measuring visual stability because it helps quantify how often users experience unexpected layout shifts---a low CLS helps ensure that the page is delightful. | < 0.1 | 0.1 to 0.25 | >= 0.25 |
Best Practices¶
Use Efficient Processes¶
The code should be efficient, and should not affect TTFB in a way where the site would go down.
Incorrect
<mvt:assign name="l.settings:has_forbidden_items" value="0" />
<mvt:foreach iterator="group" array="basket:groups">
<mvt:item name="customfields" param="Read_Product_ID( l.settings:group:product_id, 'forbidden', l.settings:group:customfield_values:customfields:forbidden )" />
<mvt:if expr="l.settings:group:customfield_values:customfields:forbidden">
<mvt:assign name="l.settings:has_forbidden_items" value="1" />
</mvt:if>
</mvt:foreach>
Correct
<mvt:assign name="l.settings:has_forbidden_items" value="0" />
<mvt:foreach iterator="group" array="basket:groups">
<mvt:item name="customfields" param="Read_Product_ID( l.settings:group:product_id, 'forbidden', l.settings:group:customfield_values:customfields:forbidden )" />
<mvt:if expr="l.settings:group:customfield_values:customfields:forbidden">
<mvt:assign name="l.settings:has_forbidden_items" value="1" />
<mvt:foreachstop />
</mvt:if>
</mvt:foreach>
Use Efficient Functions¶
Incorrect
<mvt:do file="g.Module_Library_DB" name="l.product_loaded" value="Product_Load_Code( l.product_code, l.product )" />
Correct
<mvt:do file="g.Module_Library_DB" name="l.product_loaded" value="Product_Load_Code_Cached( l.product_code, l.product )" />
Avoid Infinite Loops¶
There should not be a way to create an infinite loop.
Incorrect
<mvt:if expr="g.Empty_Cart">
<mvt:do file="g.Module_Library_DB" name="l.success" value="Runtime_Basket_Empty( g.Basket:basket_id )" />
<mvt:do file="g.Module_Feature_PGR_DB" name="l.success" value="BasketDiscountTotal_Delete_All_Basket( g.Basket:basket_id )" />
<mvt:assign name="l.result" value="miva_output_header( 'Status', '302 Moved Temporarily' )" />
<mvt:eval expr="miva_output_header( 'Location', 'https://' $ encodeentities(g.domain:name) $ s.request_uri )" />
<mvt:exit />
</mvt:if>
<a href="&mvte:urls:BASK:auto_sep;Empty_Cart=1">Empty Cart</a>
?Empty_Cart=1
will continue to get passed in the s.request_uri
of the following Location
headers.
Correct
<mvt:if expr="g.Empty_Cart">
<mvt:do file="g.Module_Library_DB" name="l.success" value="Runtime_Basket_Empty( g.Basket:basket_id )" />
<mvt:do file="g.Module_Feature_PGR_DB" name="l.success" value="BasketDiscountTotal_Delete_All_Basket( g.Basket:basket_id )" />
<mvt:assign name="l.result" value="miva_output_header( 'Status', '302 Moved Temporarily' )" />
<mvt:assign name="l.result" value="miva_output_header( 'Location', encodeentities( l.settings:urls:BASK:auto ) )" />
<mvt:exit />
</mvt:if>
<a href="&mvte:urls:BASK:auto_sep;Empty_Cart=1">Empty Cart</a>