diff --git a/README.md b/README.md
index 9916cf2..2ca0a22 100644
--- a/README.md
+++ b/README.md
@@ -155,11 +155,13 @@ Webpack >= 4).
### Preloading
-`` doesn't work as expected in current Chrome versions, even
-if the integrity attribute is added to the `link tag (which the current version
-of webpack-subresource-integrity does _not_ do.) The resource will be loaded
-twice, defeating the purpose of preloading. This issue doesn't appear to exist
-in Firefox or Safari. See issue #111 for more information.
+This plugin adds the integrity attribute to ``
+tags, but preloading with SRI doesn't work as expected in current
+Chrome versions. The resource will be loaded twice, defeating the
+purpose of preloading. This problem doesn't appear to exist in
+Firefox or Safari. See [issue
+#111](https://github.com/waysact/webpack-subresource-integrity/issues/111)
+for more information.
### Proxies
diff --git a/examples/webpack-preload/README.md b/examples/webpack-preload/README.md
new file mode 100644
index 0000000..4f18dd9
--- /dev/null
+++ b/examples/webpack-preload/README.md
@@ -0,0 +1,3 @@
+# With `/* webpackPreload: "true" */`
+
+https://github.com/waysact/webpack-subresource-integrity/issues/111
diff --git a/examples/webpack-preload/index.js b/examples/webpack-preload/index.js
new file mode 100644
index 0000000..97f0403
--- /dev/null
+++ b/examples/webpack-preload/index.js
@@ -0,0 +1 @@
+import('./lazy-chunk-1.js');
diff --git a/examples/webpack-preload/lazy-chunk-1.js b/examples/webpack-preload/lazy-chunk-1.js
new file mode 100644
index 0000000..4f767a1
--- /dev/null
+++ b/examples/webpack-preload/lazy-chunk-1.js
@@ -0,0 +1,5 @@
+setTimeout(() => {
+ import(/* webpackPreload: true */ './lazy-chunk-2.js').then(mod =>
+ mod.test()
+ );
+}, 750);
diff --git a/examples/webpack-preload/lazy-chunk-2.js b/examples/webpack-preload/lazy-chunk-2.js
new file mode 100644
index 0000000..261c726
--- /dev/null
+++ b/examples/webpack-preload/lazy-chunk-2.js
@@ -0,0 +1,16 @@
+module.exports.test = () => {
+ const linkTag = Array.from(document.getElementsByTagName('link')).find(
+ el => el.rel === 'preload'
+ );
+ const scriptTag = Array.from(document.getElementsByTagName('script')).find(
+ el => linkTag && el.src === linkTag.href
+ );
+ console.log(
+ scriptTag &&
+ linkTag &&
+ scriptTag.integrity &&
+ scriptTag.integrity === linkTag.integrity
+ ? 'ok'
+ : 'error'
+ );
+};
diff --git a/examples/webpack-preload/test.js b/examples/webpack-preload/test.js
new file mode 100644
index 0000000..fa9fadc
--- /dev/null
+++ b/examples/webpack-preload/test.js
@@ -0,0 +1,8 @@
+var webpackVersion = Number(
+ require('webpack/package.json').version.split('.')[0]
+);
+
+module.exports.skip = function skip() {
+ // webpack-preload tag requires Webpack 4
+ return webpackVersion < 4;
+};
diff --git a/examples/webpack-preload/webpack.config.js b/examples/webpack-preload/webpack.config.js
new file mode 100644
index 0000000..51b9b7a
--- /dev/null
+++ b/examples/webpack-preload/webpack.config.js
@@ -0,0 +1,18 @@
+var SriPlugin = require('webpack-subresource-integrity');
+var HtmlWebpackPlugin = require('html-webpack-plugin');
+
+module.exports = {
+ entry: {
+ index: './index.js'
+ },
+ output: {
+ crossOriginLoading: 'anonymous'
+ },
+ plugins: [
+ new SriPlugin({
+ hashFuncNames: ['sha256', 'sha384'],
+ enabled: true
+ }),
+ new HtmlWebpackPlugin()
+ ]
+};
diff --git a/jmtp.js b/jmtp.js
index 55e3015..1808f94 100644
--- a/jmtp.js
+++ b/jmtp.js
@@ -43,6 +43,24 @@ WebIntegrityJsonpMainTemplatePlugin.prototype.addSriHashes =
return source;
};
+/*
+ * Patch jsonp-script code to add the integrity attribute.
+ */
+WebIntegrityJsonpMainTemplatePlugin.prototype.linkPreloadPlugin =
+ function linkPreloadPlugin(mainTemplate, source) {
+ if (!mainTemplate.outputOptions.crossOriginLoading) {
+ this.sriPlugin.errorOnce(
+ this.compilation,
+ 'webpack option output.crossOriginLoading not set, code splitting will not work!'
+ );
+ }
+ return (Template.asString || mainTemplate.asString)([
+ source,
+ 'link.integrity = sriHashes[chunkId];',
+ 'link.crossOrigin = ' + JSON.stringify(mainTemplate.outputOptions.crossOriginLoading) + ';',
+ ]);
+ };
+
/*
* Patch jsonp-script code to add the integrity attribute.
*/
@@ -65,6 +83,7 @@ WebIntegrityJsonpMainTemplatePlugin.prototype.apply = function apply(
mainTemplate
) {
var jsonpScriptPlugin = this.jsonpScriptPlugin.bind(this, mainTemplate);
+ var linkPreloadPlugin = this.linkPreloadPlugin.bind(this, mainTemplate);
var addSriHashes = this.addSriHashes.bind(this, mainTemplate);
if (!mainTemplate.hooks) {
@@ -72,6 +91,7 @@ WebIntegrityJsonpMainTemplatePlugin.prototype.apply = function apply(
mainTemplate.plugin('local-vars', addSriHashes);
} else if (mainTemplate.hooks.jsonpScript && mainTemplate.hooks.localVars) {
mainTemplate.hooks.jsonpScript.tap('SriPlugin', jsonpScriptPlugin);
+ mainTemplate.hooks.linkPreload.tap('SriPlugin', linkPreloadPlugin);
mainTemplate.hooks.localVars.tap('SriPlugin', addSriHashes);
} else {
this.sriPlugin.warnOnce(