mpen
mpen

Reputation: 282805

Webpack all files in directory?

I'm using the assets plugin to generate a JSON file that looks like this:

{
  "all": {
    "js": "/assets/all.03c9f6c878ff0040c1a8.js",
    "css": "/assets/all.3286a6b6845c992b2bcc.css"
  },
  "login": {
    "js": "/assets/login.b6b875faa8c0e5869d82.js",
    "css": "/assets/login.6cfad06a1cc88893929b.css"
  }
}

With this I can add the appropriate <script> and <link> tags to my HTML.

Now I want to do the same for images. i.e., I want webpack to optimize all the images in a directory, generate unique hash-based filenames for each of them, and then spit out a JSON file that shows the mapping. Something like:

{
  "image1.jpg": "/assets/03c9f6c878ff0040c1a8.jpg",
  "image2.gif": "/assets/anotherhash.gif",
  "image3.svg": "/assets/hashyhashyhash.svg",
  "tinyimg.png": "data:image/png;base64,iVBORw0KGgoAAAANSUhE...zlgHe8AAAAASUVORK5CYII="
}

Is this possible with a plugin? If so, how?

Upvotes: 0

Views: 746

Answers (1)

mpen
mpen

Reputation: 282805

I managed to do it with a lot of hackery.

1. Add an entry point

entry: {
    icons: 'icons',
},

2. Create an index

Create your icons directory. Drop all your files in there. Also add this index.js to the directory:

module.exports = require.context('!!file?name=[name]-[sha1:hash:hex:10].[ext]!./', true, /\.(jpe?g|png|gif|svg)($|\?)/i);

This will force webpack to bundle all the images.

3. Use this custom plugin to create the mapping

plugins: [
    {
        apply: function(compiler) {
            //let compilerOpts = this._compiler.options;
            compiler.plugin('done', function(stats, done) {

                let icons = stats.compilation.namedChunks.icons.modules
                    .map(mod => {
                        if(!mod.assets) return [];
                        return Object.keys(mod.assets)
                            .filter(k => mod.assets[k].emitted)
                            .map(k => [path.relative('resources/assets/icons',mod.resource), mod.assets[k].existsAt])
                    })
                    .reduce((a, b) => a.concat(b))
                    .reduce((o, a) => {
                        o[a[0]] = path.relative(publicDir, a[1]).replace(/\\/g,'/');
                        return o;
                    }, {});

                fs.writeFile('icons.json', JSON.stringify(icons,null,2), done);
            });
        }
    },
],

This will spit out a file that looks like this:

{
  "1480223500_Tick_Mark_Dark.png": "assets/1480223500_Tick_Mark_Dark-0bca351fd7.png",
  "1480223511_Tick_Mark.png": "assets/1480223511_Tick_Mark-7032400d2f.png",
  "Close_Icon_Dark-128.png": "assets/Close_Icon_Dark-128-e9df07bbd6.png"
}

Upvotes: 1

Related Questions