melmquist
melmquist

Reputation: 470

React component not able to dynamically require() an image file when filename is passed down via props

I am trying to create a reusable Feature component that will render text and images based on what I pass down to it from a parent FeatureList component.

When I try to require() the image dynamically from within the component it throws an error but when I require an unchanging image at the top of the file, it is fine. I am unsure of whether or not this is a issue with Webpack, Typescript perhaps the React component lifecycle.

I have worked off of and subsequently ejected this Microsoft/TypeScript-React-Starter from https://github.com/Microsoft/TypeScript-React-Starter#typescript-react-starter

Parent Component:

import * as React from 'react';
import SingleFeature from './SingleFeature';

var data = {
    header: 'I am header copy',
    image: '../path/to/image.png'
};

function FeatureList() {
    return (
        <div>
            <SingleFeature
                image={data.image}
                header={data.header}
             />
        </div>
    );
}
export default FeatureList;

Child Component:

import * as React from 'react';

const horizontalLine = require('../path/to/genericImage.png'); //THIS WORKS FINE

export interface Props {
    image: string;
    header: string;
}

function SingleFeature({ header, image }: Props) {

    const dynamicallyRequiredImage = require(image)   //THROWS ERROR

    return (

        <div>
            <h1>{header}</h1>                  //-->this accesses props
            <img src={horizontalLine} />       //-->this displays 
            <img src={dynamicallyRequiredImage} />    //THROWS ERROR
        </div>
    );
}

export default SingleFeature;

The Error that I am getting is: "Uncaught Error: Cannot find module "." at webpackMissingModule..." followed by a collapsed stack of 34+ other React specific Errors.

I am new to TypeScript and by no means a WebPack expert. If anyone knows why this is happening only with the dynamically required image or can point me in the right direction, I would greatly appreciate it!

Upvotes: 2

Views: 883

Answers (1)

Aftab Khan
Aftab Khan

Reputation: 3923

You need to understand the way webpack works is it looks all your require() and imports() and bundles them. That is if what you are importing is static string. Not an expression that resolves to string.

For webpack to resolve dynamic expressions, you need to build it a "context". Link

Context is a way to tell webpack that you will be using files from a particular directory, and you want webpack to include them.

Your problem can be solved by

let assetRequire = require.context('../path/to/imagesDir/', true, /\.(png|jpg|svg)$/)
const dynamicallyRequiredImage =  assetRequire('myImage.png')

Try to keep the context building to the innermost directory since it will add all the files matched by the context into the bundle.
Also note how while requiring the file from the context, you should give only path relative to folder you have built the context around.

Starting webpack 2, they started auto building contexts intelligently, like explained here. The above example works in old webpack too..:P

Upvotes: 2

Related Questions