SimenB / add-asset-html-webpack-plugin

Add a JavaScript or CSS asset to the HTML generated by html-webpack-plugin
MIT License
336 stars 42 forks source link

Hash isn't working for me #45

Closed dubcdr closed 7 years ago

dubcdr commented 7 years ago

Hello,

I'm trying to use this plugin with dllReferencePlugin. It's working and including the vendor bundle I have but its not appending the hash like it says in documentation. I believe this is a bug because like I said everything seems to be working it just isnt appending a hash to the vendor bundle.

Thanks in advance!

Here is my configuration in my main webpack config:

new webpack.DllReferencePlugin({
      context: '.',
      manifest: require('./../dll/vendor-manifest.json')
    }),

...

new AddAssetHtmlPlugin({
      filepath: require.resolve('./../dll/vendor.bundle.js'),
      hash: true
    }),

Here is the dll webpack config file

new webpack.DllPlugin({
      path: 'dll/[name]-manifest.json',
      name: '[name]_[hash]'
    })
SimenB commented 7 years ago

@dubcdr Do you have a full repro repo I could take a look at?

SimenB commented 7 years ago

@dubcdr I added a full example to the repo (https://github.com/SimenB/add-asset-html-webpack-plugin/commit/0343b92c54873e835f7d0f2678f9c5d335fd30c8), and hash works there.

<script type="text/javascript" src="vendor.dll.js?4381c3be1697639ae60e">

dubcdr commented 7 years ago

Hey @SimenB thanks, I'll check out your demo and update. Unfortunately I can't point you to the full repo.

Thanks for the quick response

dubcdr commented 7 years ago

@SimenB

I've checked out your demo and am still having the same issue. I noticed you make no mention of hash in AddAssetHtmlPlugin config. Does your plugin default to include the hash? [Note i tried both ways to no good result]

From your demo it seems that I have the same settings: in webpack.config.dll.js setting the name in plugin to '[name]_[hash]' and setting the output name to '[name].dll.js' and library to '[name]_[hash]'

output: {
  path: 'dll/',
  filename: '[name].dll.js',

  // The name of the global variable which the library's
  // require() function will be assigned to
  library: '[name]_[hash]',
},

...

new webpack.DllPlugin({
  // The path to the manifest file which maps between
  // modules included in a bundle and the internal IDs
  // within that bundle
  path: 'dll/[name]-manifest.json',
  // The name of the global variable which the library's
  // require function has been assigned to. This must match the
  // output.library option above
  name: '[name]_[hash]'
})

in my webpack.config.production.js which equates to your webpack.config.js (i'm using webpack merge for different production and dev builds)

new webpack.DllReferencePlugin({
  context: '.',
  manifest: require('./../dll/vendor-manifest.json')
}),

...

new AddAssetHtmlPlugin({
  filepath: require.resolve('./../dll/vendor.dll.js'),
  hash: true
})

Afterwards my dist folder contains:

config
-webpack.common.js
-webpack.dev.js
-webpack.dll.js
-webpack.prod.js
dist
-app.[hashValue].bundle.js {note: i use hashValue here instead of pasting the actual hash}
-app.[hashValue].bundle.map
-index.html
-stye.[hashValue].css
-vendor.dll.js {no hash, but inside javascript variable is vendor_[hashValue]}
-vendor.dll.js.map
dll
-vendor-manifest.json
-vendor.dll.js
-vendor.dll.js.map

my index.html

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <meta name="description" content="A demo of a modernized UI for HCM.">
  <title>HCM 2.0 Demo</title>
  <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
  <link href="style.e4969e975d21a54d70f4.css" rel="stylesheet">
</head>

<body flex ng-app="hcm-modern">
  <ui-view></ui-view><script src="vendor.dll.js"></script><script src="app.e4969e975d21a54d70f4.bundle.js"></script></body>

</html>
SimenB commented 7 years ago

If I clone the repo, npm install, add hash: true here: https://github.com/SimenB/add-asset-html-webpack-plugin/blob/master/example/webpack.config.js#L23 and run npm run example, I get a hash in the resulting HTML file. Does that work for you?

dubcdr commented 7 years ago

Running the example did work for me

Ok, so I don't know what I did but I am now getting the vendor.dll.js?[hashCode] in my index.html. I think initially i considered it not working because I wasn't seeing the hash in the filename. I think your method of a src parameter in index should be stated more explicitly in the readme as it's different than standard practice throughout the rest of webpack, at least from what I've seen.

Also when testing I find a new issue.

1st: I build the dll (let's call this dllV1), then I build production referencing dllV1. So now in my 2nd: I remove one of the libraries from the dll config (lets say bluebird, that was previously included) and rebuild the dll so that it has a different hash from dllV1. We'll call this dllV2. 3rd: I copy and paste the new vendor.dll.js and vendor.dll.js.map into my dist folder, overwriting dllV1 with dllV2 while still referencing dllV1 in index.html 4th: I serve my dist folder through brackets webserver (to ensure webpack dev server isn't rebuilding in any way) 5th: The website renders, even though it shouldnt be able to find the right vendor bundle.

Here's the vendor.dll.js and index.html that have different hashes but still runs.

index.html

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <meta name="description" content="A demo of a modernized UI for HCM.">
  <title>HCM 2.0 Demo</title>
  <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
  <link href="style.86bfab24f416159af0ba.css" rel="stylesheet">
</head>

<body flex ng-app="hcm-modern">
  <ui-view></ui-view><script src="vendor.dll.js?bc1f0717bbe8a376b49f"></script><script src="app.86bfab24f416159af0ba.bundle.js"></script></body>

</html>

vendor.dll.js

var vendor_c72b371b9ec48a5f00b4

Is there a reason you didn't simply append the hash to the filename?

Thanks

SimenB commented 7 years ago

The plugin doesn't touch the filename of the vendor bundle, it simply makes it available to the webpack compilation, and makes sure html-webpack-plugin knows about it. It doesn't touch the file itself.

If you want the hash to be part of the filename in disk, you have to do that when generating the dll file.

filename: '[name].dll.[hash].js', or something like that (untested).

And query params aren't actually used when looking for a file, it's just used to bust the browser cache. So it's working as intended (unless I'm missing something?)

EDIT: Although the implementation could be changed to make the hash a part of the filename instead of just a query param. Not sure how it would affect the sourcemap, though

SimenB commented 7 years ago

I think your method of a src parameter in index should be stated more explicitly in the readme

I'd love a PR clarifying the docs 😄

dubcdr commented 7 years ago

Right, I understand that the current config doesn't touch the filename, I was curious why. In the documentation for other plugins you append the hash in the filename. Here you can't do this though because if you set the hash in the filename in dll generation then you would have to reconfigure add-asset-html-webpack-plugin every time to find that specific filename.

But since you copy the dll bundle into dist based on your default config couldnt you rename that specific dist file with the hash and reference the hash in src in html file.

And i was saying in my 5step debug that I don't think it is cache busting. It seemed to me like it wasn't because if i asked for a dllV1, and only dllV2 was present in my dist folder, it would load the vendor bundle anyway.

I'm not too familiar with using this method to cache bust, again, only changing the actual file names. And from the stack overflow post I saw, it seemed the filename would need to include the hash as well. such as vendor.dll.js?{hash}, which isn't happening for me, I only see the hash value in index.html

In other words I dont understand how adding the hash as a src parameter informs the browser how to validate that hash, unless the filename itself is also changed.

once i get this working i'd be happy to submit a pr for docs. I'm going to look a little bit more on how plugins work in webpack and maybe try and look at a pr on adding hash to actual filename.

thanks again for replying so quickly and your patience.

SimenB commented 7 years ago

The cache busting in place now is to force the browser to make a new request to the server, but that hash is ignored by the server.

I think... :P I don't use dll in production, so I've never needed the hash option.

It might be more correct to just ask you to set the hash in DllPlugin, and not use the hash option here, that way webpack handles it for you, but then it's more difficult getting its path

dubcdr commented 7 years ago

Ok so after looking at it and talking with a colleague I like your cache busting technique.

I had assumed since my dll was still being served even with the wrong hash in the script tag that it was being downloaded every time. I understand now that the browser qualifies the uri as the filename and caches it that way.

I'll look to submit a pull request on the documentation.

Thanks again for helping me!