Integrate CSS lazy loading

Edit on GitHub

To implement CSS lazy loading for frontend, do the following:

  1. Update the ShopUi module to version 1.44.0, and update the spryker-shop/shop dependencies for the CatalogPage, HomePage, and ProductDetailPage modules:
COMPOSER_MEMORY_LIMIT=-1 composer update spryker-shop/shop-application spryker-shop/shop-ui spryker-shop/catalog-page spryker-shop/home-page spryker-shop/product-detail-page --with-dependencies
  1. Add "@jsdevtools/file-path-filter": "~3.0.2", into the package.json file to the devDependencies section and run the following:
npm install
  1. Make the following adjustments to the frontend/settings.js file:

    • Define criticalPatterns:
    ...
    // array of patterns for the critical components
    const criticalPatterns = [
        '**/ShopUi/**',
        '**/CatalogPage/**',
        '**/HomePage/**',
        '**/ProductDetailPage/**'
    ];
    ...
    
    • Add criticalPatterns to the returned settings object:
    ...
    // return settings
        return {
            name,
            namespaceConfig,
            theme,
            paths,
            urls,
            imageOptimizationOptions,
            criticalPatterns,
    ...   
    
    • Extend the definition of the setting for the frontend builder with the following style entry point patterns for components stylesEntryPoints:
    ...
    // define settings for suite-frontend-builder finder
      find: {
          // entry point patterns (components)
          componentEntryPoints: {
              ...
          },
    
          // style  entry point patterns (components)
          stylesEntryPoints: {
              core: {
                  // absolute dirs in which look for
                  dirs: [
                      join(globalSettings.context, paths.core),
                  ],
                  // files/dirs patterns
                  patterns: [`**/Theme/${namespaceConfig.defaultTheme}/**/style.scss`],
              },
              nonCore: {
                  // absolute dirs in which look for
                  dirs: [
                      join(globalSettings.context, paths.eco),
                      join(globalSettings.context, paths.project),
                  ],
                  // files/dirs patterns
                  patterns: [
                      `**/Theme/${namespaceConfig.defaultTheme}/components/**/*.scss`,
                      `**/Theme/${namespaceConfig.defaultTheme}/templates/**/*.scss`,
                      `**/Theme/${namespaceConfig.defaultTheme}/views/**/*.scss`,
                  ],
              },
          },
    ...
    
  2. Update the frontend/libs/finder.js file with the following code:

    1. Add the mergeEntryPoints function:
    ...
    // merge entry points
    const mergeEntryPoints = async files => Object.values(files.reduce((map, file) => {
            const dir = path.dirname(file);
            const name = path.basename(dir);
            const type = path.basename(path.dirname(dir));
            map[`${type}/${name}`] = file;
            return map;
        }, {}));
    ...
    
    1. Update the findEntryPoints function using the mergeEntryPoints as described in the previous step:
    ...
    // find entry points
    const findEntryPoints = async settings => {
        const files = await find(settings.dirs, settings.patterns,  settings.fallbackPatterns, settings.globSettings);
        return mergeEntryPoints(files);
    };
    ...
    
    1. Add the findStyleEntryPoints function:
    ...
    // find style entry points
    const findStyleEntryPoints = async settings => {
        const coreFiles = await find(settings.core.dirs, settings.core.patterns,  [], settings.globSettings);
        const nonCoreFiles = await find(settings.nonCore.dirs, settings.nonCore.patterns,  [], settings.globSettings);
        const files = [...coreFiles, ...nonCoreFiles];
        return mergeEntryPoints(files);
    };
    ...
    
    1. Pass the findStyleEntryPoints function to the exported module:
    ...
    module.exports = {
        findComponentEntryPoints,
        findStyleEntryPoints,
        findComponentStyles,
        findAppEntryPoint,
    };
    
  3. Adjust the frontend/configs/development.js file:

    1. Add the filePathFilter to the imported stuff at the top of the file:
    const filePathFilter = require("@jsdevtools/file-path-filter");
    
    1. Add findStyleEntryPoints to the import from the Finder module:
    ...
    const { findComponentEntryPoints, findStyleEntryPoints, findComponentStyles, findAppEntryPoint } = require('../libs/finder');
    ...
    
    1. Add the new local variable styleEntryPointsPromise to the getConfiguration function:
    ...
    const styleEntryPointsPromise = findStyleEntryPoints(appSettings.find.stylesEntryPoints);
    ...
    
    1. Extend the destructuring assignment with the following changes:

    From:

    const [componentEntryPoints, styles] = await Promise.all([componentEntryPointsPromise, stylesPromise]);
    

    To:

    const [componentEntryPoints, styleEntryPoints, styles] = await Promise.all([componentEntryPointsPromise, styleEntryPointsPromise, stylesPromise]);
    
    1. Add new local variables criticalEntryPoints and nonCriticalEntryPoints to the getConfiguration function:
    ...
    const criticalEntryPoints = styleEntryPoints.filter(filePathFilter({
        include: appSettings.criticalPatterns,
    }));
    
    const nonCriticalEntryPoints = styleEntryPoints.filter(filePathFilter({
        exclude: appSettings.criticalPatterns,
    }));
    ...
    
    1. Extend the entry section of the returned Webpack config object into the getConfiguration function with the new critical, non-critical, and util points:
    ...
    entry: {
        'vendor': vendorTs,
        'app': [
            appTs,
            ...componentEntryPoints,
        ],
        'critical': [
            basicScss,
            ...criticalEntryPoints,
        ],
        'non-critical': [
            ...nonCriticalEntryPoints,
            utilScss,
        ],
        'util': utilScss,
    },
    ...
    
  4. Update src/Pyz/Yves/EventDispatcher/EventDispatcherDependencyProvider.php on the project level:

    1. Add LastVisitCookieEventDispatcherPlugin to using section:
    ...
    use SprykerShop\Yves\ShopApplication\Plugin\EventDispatcher\LastVisitCookieEventDispatcherPlugin;
    ...
    
    1. Add this plugin to the returned collection of the getEventDispatcherPlugins function:
    protected function getEventDispatcherPlugins(): array
    {
        return [
            ...
            new LastVisitCookieEventDispatcherPlugin(),
            ...
        ];
    }
    
  5. Update the page-blank.twig layout on the project level in src/Pyz/Yves/ShopUi/Theme/default/templates/page-blank/page-blank.twig by adding the new isCssLazyLoadSupported twig variable:

{% extends template('page-blank', '@SprykerShop:ShopUi') %}

{% block template %}
    {% set isCssLazyLoadSupported = true %}

    {{ parent() }}
{% endblock %}
Info

Make sure your styles from node_modules are included in .scss files (not in index.ts). For example:

molecules/slick-carousel/slick-carousel.scss:

@import '~slick-carousel/slick/slick.scss';

@mixin shop-ui-slick-carousel($name: '.slick-carousel') {
...
  1. Rebuild the frontend with the new settings:
npm run yves