Search code examples
angularnpmsassng-packagrangular-package-format

How to import angular 13 library packaged SASS?


With Angular 13 and the ng-packagr when we publish SASS mixins with a library we need to add the library to exports in package.json and also declare an assets block in ng-package.json.

These are the instructions.

https://github.com/ng-packagr/ng-packagr/blob/main/docs/copy-assets.md

And it is also explained in this issue: Tilde ~ in SCSS @use statement no longer resolving to node_modules as of Angular 13

So I've done that for this project: https://github.com/fireflysemantics/big-packaged-component-example

This is the ng-package.json configuration:

{
  "$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
  "dest": "../../dist/big",
  "assets": [
    "./src/CHANGELOG.md",
    "./src/lib/**/*.theme.scss"
  ],
  "lib": {
    "entryFile": "src/public-api.ts"
  }
}

And this is the package.json configuration:


   
{
  "name": "@fireflysemantics/big-packaged-component-example",
  "version": "0.0.7",
  "exports": {
    ".": {
      "sass": "./src/lib/big.component.theme.scss"
    }
  },
  "peerDependencies": {
    "@angular/common": "^13.3.0",
    "@angular/core": "^13.3.0"
  },
  "dependencies": {
    "tslib": "^2.3.0"
  }
}

The project can be installed with NPM:

npm i @fireflysemantics/big-packaged-component-example

I've installed it into a test project: https://github.com/fireflysemantics/t/blob/master/src/styles.scss

And I'm trying to import the published theme with the declaration:

@use "@fireflysemantics/big-packaged-component-example/big.component.theme" as theme;

However it errors:

$ ng build
✔ Browser application bundle generation complete.

./src/styles.scss.webpack[javascript/auto]!=!./node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[5].rules[0].oneOf[0].use[1]!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[5].rules[0].oneOf[0].use[2]!./node_modules/resolve-url-loader/index.js??ruleSet[1].rules[5].rules[1].use[0]!./node_modules/sass-loader/dist/cjs.js??ruleSet[1].rules[5].rules[1].use[1]!./src/styles.scss - Error: Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
SassError: Can't find stylesheet to import.
  ╷
3 │ @use "@fireflysemantics/big-packaged-component-example/big.component.theme" as theme;
  │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  ╵
  src/styles.scss 3:1  root stylesheet

./src/styles.scss - Error: Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js):
HookWebpackError: Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
SassError: Can't find stylesheet to import.
  ╷
3 │ @use "~@fireflysemantics/big-packaged-component-example/big.component.theme" as theme;
  │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  ╵
  src/styles.scss 3:1  root stylesheet
    at tryRunOrWebpackError (/Users/oleersoy/Temp/sandbox/t/node_modules/webpack/lib/HookWebpackError.js:88:9)
    at __webpack_require_module__ (/Users/oleersoy/Temp/sandbox/t/node_modules/webpack/lib/Compilation.js:5049:12)
    at __webpack_require__ (/Users/oleersoy/Temp/sandbox/t/node_modules/webpack/lib/Compilation.js:5006:18)
    at /Users/oleersoy/Temp/sandbox/t/node_modules/webpack/lib/Compilation.js:5077:20
    at symbolIterator (/Users/oleersoy/Temp/sandbox/t/node_modules/neo-async/async.js:3485:9)
    at done (/Users/oleersoy/Temp/sandbox/t/node_modules/neo-async/async.js:3527:9)
    at Hook.eval [as callAsync] (eval at create (/Users/oleersoy/Temp/sandbox/t/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:15:1)
    at Hook.CALL_ASYNC_DELEGATE [as _callAsync] (/Users/oleersoy/Temp/sandbox/t/node_modules/tapable/lib/Hook.js:18:14)
    at /Users/oleersoy/Temp/sandbox/t/node_modules/webpack/lib/Compilation.js:4984:43
    at symbolIterator (/Users/oleersoy/Temp/sandbox/t/node_modules/neo-async/async.js:3482:9)
-- inner error --
Error: Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
SassError: Can't find stylesheet to import.
  ╷
3 │ @use "~@fireflysemantics/big-packaged-component-example/big.component.theme" as theme;
  │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  ╵
  src/styles.scss 3:1  root stylesheet
    at Object.<anonymous> (/Users/oleersoy/Temp/sandbox/t/node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[5].rules[0].oneOf[0].use[1]!/Users/oleersoy/Temp/sandbox/t/node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[5].rules[0].oneOf[0].use[2]!/Users/oleersoy/Temp/sandbox/t/node_modules/resolve-url-loader/index.js??ruleSet[1].rules[5].rules[1].use[0]!/Users/oleersoy/Temp/sandbox/t/node_modules/sass-loader/dist/cjs.js??ruleSet[1].rules[5].rules[1].use[1]!/Users/oleersoy/Temp/sandbox/t/src/styles.scss:1:7)
    at /Users/oleersoy/Temp/sandbox/t/node_modules/webpack/lib/javascript/JavascriptModulesPlugin.js:441:11
    at Hook.eval [as call] (eval at create (/Users/oleersoy/Temp/sandbox/t/node_modules/tapable/lib/HookCodeFactory.js:19:10), <anonymous>:7:1)
    at Hook.CALL_DELEGATE [as _call] (/Users/oleersoy/Temp/sandbox/t/node_modules/tapable/lib/Hook.js:14:14)
    at /Users/oleersoy/Temp/sandbox/t/node_modules/webpack/lib/Compilation.js:5051:39
    at tryRunOrWebpackError (/Users/oleersoy/Temp/sandbox/t/node_modules/webpack/lib/HookWebpackError.js:83:7)
    at __webpack_require_module__ (/Users/oleersoy/Temp/sandbox/t/node_modules/webpack/lib/Compilation.js:5049:12)
    at __webpack_require__ (/Users/oleersoy/Temp/sandbox/t/node_modules/webpack/lib/Compilation.js:5006:18)
    at /Users/oleersoy/Temp/sandbox/t/node_modules/webpack/lib/Compilation.js:5077:20
    at symbolIterator (/Users/oleersoy/Temp/sandbox/t/node_modules/neo-async/async.js:3485:9)

Generated code for /Users/oleersoy/Temp/sandbox/t/node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[5].rules[0].oneOf[0].use[1]!/Users/oleersoy/Temp/sandbox/t/node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[5].rules[0].oneOf[0].use[2]!/Users/oleersoy/Temp/sandbox/t/node_modules/resolve-url-loader/index.js??ruleSet[1].rules[5].rules[1].use[0]!/Users/oleersoy/Temp/sandbox/t/node_modules/sass-loader/dist/cjs.js??ruleSet[1].rules[5].rules[1].use[1]!/Users/oleersoy/Temp/sandbox/t/src/styles.scss
1 | throw new Error("Module build failed (from ./node_modules/sass-loader/dist/cjs.js):\nSassError: Can't find stylesheet to import.\n  ╷\n3 │ @use \"~@fireflysemantics/big-packaged-component-example/big.component.theme\" as theme;\n  │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  ╵\n  src/styles.scss 3:1  root stylesheet");

Any ideas?

Update

So if I renamed big.component.theme.scss to index.scss and change the package.json export to this:

"sass": "./src/lib/index.scss",

And import like this:

@use "@fireflysemantics/big-packaged-component-example/" as theme;

It works ... But is it a requirement to name the scss file index?

Also asked about this on the ng-packagr repository:

https://github.com/ng-packagr/ng-packagr/issues/2337


Solution

  • The sass resolvers used in ng-packagr and @angular-devkit/build-angular:browser supports package exports. In short, that means that you can't reach anything in the ~@fireflysemantics/big-packaged-component-example package that isn't explicitly exported from the package.

    This is what your package declares as exports:

    // node_modules/@fireflysemantics/big-packaged-component-example/package.json
    {
      // ...
      "exports": {
        ".": {
          "sass": "./src/lib//big.component.theme.scss",
          "types": "./fireflysemantics-big-packaged-component-example.d.ts",
          "esm2020": "./esm2020/fireflysemantics-big-packaged-component-example.mjs",
          "es2020": "./fesm2020/fireflysemantics-big-packaged-component-example.mjs",
          "es2015": "./fesm2015/fireflysemantics-big-packaged-component-example.mjs",
          "node": "./fesm2015/fireflysemantics-big-packaged-component-example.mjs",
          "default": "./fesm2020/fireflysemantics-big-packaged-component-example.mjs"
        },
        "./package.json": {
          "default": "./package.json"
        }
      },
      // ...
    }
    

    There are only two exports in that package: . and ./package.json. You can't import ~@fireflysemantics/big-packaged-component-example/big.component.theme in your SASS file because ./big.component.theme is not exported from the package.

    Try adding the following to the exports of @fireflysemantics/big-packaged-component-example.

        "./big.component.theme": {
          "sass": "./src/lib/big.component.theme.scss"
        },
    

    Now the SASS loader of angular's application builder can access the import and compilation will succeed.

    You are not required to name the SASS file index.scss or _index.scss. In fact, you could name it anything you want (as long as it has a .scss file extension). The important bit is the key in the exports object.