Search code examples
reactjsnext.jstailwind-cssnext.js14

Module not found: Can't resolve './${externalUrl}' when using background image with an external URL


I have a component that gets data from Advance Custom Fields from a WordPress CMS. The component then receives an image, then the image is added as a background image on the div.

This is the component:

const Hero = ({ content, ...rest}) => {
const { addImage, image, imagePosition } = content

const backgroundImageClass = twMerge(
    className({
        [`bg-[url('${image.node.sourceUrl}')] bg-cover rounded-[2.5rem] px-5 md:px-[6.75] my-10`]: addImage && imagePosition[0] == 'back'
    }),
    rest.className
)

return(
    <div className={`grid grid-cols-12 py-20 ${backgroundImageClass}`}>
        ...
    </div>
)

}

Using the Classnames package I validate if I should add the image, and if the image goes on the background. Then I concatenate the image URL into the Tailwind class.

When I do this, I get this error message

enter image description here

I try to debug this but I can't find the issue.

I used the external URL as a string on the Tailwind class and it works. I checked the CSS output when I concatenate the image URL variable and it looks ok, this is the output:

.bg-\[url\(\'http\:\/\/anyness-cms\.local\/wpcontent\/uploads\/2024\/04\/dylan\.png\'\)\] { 
   background-image: url('http://anyness-cms.local/wp-content/uploads/2024/04/dylan.png');
}

So right now I don't know if this is a Nextjs, React, Tailwind, or Classnames issue.

I have Nextjs (v14.1.1) with a headless WordPress CMS (v6.5.2), Classname package (v2.3.2), and TailwindCSS (v3.3.3).


Solution

  • As per the documentation:

    The most important implication of how Tailwind extracts class names is that it will only find classes that exist as complete unbroken strings in your source files.

    If you use string interpolation or concatenate partial class names together, Tailwind will not find them and therefore will not generate the corresponding CSS:

    Don’t construct class names dynamically

    <div class="text-{{ error ? 'red' : 'green' }}-600"></div>
    

    In the example above, the strings text-red-600 and text-green-600 do not exist, so Tailwind will not generate those classes. Instead, make sure any class names you’re using exist in full:

    Always use complete class names

    <div class="{{ error ? 'text-red-600' : 'text-green-600' }}"></div>
    

    Thus, with regards to the error, Tailwind interprets the class bg-[url('${image.node.sourceUrl}')] literally:

    .bg-\[url\(\$\{image\.node\.sourceUrl\}\)\] {
      background-image: url(${image.node.sourceUrl});
    }
    

    and as the error suggests, Next cannot find this file named ${image.node.sourceUrl} literally.

    To work around this, consider using the style attribute:

    <div … style={{ backgroundImage: `url('${image.node.sourceUrl}')` }}>