Динамічно імпортуйте зображення з каталогу за допомогою webpack


99

Ось мій поточний робочий процес для імпорту зображень та піктограм у веб-пакет через 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} />

Це швидко стає брудним. Ось що я хочу:

import * from './images'

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

Я відчуваю, що має бути певний спосіб динамічно імпортувати всі файли з певного каталогу як їх розширення без розширення, а потім використовувати ці файли за потреби.

Хтось бачив, як це робиться, або думає про найкращий спосіб це зробити?


ОНОВЛЕННЯ:

Використовуючи вибрану відповідь, я зміг зробити це:

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']} />

7
Я просто хочу зазначити, що .mapтакий тип очікує прибутку. У вашому випадку forEachзамість цього можна було б використати хороший старий .
Брем Ванрой,

1
@BramVanroy або просто зробіть його однокласним і поверніться r.keys.().map(...)безпосередньо ...
LinusGeffarth

Відповіді:


120

Я відчуваю, що має бути певний спосіб динамічно імпортувати всі файли з певного каталогу як їх розширення без розширення, а потім використовувати ці файли за потреби.

Не в ES6. Вся суть importі exportполягає в тому, що залежності можуть бути визначені статично , тобто без виконання коду.

Але оскільки ви використовуєте веб-пакет, подивіться require.context. Ви зможете зробити наступне:

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

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

Цікаво ... Отже, зараз я використовую "file-loader" у конфігурації веб-пакета для переміщення всіх цих файлів в одне місце в загальнодоступній директорії моїх програм. Тут цього не відбувається. Як працюють навантажувачі з require.context?
klinore

1
"Цього тут не відбувається" Ви маєте на увазі, що файли не відображаються у вихідній папці? Ти все ще отримуєш шлях до них із наведеним вище кодом? Я не думаю, що потрібно робити щось особливе, щоб підтримати це ...
Фелікс Клінг

2
Не знаю, чому, придбати мій навантажувач не було запущено, і я отримував початковий шлях. Зараз навантажувач працює нормально, і вказано правильний шлях! Приголомшливо Дякуємо за введення в require.context: D!
klinore

1
Що використовувати, якщо у мене є create-response-app (cra)? в cra importAllнічого не повернув.
giorgim

2
Це працює для мене, але як би ви написали те саме в TypeScript? Які для цього будуть правильні типи?
Максиміліан Ліндсі

10

Це легко. Ви можете використовувати require(статичний метод, імпорт призначений лише для динамічних файлів) всередині render. Як приклад нижче:

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

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

    return (
    <img src={graphImage}/>
    )
}

1
Я думаю, що для роботи з webpack потрібно зробити більше.
Фелікс Клінг

Чи можете ви вставити сюди свій конфігураційний файл webpack?
Robsonsjre

3
Це славно. Дякую!
poweratom

1
Я б не рекомендував використовувати такі глобальні вимоги
markyph

7

У мене є каталог прапорців країн png з назвою au.png, nl.png тощо. Отже, я маю:

-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;

Я прочитав такий файл:

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;

5

Функціональний підхід до вирішення цієї проблеми:

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)$/)
);

Дякую! Працює ідеально!
Zakalwe

4

ОНОВЛЕННЯ Здається, я не зовсім зрозумів питання. @Felix все зрозумів, тому перевірте його відповідь. Наступний код працюватиме лише в середовищі Nodejs.

Додайте index.jsфайл у imagesпапку

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;

Це дозволить імпортувати все з іншого файлу, а Wepback проаналізує його та завантажить потрібні файли.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.