Webpack 5 Assets Module: How to keep the folder structure in the output folder?
Asked Answered
C

1

9

I try to configure Webpack 5 such it keeps the assets folder structure for my images and fonts.

I have the following structure:

- /app
    /assets
        /images
            /topic1
            /topic2
        /fonts

In my webpack config I have configured the Assets module like that:

{
    test: /\.(png|svg|jpg|jpeg|gif|xml)$/i,
    type: 'asset/resource'
}
...
same for Font files...

If I run the Webpack 5 build it copies the assets by default to my dist/ folder in a flat structure, e.g. images below the folder /topic1 are directly copied to dist/my-topic1-img.png but actually I would like to have it here: dist/assets/images/topic1/my-topic1-img.png.

How can I easily achieve this?

I have seen this doc link here: https://webpack.js.org/configuration/module/#rulegeneratorfilename. So I assume a solution could be to write some custom filename function which would set dynamically depending on the file path a new filename including the path elements for each asset.

Does Webpack 5 support such a config out-of-the-box or do I really need to write some custom function for this?

Thanks for help and inputs.

Compression answered 17/8, 2021 at 9:24 Comment(0)
B
22

You can use output.assetModuleFilename option and Template strings to do this.

assetModuleFilename can be a function. We can get the filename like app/assets/images/topic1/icons8-apple-logo-16.png from pathData.filename. Then, we remove app/ path segment.

The destination assets directory will become assets/images/topic1/icons8-apple-logo-16.png

E.g. Folder structure:

⚡  tree -L 5 -I 'node_modules'
.
├── app
│   ├── assets
│   │   └── images
│   │       ├── topic1
│   │       │   └── icons8-apple-logo-16.png
│   │       └── topic2
│   │           └── icons8-itunes-store-16.png
│   └── index.js
├── package-lock.json
├── package.json
└── webpack.config.js

5 directories, 6 files

app/index.js:

import appleLogo from "./assets/images/topic1/icons8-apple-logo-16.png";
import itunesLogo from "./assets/images/topic2/icons8-itunes-store-16.png";

console.log("appleLogo: ", appleLogo);
console.log("itunesLogo: ", itunesLogo);

webpack.config.js:

const path = require("path");

module.exports = {
  entry: "./app/index.js",
  output: {
    filename: "[name].js",
    path: path.resolve(__dirname, "dist"),
    publicPath: '',
    assetModuleFilename: (pathData) => {
      const filepath = path
        .dirname(pathData.filename)
        .split("/")
        .slice(1)
        .join("/");
      return `${filepath}/[name].[hash][ext][query]`;
    },
  },
  mode: "development",
  module: {
    rules: [
      {
        test: /\.png/,
        type: "asset/resource",
      },
    ],
  },
};

We get the output directory structure:

⚡  tree -L 5 -I 'node_modules'
.
├── app
│   ├── assets
│   │   └── images
│   │       ├── topic1
│   │       │   └── icons8-apple-logo-16.png
│   │       └── topic2
│   │           └── icons8-itunes-store-16.png
│   └── index.js
├── dist
│   ├── assets
│   │   └── images
│   │       ├── topic1
│   │       │   └── icons8-apple-logo-16.eb98638de0872628930f.png
│   │       └── topic2
│   │           └── icons8-itunes-store-16.960fdc610bcb77ab473c.png
│   └── main.js
├── package-lock.json
├── package.json
└── webpack.config.js

Logs of executing the dist/main.js:

⚡  node dist/main.js
appleLogo:  assets/images/topic1/icons8-apple-logo-16.eb98638de0872628930f.png
itunesLogo:  assets/images/topic2/icons8-itunes-store-16.960fdc610bcb77ab473c.png

webpack version:

"devDependencies": {
  "webpack": "^5.51.1",
  "webpack-cli": "^4.8.0"
}
Behlau answered 24/8, 2021 at 6:5 Comment(4)
work like a charm! saved my life. thank you!Suggestive
in my case, svg files are also copied to fonts folder for some reason, i don't want them in my dist, only the fonts. is there a way to do that?Bambibambie
> assetModuleFilename can be a function. bingo! that's what I need, was also trying to keep the folders structure in /dist. Thanks!Comfy
Been looking around for this solution, thank you! I'm having a hard time finding any documentation that describes pathData parameter, and ended up here.Idle

© 2022 - 2024 — McMap. All rights reserved.