1

I upgraded my application to Angular 12.2.5

Everything went relatively smoothly, and I was able to serve my application after the update.

However when I ran ng test, It errored out with the following:

 Error: Cannot find module 'node-sass'

It looks to be from the Karma-scss-preprocessor, specifically in their source, I found

var _nodeSass = require('node-sass');

My understanding was that Angular 12 had been built to work with the new sass implementation (dart-sass), and not with node-sass. At least that's what the error said when I updated, and removed node-sass.

I've tried looking for other scss preprocessor plugins, but all the projects are abandoned and haven't been updated in a while.

Has anyone been able to resolve this issue? Is there some sort of config setting I need to change?

Here's what my Karma config looks like:

// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html

module.exports = function(config) {
  config.set({
    basePath: '../..',
    frameworks: ['jasmine', '@angular-devkit/build-angular'],
    plugins: [
      require('karma-jasmine'),
      require('karma-chrome-launcher'),
      require('karma-jasmine-html-reporter'),
      require('karma-coverage-istanbul-reporter'),
      require('@angular-devkit/build-angular/plugins/karma'),
      require('karma-scss-preprocessor')
    ],
    customLaunchers: {
      ChromeHeadlessCI: {
        base: 'ChromeHeadless',
        flags: ['--no-sandbox', '--headless', '--window-size=1920,1080']
      },
      ChromeHeadless1920: {
        base: 'ChromeHeadless',
        flags: ['--window-size=1920,1080']
      }
    },
    files: [
      { pattern: 'node_modules/jquery/dist/jquery.min.js', watched: false, included: true, nocache: false },
      { pattern: 'projects/shared-library/src/assets/css/styles.scss', included: true, watched: true },
      {
        pattern: 'projects/shared-library/src/assets/css/tinymce-custom-styling.css',
        watched: true,
        included: true
      },
      { pattern: 'node_modules/@angular/cdk/overlay-prebuilt.css', included: true, watched: true },
      { pattern: 'node_modules/leaflet/dist/leaflet.css', included: true, watched: true },
      {
        pattern: 'node_modules/leaflet.markercluster/dist/MarkerCluster.Default.css',
        included: true,
        watched: true
      },
      {
        pattern: 'projects/shared-library/src/assets/icons/**',
        watched: false,
        included: false,
        nocache: false,
        served: true
      },
      // Commented the assets folder, as we only need the tinymce plugin which is included below
      // {
      //   pattern: 'projects/shared-library/src/assets/**/*.js',
      //   watched: false,
      //   included: true,
      //   nocache: false,
      //   served: true
      // },
      // Only including the tinymce file, since we don't need anything else from there for the tests
      // { pattern: 'node_modules/tinymce/**/*.*', watched: true, included: false, served: true },
      {
        pattern: 'projects/shared-library/src/assets/tinymce.min.js',
        watched: true,
        included: true,
        served: true
      },
      {
        pattern: 'node_modules/dhtmlx-gantt/codebase/dhtmlxgantt.css',
        included: true,
        watched: false
      }
      // { pattern: 'node_modules/tinymce/themes/**', watched: true, included: false, served: true },
      // { pattern: 'node_modules/tinymce/plugins/**', watched: true, included: false, served: true }
    ],
    proxies: {
      '/assets/': '/base/projects/shared-library/src/assets/',
      '/tinymce/': '/base/node_modules/tinymce/'
    },
    preprocessors: {
      'projects/shared-library/src/assets/css/styles.scss': ['scss']
    },
    client: {
      clearContext: false // leave Jasmine Spec Runner output visible in browser
    },
    scssPreprocessor: {
      options: {
        includePaths: ['node_modules'],
        importer: require('node-sass-tilde-importer')
      }
    },
    coverageIstanbulReporter: {
      dir: require('path').join(__dirname, '../../coverage/shared-library'),
      reports: ['html', 'lcovonly'],
      fixWebpackSourcePaths: true
    },
    reporters: ['progress', 'kjhtml'],
    port: 9876,
    colors: true,
    logLevel: config.LOG_ERROR,
    autoWatch: true,
    browsers: ['Chrome', 'ChromeHeadlessCI', 'ChromeHeadless1920'],
    singleRun: false,
    restartOnFileChange: true
  });
};

So far, I tried installing node-sass and it does start running, but then it breaks the actual app since node-sass can't process the new syntax. I also updated material which forces you to use the new syntax, so I can't go back to node-sass.

Thank you in advance for any help or advice you may have!

Here's my package.json

{
  "name": "-shared-library",
  "version": "0.0.0",
  "scripts": {
  "preinstall": "npx npm-force-resolutions",
    "ng": "ng",
    "start": "npm run get-lib-version && ng serve -o",
    "serve-mac": "npm run get-lib-version && node --max_old_space_size=8192 node_modules/@angular/cli/bin/ng serve",
    "serve-mac-ngrok": "node --max_old_space_size=8192 node_modules/@angular/cli/bin/ng serve --disable-host-check",
    "build-lib": "ng build -shared-library",
    "build-tester": "ng build ui-tester --prod",
    "build-watch": "ng build -shared-library --watch",
    "test": "ng test --browsers Chrome --code-coverage",
    "test-ci": "ng test  --browsers ChromeHeadlessCI --code-coverage --watch=false",
    "test-watch": "ng test --watch",
    "lint": "ng lint",
    "e2e": "ng e2e",
    "npm-pack": "cd dist/-shared-library && npm pack",
    "package": "npm run get-lib-version && npm run build-lib && npm run npm-pack",
    "build-pack": "npm run package && npm run build-tester",
    "all": "npm run package && npm run start",
    "get-lib-version": "./replace-lib-version",
    "precommit": "run-s format:fix lint && ng test --watch=false",
    "format:fix": "pretty-quick --staged",
    "format:check": "prettier --config ./.prettierrc --list-different \"projects/-shared-library/src/lib/**/*{.ts,.js,.json,.scss,.html,.scss}\"",
    "format:lib": "prettier --config ./.prettierrc --write \"projects/-shared-library/src/lib/**/*{.ts,.js,.json,.scss,.html,.scss}\"",
    "sonar": "sonar-scanner"
},
  "private": true,
  "dependencies": {
  "@angular/animations": "~12.2.5",
    "@angular/cdk": "^12.2.5",
    "@angular/common": "~12.2.5",
    "@angular/compiler": "~12.2.5",
    "@angular/core": "~12.2.5",
    "@angular/flex-layout": "^12.0.0-beta.34",
    "@angular/forms": "~12.2.5",
    "@angular/localize": "^12.2.5",
    "@angular/material": "^12.2.5",
    "@angular/material-moment-adapter": "^12.2.5",
    "@angular/platform-browser": "~12.2.5",
    "@angular/platform-browser-dynamic": "~12.2.5",
    "@angular/router": "~12.2.5",
    "@cloudinary/angular-5.x": "^1.3.3",
    "@ngx-translate/core": "^11.0.1",
    "@ngx-translate/http-loader": "^4.0.0",
    "@tinymce/tinymce-angular": "^4.2.0",
    "@types/file-saver": "^2.0.1",
    "angular-resize-event": "^2.1.0",
    "bootstrap": "^4.5.3",
    "chart.js": "^2.9.4",
    "cloudinary-core": "^2.11.3",
    "core-js": "^2.5.4",
    "dhtmlx-gantt": "file:packages/gantt_7.0.1_ultimate",
    "file-saver": "^2.0.2",
    "fp-ts": "^2.9.5",
    "googleapis": "^64.0.0",
    "jquery": "^3.4.1",
    "leaflet": "^1.7.1",
    "leaflet.markercluster": "^1.4.1",
    "lodash-es": "^4.17.21",
    "moment": "^2.29.1",
    "ng2-pdf-viewer": "7.0.1",
    "ngx-ui-switch": "^11.0.1",
    "popper.js": "^1.16.0",
    "postcss-loader": "^4.0.4",
    "rxjs": "~6.6.3",
    "scroll-into-view-if-needed": "^2.2.24",
    "smoothscroll-polyfill": "^0.4.4",
    "tinymce": "5.0.15",
    "tslib": "^2.0.0",
    "zone.js": "~0.11.4"
},
  "devDependencies": {
  "@angular-devkit/build-angular": "~12.2.5",
    "@angular/cli": "~12.2.5",
    "@angular/compiler-cli": "~12.2.5",
    "@angular/language-service": "~12.2.5",
    "@types/jasmine": "^3.6.1",
    "@types/jasminewd2": "~2.0.8",
    "@types/node": "^12.11.1",
    "codelyzer": "^5.1.2",
    "husky": "^2.2.0",
    "jasmine-core": "~3.5.0",
    "jasmine-spec-reporter": "~5.0.0",
    "karma": "~6.3.4",
    "karma-chrome-launcher": "~3.1.0",
    "karma-coverage-istanbul-reporter": "~3.0.2",
    "karma-jasmine": "~4.0.0",
    "karma-jasmine-html-reporter": "^1.5.0",
    "karma-scss-preprocessor": "^4.0.0",
    "ng-packagr": "^12.2.1",
    "node-sass-tilde-importer": "^1.0.2",
    "npm-force-resolutions": "0.0.3",
    "npm-run-all": "^4.1.5",
    "prettier": "^1.17.0",
    "pretty-quick": "^1.10.0",
    "protractor": "~7.0.0",
    "sonar-scanner": "^3.1.0",
    "ts-node": "~7.0.0",
    "tslint": "~6.1.0",
    "typescript": "~4.3.5"
},
  "resolutions": {
  "webpack": "^5.0.0"
}
}
  • you've still got node-sass-tilde-importer in package.json, also do you still need resolutions in package.json? – danday74 Sep 14 '21 at 16:09
  • @danday74 I just tried uninstalling it and removing it from my project, as well as the karma config file. I'm still getting the same error. The call stack shows it coming directly from Karma-scss-preprocessor. Speaking of which, when I looked at that source code, nothing seems to be importing the new sass package! It seems to be built to only work with node-sass. Which makes no sense to me since the new version of angular is supposed to work with the new sass. According to the angular upgrade guide, yes to use Webpack 5 – Gabriel Rivera Sep 14 '21 at 17:43

1 Answers1

0

Okay, so I think I figured it out. For some reason this is the karma-scss-preprocessor that was getting installed https://github.com/amercier/karma-scss-preprocessor

I ended up finding this: https://www.npmjs.com/package/@alasdair/karma-scss-preprocessor

I installed this package, and replaced it in my karma config.

  config.set({
basePath: '../..',
frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [
  require('karma-jasmine'),
  require('karma-chrome-launcher'),
  require('karma-jasmine-html-reporter'),
  require('karma-coverage-istanbul-reporter'),
  require('@angular-devkit/build-angular/plugins/karma'),
  require('karma-scss-preprocessor')
],

Side note: I also downgraded to webpack 4, as I was getting this error: Error: Content and Map of this Source is not available (only size() is supported)

But only on the first ng build. If i killed it and ran it again, it would work. It is no longer appearing now that I removed the resolution for webpack 5.

I hope this can help someone. I've been hitting on a wall on this for far too long haha.