Webpack 4 build with Angular 7 gives problem with the sass-loader when trying to access to node_modules

主宰稳场 提交于 2020-12-04 08:57:19

问题


I was working on a upgrade from Angular v4 to v7. There are some breaking changes due to the .angular-cli.json to angular.json and their structure. And then also upgrading the versions of angular and webpack has its impact.

In Angular 4 it has worked fine with the custom webpack builder but upgrading to v7 has its complications. It is also worth mentioning that trying the build without any @imports in the scss on the node_modules that I use does work as expected too. So I see that the issue comes with the path to/from the webpack.

The main issue we have right now is that the sass-loader is compaining about the @import 'path/to/file' that it doesn't find it and then fails the build.

Doing ng serve and ng build does work without any problem, but doing the build with the custom webpack it does fail because it doesn't find the path.

The error I get is:

ERROR in Module build failed (from ./node_modules/sass-loader/lib/loader.js): @import '../../styles/src/abstracts/_mixins.scss"; ^ File to import not found or unreadable: '../../styles/src/abstracts/_mixins.scss"; Parent style sheet: stdin in /Path/to/project (line 4, column 1)

I have also tried doing npm link from the package from my local machine to the node_modules without any progress.

The packages are components that I import in my projects, it is only packages with components and its scss.

The webpack config files looks like this:

* webpack.config.app.prod.js *

var webpackMerge = require('webpack-merge');
var prod = require('./webpack.config.prod');
var AotPlugin = require('@ngtools/webpack').AngularCompilerPlugin;

module.exports = webpackMerge.strategy({
    plugins: 'prepend'
})(prod.config, {
    entry: './src/main-wp.editor.aot.ts',
    output: {
        filename: 'editor.bundle.js',
        chunkFilename: '[id].chunk.js',
        library: '_' + 'child',
        libraryTarget: 'jsonp'
    },
    plugins: [
        new AotPlugin({
            tsConfigPath: 'tsconfig.aot.json',
            entryModule: './src/app/modules/app.module#EditorModule',
            debug: true
        })
    ]
});

* webpack.config.prod.js *

var path = require('path');

var webpack = require('webpack');
var webpackMerge = require('webpack-merge');
var commonConfig = require('./webpack.config.common');
var UglifyJsPlugin = require("uglifyjs-3-webpack-plugin");

module.exports = {
    config: webpackMerge(commonConfig, {
        output: {
            path: path.resolve(__dirname, 'dist'),
            publicPath: '/',
            filename: 'bundle.js',
            chunkFilename: '[id].[hash].chunk.js'
        },
        module: {
            rules: [
                {
                    test: /\.ts$/,
                    use: ['@ngtools/webpack']
                },

                {
                    test: /\.js$/,
                    loader: '@angular-devkit/build-optimizer/webpack-loader',
                    options: {
                        sourceMap: false
                    }
                }
            ]
        },
        plugins: [
            new UglifyJsPlugin({
                uglifyOptions: {
                    warnings: false,
                    ie8: false,
                    output: {
                        comments: false
                    }
                }
            })
        ]
    }),
    buildPath: function root(args) {
        var _root = path.resolve(__dirname);
        args = Array.prototype.slice.call(arguments, 0);
        return path.join.apply(path, [_root].concat(args));
    }
};

* webpack.config.common.js *

var HtmlWebpackPlugin = require('html-webpack-plugin');
var glob = require("glob");
var path = require('path');

module.exports = {
    entry: './src/main.ts',
    resolve: {
        extensions: ['.js', '.ts']
    },
    module: {
        rules: [
            {
                test: /\.html$/,
                loaders: ['html-loader']
            },
            {
                test: /\.scss$/,
                use: [
                    {
                        loader: "to-string-loader"
                    },
                    {
                        loader: "css-loader", // translates CSS into CommonJS
                        options: {
                            sourceMap: true
                        }
                    },
                    {
                        loader: "sass-loader", // compiles Sass to CSS
                        options: {
                            sourceMap: true,
                            includePaths: glob.sync(
                                path.join(__dirname, '**/node_modules/@mypackage/styles/src/abstracts')
                              ).map((dir) => path.dirname(dir)),
                            // includePaths: [path.resolve("node_modules/@mypackage")],
                            // includePaths: [
                            //     path.resolve('../node_modules')
                            // ]
                        }
                    }
                ]
            }

        ],
        exprContextCritical: false
    },
    plugins: [

        new HtmlWebpackPlugin({
            template: 'src/index.html'
        })
    ]
};

Versions I use for this. "@angular/compiler-cli": "7.2.15"
"uglifyjs-3-webpack-plugin": "1.2.4"
"@angular-builders/custom-webpack": "7.4.3"
"@ngtools/webpack": "7.0.7",
"@types/node": "8.9.5"
"node-sass": "4.5.3"
"sass-loader": "7.3.1"
"to-string-loader": "1.1.5"
"ts-node": "7.0.1"
"typescript": "3.2.4"
"webpack": "4.29.0"
"webpack-cli": "3.3.10"
"webpack-merge": "4.2.2"
And node 8.9.5 with npm 5.5.1

Thanks!


回答1:


I had the same issue and I resolved it with sass-loader applying the following rule for scss the webpack.config.common.js :

            {
                test: /\.component\.(css|sass|scss)$/,
                use: [
                    'to-string-loader',                  
                    'css-loader',
                    {
                        loader: 'sass-loader',
                        options: {
                            sassOptions: {
                                importer: url => {
                                    if (url.startsWith('@angular/')) {
                                        return {
                                            file: path.resolve(`./node_modules/${url}`),
                                        };
                                    }
                                    return null;
                                },
                            },
                        }
                    }
                ]
            }

If you have another library in node_module that you need to use you can add another else if statement:

Example, let's say I have a custom library my-library in node_modules and I want to access to: node_modules/my-library/style.scss so I have to add the following else if statement:

       {
            test: /\.component\.(css|sass|scss)$/,
            use: [
                'to-string-loader',                  
                'css-loader',
                {
                    loader: 'sass-loader',
                    options: {
                        sassOptions: {
                            importer: url => {
                                if (url.startsWith('@angular/')) {
                                    return {
                                        file: path.resolve(`./node_modules/${url}`),
                                };
                                else if (url.startsWith('my-library/')) {
                                        return {
                                            file: path.resolve(`./node_modules/${url}`),
                                        };
                                    }
                                return null;
                            },
                        },
                    }
                }
            ]
        }

Take in count that this was my project structure:

node_modules
dist
config
  - webpack.common.js
  - webpack.dev.js
  - webpack.prod.js
  - webpack.test.js
src
  - app
    - app-routing.module.ts
    - app.component.html
    - app.component.scss
    - app.component.ts
    - app.module.ts
    - index.ts
  - index.html
  - main.browser.ts
  - polyfills.browser.ts
angular.json
package.json
postcss.config.js
tsconfig.json
tsconfig.webpack.json
webpack.config.js

Let me know if this works for you.



来源:https://stackoverflow.com/questions/59901516/webpack-4-build-with-angular-7-gives-problem-with-the-sass-loader-when-trying-to

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!