使用 Angular 7 构建的 Webpack 4 在尝试访问 node_modules 时会出现 sass-loader 问题

Posted

技术标签:

【中文标题】使用 Angular 7 构建的 Webpack 4 在尝试访问 node_modules 时会出现 sass-loader 问题【英文标题】:Webpack 4 build with Angular 7 gives problem with the sass-loader when trying to access to node_modules 【发布时间】:2020-05-11 01:55:39 【问题描述】:

我正在从 Angular v4 升级到 v7。由于 .angular-cli.json 到 angular.json 及其结构,存在一些重大变化。然后升级 angular 和 webpack 的版本也会产生影响。

在 Angular 4 中,它与自定义 webpack 构建器配合得很好,但升级到 v7 有其复杂性。还值得一提的是,在我使用的 node_modules 上的 scss 中尝试没有任何 @imports 的构建也可以按预期工作。所以我看到问题来自于 webpack 的路径。

我们现在遇到的主要问题是 sass-loader 对 @import 'path/to/file' 感到不满,它没有找到它,然后构建失败。

执行ng serveng build 确实没有任何问题,但是使用自定义webpack 构建它确实会失败,因为它找不到路径。

我得到的错误是:

模块构建失败(来自 ./node_modules/sass-loader/lib/loader.js): @import '../../styles/src/abstracts/_mixins.scss"; ^ 找不到或无法读取要导入的文件:'../../styles/src/abstracts/_mixins.scss"; 父样式表:stdin 在 /Path/to/project 中(第 4 行,第 1 列)

我也尝试过从本地机器到 node_modules 的包中的 npm link 没有任何进展。

这些包是我在项目中导入的组件,它只是带有组件及其 scss 的包。

webpack 配置文件如下所示:

* 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'
        )
    ]
;

我为此使用的版本。 "@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” “到字符串加载器”:“1.1.5” “ts-node”:“7.0.1” “打字稿”:“3.2.4” “webpack”:“4.29.0” “webpack-cli”:“3.3.10” “webpack 合并”:“4.2.2” 和节点 8.9.5 和 npm 5.5.1

谢谢!

【问题讨论】:

【参考方案1】:

我遇到了同样的问题,我通过 sass-loader 将以下规则应用于 scss 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;
                                ,
                            ,
                        
                    
                ]
            

如果您需要使用 node_module 中的另一个库,您可以添加另一个 else if 语句:

例如,假设我在node_modules 中有一个自定义库my-library,我想访问:node_modules/my-library/style.scss,所以我必须添加以下else if 语句:

       
            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;
                            ,
                        ,
                    
                
            ]
        

考虑一下这是我的项目结构:

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

让我知道这是否适合你。

【讨论】:

嗨@gquinteros93!我喜欢你拥有的 sassOptions,但它对我不起作用。如果值得一提,在我在这里提到的这个错误之前,我得到了另一个错误,我通过在我的本地包中执行 npm link 和在项目文件夹中执行 npm link packageName 解决了这个错误。这样我就解决了第一个问题(请参阅此链接的最后一条评论。[***.com/questions/43037590/…)我不知道这是否与此有关?我已经尝试了所有可能的解决方案,但没有任何好的解决方案。感谢您的帮助!

以上是关于使用 Angular 7 构建的 Webpack 4 在尝试访问 node_modules 时会出现 sass-loader 问题的主要内容,如果未能解决你的问题,请参考以下文章

Angular 项目中的 Webpack 错误

使用 Angular 7 + Webpack 4 封装 css

“模板解析错误:'app' 不是已知元素”当使用 Webpack2 构建和部署“OK”angular2 应用程序时

angular1结合webpack构建工具

Angular Webpack ES2015 组件构建中未触发 angular-ui-router $stateChangeStart 事件

升级后或新项目无法构建 Angular 12 和 Webpack 5