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

Posted

技术标签:

【中文标题】图片不显示在生产版本中,仅在开发中(webpack/sass-loader)【英文标题】:Images not displaying on production build, only in dev (webpack/sass-loader) 【发布时间】:2018-09-10 16:26:52 【问题描述】:

在 webpack 开发服务器上运行我的应用程序时,我的所有图像文件都可以在我的 index.html 或 background-image 中作为 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')

在brand.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' 
	  ]), 
	]
  

【问题讨论】:

【参考方案1】:

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

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

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

【讨论】:

嘿@RobIsAnxious 我试过了,但我得到一个构建错误:找不到模块:错误:无法解析'../../img/image-title.png' 【参考方案2】:

我认为您在生产中使用的文件夹结构与在本地使用的文件夹结构不同,即在本地,它只是 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,它会正确加载所有环境。

【讨论】:

啊,非常感谢你!在阅读了 urls 和 sass 加载器的大部分问题之后,我永远不会想到它是 css-loader。 不客气。我目前在同一条船上,但由于涉及节点组件,我的问题更糟。【参考方案3】:

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

波浪号~ 问题

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

url()问题

sass-loader doesn't not resolve url() correctly 如果它们不在入口文件的同一目录中。

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

注意:对于 “主 scss 入口点”,我的意思是您在 javascript 入口点中导入的 scss 文件 src/js/index.js

因此,在您的示例中,在 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')

【讨论】:

【参考方案4】:

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

【讨论】:

以上是关于图片不显示在生产版本中,仅在开发中(webpack/sass-loader)的主要内容,如果未能解决你的问题,请参考以下文章

Vue-cli 生产版本不显示静态图像

为啥 React Webpack 生产版本显示空白页面?

.json数据显示在webpack服务器中,但不是生成版本

-initWithDocumentTypes iCloud 仅在生产版本中崩溃

vue生产环境图片无法显示200

同一组件中的不同样式,仅在 gatsby 构建版本中