Webpack 5 - how to bundle assets from an npm module

Viewed 427

I have built an npm module. I am struggling to find a way to configure webpack 5 to include module-assets in an app that has the module as a dependency.

Context

What I have is something like:

myNpmModule

dist/
    index.js
    assets/
        image.png

I use the module as follows

// project/app.jsx
import Component from 'myNpmModule'
return <Component />

In this example, <Component /> renders image.png.

When I run this however I have two problems:

  1. image.png is sought at the root directory
  2. image.png is not in the webpack bundle

To get around this issue I have converted all images in myNpmModule to data URL's using the webpack asset module ("asset/inline"). This is an approach I've copied from bootstrap and it works. The problem is the file size of app.jsx, as it includes numerous 1MB+ images.

Similar questions and issues I've found

The question is tied to scss processing, rather than the inclusion of images in .js files. I've read the resolve modules documentation for webpack I couldn't see a way to tie it to a solution.

This effectively copies the assets from node_modules/myNpmModule/dist/assets to your build directory, which is hacky. From what I can tell I'd need to modify myNpmModule to only ever look for assets in that destination directory which doesn't scale.

Recommends you use new URL('./image.png', import.url.meta) to import the images. That doesn't work - or at least the images aren't bundled by the webpack process for project/app.jsx

My questions

One approach I've thought of is to configure webpack to convert data URL's into files during the webpack build process. The view is that these would then be pushed to the build directory.

  1. is there a webpack loader to convert data URL's into files?
  2. is there a better approach?

Unfortunately none of these give satisfactory answers for 3rd parties that will be installing my myNpmModule.

1 Answers

If you have a webpack.config.js file, test for your static files and use the asset/inline module. This will inline all the static assets you utilise into your index.js or whatever happens to be your final build artefact.

webpack.config.js
...
...

module: {
    rules: [
        {
          test: /\.(js|jsx)$/,
          exclude: /node_modules/,
          use: ["babel-loader"],
        },
        {
          test: /\.css$/i,
          use: ["style-loader", "css-loader"],
        },
        {
          test: /\.(png|jpg|gif)$/i,
          type: "asset/inline",
        },
      ],
    },
 
...
...

Read https://stackoverflow.com/a/73417058/14358290 and https://stackoverflow.com/a/73442491/14358290 for a more in-depth answer directly related to your question.

Related