Best Practices
Site-Build Best Practices¶
Standards¶
Site-builds should be built according to our Genesis standards wherever possible
Redis¶
By default, Genesis is developed with Redis in mind.
If you are new to using Redis, review Our Redis Guide.
Configuration¶
Ensure Redis is connected by going to the Store Settings > Cache Configuration
.
Status
should say Connected
.
If you are unable to connect, work with TAC to ensure Redis is available on the server.
During development, you will want to turn off Redis Caching. Once live, confirm Redis is connected, and turned on.
Store Settings > Cache Settings¶
Add the following Settings, if they're not already there:
Name | Type | Mode | Value |
---|---|---|---|
utm_campaign |
Parameter | Don't Include in Cache Key | |
utm_content |
Parameter | Don't Include in Cache Key | |
utm_medium |
Parameter | Don't Include in Cache Key | |
utm_source |
Parameter | Don't Include in Cache Key | |
utm_term |
Parameter | Don't Include in Cache Key |
Check with the client to see if there any other parameters they use for tracking purposes. This includes, but is not limited to:
- Ad Parameters (Google, Bing, etc.)
- Email Marketing Parameters
- Affiliate Link/Marketing Parameters
Page Cache¶
By default, most pages will have a cache level of Empty Baskets (Anonymous)
.
However, there are some pages that should have their Cache Page setting set to Never Cache This Page:
- BASK
- CTUS
- INVC
- JAPI
- MNTN
- SERT
- GENESIS_EMPW
- OAUTH_REDIRECT
Additionally, if you have/add a custom page that is used for API calls, you should consider setting those pages to Cache: Never
as well as any pages with a C&L form (ex. CTUS page). An example of an API page would be a page that is loading in "Recently Viewed" items, or trigger an email (like sharing a wishlist).
Search Rule Configuration¶
By default, The Searchable Fields that will be enabled are:
- Product Code
- Product Name
- Product SKU
- Product Description
Any module that supports the fields_prod
feature, will most likely support the search
capability. For 3rd Party Modules, or older modules, this may not be the case.
Be careful with how many Searchable Fields you are enabling. The more you enable, the larger the SQL query becomes.
If you enable 25+ fields, that could cause some degradation when utilizing Miva's Native Search. Work with the client to be selective on what is and is not important to be searched, or see if some fields can be combined into 1.
Depending on the needs of the fields, you will want ensure the Search Type
selected makes the best use of the field. By default, these are all set to Contains (Term)
.
We recommend only using Full Text Search to be used on fields where you don't need an exact string match (Example: Product Description, or Product Name). For all other fields, we recommend Contains (Term).
If you do need an exact match, use Exact Match. An example of this would be if a customer is used to typing in SKUs and is looking to get the exact SKU match in their search.
See more details here: Miva Docs - Expanded Search Rules
JavaScript¶
webpack¶
webpack Module Methods¶
Note
Suggested Reading: webpack > Module Methods
- Static Imports will include the asset in the current chunk; thus increasing the bundle-size.
- Example Syntax:
import foobar from 'extensions/foobar.js'
- This is similar to server-side concatenation that used to exist in our
all.php
orcss.php
files - Use this for assets that you need on-load for all customers, user-journeys, experiences.
- Example Syntax:
- Alternatively, Dynamic Imports will create a separate chunk for the assets that are being imported and it will asynchronously load in the asset.
- Example Syntax:
import('foobar')
- This is similar to lazy-loading that we did through the
loadScript()
methods. - Use this if you have scenarios where customers may not experience a feature or where it may be below the fold and can be loaded in later.
- Example Syntax:
Creating Extensions¶
When building with Genesis, you may need to build new features that are re-used throughout the site on various pages, so our recommendation would be to create a folder for each feature to encapsulate the CSS & JS of the feature. Then use the pages/
directory & files to import the feature on the pages it is needed.
For reference, feel free to review the different extensions that were created for the Duluth Pack build
Building in this method will keep your project code DRY, allow you to leverage Webpack imports/chunking, and eventually make it easy to share features with other projects & re-incorporate them into Genesis after the build is over.
Design Files & Design System¶
Currently, there is not a 1:1 mapping of what is represented in the design files that Design provides and how Genesis exists today. It is a known issue that we are planning to address in the next 0.7 release of Genesis.
Tons of feedback, notes, changes, & requests have been assembled and outlined, so please review the items described there to understand some potential challenges when styling with the current framework.
In the coming weeks, we will be working with Design and on Genesis to streamline and solve for these issues.
In the mean time, the project/build may experience some challenges & may need to make some compromises on the final output of the design, the amount of time it takes to make the framework match the mock-up, and more, so take note of these tips & ideas
- Consistency & Acceptable Level of Tolerance
- The Design files may have inconsistent margins, paddings, font-sizes, etc. where built-in Genesis features do not match the design 100% and are off by a pixel or two here or there. If there is time remaining for you to fix it, then please do. However, if you're low on time, this may be an opportunity for you to communicate the discrepancy to Design to see if a compromise can be made or if the PO will allow you more time to make the change.
- It's ok to say, "No"
- Similarly, there are times where Design mocks-up items that are time-consuming, scope-creep, or break the framework and require extra to to achieve.
- Make every attempt, within the scope of the project's time-estimates, to meet the design-requirements, but notify the Designer & PO about elements that would take you over the estimated time.
- You can also just describe the scenario & provide an estimate to the PO about what it would take to achieve the functionality and leave the decision about whether or not it is in-scope up to them.
SCSS¶
Theming & Overriding Variables¶
The best place to start when theming your site is going to be in the themes/genesis/src/_variables.scss
file.
It starts off empty, so you can cherry-pick the variables & items that you want to override. You can reference the variables within the scss/config/_variables.scss
file and copy them into your project's src/_variables.scss
file as you need to customize/overwrite them.
Creating Mixins¶
Since there is not a 1:1 mapping of the Design files to Genesis at this time, we recommend creating SCSS mixins & utility classes to represent some of the concepts & components illustrated in the Design System file. For reference, see the Lighting Trendz variables file.
Misc.¶
Adding Additional Variables & Styles¶
The variables and styles within a Genesis store should always correspond with that clients UX Style Guide. If the client wants to add or change styles than what is in their style guide the best practice would be to recommend updating their style guide with those changes and define the hierarchy across the site where those variables are used.
Adding Pages¶
If you need to add some JS or CSS to a new page, then you can:
- Copy the
themes/genesis/src/pages/_example
folder - Paste it in the
pages/
directory and rename the folder & files to match the page-code you're adding. For example:- The
pages/_example/
directory becomespages/ABUS/
pages/_example/_example.js
JS file becomespages/ABUS/ABUS.js
pages/_example/_example.scss
SCSS file becomespages/ABUS/ABUS.scss
- The
- Update the
ABUS.js
(previously_example.js
)- Update
import '_example.scss';
to the page-codeimport 'ABUS.scss';
- Update
export default class PAGECODE extends PageManager {
toexport default class ABUS extends PageManager {
- Update
- That's it.
- Import additional dependencies within your JS file if need be
- Initialize/execute your JS in the
onReady
function call. - Add your SCSS to the SCSS file too.
Dealing with Alternate Display Pages¶
If you're creating alternate display pages for PROD pages, then we recommend adding them within the themes/genesis/src/pages/PROD/
folder. Your directory structure might look like this:
Note
The following example also applies to CTGY Alternate Display pages as well
themes/
genesis/
src/
pages/
PROD/
PROD.js
PROD.scss
PROD_ALT.js
PROD_ALT.scss
CTGY/
CTGY.js
CTGY.scss
CTGY_ALT.js
CTGY_ALT.scss
Then within the themes/genesis/src/theme.js
file you have some options for importing those files using the screenImports
object of the pageCodeImports
object:
Alternate Display Pages: Shared Code¶
If the Alternate Display (ex. PROD_ALT
) page shares many of the same features as the regular PROD
page, then:
- You can setup the
PROD.js
to contain all of the shared functionality for both pages. - Keep the
PROD.js
file in thetheme.js
file'sscreenImports
section so that it is imported onPROD
&PROD_ALT
pages. - Add the additional/unique-to-
PROD_ALT
elements to to thePROD_ALT.js
file and it to thepageCodeImports
section. - This will ensure shared code for PROD pages are maintained in one location and extra code is only executed on the
PROD_ALT
page.
For example, he's an abreviated version of the theme.js
showing how code can be shared.:
// ...
bootstrap({
// ...
screenImports: {
// ...
PROD: () => import( 'pages/PROD/PROD.js' ),
// ...
},
pageCodeImports: {
PROD_ALT: () => import( 'pages/PROD/PROD_ALT.js' )
}
//...
});
Alternate Display Pages: Separate Code¶
Alternatively, if the PROD
and PROD_ALT
pages are very different and do not share many of the same features, then:
- In
theme.js
, move thePROD.js
file fromscreenImports
to thepageCodeImports
section - Add the
PROD_ALT.js
file to thepageCodeImports
- This will ensure each page has it's own unique set of code that will execute independently.
For example, he's an abreviated version of the theme.js
showing how code can be separated.:
// ...
bootstrap({
// ...
screenImports: {
// ...
},
pageCodeImports: {
PROD: () => import( 'pages/PROD/PROD.js' ),
PROD_ALT: () => import( 'pages/PROD/PROD_ALT.js' )
}
//...
});
NPM¶
Overriding, Extending, & Cherry-Picking Files¶
In themes/genesis/src/pages/Global.scss
we import various packages' index files; which in-turn import additional sub-files for various features. There may be times where the scope of all the files that are included is more than you need or they are imported in an order that doesn't work for you. When that is the case, you can pick and chose which files are imported.
For example, by default in Global.scss
it has the following imports:
@import "variables";
@import "scss/styles";
@import "extensions/icons/index";
@import "extensions/messages/index";
@import "extensions/transfigure-navigation/index";
@import "extensions/breadcrumbs/index";
@import "extensions/search-preview/index";
@import "extensions/mini-basket/index";
@import "extensions/carousel/index";
extensions
, you could omit that import re-create the import how you want it. For example, (this is not recommended), but if you didn't want to import Genesis' search preview objects and you wanted to use another 3rd-party CSS-layout-framework, then you could do something like this:
@import "variables";
@import "scss/styles";
@import "extensions/icons/index";
@import "extensions/messages/index";
@import "extensions/transfigure-navigation/index";
@import "extensions/breadcrumbs/index";
//@import "extensions/search-preview/index";
@import "custom-extensions/search-preview/index";
@import "extensions/mini-basket/index";
@import "extensions/carousel/index";
Note
The above concept can apply to any extensions/
import for other packages and other SCSS or JS files.
Accessibility¶
Animations / Transitions for users who prefer reduced motion¶
When adding a transition or animation, please reference the following below for examples on how to check if a user prefers reduced motion.
SCSS¶
Add the media query around your transition or animation to only run for users who have no preference on motion/animation.
// Transition Example
@media ( prefers-reduced-motion: no-preference ) {
transition: all 200ms ease-in;
}
// Animation Example
@media ( prefers-reduced-motion: no-preference ) {
animation: miniBasketSlideOut 150ms cubic-bezier(0.4,0.01,0.1,1);
}
JS¶
Detect the media query in javascript to wrap any references to animation (event listeners, and plugins).
// Determine if user want reduced motion. If they do, no animations.
const allowAnimation = window.matchMedia('(prefers-reduced-motion: no-preference)').matches;
if (allowAnimation) {
const animationHandler = () => {
this.rootElement.classList.add(this.hiddenClass);
this.rootElement.removeEventListener('animationend', animationHandler, false);
};
this.rootElement.addEventListener('animationend', animationHandler, false);
}
How to Test¶
Disable animations on your computer. Use one of the following links to turn them off:
Visit your Genesis Development Store and ensure functionality still works with animations turned off.
Production Sync Incremental Commits¶
git add -A && git diff --cached -w | git apply --cached -R && git commit -m "production sync of whitespace changes"
git add \*.json && git commit -m "production sync of json files"
git add -A && git commit -m "production sync of template changes"