生产版本中图片无法显示,仅在开发环境中可见(webpack/sass-loader)

3
在webpack dev服务器上运行我的应用程序时,所有的图像文件都能正常工作,无论是在我的index.html文件中作为img标签还是在background-image: 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加载器中引用图片时有些混淆了,无法弄清如何让图片路径在开发和生产环境下同时工作,我只能让其中一个环境下的图片路径正常。

生产环境目录结构:

- 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'} 
   ]), 
 ]
  }
}

4个回答

5
我认为你在生产环境和本地使用不同的文件夹结构,即在本地只有http://localhost:PORT/app,但是在生产环境中,它必须类似于http://produrl/Some_Folder/app
现在来到实际问题-这是你的CSS加载器。
默认情况下,css-loader具有url=true,导致所有URL都相对于根目录进行映射。因此,这对你有效。
background: url('~/img/img-title.png')

但这并不

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

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


哇,非常感谢你!我从来没有想到是css-loader的问题,因为我之前看到的大多数问题都与url和sass loader有关。 - joshuaaron
不用谢。我目前也处于同样的困境,但我的问题更严重,因为涉及到了节点组件。 - Bikas

3

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

波浪线 ~ 问题

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

url() 问题

sass-loader 不正确地解析 url() 如果它们不在入口文件的同一目录中。

在您的特定示例中,您在 src/scss/layout/landing.scsssrc/scss/layout/brands.scss 中导入了一些 url,但我猜您的主 scss 入口点位于 src/scss 文件夹中。

注意:对于“主要scss入口点”,我指的是您在JavaScript入口点src/js/index.js中导入的scss文件。
因此,在您的示例中,导入到不在src/scss文件夹内的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不会输出您的图像,而是将它们内联,当文件大小超过限制(以字节为单位)时,file-loader会输出图像。

file-loader将在dist/img文件夹中输出您的图像,因为您设置了name:'img / [name]。[ext]' ,并且您设置了output.path: path.resolve(__dirname, 'dist')


0

嘿,我认为你的问题只是在于你在 scss 中引用图像的方式。

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

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


嘿@RobIsAnxious,我已经尝试过了,但是我遇到了一个构建错误: 模块未找到:错误:无法解析'../../img/image-title.png' - joshuaaron

0
您可以修改“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/"
            }
          }
        ]
      }
    ]
  }


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接