图片未在生产版本中显示,仅在开发中显示 (webpack/sass-loader)

Images not displaying on production build, only in dev (webpack/sass-loader)

当 运行 我的应用程序在 webpack 开发服务器上时,我所有的图像文件都在工作,无论是作为我的 index.html 中的 img 标签还是背景图像:url()..

运行 我的项目虽然在生产构建中,但我收到无法找到的文件引用错误。

GET file:///img/featured.png net::ERR_FILE_NOT_FOUND
GET file:///img/header-img1-1.jpg net::ERR_FILE_NOT_FOUND

我添加了复制 webpack 插件,因为我认为这会将所有图像从我的 src/img 文件夹移动到我在 dist 中的 img 文件夹。

我应该为 webpack-dev-server 使用 contentBase 选项吗?还是 copy-webpack-plugin 没有得到正确的参考?超级糊涂

项目树:

- webpack.config.js
- package.json
- .babelrc
- src
  - js
    - index.js
    - ...
  - img
    - ALL IMAGES LOCATED HERE
  - scss
    - layout
      - landing.scss
      - brands.scss 
    - base
  - index.html

里面landing.scss 我用过

background: url('~/img/img-title.png')

在其他文件中相同 brands.scss

background: url('~/img/img-title.png')

一切正常,我想我对 webpack/sass 加载程序如何引用图像感到困惑,似乎无法弄清楚如何让图像路径同时适用于两者dev/production,我好像一次只能搞一个。

生产树:

- dist
  - css
  - img
  - js
  - index.html

webpack.config.js:

const path = require('path');
const autoprefixer = require('autoprefixer');

const ExtractTextPlugin = require('extract-text-webpack-plugin');
const extractPlugin = new ExtractTextPlugin({
  filename: 'css/main.css'
});

const HtmlWebpackPlugin = require('html-webpack-plugin');
const ScriptExtPlugin = require('script-ext-html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');

module.exports = (env) => {
  const isProduction = env.production === true

  return {
 entry: './src/js/index.js',
 output: {
  path: path.resolve(__dirname, 'dist'),
  filename: 'js/bundle.js', 
 },
 module: {
   rules: [
  {
       test: /\.js$/,
       include: path.resolve(__dirname, 'src'),
    use: 'babel-loader' 
  },
  {
    test: /\.css$|\.scss$/,
    include: path.resolve(__dirname, 'src'),
    use: extractPlugin.extract({  
   fallback: "style-loader",
   use: [
     { loader: 'css-loader', options: { importLoaders: 2, sourceMap: true }},
     { loader: 'postcss-loader', options: { sourceMap: true, plugins: () => [autoprefixer] }},
     { loader: 'sass-loader', options: { sourceMap: true }},
   ],
    }) 
  },
  {
    test: /\.html$/,
    use: ['html-loader']
  },
  {
    test: /\.(jpe?g|png|gif)$/,
    use: [
   {
        loader: 'url-loader',
     options: {
    limit: 1000,
    name: 'img/[name].[ext]',
     }
   }
    ]
  }
   ]
 },
 plugins: [
   extractPlugin,
   new HtmlWebpackPlugin({ 
  filename: 'index.html',
  inject: true,
  template: './src/index.html'
   }),
   new ScriptExtPlugin({
     defaultAttribute: 'async'
   }),
   new CleanWebpackPlugin(['dist']),
   new CopyWebpackPlugin([
     {from:'src/img',to:'img'} 
   ]), 
 ]
  }
}

嘿,我认为你的问题在于你如何在 scss 中引用图像。

根据您的文件夹结构,它应该是:

background: url('../../img/img-title.png')

我认为您在生产环境中使用的文件夹结构与在本地环境中使用的文件夹结构不同,即在本地环境中,它只是 http://localhost:PORT/app, but on prod, it must be similar to http://produrl/Some_Folder/app

现在进入实际问题 - 这是您的 CSS 装载程序。

默认css-loader,有url=true,导致所有 URLs 相对于 root 进行映射。因此这对你有用 -

background: url('~/img/img-title.png')

但这不是

background: url('../../img/img-title.png')

只需设置url=false,您就可以提供相对URL和它将正确加载所有环境。

虽然接受的答案可能适用于您的特定情况,但我认为有更好的解决方案不涉及禁用 css-loader url() 处理,并且在大多数情况下效果更好。

波浪线 ~ 问题

当您使用 ~ 在 css 中导入某些内容时,css-loader 将在 node_modules 中搜索该文件。您的图片位于 src/img 文件夹中,因此您 不需要 需要波浪号 ~ 来导入您的图片。

url() 问题

sass-loader doesn't not resolve url() correctly如果不在同一个目录下entry-file.

在您的具体示例中,您在 src/scss/layout/landing.scss[=79 中导入了一些 urls =].scss 但我猜你的主要 scss 入口点在 src/scss 文件夹内。

注意:对于 "main scss entry point",我指的是您在 javascript 入口点 中导入的 scss 文件src/js/index.js

因此,在您的示例中,在 src/scss[=65= 中 而不是 的 scss 文件中导入的每个图像]文件夹会报错。

要解决此问题,请使用 resolve-url-loader,它根据原始源文件解析 url() 语句中的相对路径。

[
  { loader: 'css-loader'}, // set `importLoaders: 3` if needed but should works fine without it
  { loader: 'postcss-loader'},
  { loader: 'resolve-url-loader' }, // add this
  { loader: 'sass-loader',
    // sourceMap is required for 'resolve-url-loader' to work
    options: { sourceMap: true }
  }
]

CopyWebpackPlugin 可选

根据您的配置,您不需要 CopyWebpackPlugin,因为您的图像已由 url-loader 处理。

注意:url-loader doesn't output your images but inline them, images are outputted by file-loader当文件大于限制(以字节为单位)时。

file-loader会输出你的图片到dist/img文件夹,因为你设置了name: 'img/[name].[ext]',你设置了output.path: path.resolve(__dirname, 'dist')

您可以修改“publicPath”URL(相对于服务器根目录)以匹配文件结构。

//webpack.config.js
 ...
   module: {
    rules: [
      {
        test: /\.(jpe?g|png|gif|svg)$/i,
        use: [
          {
            loader: "file-loader",
            options: {
              name: "[name].[ext]",
              outputPath: "assets/images/",
              publicPath: "/other-dir/assets/images/"
            }
          }
        ]
      }
    ]
  }