Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Webpack 5 and webpack-subresource-integrity compatibility #10826

Closed
jscheid opened this issue May 2, 2020 · 11 comments
Closed

Webpack 5 and webpack-subresource-integrity compatibility #10826

jscheid opened this issue May 2, 2020 · 11 comments

Comments

@jscheid
Copy link
Contributor

jscheid commented May 2, 2020

Hi, our plugin works by creating a map from chunk ID to integrity value, adding that map as a constant into the JSONP template and adding code to set the integrity attribute on each injected script and link tag by looking up the chunk ID in that map.

I suppose this has always been a hack but it used to work fine up until Webpack 5 beta 9. In more recent beta versions there is the following problem from our plugin's perspective:

The code for generating script and link preload tags now lives in separate closures, which means that if we add the variable containing the map from chunk ID to integrity in one of the templates, it isn't visible from the other.

I've tried finding a workaround and there are various hacks we could do, but I think the best solution is to add a new hook that would let us inject code into the template around where var installedChunks is defined. Unless I'm missing another way of doing this cleanly, would you consider adding a hook like this?

sokra added a commit that referenced this issue Jul 2, 2020
improve compat for MainTemplate runtime hooks

fixes #10826
@sokra
Copy link
Member

sokra commented Jul 2, 2020

I'll fix that in the compat layer, so the plugin should work (with deprecation warnings) without change.

@jscheid
Copy link
Contributor Author

jscheid commented Jul 2, 2020

Thanks, but we already have a webpack-5 branch that was passing without warnings up to Webpack 5 beta 9. Ideally we could fix it properly, you don't think adding that new hook is a good solution?

@sokra
Copy link
Member

sokra commented Jul 3, 2020

To fix it properly attach all information shared between runtime modules to the __webpack_require__ object. RuntimeModule might live in different chunks, so you can't rely on they sharing a common scope.

@jscheid
Copy link
Contributor Author

jscheid commented Jul 3, 2020

Interesting, but if RuntimeModule is in a different chunk, how is that chunk loaded? I'm asking because it will also need to be loaded with SRI. Are you talking about a hypothetical future Webpack release or is this something that is possible with version 5?

@sokra
Copy link
Member

sokra commented Jul 3, 2020

This e. g. happens for HMR updates. When you add a chunk the runtime module with the chunk mapping need to be updated. So the HMR chunk would contain the updated RuntimeModule (e. g. here the JsonpChunkLoadingRuntimeModule). Technically this could happen for all RuntimeModules. When they are in the HMR chunk they won't share the scope with the original runtime chunk.

We also would like to have the option to lazy load runtime modules. This is not used yet, but would also cause non-shared scopes.

That's why you should use __webpack_require__ to communicate between runtime modules. Attach your properties there.

@sokra
Copy link
Member

sokra commented Jul 3, 2020

webpack 4 didn't have the ability to put runtime code into HMR chunks. This causes bugs if the add chunks and chunks use something else than [id], e. g. [name] or [contenthash].

@jscheid
Copy link
Contributor Author

jscheid commented Jul 3, 2020

I see, thanks for the explanation. I'm guessing attaching to __webpack_require__ is rarely done and there isn't a preferred naming/namespacing scheme? Could use a Symbol but that seems unnecessarily careful and might break compatibility.

@sokra
Copy link
Member

sokra commented Jul 3, 2020

I'm guessing attaching to __webpack_require__ is rarely done and there isn't a preferred naming/namespacing scheme?

Best use a prefix like sri for your plugin.

webpack itself often uses single letter properties, so avoid these.

Could use a Symbol but that seems unnecessarily careful and might break compatibility.

I don't think that's necessary. You would have to use a named symbol anyway, which would be global too^^

@jscheid
Copy link
Contributor Author

jscheid commented Jul 3, 2020

Oh, good point.. ha! Ok, I'm going to give that a try and let you know., can't see why it wouldn't work.

@jscheid
Copy link
Contributor Author

jscheid commented Jul 5, 2020

This works nicely! There's one minor snag: it seems we also need to hook into the LoadScriptRuntimeModule compilation hooks (the createScript hook specifically.) I can't see a way to get to it though without require('webpack/lib/runtime/LoadScriptRuntimeModule'). That file doesn't exist in earlier Webpack versions, which means we would have to make the require optional (catch the load error) or conditional (check for Webpack version first), both of which are a bit awkward. Is there another way to get to that hook, and if not, could you add one?

Alternatively, if there was a new type of hook called for every inserted script tag (and other tags that can receive SRI, i.e.link) then our code could be both more elegant and more robust as we wouldn't have to worry about implementation details like this one; plus, such a hook could be reused by other plugins that inject tags and other plugins that wish to modify injected tags. See webpack-contrib/mini-css-extract-plugin#40 and webpack-contrib/mini-css-extract-plugin#526 where we've explored this idea some more.

@sokra sokra closed this as completed in 115aa13 Jul 6, 2020
@jscheid
Copy link
Contributor Author

jscheid commented Oct 19, 2020

@sokra we're now using a hash in __webpack_require__.sriHashes that maps from chunk ID to SRI hash. As a workaround, we're extracting the chunk ID from the key:

https://github.com/waysact/webpack-subresource-integrity/blob/ed3c8cdc095cc3a5073db52f66514a89252303b6/jmtp.js#L66

I'm assuming you're not making any guarantees that the key will keep using this format, so I would like to turn this into something less brittle as soon as possible.

I suppose we could also use url, but that's coming in already resolved against the current origin; I'm not sure how to reliably turn it back into a canonical, relative URL. Also, it would be less compact, although most of the overhead would likely be gzipped away.

Could you advise, please? I believe the cleanest solution would be if chunkId could be added back.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants