代码之家  ›  专栏  ›  技术社区  ›  Magnus

网页包样式加载器/css加载器:url()路径解析不起作用

  •  2
  • Magnus  · 技术社区  · 6 年前

    有一些关于 style-loader css-loader 尽管如此,我还是没能找到解决问题的办法。

    总之,当我 @import css 其他文件 css格式 包含 url()

    基本上,错误消息显示Webpack最终认为 导入的css中的路径相对于 src css格式 导入到的文件:

    // css-one.scss
    @import "./assets/open-iconic-master/font/css/open-iconic-bootstrap.css";
    
    // open-iconic-bootstrap.css
    @font-face {
        src: url('../fonts/open-iconic.eot');
    }
    

    错误:

    错误在./src/主.scss (./node\模块/css加载器??参考——5-1!。/节点\模块/postss加载器/src??参考——5-2!。/节点\模块/sass加载程序/lib/加载器.js??参考——5-3!。/src公司/主.scss)

    错误:无法解析“../fonts/open”-标志性.eot' 在里面 'C:\Users\…\src' @/src公司/主.scss

    我尝试过:

    const path = require('path');
    const webpack = require('webpack'); // for webpack built-in plugins
    const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
    const CleanWebpackPlugin = require('clean-webpack-plugin');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const MiniCssExtractPlugin = require('mini-css-extract-plugin');
    const CopyWebpackPlugin = require('copy-webpack-plugin');
    // const WriteFilePlugin = require('write-file-webpack-plugin');
    // const ManifestPlugin = require('webpack-manifest-plugin');
    // const InlineManifestWebpackPlugin = require('inline-manifest-webpack-plugin');
    
    // const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
    
    const PATHS = {
      // when using __dirname, resolve and join gives same result,
      // because __dirname is absolute path to directory of this file.
      // OK to use no slashes,
      // both resolve and join adds platform-specific separators by default
      src: path.resolve(__dirname, 'src'),
      dist: path.resolve(__dirname, 'dist'),
      build: path.resolve(__dirname, 'build'),
      test: path.resolve(__dirname, 'test')
    };
    
    const NAMES = {
      // JS FILES
      index: 'index',
      print: 'print',
      // Chrome Extension Development
      popup: 'popup',
      options: 'options',
      background: 'background',
      contentScript: 'contentScript',
    
      // FOLDERS
      assets: 'assets',
      utilities: 'utilities',
      images: 'images',
      fonts: 'fonts',
      include: 'include'
    };
    
    const FILE_PATHS = {
      // JS
      indexJs: `${path.join(PATHS.src, NAMES.index)}.js`,
      printJs: `${path.join(PATHS.src, NAMES.print)}.js`,
      // Chrome Extension Development
      popupJs: `${path.join(PATHS.src, NAMES.popup)}.js`,
      optionsJs: `${path.join(PATHS.src, NAMES.options)}.js`,
      backgroundJs: `${path.join(PATHS.src, NAMES.background)}.js`,
      contentScriptJs: `${path.join(
        PATHS.src,
        NAMES.include,
        NAMES.contentScript
      )}.js`,
    
      // HTML
      indexHtml: `${path.join(PATHS.src, NAMES.index)}.html`,
      printHtml: `${path.join(PATHS.src, NAMES.print)}.html`,
      // Chrome Extension Development
      popupHtml: `${path.join(PATHS.src, NAMES.popup)}.html`,
      optionsHtml: `${path.join(PATHS.src, NAMES.options)}.html`,
      backgroundHtml: `${path.join(PATHS.src, NAMES.background)}.html`
    };
    
    // Third-party (vendor) libraries to include
    // const VENDORS = ['react', 'bootstrap', 'lodash', 'jQuery']; // Relative paths to node_modules
    
    // Note: These are relative
    const ASSETS = {
      images: path.join(NAMES.assets, NAMES.images),
      fonts: path.join(NAMES.assets, NAMES.fonts)
    };
    
    // CleanWebpackPlugin config
    const pathsToClean = [PATHS.dist, PATHS.build];
    const cleanOptions = {
      root: __dirname,
      exclude: ['shared.js'],
      verbose: true,
      dry: false
    };
    
    // CopyWebpackPlugin config
    const copyPattern = [
      // {
      // from: NAMES.assets,
      // to: NAMES.assets
      // },
      // {
      // from: path.join(NAMES.include, 'contentScript.css')
      // },
      // {
      // from: 'manifest.json',
      // transform(content, copyPath) {
      // // generates the manifest file using the package.json informations
      // return Buffer.from(
      // JSON.stringify({
      // ...JSON.parse(content.toString())
      // // description: env.npm_package_description,
      // // version: env.npm_package_version
      // })
      // );
      // }
      // }
    ];
    const copyOptions = {
      // ignore: ['*.js'],
      context: PATHS.src
    };
    
    module.exports = (env = {}) => {
      // webpack injects env variable, into webpack config.
      // perfect to check for production.
      // remember to specify --env.production in command
      // (if in production mode).
      const isProduction = env.production === true;
    
      return {
        entry: {
          index: FILE_PATHS.indexJs
    
          // Chrome Extension Development
          // popup: FILE_PATHS.popupJs,
          // contentScript: FILE_PATHS.contentScriptJs
          // options: FILE_PATHS.optionsJs,
          // background: FILE_PATHS.backgroundJs,
    
          // vendor: VENDORS
        },
        mode: isProduction ? 'production' : 'development',
        devtool: isProduction ? 'source-map' : 'inline-source-map',
        optimization: {
          splitChunks: {
            chunks: 'all'
          }
        },
        output: {
          filename: isProduction ? '[name].[chunkhash:8].js' : '[name].js',
          // chunkFilename determine name of non-entry chunk files,
          // for example dynamic imports in the app
          chunkFilename: isProduction ? '[name].[chunkhash:8].js' : '[name].js',
          path: PATHS.dist
        },
        plugins: [
          // new webpack.SourceMapDevToolPlugin({
          // filename: '[file].map',
          // exclude: ['vendor', 'runtime']
          // }),
          new webpack.DefinePlugin({
            // specifies environment variable for dependencies.
            // does not apply to browser runtime environment
            // (process.env is provisioned by Node)
            'process.env.NODE_ENV': isProduction ?
              JSON.stringify('production') :
              JSON.stringify('development')
          }),
          // new BundleAnalyzerPlugin(),
          new CleanWebpackPlugin(pathsToClean, cleanOptions),
          new MiniCssExtractPlugin({
            // Options similar to the same options in webpackOptions.output
            // both options are optional
            // does not work with Hot Module Replacement (HMR)
            // allows HMR in development (will only use this plugin in production)
            filename: isProduction ? '[name].[contenthash].css' : '[name].css',
            chunkFilename: isProduction ? '[id].[contenthash].css' : '[id].css'
          }),
          new webpack.HashedModuleIdsPlugin(),
          isProduction ?
          new UglifyJSPlugin({
            cache: true,
            parallel: true,
            sourceMap: true // set to true if you want JS source maps
          }) :
          () => {},
          new CopyWebpackPlugin(copyPattern, copyOptions),
          // new WriteFilePlugin(),
          new HtmlWebpackPlugin({
            template: FILE_PATHS.indexHtml,
            filename: `${NAMES.index}.html`
          })
          // new HtmlWebpackPlugin({
          // template: FILE_PATHS.popupHtml,
          // filename: `${NAMES.popup}.html`,
          // excludeChunks: [NAMES.contentScript]
          // In dev mode, chunks excluded vendor chunk (which holds CSS).
          // Above check fixes it.
          // }),
          // new HtmlWebpackPlugin({
          // filename: `${NAMES.contentScript}.html`,
          // excludeChunks: [NAMES.popup, 'runtime'] // Runtime only needed in one HTML
          // }),
          // new HtmlWebpackPlugin({
          // template: FILE_PATHS.optionsHtml,
          // filename: `${NAMES.options}.html`,
          // chunks: isProduction ? [NAMES.options] : ''
          // }),
          // new HtmlWebpackPlugin({
          // template: FILE_PATHS.backgroundHtml,
          // filename: `${NAMES.background}.html`,
          // chunks: isProduction ? [NAMES.background] : ''
          // }),
          // no need for CSS minimization here <-- Done by PostCSS (cssnano)
          // new InlineManifestWebpackPlugin(),
          // new ManifestPlugin({fileName: 'webpack-manifest.json'}),
        ],
        module: {
          rules: [{
              test: /\.js$/,
              exclude: /(node_modules|bower_components)/,
              use: {
                loader: 'babel-loader',
                options: {
                  presets: ['@babel/preset-env']
                }
              }
            },
            {
              test: /\.s?[ac]ss$/,
              exclude: /node_modules/,
              use: [
                isProduction ?
                MiniCssExtractPlugin.loader :
                {
                  // creates style nodes from JS strings
                  loader: 'style-loader',
                  options: {
                    sourceMap: true,
                    convertToAbsoluteUrls: true
                  }
                },
                {
                  // CSS to CommonJS (resolves CSS imports into exported CSS strings)
                  loader: 'css-loader',
                  options: {
                    sourceMap: true,
                    importLoaders: 2
                  }
                },
                {
                  loader: 'postcss-loader',
                  options: {
                    config: {
                      ctx: {
                        cssnext: {},
                        cssnano: {},
                        autoprefixer: {}
                      }
                    },
                    sourceMap: true
                  }
                },
                {
                  // compiles Sass to CSS
                  loader: 'sass-loader',
                  options: {
                    sourceMap: true
                  }
                }
              ]
            },
            {
              test: /\.(png|svg|jpg|gif)$/,
              use: [{
                loader: 'file-loader',
                options: {
                  name: '[name].[hash:4].[ext]',
                  outputPath: ASSETS.images
                }
              }]
            },
            {
              test: /\.(woff|woff2|eot|ttf|otf)$/,
              use: [{
                loader: 'file-loader',
                options: {
                  name: '[name].[hash:4].[ext]',
                  outputPath: ASSETS.fonts
                }
              }]
            },
            {
              test: /\.(csv|tsv)$/,
              use: ['csv-loader']
            },
            {
              test: /\.xml$/,
              use: ['xml-loader']
            },
            {
              test: /\.(html)$/,
              use: {
                loader: 'html-loader',
                options: {
                  interpolate: 'require',
                  minimize: true
                }
              }
            }
            // {
            // test: /\.tsx?$/,
            // exclude: /(node_modules|bower_components)/,
            // use: 'ts-loader'
            // }
          ]
        },
        devServer: {
          // contentBase: path.join(__dirname, 'dist'),
          contentBase: PATHS.dist,
          compress: false,
          port: 8080,
          open: false
        }
      };
    };
    1 回复  |  直到 6 年前
        1
  •  10
  •   Alejandro Giraldo    5 年前

    我的问题是,所有的url()规则(包括字体和图像)都是由css加载程序作为[object Module]加载的,它们是由文件加载程序导出的,但从未加载,所以如果我添加了?url=false对于css加载器,它从不复制文件并导出它们。我不得不说,这是一个完全皮塔,但我得到了它的工作,我希望它适用于其他人在世界上,这是与网页4。

    const webpack = require("webpack");
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const MiniCssExtractPlugin = require("mini-css-extract-plugin");
    const ImageminPlugin = require('imagemin-webpack-plugin').default;
    const CopyPlugin = require('copy-webpack-plugin');
    module.exports = {
        entry: "./src/index.js",
        mode: "development",
        module: {
            rules: [
            {
                test: /\.(js|jsx)$/,
                exclude: /(node_modules|bower_components)/,
                loader: "babel-loader",
                options: { presets: ["@babel/env"] }
            },
            {
                test: /\.(gif|png|jpe?g|svg)$/i,
                use: [
                {
                    loader: 'image-webpack-loader',
                    options: {
                        mozjpeg: {
                            progressive: true,
                            quality: 65
                        },
    
                        optipng: {
                            enabled: false,
                        },
                        pngquant: {
                            quality: [0.65, 0.90],
                            speed: 4
                        },
                        gifsicle: {
                            interlaced: false,
                        },
    
                        webp: {
                            quality: 75
                        },
                    }
                },
                {
                    loader: 'file-loader',
                    options:{
                        name: '[name].[ext]',
                        outputPath: 'images/',
                        publicPath: 'images/'
                    }
                },
                'url-loader?limit=100000'
                ],
            },
            {
                test: /\.(woff(2)?|ttf|eot)(\?v=\d+\.\d+\.\d+)?$/,
                use: [
                {
                    loader: 'file-loader',
                    options: {
                        name: '[name].[ext]',
                        outputPath: 'fonts/'
                    }
                }
                ]
            },
            {
                test: /\.s[ac]ss$/i,
                use: [
                MiniCssExtractPlugin.loader,
                { loader: 'css-loader?url=false'},
                { loader: 'sass-loader', options: { sourceMap: true } }
                ],
            },
            ]
        },
        resolve: { extensions: ["*", ".js", ".jsx"] },
        output: {
            path: path.resolve(__dirname, "dist/"),
            publicPath: "",
            filename: "bundle.js"
        },
        devServer: {
            contentBase: path.join(__dirname, "dist/"),
            port: 3000,
            publicPath: "http://localhost:3000/dist/",
            hotOnly: true
        },
        plugins: [ new MiniCssExtractPlugin(),
        new CopyPlugin([{ from: 'src/images/', to: 'images/' }]),
        new CopyPlugin([{ from: 'src/fonts/', to: 'fonts/' }]),
        new ImageminPlugin({ test: /\.(jpe?g|png|gif|svg)$/i }),
        new HtmlWebpackPlugin({
            hash: true,
            template: './src/index.html',
                filename: './index.html' //relative to root of the application
            }),
        ]
    };
    
        2
  •  8
  •   Magnus    6 年前

    我能自己解决这个问题。如果它能在将来帮助其他人,请找到下面的解决方案。


    1. 首先,如果你两者都用 postcss-loader postcss-import 插件,和 css-loader ,关闭/删除 PostSS导入 插件。您不需要一个以上的工具来解析 @import 规则。如果装载机的顺序正确,这并不是一个真正的问题,但是您最好将其删除。
    2. sass-loader read the following :

    由于Sass/libsass不提供url重写,因此所有链接的资产 必须相对于输出。

    • 如果您将生成的CSS传递给CSS加载器,那么所有url都必须相对于条目文件(例如。主.scss).

    你很可能会被第二个问题打乱。很自然地,我们希望相对引用能够根据指定它们的.scss文件进行解析(就像在常规的.css文件中一样)。谢天谢地,这个问题有两种解决办法:

    • 使用解析url加载程序添加缺少的url重写。将其放在装载机链条中的sass装载机之前。

    我决定跟着第二个子弹,再加上 resolve-url-loader sass-loader 网页包 配置。它现在可以正常工作了。

    我的最终网页包配置(目前)如下所示:

        {
          test: /\.s?[ac]ss$/,
          exclude: /node_modules/,
          use: [
            isProduction
              ? MiniCssExtractPlugin.loader
              : {
                  // creates style nodes from JS strings
                  loader: 'style-loader',
                  options: {
                    sourceMap: true,
                    // convertToAbsoluteUrls: true
                  }
                },
            {
              // CSS to CommonJS (resolves CSS imports into exported CSS strings)
              loader: 'css-loader',
              options: {
                sourceMap: true,
                importLoaders: 2
                // url: false,
                // import: false
              }
            },
            {
              loader: 'postcss-loader',
              options: {
                config: {
                  ctx: {
                    cssnext: {},
                    cssnano: {},
                    autoprefixer: {}
                  }
                },
                sourceMap: true
              }
            },
            {
              loader: 'resolve-url-loader',
              options: {
                attempts: 1,
                sourceMap: true
              }
            },
            {
              // compiles Sass to CSS
              loader: 'sass-loader',
              options: { sourceMap: true }
            }
          ]
        },
    

    旁注

    1. 我注意到Chrome调试器中“无域”下的源映射路径是重复的。如果有人知道原因,请分享
    2. 记住要包括以下副作用 package.json

      “副作用”:[ " .css“, " .scss“ ],

        3
  •  4
  •   Tactical Catgirl    4 年前

    url()

    {
      loader: 'css-loader',
      options: {
        ...
        url: false,
      }
    },