Cómo cargar archivos de imagen con el cargador de archivos de webpack

Estoy usando webpack para gestionar un proyecto reactjs. Quiero cargar imágenes en javascript mediante el file-loader de webpack. Abajo está el webpack.config.js:

const webpack = require('webpack');
const path = require('path');
const NpmInstallPlugin = require('npm-install-webpack-plugin');

const PATHS = {
    react: path.join(__dirname, 'node_modules/react/dist/react.min.js'),
    app: path.join(__dirname, 'src'),
    build: path.join(__dirname, './dist')
};

module.exports = {
    entry: {
        jsx: './app/index.jsx',
    },
    output: {
        path: PATHS.build,
        filename: 'app.bundle.js',
    },
    watch: true,
    devtool: 'eval-source-map',
    relativeUrls: true,
    resolve: {
        extensions: ['', '.js', '.jsx', '.css', '.less'],
        modulesDirectories: ['node_modules'],
        alias: {
            normalize_css: __dirname + '/node_modules/normalize.css/normalize.css',
        }
    },
    module: {
        preLoaders: [

            {
                test: /\.js$/,
                loader: "source-map-loader"
            },
        ],
        loaders: [

            {
                test: /\.html$/,
                loader: 'file?name=[name].[ext]',
            },
            {
                test: /\.jsx?$/,
                exclude: /node_modules/,
                loader: 'babel-loader?presets=es2015',
            },
            {test: /\.css$/, loader: 'style-loader!css-loader'},
            {test: /\.(jpe?g|png|gif|svg)$/i, loader: "file-loader?name=/public/icons/[name].[ext]"},
            {
                test: /\.js$/,
                exclude: /node_modules/,
                loaders: ['babel-loader?presets=es2015']
            }
        ]
    },
    plugins: [
        new webpack.optimize.UglifyJsPlugin({
            compress: {
                warnings: false,
            },
            output: {
                comments: false,
            },
        }),
        new NpmInstallPlugin({
            save: true // --save
        }),
        new webpack.DefinePlugin({
            "process.env": {
                NODE_ENV: JSON.stringify("production")
            }
        }),
    ],
    devServer: {
        colors: true,
        contentBase: __dirname,
        historyApiFallback: true,
        hot: true,
        inline: true,
        port: 9091,
        progress: true,
        stats: {
            cached: false
        }
    }
}

Utilizo esta línea para cargar los archivos de imagen y copiarlos en el directorio dist/public/icons y mantener el mismo nombre de archivo.

{test: /\.(jpe?g|png|gif|svg)$/i, loader: "file-loader?name=/public/icons/[name].[ext]"}

Pero tengo dos problemas al usarla. Cuando ejecuto el comando webpack, el archivo de imagen se copió al directorio dist/public/icons/ como se esperaba. Cómo, ver también fue copiado a dist directorio con este nombre de archivo "df55075baa16f3827a57549950901e90.png".

Abajo está la estructura de mi proyecto:

Otro problema es que utilizo el siguiente código para importar este archivo de imagen, pero no se puede mostrar en el navegador. Si utilizo la url 'public/icons/imageview_item_normal.png' en la etiqueta img, funciona bien. ¿Cómo utilizar el objeto importado del archivo de imagen?

import React, {Component} from 'react';
import {render} from 'react-dom';
import img from 'file!../../public/icons/imageview_item_normal.png'

export default class MainComponent extends Component {

  render() {
    return (
      <div style={styles.container}>
        download
        <img src={img}/>
      </div>
    )
  }

}

const styles = {
  container: {
    width: '100%',
    height: '100%',
  }
}
Solución

En relación con el problema nº 1

Una vez que tienes el cargador de archivos configurado en el webpack.config, cada vez que usas import/require comprueba la ruta contra todos los cargadores, y en caso de que haya una coincidencia pasa el contenido a través de ese cargador. En tu caso, coincidió con

{
    test: /\.(jpe?g|png|gif|svg)$/i, 
    loader: "file-loader?name=/public/icons/[name].[ext]"
}

y por lo tanto ves la imagen emitida a

dist/public/icons/imageview_item_normal.png

que es el comportamiento deseado.

La razón por la que también se obtiene el nombre de archivo hash, es porque se está añadiendo un cargador de archivos en línea adicional. Usted está importando la imagen como:

'file!../../public/icons/imageview_item_normal.png'.

Prefijo con file!, pasa el archivo en el cargador de archivos de nuevo, y esta vez no tiene la configuración del nombre.

Así que su importación debe ser realmente sólo:

import img from '../../public/icons/imageview_item_normal.png'

Actualización

Como señala @cgatian, si realmente quieres usar un cargador de archivos en línea, ignorando la configuración global de webpack, puedes anteponer a la importación dos signos de exclamación (!!):

import '!!file!../../public/icons/imageview_item_normal.png'.

En cuanto al problema #2

Después de importar el png, la variable img sólo contiene la ruta que el cargador de archivos "conoce", que es public/icons/[nombre].[ext] (también conocido como "file-loader? name=/public/icons/[nombre].[ext]"). Su dir de salida "dist" es desconocido. Puedes resolver esto de dos maneras:

  1. Ejecute todo su código bajo la carpeta "dist".
  2. Añadir la propiedad publicPath a su configuración de salida, que apunta a su directorio de salida (en su caso ./dist).

Ejemplo:

output: {
  path: PATHS.build,
  filename: 'app.bundle.js',
  publicPath: PATHS.build
},
Comentarios (6)

Tuve un problema al cargar imágenes en mi proyecto React JS. Estaba tratando de usar el cargador de archivos para cargar las imágenes; también estaba usando Babel-loader en mi react.

Utilicé la siguiente configuración en el webpack:

{test: /\.(jpe?g|png|gif|svg)$/i, loader: "file-loader?name=app/images/[name].[ext]"},

Esto ayudó a cargar mis imágenes, pero las imágenes cargadas eran una especie de corrupto. Luego, después de algunas investigaciones, llegué a saber que file-loader tiene un error de corromper las imágenes cuando babel-loader está instalado.

Por lo tanto, para solucionar el problema traté de usar URL-loader que funcionó perfectamente para mí.

He actualizado mi webpack con la siguiente configuración

{test: /\.(jpe?g|png|gif|svg)$/i, loader: "url-loader?name=app/images/[name].[ext]"},

Luego usé el siguiente comando para importar las imágenes

import img from 'app/images/GM_logo_2.jpg'

..;

<div className="large-8 columns">


</div>
Comentarios (0)

También puede escribir lo mismo como

{
    test: /\.(svg|png|jpg|jpeg|gif)$/,
    include: 'path of input image directory',
    use: {
        loader: 'file-loader',
        options: {
            name: '[path][name].[ext]',
            outputPath: 'path of output image directory'
        }
    }
}

y luego utilizar la importación simple

importar varName de 'ruta relativa';

y en jsx escribir como ``

.... son para otros atributos de la imagen

Comentarios (1)