bholloway / resolve-url-loader

Webpack loader that resolves relative paths in url() statements based on the original source file
563 stars 71 forks source link

4.0.0-alpha.3: webpack misconfiguration #190

Closed yoyo837 closed 3 years ago

yoyo837 commented 3 years ago

Upgrade to 4.0.0-alpha.3, I got this:

resolve-url-loader: webpack misconfiguration webpack or the upstream loader did not supply a source-map

webpack-base-config.js:

const path = require('path');
const webpack = require('webpack');
const { merge } = require('webpack-merge');
const StylelintPlugin = require('stylelint-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');
// const DuplicatePackageCheckerPlugin = require('duplicate-package-checker-webpack-plugin');
const ProgressBarPlugin = require('progress-bar-webpack-plugin');
const postcssNormalize = require('postcss-normalize');
const loaderUtils = require('loader-utils');

// 对码表索引
let index = 0;
// 对码表 原css变量/缩短映射变量
const cssKeyMap = new Map();

// common function to get style loaders
const getStyleLoaders = (cssOptions, preProcessor, preProcessorOptions) => {
  const isEnvDevelopment = process.env.NODE_ENV === 'development';
  const isEnvProduction = process.env.NODE_ENV === 'production';
  const loaders = [
    isEnvDevelopment && require.resolve('style-loader'),
    isEnvProduction && {
      loader: MiniCssExtractPlugin.loader,
      options: {},
    },
    {
      loader: require.resolve('css-loader'),
      options: {
        importLoaders: 1,
        ...cssOptions,
      },
    },
    {
      // Options for PostCSS as we reference these options twice
      // Adds vendor prefixing based on your specified browser support in
      // package.json
      loader: require.resolve('postcss-loader'),
      options: {
        // Necessary for external CSS imports to work
        // https://github.com/facebook/create-react-app/issues/2677
        ident: 'postcss',
        plugins: () => [
          // eslint-disable-next-line global-require
          require('postcss-flexbugs-fixes'),
          // eslint-disable-next-line global-require
          require('postcss-preset-env')({
            autoprefixer: {
              flexbox: 'no-2009',
            },
            stage: 3,
          }),
          // Adds PostCSS Normalize as the reset css with default options,
          // so that it honors browserslist config in package.json
          // which in turn let's users customize the target behavior as per their needs.
          postcssNormalize(),
        ],
        sourceMap: isEnvProduction,
      },
    },
  ].filter(Boolean);
  if (preProcessor) {
    loaders.push(
      {
        loader: require.resolve('resolve-url-loader'),
        options: {
          sourceMap: isEnvProduction,
        },
      },
      {
        loader: require.resolve(preProcessor),
        options: {
          sourceMap: isEnvProduction,
          ...preProcessorOptions,
        },
      }
    );
  }
  return loaders;
};

module.exports = function (webToolsConfig) {
  const isEnvDevelopment = process.env.NODE_ENV === 'development';
  const isEnvProduction = process.env.NODE_ENV === 'production';
  const { paths, modifyVars, webpackConfig } = webToolsConfig;
  return merge(
    {
      entry: paths.appIndexJs,
      output: {
        // The build folder.
        path: isEnvProduction ? paths.appBuild : undefined,
        // Add /* filename */ comments to generated require()s in the output.
        pathinfo: isEnvDevelopment,
        // There will be one main bundle, and one file per asynchronous chunk.
        // In development, it does not produce real files.
        filename: isEnvProduction ? 'static/js/[name].[contenthash:8].js' : isEnvDevelopment && 'static/js/bundle.js',
        // TODO: remove this when upgrading to webpack 5
        futureEmitAssets: true,
        // There are also additional JS chunk files if you use code splitting.
        chunkFilename: isEnvProduction
          ? 'static/js/[name].[contenthash:8].chunk.js'
          : isEnvDevelopment && 'static/js/[name].chunk.js',
        // We inferred the "public path" (such as / or /my-project) from homepage.
        // We use "/" in development.
        publicPath: '/',
        // Point sourcemap entries to original disk location (format as URL on Windows)
        devtoolModuleFilenameTemplate: isEnvProduction
          ? info => path.relative(paths.appSrc, info.absoluteResourcePath).replace(/\\/g, '/')
          : isEnvDevelopment && (info => path.resolve(info.absoluteResourcePath).replace(/\\/g, '/')),
        // Prevents conflicts when multiple Webpack runtimes (from different apps)
        // are used on the same page.
        // jsonpFunction: `webpackJsonp${appPackageJson.name}`,
        // this defaults to 'window', but by setting it to 'this' then
        // module chunks which are built will work in web workers as well.
        globalObject: 'this',
      },
      externals: {
        jWeixin: 'jWeixin',
      },
      resolve: {
        extensions: paths.moduleFileExtensions.map(ext => `.${ext}`),
      },
      module: {
        rules: [
          { parser: { requireEnsure: false } },
          // First, run the linter.
          // It's important to do this before Babel processes the JS.
          {
            test: /\.(js|ts|tsx)$/,
            enforce: 'pre',
            use: [
              {
                options: {
                  cache: true,
                  // formatter:,
                  eslintPath: require.resolve('eslint'),
                },
                // eslint-loader 后续可能会被 https://github.com/webpack-contrib/eslint-webpack-plugin 替代
                // 试了下,有些问题,如修改文件后的实时HMR编译变慢等
                loader: require.resolve('eslint-loader'),
              },
            ],
            include: paths.appSrc,
          },
          {
            test: /\.js$/,
            exclude: /node_modules/,
            use: [
              {
                loader: 'babel-loader',
              },
            ],
          },
          {
            test: /\.(ts|tsx)$/,
            exclude: /node_modules/,
            use: [
              {
                loader: 'babel-loader',
              },
              {
                loader: 'ts-loader',
              },
            ],
          },
          {
            test: /\.css$/,
            use: getStyleLoaders({
              sourceMap: isEnvProduction,
            }),
            // Don't consider CSS imports dead code even if the
            // containing package claims to have no side effects.
            // Remove this when webpack adds a warning or an error for this.
            // See https://github.com/webpack/webpack/issues/6571
            sideEffects: true,
          },
          {
            test: /\.less$/,
            include: /node_modules/,
            use: getStyleLoaders(
              {
                sourceMap: isEnvProduction,
              },
              'less-loader',
              {
                lessOptions: {
                  javascriptEnabled: true,
                  modifyVars,
                  // FIXME: 升级antd@4.10.0之后,可以调整less文件然后去掉这个配置
                  // http://lesscss.org/usage/#less-options-math
                  math: 'always',
                },
              }
            ),
            sideEffects: true,
          },
          {
            test: /\.less$/,
            exclude: /node_modules/,
            use: getStyleLoaders(
              {
                sourceMap: isEnvProduction,
                modules: {
                  getLocalIdent: (context, localIdentName, localName, options) => {
                    // Use the filename or folder name, based on some uses the index.js / index.module.(css|scss|sass) project style
                    const fileNameOrFolder = /index\.less$/.test(context.resourcePath) ? '[folder]' : '[name]';
                    // Create a hash based on a the file location and class name. Will be unique across a project, and close to globally unique.
                    const hash = loaderUtils.getHashDigest(
                      path.posix.relative(context.rootContext, context.resourcePath) + localName,
                      'md5',
                      'base64',
                      5
                    );
                    // Use loaderUtils to find the file or folder name
                    const className = loaderUtils.interpolateName(
                      context,
                      `${fileNameOrFolder}_${localName}__${hash}`,
                      options
                    );
                    // remove the .module that appears in every classname when based on the file.
                    const cssKey = className.replace('.module_', '_');
                    if (isEnvDevelopment) {
                      return cssKey;
                    }
                    const mappingKey = cssKeyMap.get(cssKey);
                    if (mappingKey) {
                      return mappingKey;
                    }
                    index += 1;
                    // 16进制有数字开头,css名称不能以数字开头,补一个合法的字符
                    const newMappkey = `_${index.toString(16)}`;
                    cssKeyMap.set(cssKey, newMappkey);
                    return newMappkey;
                  },
                },
              },
              'less-loader',
              {
                lessOptions: {
                  javascriptEnabled: true,
                  modifyVars,
                  // FIXME: 升级antd@4.10.0之后,可以调整less文件然后去掉这个配置
                  // http://lesscss.org/usage/#less-options-math
                  math: 'always',
                },
              }
            ),
            sideEffects: true,
          },
          {
            test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
            loader: require.resolve('url-loader'),
            options: {
              limit: 10000, // url-loader 包含file-loader,这里不用file-loader, 小于10000B的图片base64的方式引入,大于10000B的图片以路径的方式导入
              name: 'static/img/[name].[hash:8].[ext]',
            },
          },
          {
            test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
            loader: require.resolve('url-loader'),
            options: {
              limit: 10000, // 小于10000B的图片base64的方式引入,大于10000B的图片以路径的方式导入
              name: 'static/fonts/[name].[hash:8].[ext]',
            },
          },
          // {
          //   loader: require.resolve('file-loader'),
          //   // Exclude `js` files to keep "css" loader working as it injects
          //   // its runtime that would otherwise be processed through "file" loader.
          //   // Also exclude `html` and `json` extensions so they get processed
          //   // by webpacks internal loaders.
          //   exclude: [/\.(js|mjs|jsx|ts|tsx|less)$/, /\.html$/, /\.json$/],
          //   options: {
          //     name: 'static/media/[name].[hash:8].[ext]',
          //   },
          // },
        ],
      },
      optimization: {
        usedExports: true,
      },
      plugins: [
        // antd-dayjs-webpack-plugin 有问题,所以先采取其他方法
        // 1
        // new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
        // 2
        new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /zh-cn/),
        new ProgressBarPlugin({
          color: 'green',
          // reporters: ['fancy'],
        }),
        // new DuplicatePackageCheckerPlugin(),
        new FriendlyErrorsWebpackPlugin({
          quiet: true,
        }),
        new StylelintPlugin({
          files: '**/*.less',
        }),
      ],
    },
    webpackConfig || {}
  );
};

webpack.dev.config.js:

const { merge } = require('webpack-merge');
const getCommonConfig = require('./webpack.base.config');

const devConfig = {
  mode: 'development',
  devtool: 'cheap-module-source-map',
};

module.exports = function (...args) {
  return merge(getCommonConfig(...args), devConfig);
};
bholloway commented 3 years ago

Per the docs here your preprocessor needs to have sourceMap: true always.

    {
        loader: require.resolve(preProcessor),
        options: {
          sourceMap: isEnvProduction,  // <--- sourceMap: true
          ...preProcessorOptions,
        },
      }

If webpack worked before this release then it means that resolve-url-loader wasn't actually doing anything. So you can probably remove it from your project. Certainly your compile time will be faster if you don't use the loader.

yoyo837 commented 3 years ago

Thanks a lot. I got the point.