首页 > 解决方案 > 无法使用“html-loader”解析资产

问题描述

我正在尝试为我的 AngularJs 将 Gulp 迁移到 Webpack,以准备迁移到 Angular。加载 html 文件时,我无法解析我的资产,并且出现很多类似这样的错误:

ERROR in ./src/app/space/tender-summary/actions-popup.html 6:33-72
Module not found: Error: Can't resolve './assets/icons/hourglass.svg' in '/home/marvin/workspace/plateforme/source/front/src/app/space/tender-summary'
 @ ./src/app/space/tender-summary/tender-summary.controller.js 738:18-123
 @ ./src/app/ sync (?<!\.spec)\.(js)$ ./space/tender-summary/tender-summary.controller.js
 @ ./src/app.js 12:11-64

所以我的根项目是:

/home/marvin/workspace/plateforme/source/front/

文件在

/src/app/space/tender-summary

资产都在这个文件夹中:

/src/资产/

我知道我可以通过改变让它发挥作用

<img src="assets/icons/hourglass.svg">

<img src="../../../assets/icons/hourglass.svg">

但我不想重写我所有的 html 文件,因为有很多。这是我的 webpack.config.js

const path = require('path');
const webpack = require('webpack');
const {
  CleanWebpackPlugin
} = require('clean-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const glob = require('glob');

// assets.js
const Assets = require('./assets');

const paths = {
  assets: path.resolve(__dirname, './assets'),
  dist: path.resolve(__dirname, './dist'),
  node: path.resolve(__dirname, './node_modules'),
  src: path.resolve(__dirname, './src')
};

const vendor = Assets.JS.map(item => {
  return paths.node + '/' + item + '/';
});
vendor.push(paths.node + '/jquery-jcrop/js/jquery.Jcrop');
vendor.push(paths.node + '/ng-jcrop/ng-jcrop');
vendor.push(paths.src + '/app/core/modules/angular-google-places-autocomplete/autocomplete.min');
vendor.push(paths.src + '/app/core/preloader/preloader');
vendor.push(paths.src + '/app/core/services/underscore');
vendor.push(paths.src + '/assets/scripts/fa5-pro');

Assets.CSS.forEach(item => {
  vendor.push(paths.node + '/' + item);
})

module.exports = {
    entry: {
      vendor,
      app: paths.src + '/app.js'
    },
    output: {
      path: paths.dist,
      filename: '[name].js',
      publicPath: '/'
    },

    // Spin up a server for quick development
    devServer: {
      historyApiFallback: true,
      contentBase: paths.dist,
      open: true,
      compress: true,
      hot: true,
      port: 3000
    },

    plugins: [
      new CleanWebpackPlugin(),

      new CopyPlugin({
        patterns: [
          {
            from: paths.src + '/app/languages/',
            to: paths.dist + '/languages/'
          }
        ],
      }),

      new MiniCssExtractPlugin(),

      // Generates an HTML file from a template
      // Generates deprecation warning: https://github.com/jantimon/html-webpack-plugin/issues/1501
      new HtmlWebpackPlugin({
        title: 'FretlyFrontend',
        favicon: paths.src + '/favicon.ico',
        template: paths.src + '/index.html', // template file
        filename: 'index.html' // output file
      })
    ],

    // Determine how modules within the project are treated
    module: {
      rules: [{
          // Add jQuery as a global object (needed for ng-jcrop)
          test: require.resolve('jquery'),
          loader: 'expose-loader',
          options: {
            exposes: ['$', 'jQuery']
          }
        },
        {
          // Add jQuery.Jcrop to the global jQuery (needed for ng-jcrop)
          test: require.resolve('jquery-jcrop'),
          loader: 'expose-loader',
          options: {
            exposes: ['$', 'jQuery.Jcrop']
          }
        },
        {
          test: require.resolve('moment'),
          loader: 'expose-loader',
          options: {
            exposes: ['moment', 'moment']
          }
        },
        {
          test: require.resolve('malarkey'),
          loader: 'expose-loader',
          options: {
            exposes: ['malarkey', 'malarkey']
          }
        },

        // JavaScript: Use Babel to transpile JavaScript files
        {
          test: /\.m?js$/,
          exclude: [/\.(spec|e2e)\.js$/, /node_modules/],
          use: [{
              loader: 'babel-loader',
              options: {
                presets: ['@babel/preset-env']
              }
            },
            {
              loader: 'angularjs-template-loader',
              options: {
                relativeTo: paths.src
              }
            }
          ],
        },

        // Styles: Inject CSS into a new file
        {
          test: /\.(scss|css)$/,
          use: [
            MiniCssExtractPlugin.loader, // 4. Take all .css files into a single .css file
            'css-loader', // 3. Inject .css files
            {
              // 2. Adds css processors
              loader: 'postcss-loader',
              options: {
                postcssOptions: {
                  plugins: [
                    [
                      'postcss-preset-env', // convert modern CSS into compatible CSS
                      'autoprefixer' // auto adds vendor prefixes
                    ]
                  ]
                }
              }
            },
            {
              // 1. Import .scss files and convert it to .css
              loader: 'sass-loader',
              options: {
                additionalData: (content, loaderContext) => {
                  const {
                    resourcePath,
                    rootContext
                  } = loaderContext;
                  const relativePath = path.relative(rootContext, resourcePath);

                  let newContent = '';

                  // include dependencies in every files except themself
                  if (relativePath !== 'src/app/styles/variables.scss') {
                    newContent += '@import "' + rootContext + '/src/app/styles/variables.scss";';
                  }
                  if (relativePath !== 'src/app/styles/mixins.scss') {
                    newContent += '@import "' + rootContext + '/src/app/styles/mixins.scss";';
                  }

                  return newContent + content;
                }
              }
            }
          ]
        },

        {
          test: /\.html$/,
          use: [{
            loader: 'html-loader',
            options: {
              attributes: {
                root: paths.src,
              },
            },
          }],
        exclude: /node_modules/
      },

      // Images: Copy image files to build folder
      {
        test: /\.(?:ico|png|jpe?g|gif)$/i,
        use: ['file-loader']
      },

      // Fonts and SVGs: Inline files
      {
        test: /\.(woff(2)?|eot|ttf|otf|svg|)$/,
        type: 'asset/resource'
      }
    ]
  },
  optimization: {
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendors: {
          minChunks: 3,
          test: /[\\/]node_modules[\\/]/,
          priority: -10
        },
        default: {
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true
        }
      }
    },
    minimize: false,
    minimizer: [
      new TerserPlugin({
        terserOptions: {
          keep_classnames: true,
          keep_fnames: true
        }
      }),
      new CssMinimizerPlugin()
    ]
  }
};

我尝试使用 attributes.root 选项使用 html-loader 编辑“/src”的相对路径,但它不起作用。如何让我的资产发挥作用?

标签: webpackassetswebpack-html-loader

解决方案


推荐阅读