blueprint: Unable to compile BluePrint 4 SCSS with webpack sass-loader

Environment

  • Package version(s): @blueprintjs/core: 4.17.8, sass: 1.60.0, sass-loader: 13.2.2, webpack: 5.73.0, node 16.16.0
  • Operating System: Ubuntu 22.04
  • Browser name and version: Chrome: 111.0.5563.110

Steps to reproduce

  1. Install @blueprintjs/core using npm: npm install @blueprintjs/core@4.17.8
  2. Create an index.scss file that imports the blueprint scss file:
@import '@blueprintjs/core/src/blueprint';
  1. Add webpack configuration using sass-loader e.g.
module: {
      rules: [
        {
          test: /\.(css|scss|sass)/,
          use: [
            {
              loader: 'sass-loader',
            },
          ],
        }
},

Actual behavior

ERROR in ./style/index.scss (./node_modules/css-loader/dist/cjs.js!./node_modules/postcss-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./style/index.scss)
Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
SassError: (path: (fill: hsl(213.75, 10.8108108108%, 50%))) isn't a valid CSS value.
   ╷
39 │       background: svg-icon("16px/chevron-right.svg", (path: (fill: $pt-icon-color)));
   │                                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ value
   │                   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ unknown function treated as plain CSS
   ╵
  node_modules/@blueprintjs/core/src/components/breadcrumbs/_breadcrumbs.scss 39:54  @import
  node_modules/@blueprintjs/core/src/components/_index.scss 5:9                      @import
  node_modules/@blueprintjs/core/src/blueprint.scss 18:9                             @import
  style/index.scss 5:9                                                               root stylesheet
SassError: SassError: (path: (fill: hsl(213.75, 10.8108108108%, 50%))) isn't a valid CSS value.
   ╷
39 │       background: svg-icon("16px/chevron-right.svg", (path: (fill: $pt-icon-color)));
   │                                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ value
   │                   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ unknown function treated as plain CSS
   ╵
  node_modules/@blueprintjs/core/src/components/breadcrumbs/_breadcrumbs.scss 39:54  @import
  node_modules/@blueprintjs/core/src/components/_index.scss 5:9                      @import
  node_modules/@blueprintjs/core/src/blueprint.scss 18:9                             @import
  style/index.scss 5:9                                                               root stylesheet
    at Object.loader (/home/adam/Documents/source/frontend/node_modules/sass-loader/dist/index.js:56:14)
 @ ./style/index.scss 8:6-183 22:17-24 26:7-21 58:25-39 59:36-47 59:50-64 63:6-73:7 64:54-65 64:68-82 70:42-53 70:56-70 72:21-28 83:0-153 83:0-153 84:22-29 84:33-47 84:50-64 61:4-74:5
 @ ./src/index.ts 4:0-29

Expected behavior

I would expect all of the blueprint internal SCSS files (e.g. the breadcrumb component scss file) to compile out of the box.

I have looked at all the similar issues raised but I am unable to follow them or to get this SCSS compiling. Are there any other steps that need to be done after installing this version of Blueprint? Previously working on Blueprint v3 had no compilation issues.

About this issue

  • Original URL
  • State: open
  • Created a year ago
  • Comments: 20 (5 by maintainers)

Most upvoted comments

Hi, wondering if there is any chance of an update on resolving this issue within the library? There are a number of things that make the source issue a pain, including:

  1. The svg-loader issue for Dart-SASS
  2. For Node-SASS (workaround), many other SCSS functions in the BlueprintJS library aren’t supported.

Given it is a few functions, wondering if it would be possible to take another look?

Thanks

@eastside Thank you for the gist, I managed to make it work with Vite 4. There were 2 errors in your code which required adjustments:

  1. SVG wasn’t properly encoded to base64. Creating new buffer was required instead of encoding string directly
  2. Closing " was missing at the end of url("...) in base64 case
function encode(content, opts) {
    let buff = new Buffer(content)

    if (opts.encodingFormat === "uri") {
        return new sass.SassString(
            `url("${svgToDataUri(buff.toString("UTF-8"))}")`,
            {quotes: false}
        )
    }

    if (opts.encodingFormat === "base64") {
        return new sass.SassString(
            `url("data:image/svg+xml;base64,${buff.toString("base64")}")`,
            {quotes: false}
        )
    }

    throw new Error(
        `[node-build-scripts] encodingFormat ${opts.encodingFormat} is not supported`
    )
}

Additionally, it was required to install postcss-scss and create postcss.config.js config file to support scss imports:

module.exports = {
    syntax: 'postcss-scss',
};

That’s all I had to adjust

FYI @prachibansal01

Thanks all!

For anyone else who needs a workaround literally asap, I made a quick gist here: https://gist.github.com/eastside/adcdf0d189c7470be241a851c5add350

Instead of the normal factory, you’d use legacySassSvgInlinerFactory. It works almost the same as the original factory, (except optimize doesn’t work), at least through the current version of Blueprint.js.

You’d just make a new file, maybe call it sassSvgInliner.mjs, and then of course import it:

import { legacySassSvgInlinerFactory } from './path-to/sassSvgInliner.mjs';

...<snip>...

          {
            loader: "sass-loader",
            options: {
              implementation: "sass",
              sassOptions: {
                "functions": {
                  // /**
                  //  * Sass function to inline a UI icon svg and change its path color.
                  //  *
                  //  * Usage:
                  //  * svg-icon("16px/icon-name.svg", (path: (fill: $color)) )
                  //  */
                  "svg-icon($path, $selectors: null)": legacySassSvgInlinerFactory("blueprint-icons/icons"),
                }
              }
            }
          }

@adidahiya I got the above to start running by turning my webpack config into es6 format.

However, I get an error when running webpack with the sassSvgInliner is this something that has been seen before or could something be configured wrong?

@blueprintjs/node-build-scripts/src/sass/sassSvgInliner.mjs:42
        const resolvedPath = resolve(base, path.text);
                                                ^
TypeError: Cannot read properties of undefined (reading 'text')
    at Object.<anonymous> (file:///home/source/node_modules/@blueprintjs/node-build-scripts/src/sass/sassSvgInliner.mjs:42:49)

When I add console logs to sassSvgInliner function, I get this output for the args paramter: sass.types.String { dartValue: "16px/chevron-right.svg" }

The sass in _breadcrumbs.scss is: background: svg-icon("16px/chevron-right.svg", (path: (fill: $pt-icon-color)));

and later on in the file background: svg-icon("16px/chevron-right.svg", (path: (fill: $pt-dark-icon-color)));

am I right that to use the node-build-scripts library I need to use node 18?

@ahaganDEV Yes, this is enforced by the “engines” constraint defined for the @blueprintjs/node-build-scripts package.

I tried to follow the webpack suggestion as well https://github.com/palantir/blueprint/issues/5334#issuecomment-1444223876 however this doesn’t work

Sorry for the trouble here, could you share some of the issues you encountered with that approach? I’m open to making bugfixes which make it possible to continue compiling Blueprint’s Sass code when it’s consumed as an NPM package.

I don’t have a great alternative solution right now that doesn’t involve advanced Blueprint consumers storing a copy of the icons SVG folder. We inline icons in a few places across the code base and there’s a bit of work to untangle that which I don’t have the bandwidth to do right now. So the inlining has to stay, at least for now.

Note that the svg-icon() function is only used for a few specific icons, so you really only need to ensure these files exist (I don’t have plans to add any more usage of svg-icon() to the code base):

  • 16px/chevron-right.svg
  • 16px/more.svg
  • 16px/chevron-right.svg
  • 16px/more.svg
  • 16px/small-tick.svg
  • 16px/small-minus.svg