Nhập động hình ảnh từ một thư mục bằng cách sử dụng webpack


99

Vì vậy, đây là quy trình làm việc hiện tại của tôi để nhập hình ảnh và biểu tượng trong webpack qua 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} />

Điều này trở nên lộn xộn nhanh chóng. Đây là những gì tôi muốn:

import * from './images'

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

Tôi cảm thấy như phải có một số cách để nhập động tất cả các tệp từ một thư mục cụ thể dưới dạng phần mở rộng không có tên của chúng, và sau đó sử dụng các tệp đó nếu cần.

Bất cứ ai đã thấy điều này được thực hiện, hoặc có bất kỳ suy nghĩ về cách tốt nhất để thực hiện nó?


CẬP NHẬT:

Sử dụng câu trả lời đã chọn, tôi có thể làm điều này:

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
Tôi chỉ muốn chỉ ra rằng .maploại mong đợi một giá trị trả lại. Trong trường hợp của bạn, người ta sẽ sử dụng ol 'tốt forEachđể thay thế.
Bram Vanroy

1
@BramVanroy hoặc chỉ làm cho nó một lớp lót và gửi lại r.keys.().map(...)trực tiếp ...
LinusGeffarth

Câu trả lời:


120

Tôi cảm thấy như phải có một số cách để nhập động tất cả các tệp từ một thư mục cụ thể dưới dạng phần mở rộng không có tên của chúng, và sau đó sử dụng các tệp đó nếu cần.

Không có trong ES6. Toàn bộ điểm của importexportlà các phụ thuộc có thể được xác định tĩnh , tức là không cần thực thi mã.

Nhưng vì bạn đang sử dụng webpack, hãy xem require.context. Bạn có thể làm như sau:

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

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

Thật thú vị ... Vì vậy, tôi hiện đang sử dụng 'trình tải tệp' trong cấu hình webpack của mình để di chuyển tất cả các tệp đó đến một vị trí duy nhất trong dir công khai ứng dụng của tôi. Điều đó không xảy ra ở đây. Làm cách nào để trình tải hoạt động với request.context?
klinore

1
"Điều đó không xảy ra ở đây" Ý bạn là các tệp không xuất hiện trong thư mục đầu ra? Mặc dù vậy, bạn vẫn nhận được đường dẫn đến chúng bằng đoạn mã trên chứ? Tôi không nghĩ rằng có cần phải làm bất cứ điều gì đặc biệt để hỗ trợ điều này ...
Felix Kling

2
Không chắc tại sao, mua bộ tải của tôi không được chạy và tôi đang nhận được đường dẫn ban đầu. Bộ tải hiện đang hoạt động tốt và đường dẫn chính xác đang được cung cấp! Tuyệt vời. Cảm ơn bạn đã giới thiệu vào request.context: D!
klinore

1
Sử dụng gì nếu tôi có ứng dụng tạo (cra)? trong cra importAlltrở gì.
giorgim

2
Điều này phù hợp với tôi, nhưng làm thế nào bạn sẽ viết điều tương tự trong TypeScript? Những gì sẽ là các loại chính xác cho nó?
Maximilian Lindsey

10

Dễ thôi. Bạn có thể sử dụng require(một phương thức tĩnh, nhập chỉ dành cho các tệp động) bên trong render. Như ví dụ dưới đây:

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

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

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

1
Tôi nghĩ cần phải làm nhiều hơn nữa để làm cho điều này hoạt động với webpack.
Felix Kling

Bạn có thể dán tệp cấu hình webpack của mình vào đây không?
Robsonsjre

3
Đây là vinh quang. Cảm ơn!
poweratom

1
Tôi không khuyên bạn nên sử dụng các yêu cầu toàn cầu như thế này - xem eslint.org/docs/rules/global-require
markyph Ngày

7

Tôi có thư mục cờ nước png có tên như au.png, nl.png, v.v. Vì vậy, tôi có:

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

Tôi đọc một tệp như thế này:

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

Một cách tiếp cận chức năng để giải quyết vấn đề này:

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

Cảm ơn bạn! Hoạt động hoàn hảo!
Zakalwe

4

CẬP NHẬT Có vẻ như tôi không hiểu rõ câu hỏi. @Felix hiểu đúng vì vậy hãy kiểm tra câu trả lời của anh ấy. Đoạn mã sau sẽ chỉ hoạt động trong môi trường Nodejs.

Thêm một index.jstệp trong imagesthư mục

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;

Điều này sẽ cho phép bạn nhập mọi thứ từ một tệp khác và Wepback sẽ phân tích cú pháp nó và tải các tệp cần thiết.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.