Como carregar arquivos de imagem com o webpack file-loader


141

Estou usando o webpack para gerenciar um projeto reactjs . Quero carregar imagens em javascript por webpack file-loader. Abaixo está o 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
        }
    }
}

Usei essa linha para carregar arquivos de imagem e copiá-los para o diretório dist / public / icons e manter o mesmo nome de arquivo.

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

Mas tenho dois problemas ao usá-lo. Quando executo o webpackcomando, o arquivo de imagem foi copiado para o diretório dist / public / icons / conforme o esperado. No entanto, também foi copiado para o diretório dist com este nome de arquivo "df55075baa16f3827a57549950901e90.png".

Abaixo está a estrutura do meu projeto: insira a descrição da imagem aqui

Outro problema é que usei o código abaixo para importar esse arquivo de imagem, mas ele não está sendo exibido no navegador. Se eu estiver usando o url 'public / icons / imageview_item_normal.png' na tag img, ele funcionará bem. Como usar o objeto importado do arquivo de imagem?

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%',
  }
}

1
Você já tentou remover o carregador de URL?
Jaime

Eu removi o url-loader do arquivo de configuração webpack e remova o diretório dist e execute novamente o comando webpack, o problema ainda está lá. O arquivo foi gerado.
Joey Yi Zhao

Respostas:


196

Em relação ao problema nº 1

Depois de configurar o carregador de arquivos no webpack.config, sempre que você usa import / exija, o caminho é testado em todos os carregadores e, caso haja uma correspondência, ele passa o conteúdo por esse carregador. No seu caso, ele correspondeu

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

e, portanto, você vê a imagem emitida para

dist/public/icons/imageview_item_normal.png

qual é o comportamento desejado.

O motivo pelo qual você também está obtendo o nome do arquivo hash é porque está adicionando um carregador de arquivos embutido adicional. Você está importando a imagem como:

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

Prefixando com file!, passa o arquivo para o carregador de arquivos novamente e, desta vez, não possui a configuração de nome.

Portanto, sua importação deve ser apenas:

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

Atualizar

Conforme observado por @cgatian, se você realmente deseja usar um carregador de arquivos em linha, ignorando a configuração global do webpack, é possível prefixar a importação com dois pontos de exclamação (!!):

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

Em relação ao problema nº 2

Após importar o png, a imgvariável mantém apenas o caminho que o carregador de arquivos "conhece", que é public/icons/[name].[ext](aka "file-loader? name=/public/icons/[name].[ext]"). O diretório de saída "dist" é desconhecido. Você pode resolver isso de duas maneiras:

  1. Execute todo o seu código na pasta "dist"
  2. Adicione publicPathpropriedade à sua configuração de saída, que aponta para o diretório de saída (no seu caso ./dist).

Exemplo:

output: {
  path: PATHS.build,
  filename: 'app.bundle.js',
  publicPath: PATHS.build
},

152
ESTE É O ÚNICO DOCUMENTO NA INTERNET INTEIRA que diz "publicPath" alterará o URL usado pelo carregador de arquivos.
Tyler Jones

@TylerJones, o que você quer dizer?
precisa saber é o seguinte

1
@ Sag1v, eu acho que é melhor para você postar uma nova pergunta, com mais informações, incluindo o seu Webpack configuração
omerts

1
Apenas para adicionar à resposta. (por favor edite como eu acho que isso é útil) Você se você se encontra em uma situação onde você quiser ignorar a configuração Webpack em uma exigem declaração que você pode adicionar dois estrondos adicionais antes da importaçãorequire('!!file-loader!wenis.png');
cgatian

2
A documentação foi bastante aprimorada desde as reivindicações acima :) - Veja: github.com/webpack-contrib/file-loader#options e mais informações sobre publicPath: github.com/webpack-contrib/file-loader#publicpath
Pavelloz,

15

Ocorreu um problema ao fazer upload de imagens para o meu projeto React JS. Eu estava tentando usar o carregador de arquivos para carregar as imagens; Eu também estava usando o Babel-loader na minha reação.

Eu usei as seguintes configurações no webpack:

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

Isso ajudou a carregar minhas imagens, mas as imagens carregadas estavam meio que corrompidas. Depois de algumas pesquisas, soube que o carregador de arquivos tem um erro de corromper as imagens quando o babel-loader é instalado.

Portanto, para contornar o problema, tentei usar o URL-loader, que funcionou perfeitamente para mim.

Atualizei meu webpack com as seguintes configurações

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

Em seguida, usei o seguinte comando para importar as imagens

import img from 'app/images/GM_logo_2.jpg'
<div className="large-8 columns">

      <img  style={{ width: 300, height: 150 }} src={img} />
</div>

6

Instale o carregador de arquivos primeiro:

$ npm install file-loader --save-dev

E adicione esta regra no webpack.config.js

           {
                test: /\.(png|jpg|gif)$/,
                use: [{
                    loader: 'file-loader',
                    options: {}
                }]
            }

5

Como alternativa, você pode escrever o mesmo 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'
        }
    }
}

e use importação simples

import varName from 'relative path';

e em jsx escreva como <img src={varName} ..../>

.... são para outros atributos de imagem


1
Esta parte final é muito importante para imagens inseridas por jsx thanks @ gaurav-paliwal. usando imgPath importação me ajudou a resolvê-lo e as imagens foram copiados para a pasta dist / build
Ebrahim

1
Essa outputPathchave me ajudou a descobrir onde colocar arquivos com subpastas e tudo mais. As outras respostas aqui não funcionaram. Muito obrigado.
Thielicious 16/07

0

webpack.config.js

{
    test: /\.(png|jpe?g|gif)$/i,
    loader: 'file-loader',
    options: {
        name: '[name].[ext]',
    },
}

anyfile.html

<img src={image_name.jpg} />

0

Este é o meu exemplo de trabalho do nosso componente simples do Vue.

<template functional>
    <div v-html="require('!!html-loader!./../svg/logo.svg')"></div>
</template>
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.