I have reproduced my issue at https://github.com/franklin626/custom_webpack_undebuggable.
Starting with a standard Angular 9 CLI application, I had a need to customize the webpack build so that my SCSS files can import JSON configs. This means, in angular.json
, moving from
"serve": {
"builder": "@angular-devkit/build-angular:dev-server"
to
"serve": {
"builder": "@angular-builders/custom-webpack:dev-server",
"options": {
"customWebpackConfig": {
"path": "webpack.config.js"
}
...
With webpack.config.js
containing the following:
const jsonImporter = require('node-sass-json-importer');
module.exports = {
mode: 'development',
module: {
rules: [
{
test: /\.scss$|\.sass$/,
use: [
{
loader: require.resolve('sass-loader'),
options: {
implementation: require('node-sass'),
sassOptions: {
// bootstrap-sass requires a minimum precision of 8
precision: 8,
importer: jsonImporter(),
outputStyle: 'expanded'
}
}
}
]
}
]
}
};
I am only getting the source maps for the css, but not for the javascript. And yes, my Chrome has JS and CSS maps enabled. Not sure what is going on here ?
angular.json
:
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"my-web-app": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"style": "scss"
}
},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-builders/custom-webpack:browser",
"options": {
"customWebpackConfig": {
"path": "./webpack.deploy.config.js",
"replaceDuplicatePlugins": true
},
"outputPath": "dist/my-web-app",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"aot": true,
"assets": ["src/favicon.ico", "src/assets"],
"styles": ["src/styles.scss"],
"scripts": []
},
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "6kb",
"maximumError": "10kb"
}
]
}
}
},
"serve": {
"builder": "@angular-builders/custom-webpack:dev-server",
"options": {
"customWebpackConfig": {
"path": "webpack.config.js",
"sourceMap": true
},
"browserTarget": "my-web-app:build"
},
"configurations": {
"production": {
"browserTarget": "my-web-app:build:production"
}
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "my-web-app:build"
}
},
"test": {
"builder": "@angular-builders/custom-webpack:karma",
"options": {
"customWebpackConfig": {
"path": "webpack.config.js"
},
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"assets": ["src/favicon.ico", "src/assets"],
"styles": ["src/styles.scss"],
"scripts": []
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": ["tsconfig.app.json", "tsconfig.spec.json", "e2e/tsconfig.json"],
"exclude": ["**/node_modules/**"]
}
},
"e2e": {
"builder": "@angular-builders/custom-webpack:protractor",
"options": {
"customWebpackConfig": {
"path": "webpack.config.js"
},
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "my-web-app:serve"
},
"configurations": {
"production": {
"devServerTarget": "my-web-app:serve:production"
}
}
}
}
}
},
"defaultProject": "my-web-app"
}
package.json
{
"name": "my-web-app",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"test": "ng test",
"test-headless": "ng test --watch=false --browsers=ChromeHeadless",
"lint": "ng lint",
"e2e": "ng e2e",
"doc": "node src/scripts/runMarked.js",
"prestart": "npm run doc",
"storybook": "start-storybook -p 6006",
"build-storybook": "build-storybook"
},
"dependencies": {
"@angular/animations": "^9.1.4",
"@angular/cdk": "^9.0.0",
"@angular/common": "^9.1.4",
"@angular/compiler": "^9.1.4",
"@angular/core": "^9.1.4",
"@angular/forms": "^9.1.4",
"@angular/material": "^9.0.0",
"@angular/platform-browser": "^9.1.4",
"@angular/platform-browser-dynamic": "^9.1.4",
"@angular/router": "^9.1.4",
"@azure/msal-angular": "^1.0.0-beta.3",
"@types/vega": "^3.2.0",
"build": "^0.1.4",
"d3": "^5.15.0",
"karma-viewport": "^1.0.5",
"marked": "^0.8.0",
"msal": "^1.2.2-beta.0",
"ng": "0.0.0",
"ngx-spinner": "^9.0.2",
"rxjs": "~6.5.4",
"tslib": "^1.10.0",
"vega": "^5.9.1",
"vega-embed": "^6.2.2",
"vega-lite": "^4.4.0",
"vega-typings": "^0.12.4",
"zone.js": "~0.10.2"
},
"devDependencies": {
"@angular-builders/custom-webpack": "^9.0.0",
"@angular-devkit/build-angular": "^0.901.0",
"@angular/cli": "^9.1.4",
"@angular/compiler-cli": "^9.1.4",
"@angular/language-service": "^9.1.4",
"@babel/core": "^7.9.0",
"@storybook/addon-actions": "^5.3.18",
"@storybook/addon-links": "^5.3.18",
"@storybook/addon-notes": "^5.3.18",
"@storybook/addons": "^5.3.18",
"@storybook/angular": "^5.3.18",
"@types/jasmine": "~3.5.0",
"@types/jasminewd2": "~2.0.3",
"@types/node": "^12.11.1",
"babel-loader": "^8.1.0",
"codelyzer": "^5.1.2",
"compression-webpack-plugin": "^3.1.0",
"jasmine-core": "~3.5.0",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~4.3.0",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage-istanbul-reporter": "~2.1.0",
"karma-jasmine": "~2.0.1",
"karma-jasmine-html-reporter": "^1.4.2",
"karma-junit-reporter": "^2.0.1",
"minimist": "^1.2.0",
"node-sass": "^4.13.1",
"node-sass-json-importer": "^4.1.2",
"prettier": "1.19.1",
"protractor": "~5.4.3",
"terser-webpack-plugin": "^2.3.5",
"ts-node": "~8.3.0",
"tslint": "~5.18.0",
"tslint-config-prettier": "^1.18.0",
"typescript": "~3.7.5"
}
}
To be honest I can't reproduce your issue with sourcemaps (I mean js sourcemaps, maybe you turned them off in browser? I usually turn js source maps off in angular applications to debug ngfactories and etc), but I almost sure that you got into conflicting webpack rules problem.
Please change your custom webpack config to the following to understand the problem:
const merge = require('webpack-merge');
const jsonImporter = require('node-sass-json-importer');
module.exports = function (defaultConfig) {
console.log('>>>>> debug default config rules', defaultConfig.module.rules);
const config = {
mode: 'development',
module: {
rules: [
{
test: /\.scss$|\.sass$/,
use: [
{
loader: require.resolve('sass-loader'),
options: {
implementation: require('node-sass'),
sassOptions: {
// bootstrap-sass requires a minimum precision of 8
precision: 8,
importer: jsonImporter(),
outputStyle: 'expanded'
}
}
}
]
}
]
}
};
return merge(defaultConfig, config);
}
In this log you will see that default anguar config already have two rules for /\.scss$|\.sass$/
.
First one for component or directive styles (component.scss
):
{
exclude: [
'/Users/nikitabalakirev/Desktop/Projects/angular-webpack-custom-sass-rule-example/src/styles.scss'
],
test: /\.scss$|\.sass$/,
use: [ ... ]
},
And the second for global styles:
{
include: [
'/Users/nikitabalakirev/Desktop/Projects/angular-webpack-custom-sass-rule-example/src/styles.scss'
],
test: /\.scss$|\.sass$/,
use: [
...
]
},
This means that your rule and default rules overlapping each other and that can lead to unexpected behavior.
What you can do with this information:
scss
files to be able to import json files you need to change existing default rule, not to add your own, something like that:const myRule = {
loader: require.resolve('sass-loader'),
options: {
implementation: require('node-sass'),
sassOptions: {
// bootstrap-sass requires a minimum precision of 8
precision: 8,
importer: jsonImporter(),
outputStyle: 'expanded'
}
}
}
const scssComponentRule = defaultConfig.module.rules.find(rule => rule.test.toString().includes('scsss'));
scssComponentRule.use.unshift(myRule);
test: /\.special\.scss$|\.sass$/,
and file name for example styles.special.scss
, but you still need to exclude them from Angular's rules! Tip: you can find and research angular default config here
Also please make sure that your angular.json
looks like this:
"build": {
"builder": "@angular-builders/custom-webpack:browser",
"options": {
"customWebpackConfig": {
"path": "./webpack.config.js"
},
and
"serve": {
"builder": "@angular-builders/custom-webpack:dev-server",
"options": {
"browserTarget": "angular-webpack-custom-sass-rule-example:build"
},
UPD
I opened a pr in your repo, thanks for the easy reproduction.
As I said previously it is about default and custom config conflicts.
Angular uses SourceMapDevToolPlugin
for source maps so you don't need to set devtool
property, just leave it blank.
Here is working the webpack
and angular.json
configurations:
{
...
"architect": {
"build": {
"builder": "@angular-builders/custom-webpack:browser", // <---
"options": {
"customWebpackConfig": {
"path": "./webpack.config.js", // <---
},
...
}
}
},
"serve": {
"builder": "@angular-builders/custom-webpack:dev-server", // <---
"options": {
"browserTarget": "test:build" // <---
},
...
},
...
}
const jsonImporter = require("node-sass-json-importer");
module.exports = {
module: {
rules: [
{
test: /\.scss$|\.sass$/,
use: [
{
loader: require.resolve("sass-loader"),
options: {
implementation: require("node-sass"),
sassOptions: {
// bootstrap-sass requires a minimum precision of 8
precision: 8,
importer: jsonImporter(),
outputStyle: "expanded",
},
},
},
],
},
],
}
};
ng serve/build/build --prod
work. And I got this result (changed colors as in your json file)
In general, the past answer looks correct. But something wrong with the merging of default and custom webpack configs. @angular-builders/custom-webpack
merges configs itself if the custom webpack config returns an object. If it returns a function then this function should merge them itself. And maybe this merging produced and issue.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With