Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to compile BluePrint 4 SCSS with webpack sass-loader #6051

Open
ahaganDEV opened this issue Apr 3, 2023 · 23 comments
Open

Unable to compile BluePrint 4 SCSS with webpack sass-loader #6051

ahaganDEV opened this issue Apr 3, 2023 · 23 comments

Comments

@ahaganDEV
Copy link

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/[email protected]
  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.

@ahaganDEV
Copy link
Author

ahaganDEV commented Apr 3, 2023

I tried to follow the webpack suggestion as well #5334 (comment) however this doesn't work and I would preferably not want to store a local copy of blueprint's icons.

@adidahiya
Copy link
Contributor

I tried to follow the webpack suggestion as well #5334 (comment) 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

@ahaganDEV
Copy link
Author

Thanks @adidahiya I will try storing those icons locally and see if that works.

  1. I was originally using React 16 and upgraded to React 18 via NPM.
  2. I also then upgraded blueprint from v3 to v4 with NPM and upgraded to use the latest version of the core package:
    @blueprintjs/core 4.17.8
  3. I remembered that there was a migration from node-sass to the dart-based sass. I upgraded the webpack sass-loader package to the latest version, uninstalled node-sass and then installed sass.

Once this was done, I ran npm start to run the dev server version of webpack where I then get the error above. If I run npm run build to create a production build, I also get the same error.

@adidahiya
Copy link
Contributor

@ahaganDEV so it sounds like you did not try using the new sassSvgInlinerFactory as suggested in #5334 (comment) and documented here in the docs, can you please try that? It requires adding a dependency on the @blueprintjs/node-build-scripts NPM package and using some of the utilities available there.

@ahaganDEV
Copy link
Author

@adidahiya I didn't see that in the docs! I'll give that a go. I am currently using node 16 am I right that to use the node-build-scripts library I need to use node 18?

@adidahiya
Copy link
Contributor

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.

@ahaganDEV
Copy link
Author

ahaganDEV commented Apr 4, 2023

@adidahiya I am trying to import the node-build scripts into my webpack.config.js file like in the example. However, I get the error:

[webpack-cli] Failed to load '/my-project/webpack.config.js' config [webpack-cli] Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: No "exports" main defined in /my-project/node_modules/@blueprintjs/node-build-scripts/package.json

My project is using node 18.13.0, the compilerOptions in tsconfig.json are set totarget: es6, module: commonjs and we use babel.

I tried importing using require('@blueprintjs/node-build-scripts/import') as the package.json for @blueprintjs/node-build-scripts' has that in its exports section but that doesn't work either.

Do you know how I can get this importing correctly in the project. Thanks.

Here are some snippets of the webpack config:

webpack.config.js

// node build scripts import
const { sassSvgInlinerFactory, sassNodeModulesLoadPaths} = require('@blueprintjs/node-build-scripts');
const sass = require('sass');

// sass function
const sassFunctions = {
  /**
   * 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)': sassSvgInlinerFactory('style/blueprint/local-icons', {
    optimize: true,
    encodingFormat: 'uri',
  }),
};

// sass-loader config

{
   loader: 'sass-loader',
   options: {
      sassOptions: {
         loadPaths: sassNodeModulesLoadPaths,
         functions: sassFunctions,
     }, 
   },
},

@ahaganDEV
Copy link
Author

@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)));

@DaivsP
Copy link

DaivsP commented Apr 21, 2023

Hello @ahaganDEV I am having the exact same problem that you described, have you found a solution to this yet?@adidahiya Do you have any idea how to resolve this?

@prachibansal01
Copy link

Hi @adidahiya, I am also facing same issue.
Can you please help us.

@eastside
Copy link

eastside commented May 6, 2023

Just wanted to add my +1 to the issue @ahaganDEV brought up above. I feel like I've got everything set up right, and yet, this custom function doesn't compile.

My feeling is like, I don't know what the heck is going on, but I'm pretty sure the fault is with sass-loader. I made an issue there asking for help.

webpack-contrib/sass-loader#1137

@alexander-akait
Copy link

There is an answer webpack-contrib/sass-loader#1137 (comment).

Shortly - sass-loader (and other sass loader/transformers for other bundlers, like vite/rollup plugins/esbuild plugins/etc) are on the old API, i.e. use render/renderSync, instead compileString/compileStringAsync due to lack abilities to implement resolving (due to lack ability to get current file where we found @import/@use), that is why it is not working, sass team recentry merge RFC to support it, so I hope we will fix it soon, maybe blueprint should provide different versions of functions for the old and the new API

feel free to feedback

@adidahiya
Copy link
Contributor

@alexander-akait thanks for the clarification, I didn't realize that sass-loader only supports the legacy Sass render APIs.

maybe blueprint should provide different versions of functions for the old and the new API

There is an SVG inliner function available for the legacy Sass API. Blueprint was using a third-party library for this before we migrated to the newer API. It's called @vgrid/sass-inline-svg, but it's not compatible with Node 18+. You can see how it was used here: https://github.com/palantir/blueprint/blob/f88e8184940d1de1ae4251a1d0c082bd08c7e328/packages/core/scripts/sass-custom-functions.js. Maybe this same setup could still be used with Blueprint v4 and sass-loader? You would need to downgrade to Node 16.x, though.

@eastside
Copy link

eastside commented May 8, 2023

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"),
                }
              }
            }
          }

@prachibansal01
Copy link

Hi

We tried your approach, but started getting new error.

image

Please help.

@bioc-druzgami
Copy link

@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

@adidahiya adidahiya changed the title Unable to compile BluePrint 4 SCSS Unable to compile BluePrint 4 SCSS with webpack sass-loader Jul 5, 2023
@pbower
Copy link

pbower commented Nov 9, 2023

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

@adidahiya
Copy link
Contributor

@pbower yes I'm interested in taking another look at the tooling issues here but a lot of things have changed since the original post so I think we should start a new thread and only concern ourselves with Blueprint v5.x, Node v18+, and dart-sass. Can you please file a new issue and describe your environment and the problems you're facing in more detail?

@pbower
Copy link

pbower commented Nov 10, 2023 via email

@JoeDuncko
Copy link

@pbower Did you ever create that new issue? I'm encountering the same thing and can't seem to find it if you have.

@vwillyams
Copy link

Looks like sass-loader fixed the underlying issue (webpack-contrib/sass-loader#774) but SassSvgInlinerFactory still fails with exactly the same problem - anyone have any insight?

@pbower
Copy link

pbower commented Jul 3, 2024

Looks like sass-loader fixed the underlying issue (webpack-contrib/sass-loader#774) but SassSvgInlinerFactory still fails with exactly the same problem - anyone have any insight?

No insights, except that it's makes it very difficult to use Blueprint 5, given that it breaks the project from compiling, including Storybook, without workarounds that rely on aging legacy plugins.

Failed to compile.
SassError: (path: #5f6b7c)) isn't a valid CSS value.
node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[5].oneOf[7].use[1]!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[5].oneOf[7].use[2]!./node_modules/resolve-url-loader/index.js??ruleSet[1].rules[5].oneOf[7].use[3]!./node_modules/react-scripts/node_modules/sass-loader/dist/cjs.js??ruleSet[1].rules[5].oneOf[7].use[4]!./src/styles/initialise-theme-palette.scss undefined

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
src/styles/scss-overrides/blueprint-js/custom-overrides.scss 8:9 @import
src/styles/initialise-theme-palette.scss 1:9 root stylesheet

Which is a shame as it's such a great set of components.

The below fix got me through the last 6 months by craco-ing around webpack, but now that dependencies for various project are forced to update, it and storybook has broken:

/* eslint-disable */

const CracoEsbuildPlugin = require("craco-esbuild");
const inliner = require("@vgrid/sass-inline-svg");

module.exports = {
plugins: [{ plugin: CracoEsbuildPlugin }],
style: {
sass: {
loaderOptions: {
// functions from blueprint : https://github.com/palantir/blueprint/blob/develop/packages/core/scripts/sass-custom-functions.js
sassOptions: {
functions: {
"svg-icon($path, $selectors: null)": inliner("./resources/icons", {
optimize: true,
encodingFormat: "uri",
}),
},
},
},
},
},
babel: {
plugins: ["@emotion","@emotion/babel-plugin"],
},
};

It relied on this plugin which now appears to be dead and incompatible- [email protected]
repo: https://github.com/artisanofcode/storybook-preset-craco

If there's any way you guys can fix this stuff will be much appreciated.

@bppdddqqqq
Copy link

I wonder if it couldn't be better to simply deprecate svg-icon function because it's only there for solely 2-3 components in the main base. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests