How can I load an image from an installed node_module in Next.js?

232 views Asked by At

I am installed a module in my project that includes a <img /> tag within it, and next.js is unable to properly render the image. Currently, the image in the module is being displayed as follows:

<img src="[Object Object]" />

I think this issue may exist after version 11 of Next.js. I am using Next.js version 14. In Next.js version 14, most aspects work smoothly without any issues. However, there is a problem with rendering images that are located in the installed node_modules.

In my opinion, this issue occurs because of the use of the next.js webpack loader, which imports the image module in the following format:

export interface StaticImageData {
    src: string;
    height: number;
    width: number;
    blurDataURL?: string;
    blurWidth?: number;
    blurHeight?: number;
}

declare module '*.png' {
  const content: import('../dist/shared/lib/image-external').StaticImageData

  export default content
}
  • Do I have to use a custom webpack loader to handle this issue?

I attempted to use the next-images package but unfortunately, I was unable to solve the issue or problem I was facing.

1

There are 1 answers

0
PooriaSetayesh On BEST ANSWER

I finally realized that Next.js uses the next-image-loader as the image loader in Webpack, based on the configuration found in the Next.js repository at this link.

Next.js webpack image loader config
{
  test: nextImageLoaderRegex,
  loader: 'next-image-loader',
  issuer: { not: regexLikeCss },
  dependency: { not: ['url'] },
  resourceQuery: {
    not: [
      new RegExp(WEBPACK_RESOURCE_QUERIES.metadata),
      new RegExp(WEBPACK_RESOURCE_QUERIES.metadataRoute),
      new RegExp(WEBPACK_RESOURCE_QUERIES.metadataImageMeta),
    ],
  },
  options: {
    isDev: dev,
    compilerType,
    basePath: config.basePath,
    assetPrefix: config.assetPrefix,
  },
}

In order to address the compatibility issue with next-image-loader, I excluded it for the specific node_module and opted instead to use the asset module of webpack to load images within the installed package. I achieved this by combining the image loader of create-react-app webpack configurations and Next.js webpack image loader. You can find the Webpack image loader configuration of Create React App's react-scripts package at this link.

My Custom webpack config in next.config.js to load all images
/** @type {import('next').NextConfig} */

const path = require("path")

const IMAGE_INLINE_SIZE_LIMIT = parseInt(
    process.env.IMAGE_INLINE_SIZE_LIMIT || '10240'
);


const NEXT_IMAGE_LOADER_EXCLUDE = ['SPECIFIC_NODE_MODULE_NAME'].map((module) => {
    return path.resolve(__dirname, `node_modules/${module}`);
})

module.exports = {
    webpack(config) {
        const nextImageLoaderIndex = config.module.rules.findIndex(item => item.loader === "next-image-loader");
        const { loader, options, ...ruleProps } = config.module.rules[nextImageLoaderIndex];

        config.module.rules[nextImageLoaderIndex] = {
            ...ruleProps,
            oneOf: [
                {
                    exclude: NEXT_IMAGE_LOADER_EXCLUDE,
                    loader,
                    options,
                },
                {
                    type: 'asset',
                    parser: {
                        dataUrlCondition: {
                            maxSize: IMAGE_INLINE_SIZE_LIMIT,
                        },
                    },
                }
            ]
        };
        return config
    }
}

If there is a better way to solve this problem, please mention it.