webdeveric / webpack-assets-manifest

This webpack plugin will generate a JSON file that matches the original filename with the hashed version.
https://www.npmjs.com/package/webpack-assets-manifest
MIT License
321 stars 33 forks source link

Feature: Export assets with their import name as key #222

Open jgraichen opened 2 years ago

jgraichen commented 2 years ago

The problem

We would like to have assets exported with the name they were imported as, as their key in the manifest file.

Example:

import "images/logo.svg"

This image would appear as images/logo.png in the manifest, independent of the actual source file location.

{
  "images/logo.svg": {  }
}

Technical details

Currently, the source path is used as the key, which can differ from the import name. For example, if app/assets is included in resolve.modules, the image can be imported using images/logo.png, but will be exported to the manifest as app/assets/images/logo.png.

Excerpt from webpack config:

    resolve: {
      modules: ["app/assets", "node_modules"],
    }

Asset manifest:

  "app/assets/images/logo.svg": {
    "src": "581d86df2e7743f2c771.svg",
    "integrity": "sha384-JcnPQPUWAADLlNOBv9MSixuv/fv43CHqBk5QEvIHk3/AGFVsg9e2oaUcWxp02WC2"
  },

We use the assets manifest to lookup files in the server-site application, for example, to inline the compiled SVG into the HTML page.

Another scenario is compiling different branded bundles. We run webpack multiple times with a different brand variable, which is added to the lookup path:

    resolve: {
      modules: [`brand/${brand}`, "app/assets", "node_modules"],
    },

If a brand contains a customized image or CSS asset, when import "images/logo.svg", it will load either the branded image, or the default from app/assets. Unfortunately, they are differently exported in the asset manifest:

  "app/assets/images/logo.svg": {
    "src": "581d86df2e7743f2c771.svg",
    "integrity": "sha384-JcnPQPUWAADLlNOBv9MSixuv/fv43CHqBk5QEvIHk3/AGFVsg9e2oaUcWxp02WC2"
  },
  // OR
  "brand/blue/images/logo.svg": {
    "src": "d1126897fcebf4fe2477.svg",
    "integrity": "sha384-TMwMRIsJ6a/tao5Dhx8lDXydyTz7kZO5SDszYmGXA9Hl6zM4wDQV/nzupeMWZGlp"
  },

It would be wonderful if there would be an option to export an asset always with the exact string used to import it, e.g.

  "images/logo.svg": {
    "src": "581d86df2e7743f2c771.svg",
    "integrity": "sha384-JcnPQPUWAADLlNOBv9MSixuv/fv43CHqBk5QEvIHk3/AGFVsg9e2oaUcWxp02WC2"
  },
  // OR
  "images/logo.svg": {
    "src": "d1126897fcebf4fe2477.svg",
    "integrity": "sha384-TMwMRIsJ6a/tao5Dhx8lDXydyTz7kZO5SDszYmGXA9Hl6zM4wDQV/nzupeMWZGlp"
  },

The server application only needs to be configured with the branded asset manifest and can always look up images/logo.svg to load the correct image.

I've made a public example here: https://github.com/jgraichen/webpack-assets-manifest-branded

Webpack version

webpack: "5.69.1",
webpack-assets-manifest: "5.1.0",
webpack-cli: "^4.9.2"

Webpack config

https://github.com/jgraichen/webpack-assets-manifest-branded/blob/main/webpack.config.js

Operating system

Linux 5.10.0-11-amd64 #1 SMP Debian 5.10.92-1 (2022-01-18) x86_64 GNU/Linux
jgraichen commented 2 years ago

If the import name(s) can be collected somewhere while processing and be made available in the customize hook, that would be fine too.

I wasn't able to find any obvious way to get the import name with the fields and stats available in the current hook, nor in webpack 5 compiler stats.

nsunga commented 11 months ago

@jgraichen were you able to find a solution for this?

in my experience, finding anything for server side rendering image assets are a nightmare

either the package is abandoned, has low adoption, or a ton of platform overhead changes

webdeveric commented 4 months ago

@jgraichen @nsunga I've published a new version of this plugin that adds rawRequest to the asset info available during customize(). It is not currently available on all assets.

Example:

new WebpackAssetsManifest({
  customize(entry, original, manifest, asset) {
    console.log(asset.info.rawRequest);
  },
});