Importieren Sie Bilder mithilfe von Webpack dynamisch aus einem Verzeichnis

96

Hier ist mein aktueller Workflow zum Importieren von Bildern und Symbolen in Webpack über ES6:

import cat from './images/cat1.jpg'
import cat2 from './images/cat2.svg'
import doggy from './images/doggy.png'
import turtle from './images/turtle.png'

<img src={doggy} />

Das wird schnell chaotisch. Folgendes möchte ich:

import * from './images'

<img src={doggy} />
<img src={turtle} />

Ich denke, es muss eine Möglichkeit geben, alle Dateien aus einem bestimmten Verzeichnis als Name ohne Erweiterung dynamisch zu importieren und diese Dateien dann nach Bedarf zu verwenden.

Hat jemand dies gesehen oder hat er sich Gedanken darüber gemacht, wie er am besten vorgehen kann?


AKTUALISIEREN:

Mit der ausgewählten Antwort konnte ich Folgendes tun:

function importAll(r) {
  let images = {};
  r.keys().map((item, index) => { images[item.replace('./', '')] = r(item); });
  return images;
}

const images = importAll(require.context('./images', false, /\.(png|jpe?g|svg)$/));

<img src={images['doggy.png']} />
klinore
quelle
7
Ich möchte nur darauf hinweisen, dass diese .mapArt einen Rückgabewert erwartet. In Ihrem Fall würde man forEachstattdessen eine gute alte verwenden.
Bram Vanroy
1
@BramVanroy oder machen Sie es einfach ein Einzeiler und kehren Sie r.keys.().map(...)direkt zurück ...
LinusGeffarth

Antworten:

118

Ich denke, es muss eine Möglichkeit geben, alle Dateien aus einem bestimmten Verzeichnis als Name ohne Erweiterung dynamisch zu importieren und diese Dateien dann nach Bedarf zu verwenden.

Nicht in ES6. Der springende Punkt von importund exportist, dass Abhängigkeiten statisch bestimmt werden können , dh ohne Code auszuführen.

Aber da Sie Webpack verwenden, schauen Sie sich das an require.context. Sie sollten in der Lage sein, Folgendes zu tun:

function importAll(r) {
  return r.keys().map(r);
}

const images = importAll(require.context('./', false, /\.(png|jpe?g|svg)$/));
Felix Kling
quelle
Interessant ... Daher verwende ich derzeit 'File-Loader' in meiner Webpack-Konfiguration, um alle diese Dateien an einen einzigen Speicherort im öffentlichen Verzeichnis meiner Apps zu verschieben. Das passiert hier nicht. Wie arbeiten Lader mit require.context?
Klinore
1
"Das passiert hier nicht" Sie meinen, die Dateien erscheinen nicht im Ausgabeordner? Erhalten Sie trotzdem den Pfad zu ihnen mit dem obigen Code? Ich denke nicht, dass etwas Besonderes getan werden muss, um dies zu unterstützen ...
Felix Kling
2
Ich bin mir nicht sicher warum, kaufe meinen Lader wurde nicht ausgeführt und ich bekam den ursprünglichen Weg. Der Lader funktioniert jetzt einwandfrei und der richtige Pfad wird angegeben! Genial. Vielen Dank für die Einführung in require.context: D!
Klinore
1
Was kann ich verwenden, wenn ich eine Create-React-App (cra) habe? in cra importAllnichts zurückgegeben.
Giorgim
2
Das funktioniert bei mir, aber wie würden Sie dasselbe in TypeScript schreiben? Was wären die richtigen Typen dafür?
Maximilian Lindsey
10

Es ist einfach. Sie können require(eine statische Methode, Import ist nur für dynamische Dateien) innerhalb der verwenden render. Wie das folgende Beispiel:

render() {
    const {
      someProp,
    } = this.props

    const graphImage = require('./graph-' + anyVariable + '.png')
    const tableImage = require('./table-' + anyVariable2 + '.png')

    return (
    <img src={graphImage}/>
    )
}
Robsonsjre
quelle
1
Ich denke, es muss noch mehr getan werden, damit dies mit Webpack funktioniert.
Felix Kling
Können Sie hier Ihre Webpack-Konfigurationsdatei einfügen?
Robsonsjre
3
Das ist herrlich. Vielen Dank!
Poweratom
Ich würde nicht empfehlen, globale Anforderungen
markyph
7

Ich habe ein Verzeichnis von PNG-Länderflaggen mit den Namen au.png, nl.png usw. Also habe ich:

-svg-country-flags
 --png100px
   ---au.png
   ---au.png
 --index.js
 --CountryFlagByCode.js

index.js

const context = require.context('./png100px', true, /.png$/);

const obj = {};
context.keys().forEach((key) => {
  const countryCode = key.split('./').pop() // remove the first 2 characters
    .substring(0, key.length - 6); // remove the file extension
  obj[countryCode] = context(key);
});

export default obj;

Ich habe eine Datei wie diese gelesen:

CountryFlagByCode.js

import React from 'react';
import countryFlags from './index';

const CountryFlagByCode = (countryCode) => {
    return (
        <div>
          <img src={countryFlags[countryCode.toLowerCase()]} alt="country_flag" />
        </div>
      );
    };

export default CountryFlagByCode;
Tudor Morar
quelle
4

UPDATE Es scheint, als hätte ich die Frage nicht ganz verstanden. @ Felix hat es richtig gemacht, also überprüfe seine Antwort. Der folgende Code funktioniert nur in einer Nodejs-Umgebung.

Fügen Sie index.jsdem imagesOrdner eine Datei hinzu

const testFolder = './';
const fs = require('fs');
const path = require('path')

const allowedExts = [
  '.png' // add any extensions you need
]

const modules = {};

const files = fs.readdirSync(testFolder);

if (files && files.length) {
  files
    .filter(file => allowedExts.indexOf(path.extname(file)) > -1)
    .forEach(file => exports[path.basename(file, path.extname(file))] = require(`./${file}`));
}

module.exports = modules;

Auf diese Weise können Sie alles aus einer anderen Datei importieren und Wepback analysiert es und lädt die erforderlichen Dateien.

kbariotis
quelle
4

Ein funktionaler Ansatz zur Lösung dieses Problems:

const importAll = require =>
  require.keys().reduce((acc, next) => {
    acc[next.replace("./", "")] = require(next);
    return acc;
  }, {});

const images = importAll(
  require.context("./image", false, /\.(png|jpe?g|svg)$/)
);
Patrick Santos
quelle
Danke dir! Funktioniert perfekt!
Zakalwe