Copy-webpack-plugin: [Feature] Support manifest file

Created on 20 Dec 2016  Â·  20Comments  Â·  Source: webpack-contrib/copy-webpack-plugin

Why?
In some projects, I use external library (example jquery) and for the implamentation of this, I use this plugin (just copy files from another directory to other). The plugin supports the use of hash, but do not know original file path and resulting file path (include hash and other stuff). There is no manifest file :sob:

Community help wanted 5 (nice to have) Minor Feature

Most helpful comment

I do thank you a lot for the code that removes the hash (see under this text) from the file names. It works like a charm and simplifies my PHP function that includes the right asset a lot!

new ManifestPlugin({
    map: (file) => {
      if (process.env.NODE_ENV === 'production') {
        // Remove hash in manifest key
        file.name = file.name.replace(/(\.[a-f0-9]{32})(\..*)$/, '$2');
      }
      return file;
    },
  })

All 20 comments

Assuming you name your destination files [name].[hash:10].[ext], try out this plugin:

new StatsWriterPlugin({
    fields: ['assets'],
    filename: 'manifest.json',
    transform(stats) {
        const manifest = {};
        stats.assets.map(asset => asset.name)
            .sort()
            .forEach((file) => {
                manifest[file.replace(/\.[a-f0-9]{10}\./, '.')] = file;
                                               // 10 is length of hash
            });
        return JSON.stringify(manifest, null, 2) + '\n';
    }
})

Isn't that something you can work with?

The guys from webpack-manifest-plugin have included a hook in their latest RC release which other plugins can use to give before and after filenames and locations. Maybe this can be used to solve the hashing issue in a more convienient way? I am by no means capable of guessing if this can work but its merely a suggestion.

https://github.com/danethurber/webpack-manifest-plugin/pull/76

Here's a slightly modified regex that works with any length hash as long as it is inbetween two . characters, except the string .bundle. will be ignored

   new StatsWriterPlugin({
      fields  : ['assetsByChunkName', 'assets'],
      filename: 'webpack-manifest.json',
      transform: function(stats) {
         const manifest = {};
         stats.assets.map(asset => asset.name)
            .sort()
            .forEach((file) => {
               // matches anything between two dots `.` such as app.bundle.636876e2051c910a7ef8.js,
               // app.chunk.636876e2051c910a7ef8.js, app.style.636876e2051c910a7ef8.css or
               // app.636876e2051c910a7ef8.js, but don't match the `.bundle.`, `.chunk.`, or `.style.`
               let regEx = /[^.]+\.(?=[^.]+$)/gmi;
               let passTest = regEx.test(file);
               let key = file.replace(regEx, '');

               // remove any leading `/`
               regEx = /^\//gmi;
               key = key.replace(regEx, '');
               // console.log(file, passTest, key);

               manifest[key] = file;
            });

         return JSON.stringify(manifest, null, 2) + '\n';
      }
   }),

Hi,

For anyone wanting to use danethurber/webpack-manifest-plugin and be able to generate asset manifest which were copied with this plugin, here's my solution:

In webpack.config.js

const path = require('path');
const CopyPlugin = require('copy-webpack-plugin');
const ManifestPlugin = require('webpack-manifest-plugin');
...

module.exports = function (env) {
    return {
        ...
        output: {
            path: path.resolve(__dirname, 'web/dist'),
            publicPath: '/dist/',
        },
        plugins: [
            new CopyPlugin([
                {
                     context: path.join('/xxx/yyy', 'images'),
                     from: '**/*{.gif,.jpg,.jpeg,.png,.svg}',
                     to: 'images/[path][name].[ext]',
                     // to: 'production' === env.NODE_ENV ? 'images/[path][name].[hash].[ext]' : 'images/[path][name].[ext]',
                     toType: 'template',
                },
            ]),
            // Order matters, manifest plugin should be registered after copy plugin
            new ManifestPlugin({
                fileName: path.resolve(__dirname, 'var/assets/images/manifest.json'),
                publicPath: '/dist/',
                filter: (file) => file.name.startsWith('images/'),
                /*map: (file) => {
                    if ('production' === env.NODE_ENV) {
                        // Remove hash in manifest key
                        file.name = file.name.replace(/(\.[a-f0-9]{32})(\..*)$/, '$2');
                    }
                    return file;
                },*/
            }),
        ],
    };
}

__This will only work with version 2.x of danethurber/webpack-manifest-plugin currently in rc2__
See issue danethurber/webpack-manifest-plugin#75 and commit danethurber/webpack-manifest-plugin@4cb95ce41ec683078a6581949ec544f4a7d4a3d2

My example copy images from a /xxx/yyy/images to a web/dist/images folder and generate a manifest for images only in var/assets/images/manifest.json (Symfony 3 project). For using hash when copying the assets you will need a little adaption on manifest plugin, you can use the maphook to remove hash from filename (See my commented code).

I hope this will help people from this thread.

I do thank you a lot for the code that removes the hash (see under this text) from the file names. It works like a charm and simplifies my PHP function that includes the right asset a lot!

new ManifestPlugin({
    map: (file) => {
      if (process.env.NODE_ENV === 'production') {
        // Remove hash in manifest key
        file.name = file.name.replace(/(\.[a-f0-9]{32})(\..*)$/, '$2');
      }
      return file;
    },
  })

On --watch the manifest file (webpack-manifest-plugin) doesn't seem to update anything copy-webpack-plugin spits out.
This this being tracked anywhere? :(

It works fine on a fresh build, but only seems to fail on watch

@jasonwilliams Should be fix it https://github.com/danethurber/webpack-manifest-plugin/issues/141 first and when i implement support webpack-manifest-plugin by default

@evilebottnawi for more info on the issue im having i created a ticket here:
https://github.com/danethurber/webpack-manifest-plugin/issues/144

Looks like the same problem

I also have the problem when hasing filenames

Webpack: 4.19.1
copy-webpack-plugin: 4.5.2

plugins: [
        new CopyWebpackPlugin([
            { from: './src/common/manifest.json', to: '[hash].[ext]' },
            { from: './src/common/favicon.ico', to: '[hash].[ext]' },
        ]),
        new ManifestPlugin({
            fileName: 'assets-manifest.json',
            writeToFileEmit: true,
        })]

here is assets-manifest.json

...
  "83e7b321450bbcdc5013d2822838febc.json": "/83e7b321450bbcdc5013d2822838febc.json",
  "4d263d3006aa8249f115a0318f48d3b3.ico": "/4d263d3006aa8249f115a0318f48d3b3.ico",
...

instead of having original names as the key - here is hashed name in both positions: key and value

any fixes here?

@budarin problem in implementation what we need event in manifest plugin (there are not one plugin) and event are difference, we can handle all plugins events. We should add hook on event https://github.com/danethurber/webpack-manifest-plugin/blob/master/lib/plugin.js#L191 and all copied files will be in manifest

thanks for the reply

Would be great if you could release a version including this on npmjs.com

@budarin Have you fix the problem —— key and value both hashed?

@evilebottnawi I met same problem with @budarin
webpack config

plugins: [
    new CopyPlugin([{
      from: 'public/src/img',
      test: /\.(png|jpe?g|gif|svg)$/i,
      to: 'img/[name].[md5:hash:hex:8].[ext]'
    }, {
      from: 'public/src/media',
      to: 'media/'
    }]),
    extractCSS,
    new ManifestPlugin({
      fileName: 'manifest.json',
      writeToFileEmit: true,
    }),
  ]

And got manifest

  "img/1-0-logo.e9833416.svg": "img/1-0-logo.e9833416.svg",
  "img/2-0-logo.89e800b4.svg": "img/2-0-logo.89e800b4.svg",
  "img/404.bfada369.png": "img/404.bfada369.png",

Any suggestion?

What is ManifestPlugin plugin? We need implement hook for this and plugins should use this hook

What is ManifestPlugin plugin? We need implement hook for this and plugins should use this hook

Here is webpack-manifest-plugin

What is ManifestPlugin plugin? We need implement hook for this and plugins should use this hook

https://github.com/webpack-contrib/copy-webpack-plugin/issues/104#issuecomment-370390225

This works for me, thanks for your reply.

I have another hack of making copy-webpack-plugin & webpack-assets-manifest works together.

static_file_mapping = {};
config = {
  plugins: [
    new CopyPlugin([{
            from: {
                glob: 'static/**/*.@(png|svg|jpg|gif|ico)',
                dot: false,
                noext: false,
            },
            to: '[contenthash].[ext]',
            // flatten: true
            transformPath(targetPath, absosutePath) {
                relative_path = path.relative(
                    path.resolve(root_dir),
                    absosutePath)
                static_file_mapping[relative_path] = targetPath;
                return targetPath;
            }
    }]),
    new ManifestPlugin({
      assets: static_file_mapping,
    })
  ]
}

The key point is to use transformPath for exposing mapping information to outside world. Then you can write this information to anywhere you want.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

BoldBigflank picture BoldBigflank  Â·  6Comments

Jocs picture Jocs  Â·  4Comments

ietabhi picture ietabhi  Â·  5Comments

alex88 picture alex88  Â·  4Comments

stq picture stq  Â·  5Comments