jharris4 / html-webpack-tags-plugin

lets you define html tags to inject with html-webpack-plugin
MIT License
255 stars 31 forks source link

Keep [hash] included within CopyWebpackPlugin #39

Closed garyvh2 closed 5 years ago

garyvh2 commented 5 years ago

Currently I'm using copy-webpack-plugin with the following configuration

{
  from: resolve('src/app/app.settings.js'),
  to: resolve(OUTPUT_PATH, 'config/[name].[hash].[ext]'),
  flatten: true,
}

The output would include the [hash] and it would look something like app.settings.3eaa9798d11464fbfd3a9c5d412d6b67.js, but as stayed in the README

Note that since copy-webpack-plugin does not actually copy the files to webpack's output directory until after html-webpack-plugin has completed, it is necessary to use the globPath to retrieve filename matches relative to the original location of any such files.

So I was wondering if there's a way for me to glob the name like app.settings.*.js so the file can be included in the html including the [hash], if I make the globPath point at the original file, it only keeps the original name.

I appreciate any direction, even if its using a different plugin.

Regards.

jharris4 commented 5 years ago

Hi, sorry for the delayed reply. I don't personally use the [hash] for any of my webpack configs, but I'll take a quick look now to see if there's an easy change I can make to the plugin to help with your use case.

The only other plugin I know of that has similar functionality to this one is https://github.com/SimenB/add-asset-html-webpack-plugin. I don't think it will help with your use case, but you can take a look if you want.

jharris4 commented 5 years ago

Ok, I've added support for the hash option to be a function to allow for your use case, and published to npm as version 1.0.7.

The README was updated to give an example:

plugins: [
  new CopyWebpackPlugin([
    { from: 'somepath/somejsfile.js', to: 'js/somejsfile.[hash].js' },
    { from: 'somepath/somecssfile.css', to: 'css/somecssfile.[hash].css' }
  ]),
  new HtmlWebpackPlugin(),
  new HtmlWebpackIncludeAssetsPlugin({
    assets: [{ path: 'js', glob: '*.js', globPath: 'somepath' }],
    assets: [{ path: 'css', glob: '*.css', globPath: 'somepath' }],
    append: false,
    hash: function(assetName, hash) {
      assetName = assetName.replace(/\.js$/, '.' + hash + '.js');
      assetName = assetName.replace(/\.css$/, '.' + hash + '.css');
      return assetName;
    }
  })
]

and a unit test was added to show that it works:

https://github.com/jharris4/html-webpack-include-assets-plugin/blob/master/spec/index.spec.js#L1352

Please let me know whether this works for you so I can close this issue! ;-)

garyvh2 commented 5 years ago

Great I'll have a look.

Thanks for addressing my problem so quickly, I'll keep you posted.

Much appreciated.

garyvh2 commented 5 years ago

Hi again, I just checked,

but there's a problem, I believe you are using the webpack compilation hash,

But copy-webpack-plugin works differently as stayed in this issue https://github.com/webpack-contrib/copy-webpack-plugin/issues/237 by [hash] they mean a unique hash, so the hash included on the import, and the one included on the file are different.

Not sure if its possible to access the hash they place on the asset itself.

jharris4 commented 5 years ago

oh... well that's going to depend on how the unique hash is generated... If you can figure out the unique hash using the assetName then you could inject that instead of the webpack compilation hash...

I just had a quick look, and I'm not sure exactly how/where copy-webpack-plugin is generating the hash for each file, but in theory it should be pretty easy to replicate, and do something like this:

new HtmlWebpackIncludeAssetsPlugin({
    assets: [{ path: 'js', glob: '*.js', globPath: 'somepath' }],
    assets: [{ path: 'css', glob: '*.css', globPath: 'somepath' }],
    append: false,
    hash: function(assetName, hash) {
      let contentHash = generateHashForContent(fs.readFileSync(assetName, 'utf8'));
      assetName = assetName.replace(/\.js$/, '.' + hash + '.js');
      assetName = assetName.replace(/\.css$/, '.' + hash + '.css');
      return assetName;
    }
  })

Where generateHashForContent is the function copy-webpack-plugin is using to generate the hash.

Also note that the assetName passed to the hash function may not be the path to the original file, but it should give you enough info to find the original...

jharris4 commented 5 years ago

also, just a thought, can you not just remove the content hash from your assets file names (as added by copy-webpack-plugin), and instead just add the webpack hash as a query parameter to the asset urls?

so instead of:

app.settings.3eaa9798d11464fbfd3a9c5d412d6b67.js

you'd have:

app.settings.js?hash=<the_webpack_compilation_hash>

depending on your use case, this might be a much simpler way to go...

garyvh2 commented 5 years ago

Yeah, you're right, the hash param was a better idea, thanks for the suggestion and the feature addition.

jharris4 commented 5 years ago

ok, I'm glad that you seem to have found a solution to your problem. I'm closing the issue...