Loading component...

Published on November 5, 2024Reading time: 4 min read

Supporting Sass Variables in XM Cloud and Storybook

Use Sitecore XM Cloud’s Sass plugin and Storybook’s Sass processing options to resolve image path issues

Loading component...

Related Articles

Sitecore

Enabling and configuring the editor toolbar in SitecoreAI Pages

Utilizing SitecoreAI’s Sites API for improved authoring experiences.

February 17, 20261 min read
Blog Card Placeholder
Sitecore

Mastering Sitecore Content Serialization Scopes

Sitecore Content Serialization Scopes Include Strategies: Navigating ItemAndChildren, ItemAndDescendants, and the Power of Ignored

February 17, 20261 min read

Loading component...

Digital solutions

Learn how to maximize your investment in Sitecore by working with us.

AI solutions

Dominate your industry. Work with us to digitally transform your business.

Fishtank's proprietary project accelerator. Save time and money. Build what matters.

Utilities

Energy

Education

Healthcare

Manufacturing

Professional services

Financial services

Non-profits and associations

About FishtankThe PlaybookSitecore SnackContact us

Solutions

  • Digital solutions
  • AI solutions
  • TIDAL for XM Cloud

About

  • About Fishtank
  • The Playbook
  • Sitecore Snack
  • Contact us

Insights

Work

Industries

  • Utilities
  • Energy
  • Education
  • Healthcare
  • Manufacturing
  • Professional services
  • Financial services
  • Non-profits and associations

Start typing to search...

Legacy Sass: Challenges in Upgrading to Sitecore XM Cloud

When upgrading a Sitecore XP solution to Sitecore XM Cloud, there are often unexpected challenges. We faced such a hurdle when we were migrating our client’s custom Sass files, which contained paths to SVG icons. These paths were hardcoded in the Sass files.

&.icon-download {
      content: url(/img/acmecorp/icons/icon_download.svg);
  }
  

File path to SVG icon in acmecorp icons folder

This worked seamlessly in normal mode. However, in the Experience Editor and Pages, these icons didn’t display because Sitecore attempted to fetch the SVGs from the Content Management (CM) server rather than the rendering host. To resolve this, we needed to dynamically reference the correct hostname, ensuring that icons would load properly for both the public website and inside Sitecore editors.

Solution: Leveraging XM Cloud’s Sass Plugin

To do this, we had to modify the src\lib\next-config\plugins\sass.js file that comes with the Sitecore XM Cloud starter kit. This file is called by next.config.js, and by default it just sets path aliases for importing Sass files. We extended the sassOptions object of that file to include an additionalData property, where we could create the Sass variable that would hold our hostname. Then to get the hostname, we called Sitecore JSS's getPublicUrl() function to fetch the domain for whichever environment the code was running on (defaulted to an empty string if it couldn’t be found).

const path = require('path');
  const SassAlias = require('sass-alias');
  // BEGIN CUSTOMIZATION - make the public URL available to the sass files
  const getPublicUrl = require('@sitecore-jss/sitecore-jss-nextjs/utils').getPublicUrl;
  const publicUrl = getPublicUrl() || '';
  // END CUSTOMIZATION
  
/* * @param {import('next').NextConfig} nextConfig */ const sassPlugin = (nextConfig = {}) => { return Object.assign({}, nextConfig, { sassOptions: { importer: new SassAlias({ '@sass': path.join(__dirname, '../../../assets', 'sass'), '@fontawesome': path.join(__dirname, '../../../../node_modules', 'font-awesome'), }).getImporter(), // BEGIN CUSTOMIZATION - make the public URL available to the sass files additionalData: `$base-url: "${publicUrl}";`, // END CUSTOMIZATION }, }); };
module.exports = sassPlugin;

Then we were able to use $base-url in the SVG paths. The icons now appeared in edit mode.

&.icon-download {
      content: url(#{$base-url}/img/acmecorp/icons/icon_download.svg);
  }
  

Configuring Sass Variables for Storybook

However, our changes caused our Storybook build to fail with the following error:

ERROR in ./src/assets/main.scss (./node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[15].use[1]!./node_modules/postcss-loader/dist/cjs.js!./node_modules/resolve-url-loader/index.js!./node_modules/@storybook/nextjs/node_modules/sass-loader/dist/cjs.js??ruleSet[1].rules[15].use[4]!./src/assets/main.scss)
  Module build failed (from ./node_modules/@storybook/nextjs/node_modules/sass-loader/dist/cjs.js):
  SassError: Undefined variable.
     ╷
  12 │           content: url(#{$base-url}/img/acmecorp/icons/icon_download.svg);
     │                          ^^^^^^^^^
     ╵
    src\assets\links.scss 12:26  @import
    src\assets\main.scss 30:11                   root stylesheet
  

Storybook doesn’t need next.config.js to run, so it won’t have access to this variable we created in our src\lib\next-config\plugins\sass.js plugin. We’ll need to configure that variable another way for Storybook.

In our Storybook’s .storybook\main.ts file, we were already using the @storybook/addon-styling addon, and found that it has further options to configure it. We used the scssBuildRule object to tell Storybook how to process the Sass files.

const config: StorybookConfig = {
    staticDirs: ['../public'],
    addons: [
      // Other addons
      {
        name: '@storybook/addon-styling',
        options: {
          scssBuildRule: {
            test: /\.s[ac]ss$/,
            use: [
              'style-loader',
              {
                loader: 'css-loader',
                options: {
                  importLoaders: 3,
                  url: {
                    filter: (url) => {
                      if (url.startsWith("/img/acmecorp/icons/")) {
                        return false;
                      }
                      return true;
                    },
                  },
                },
              },
              'postcss-loader',
              'resolve-url-loader',
              {
                loader: 'sass-loader',
                options: {
                  additionalData: '$base-url: "";'
                }
              }
            ]
          },
  
// Other options }, }, ],
// Rest of the config };

This configuration contains many parts:

  • It sets up a rule for processing .scss and .sass files (Sass stylesheets).
  • The scssBuildRule uses a series of loaders to process these files:
    • style-loader: Injects the CSS into the DOM at runtime.
    • css-loader
      • Interprets @import statements, url(), and require() and resolves them.
      • It's configured to handle 3 loaders after it (importLoaders: 3).
      • It has a custom URL filter that excludes relative URLs for icons like "/img/acmecorp/icons/". This filter is used to prevent icon paths from being resolved because they do not exist at that location in the Storybook application.
    • postcss-loader: processes CSS with PostCSS.
    • resolve-url-loader: resolves relative paths in url() statements based on the original source file.
    • sass-loader: compiles Sass/SCSS files to CSS.
      • It adds a global Sass variable $base-url: ""; to all processed files so our icon URLs stay relative without a hostname in Storybook. The icon files are located in the ../public folder configured in staticDirs.

In the process of migrating from Sitecore XP to Sitecore XM Cloud, even seemingly minor details like handling icon paths in Sass files can present unexpected challenges. By leveraging Sitecore JSS's getPublicUrl() function, extending the sass.js configuration and changing how Storybook processes Sass files, we were able to ensure that the icons loaded correctly for Experience Editor and Pages.

Solutions

  • Digital solutions
  • AI solutions

Brands

  • TIDAL for SitecoreAI
  • Sitecore Snack
  • The Playbook

Fishtank lore

  • Work
  • Insights
  • About us
  • Contact us

Industries

Utilities
Professional services
Energy
Financial services
Healthcare
Education
Non-profits and associations
Manufacturing
Utilities
Professional services
Energy
Financial services
Healthcare
Education
Non-profits and associations
Manufacturing

2026 @All Rights Reserved. Privacy Policy.

FISHTANK