diff --git a/.travis.yml b/.travis.yml index 878c310..9ba57f9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ node_js: - 6 - 8 - 10 + - 12 addons: firefox: latest env: @@ -11,13 +12,20 @@ env: - WEBPACK_SUFFIX="@2" ETWP_SUFFIX="@2" HWP_SUFFIX="@2" - WEBPACK_SUFFIX="@3" ETWP_SUFFIX="@3" HWP_SUFFIX="@2" - WEBPACK_SUFFIX="@4" ETWP_SUFFIX="@4.0.0-alpha.0" HWP_SUFFIX="@3" - - WEBPACK_SUFFIX="@4" ETWP_SUFFIX="@4.0.0-alpha.0" HWP_SUFFIX="@4.0.0-alpha.2" + - WEBPACK_SUFFIX="@4" ETWP_SUFFIX="@4.0.0-alpha.0" HWP_SUFFIX="@4" + - WEBPACK_SUFFIX="@5" ETWP_SUFFIX="@4.0.0-alpha.0" HWP_SUFFIX="@4" matrix: exclude: - node_js: 4 env: WEBPACK_SUFFIX="@4" ETWP_SUFFIX="@4.0.0-alpha.0" HWP_SUFFIX="@3" - node_js: 4 - env: WEBPACK_SUFFIX="@4" ETWP_SUFFIX="@4.0.0-alpha.0" HWP_SUFFIX="@4.0.0-alpha.2" + env: WEBPACK_SUFFIX="@4" ETWP_SUFFIX="@4.0.0-alpha.0" HWP_SUFFIX="@4" + - node_js: 4 + env: WEBPACK_SUFFIX="@5" ETWP_SUFFIX="@4.0.0-alpha.0" HWP_SUFFIX="@4" + - node_js: 6 + env: WEBPACK_SUFFIX="@5" ETWP_SUFFIX="@4.0.0-alpha.0" HWP_SUFFIX="@4" + - node_js: 8 + env: WEBPACK_SUFFIX="@5" ETWP_SUFFIX="@4.0.0-alpha.0" HWP_SUFFIX="@4" install: - npm install || true - npm rm webpack extract-text-webpack-plugin eslint @@ -29,7 +37,6 @@ before_script: services: - xvfb script: - - ./node_modules/karma/bin/karma start --single-run --browsers Firefox - $(npm bin)/nyc $(npm bin)/mocha --exit --timeout 20000 && $(npm bin)/nyc report --reporter=text-lcov | $(npm bin)/coveralls notifications: webhooks: diff --git a/README.md b/README.md index b57debe..8d94f94 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,9 @@ manipulation. ## Features -- Optional integration with [html-webpack-plugin](https://github.com/ampedandwired/html-webpack-plugin) -- Automatic support for code splitting (integrity for lazy-loaded chunks) -- Compatible with Webpack 1.x, 2.x, 3.x and 4.x +- Optional integration with [html-webpack-plugin](https://github.com/ampedandwired/html-webpack-plugin). +- Automatic support for dynamic imports (also known as code splitting.) +- Compatible with all major Webpack versions, up to and including Webpack 5. ## Installation @@ -21,6 +21,10 @@ manipulation. npm install webpack-subresource-integrity --save-dev ``` +```shell +yarn add --dev webpack-subresource-integrity +``` + ### Webpack Configuration Example ```javascript @@ -81,9 +85,11 @@ template as follows: #### Without HtmlWebpackPlugin The correct value for the `integrity` attribute can be retrieved from -the `integrity` property of Webpack assets. However, that property is -not copied over by Webpack's `stats` module so you'll have to access -the "original" asset on the `compilation` object. For example: +the `integrity` property of Webpack assets. + +Note that with Webpack versions before 5, that property is not copied over by +Webpack's `stats` module so you'll have to access the "original" asset on the +`compilation` object. For example: ```javascript compiler.plugin("done", stats => { diff --git a/appveyor.yml b/appveyor.yml index 1a7f45c..bc55b7b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,21 +1,6 @@ # Test against this version of Node.js environment: matrix: - - nodejs_version: 4 - WEBPACK_SUFFIX: '@1' - ETWP_SUFFIX: '@1' - FL_SUFFIX: '@0' - HWP_SUFFIX: '@2' - - nodejs_version: 4 - WEBPACK_SUFFIX: '@2' - ETWP_SUFFIX: '@2' - FL_SUFFIX: '@1' - HWP_SUFFIX: '@2' - - nodejs_version: 4 - WEBPACK_SUFFIX: '@3' - ETWP_SUFFIX: '@3' - FL_SUFFIX: '@1' - HWP_SUFFIX: '@2' - nodejs_version: 6 WEBPACK_SUFFIX: '@1' ETWP_SUFFIX: '@1' @@ -40,7 +25,7 @@ environment: WEBPACK_SUFFIX: '@4' ETWP_SUFFIX: '@4.0.0-alpha.0' FL_SUFFIX: '@1' - HWP_SUFFIX: '@4.0.0-alpha.2' + HWP_SUFFIX: '@4' - nodejs_version: 8 WEBPACK_SUFFIX: '@1' ETWP_SUFFIX: '@1' @@ -65,7 +50,7 @@ environment: WEBPACK_SUFFIX: '@4' ETWP_SUFFIX: '@4.0.0-alpha.0' FL_SUFFIX: '@1' - HWP_SUFFIX: '@4.0.0-alpha.2' + HWP_SUFFIX: '@4' - nodejs_version: 10 WEBPACK_SUFFIX: '@1' ETWP_SUFFIX: '@1' @@ -90,14 +75,50 @@ environment: WEBPACK_SUFFIX: '@4' ETWP_SUFFIX: '@4.0.0-alpha.0' FL_SUFFIX: '@1' - HWP_SUFFIX: '@4.0.0-alpha.2' + HWP_SUFFIX: '@4' + - nodejs_version: 10 + WEBPACK_SUFFIX: '@5' + ETWP_SUFFIX: '@4.0.0-alpha.0' + FL_SUFFIX: '@1' + HWP_SUFFIX: '@4' + - nodejs_version: 12 + WEBPACK_SUFFIX: '@1' + ETWP_SUFFIX: '@1' + FL_SUFFIX: '@0' + HWP_SUFFIX: '@2' + - nodejs_version: 12 + WEBPACK_SUFFIX: '@2' + ETWP_SUFFIX: '@2' + FL_SUFFIX: '@1' + HWP_SUFFIX: '@2' + - nodejs_version: 12 + WEBPACK_SUFFIX: '@3' + ETWP_SUFFIX: '@3' + FL_SUFFIX: '@1' + HWP_SUFFIX: '@2' + - nodejs_version: 12 + WEBPACK_SUFFIX: '@4' + ETWP_SUFFIX: '@4.0.0-alpha.0' + FL_SUFFIX: '@1' + HWP_SUFFIX: '@3' + - nodejs_version: 12 + WEBPACK_SUFFIX: '@4' + ETWP_SUFFIX: '@4.0.0-alpha.0' + FL_SUFFIX: '@1' + HWP_SUFFIX: '@4' + - nodejs_version: 12 + WEBPACK_SUFFIX: '@5' + ETWP_SUFFIX: '@4.0.0-alpha.0' + FL_SUFFIX: '@1' + HWP_SUFFIX: '@4' # Install scripts. (runs after repo cloning) install: # Get the latest stable version of Node.js or io.js - ps: Install-Product node $env:nodejs_version # install modules - - appveyor-retry npm install --global npm@3 + - npm cache clean --force + - appveyor-retry npm install --global npm@6 - npm install || true - npm rm webpack extract-text-webpack-plugin file-loader eslint - npm install "webpack%WEBPACK_SUFFIX%" --ignore-scripts --loglevel=error || true @@ -111,7 +132,7 @@ test_script: - node --version - npm --version # run tests - - npm run mocha + - npm run test # Don't actually build. build: off diff --git a/examples/disabled/webpack.config.js b/examples/disabled/webpack.config.js index 45c0037..899d1c2 100644 --- a/examples/disabled/webpack.config.js +++ b/examples/disabled/webpack.config.js @@ -1,21 +1,9 @@ var SriPlugin = require('webpack-subresource-integrity'); -var ExtractTextPlugin = require('extract-text-webpack-plugin'); -var createExtractTextLoader = require('../utils').createExtractTextLoader; -var webpackVersion = Number( - require('webpack/package.json').version.split('.')[0] -); module.exports = { entry: './index.js', output: { filename: 'bundle.js' }, - module: - webpackVersion > 1 - ? { rules: [{ test: /\.css$/, use: createExtractTextLoader() }] } - : { loaders: [{ test: /\.css$/, loader: createExtractTextLoader() }] }, - plugins: [ - new ExtractTextPlugin('styles.css'), - new SriPlugin({ hashFuncNames: ['sha256'], enabled: false }) - ] + plugins: [new SriPlugin({ hashFuncNames: ['sha256'], enabled: false })] }; diff --git a/examples/etp-content-hash/test.js b/examples/etp-content-hash/test.js index bbd399a..43d566e 100644 --- a/examples/etp-content-hash/test.js +++ b/examples/etp-content-hash/test.js @@ -1,4 +1,12 @@ var expect = require('expect'); +var webpackVersion = Number( + require('webpack/package.json').version.split('.')[0] +); + +module.exports.skip = function skip() { + // Can't use extract-text-webpack-plugin with Webpack > 4. + return webpackVersion > 4; +}; module.exports.check = function check(stats) { expect(stats.compilation.warnings).toEqual([]); diff --git a/examples/etp-path-join/test.js b/examples/etp-path-join/test.js index bbd399a..43d566e 100644 --- a/examples/etp-path-join/test.js +++ b/examples/etp-path-join/test.js @@ -1,4 +1,12 @@ var expect = require('expect'); +var webpackVersion = Number( + require('webpack/package.json').version.split('.')[0] +); + +module.exports.skip = function skip() { + // Can't use extract-text-webpack-plugin with Webpack > 4. + return webpackVersion > 4; +}; module.exports.check = function check(stats) { expect(stats.compilation.warnings).toEqual([]); diff --git a/examples/hwp-custom-template/test.js b/examples/hwp-custom-template/test.js index df068a9..90f9f14 100644 --- a/examples/hwp-custom-template/test.js +++ b/examples/hwp-custom-template/test.js @@ -2,6 +2,14 @@ var select = require('soupselect').select; var expect = require('expect'); var htmlparser = require('htmlparser'); var fs = require('fs'); +var webpackVersion = Number( + require('webpack/package.json').version.split('.')[0] +); + +module.exports.skip = function skip() { + // Can't use extract-text-webpack-plugin with Webpack > 4. + return webpackVersion > 4; +}; module.exports.check = function check(stats) { var jsIntegrity; diff --git a/examples/hwp-integrity-attributes/test.js b/examples/hwp-integrity-attributes/test.js index c915cef..1c980ea 100644 --- a/examples/hwp-integrity-attributes/test.js +++ b/examples/hwp-integrity-attributes/test.js @@ -2,6 +2,14 @@ var select = require('soupselect').select; var expect = require('expect'); var htmlparser = require('htmlparser'); var fs = require('fs'); +var webpackVersion = Number( + require('webpack/package.json').version.split('.')[0] +); + +module.exports.skip = function skip() { + // Can't use extract-text-webpack-plugin with Webpack > 4. + return webpackVersion > 4; +}; module.exports.check = function check(stats) { var jsIntegrity; diff --git a/examples/hwp-output-parent-dir/test.js b/examples/hwp-output-parent-dir/test.js index 80e6d55..d28e897 100644 --- a/examples/hwp-output-parent-dir/test.js +++ b/examples/hwp-output-parent-dir/test.js @@ -7,7 +7,10 @@ module.exports.check = function check(stats) { var jsIntegrity; expect(stats.compilation.warnings).toEqual([]); - jsIntegrity = stats.compilation.assets['bundle.js'].integrity; + + jsIntegrity = + stats.toJson().assets.find(asset => asset.name === 'bundle.js').integrity || + stats.compilation.assets['bundle.js'].integrity; expect(jsIntegrity).toMatch(/^sha/); return new Promise((resolve, reject) => { diff --git a/examples/hwp-public-path/test.js b/examples/hwp-public-path/test.js index 17b6eb9..dec2f23 100644 --- a/examples/hwp-public-path/test.js +++ b/examples/hwp-public-path/test.js @@ -7,7 +7,9 @@ module.exports.check = function check(stats) { var jsIntegrity; expect(stats.compilation.warnings).toEqual([]); - jsIntegrity = stats.compilation.assets['bundle.js'].integrity; + jsIntegrity = + stats.toJson().assets.find(asset => asset.name === 'bundle.js').integrity || + stats.compilation.assets['bundle.js'].integrity; expect(jsIntegrity).toMatch(/^sha/); return new Promise((resolve, reject) => { diff --git a/examples/hwp-subdirectories/test.js b/examples/hwp-subdirectories/test.js index f100937..acf4112 100644 --- a/examples/hwp-subdirectories/test.js +++ b/examples/hwp-subdirectories/test.js @@ -4,7 +4,9 @@ var htmlparser = require('htmlparser'); var fs = require('fs'); module.exports.check = function check(stats) { - var jsIntegrity = stats.compilation.assets['subdir/bundle.js'].integrity; + var jsIntegrity = + stats.toJson().assets.find(asset => asset.name === 'subdir/bundle.js') + .integrity || stats.compilation.assets['subdir/bundle.js'].integrity; expect(jsIntegrity).toMatch(/^sha/); return new Promise((resolve, reject) => { diff --git a/examples/mini-css-extract-plugin/test.js b/examples/mini-css-extract-plugin/test.js index 1a5fdd3..3751289 100644 --- a/examples/mini-css-extract-plugin/test.js +++ b/examples/mini-css-extract-plugin/test.js @@ -4,5 +4,5 @@ var webpackVersion = Number( module.exports.skip = function skip() { // mini-css-extract-plugin needs Webpack 4 - return webpackVersion < 4; + return webpackVersion !== 4; }; diff --git a/examples/no-error-invalid-config/test.js b/examples/no-error-invalid-config/test.js index e450ee5..94c8df1 100644 --- a/examples/no-error-invalid-config/test.js +++ b/examples/no-error-invalid-config/test.js @@ -1,5 +1,13 @@ var expect = require('expect'); var ChunkRenderError = require('webpack/lib/ChunkRenderError'); +var webpackVersion = Number( + require('webpack/package.json').version.split('.')[0] +); + +module.exports.skip = function skip() { + // Error doesn't get triggered with Webpack > 4. + return webpackVersion > 4; +}; module.exports.ignoreErrors = true; diff --git a/examples/no-error-invalid-config/webpack.config.js b/examples/no-error-invalid-config/webpack.config.js index 5a63543..9416156 100644 --- a/examples/no-error-invalid-config/webpack.config.js +++ b/examples/no-error-invalid-config/webpack.config.js @@ -1,5 +1,4 @@ var SriPlugin = require('webpack-subresource-integrity'); -var HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './index.js', diff --git a/examples/sourcemap-code-splitting/test.js b/examples/sourcemap-code-splitting/test.js index 698ba06..5b2ac25 100644 --- a/examples/sourcemap-code-splitting/test.js +++ b/examples/sourcemap-code-splitting/test.js @@ -17,6 +17,6 @@ module.exports.check = function check() { } var sriHashesInSource = findAndStripSriHashString('dist/index.js', 'sha256-', -10); - var sriHashesInMap = findAndStripSriHashString('dist/index.js.map', 'var sriHashes = '); + var sriHashesInMap = findAndStripSriHashString('dist/index.js.map', '__webpack_require__.sriHashes = '); expect(sriHashesInSource.length).toEqual(sriHashesInMap.length); }; diff --git a/index.js b/index.js index e85f09c..99517ba 100644 --- a/index.js +++ b/index.js @@ -7,7 +7,9 @@ var crypto = require('crypto'); var path = require('path'); -var ReplaceSource = require('webpack-sources/lib/ReplaceSource'); +var webpack = require('webpack'); +// eslint-disable-next-line global-require +var ReplaceSource = (webpack.sources || require('webpack-sources')).ReplaceSource; var util = require('./util'); var WebIntegrityJsonpMainTemplatePlugin = require('./jmtp'); var HtmlWebpackPlugin; @@ -41,6 +43,8 @@ function SubresourceIntegrityPlugin(options) { Object.assign(this.options, useOptions); this.emittedMessages = {}; + + this.assetIntegrity = new Map(); } SubresourceIntegrityPlugin.prototype.emitMessage = function emitMessage(messages, message) { @@ -203,29 +207,28 @@ SubresourceIntegrityPlugin.prototype.processChunk = function processChunk( Array.from(util.findChunks(chunk)).reverse().forEach(childChunk => { var sourcePath; + var files = Array.isArray(childChunk.files) ? new Set(childChunk.files) : childChunk.files; // This can happen with invalid Webpack configurations - if (childChunk.files.length === 0) return; + if (files.size === 0) return; sourcePath = compilation.sriChunkAssets[childChunk.id]; - if (childChunk.files.indexOf(sourcePath) < 0) { + if (!files.has(sourcePath)) { self.warnOnce( compilation, 'Cannot determine asset for chunk ' + childChunk.id + ', computed="' + sourcePath + - '", available=' + childChunk.files[0] + '. Please report this full error message ' + + '", available=' + Array.from(childChunk.files)[0] + '. Please report this full error message ' + 'along with your Webpack configuration at ' + 'https://github.com/waysact/webpack-subresource-integrity/issues/new' ); - sourcePath = childChunk.files[0]; + sourcePath = Array.from(files)[0]; } self.warnIfHotUpdate(compilation, assets[sourcePath].source()); - newAsset = self.replaceAsset( - assets, - hashByChunkId, - sourcePath); + newAsset = self.replaceAsset(assets, hashByChunkId, sourcePath); hashByChunkId.set(childChunk.id, newAsset.integrity); + this.assetIntegrity.set(sourcePath, newAsset.integrity); }); }; @@ -237,6 +240,16 @@ SubresourceIntegrityPlugin.prototype.chunkAsset = } }; +SubresourceIntegrityPlugin.prototype.statsFactory = + function stats(compilation, statsFactory) { + statsFactory.hooks.extract.for("asset").tap('SriPlugin', (object, asset) => { + if (this.assetIntegrity.has(asset.name)) { + // eslint-disable-next-line no-param-reassign + object.integrity = String(this.assetIntegrity.get(asset.name)); + } + }); + }; + SubresourceIntegrityPlugin.prototype.addMissingIntegrityHashes = function addMissingIntegrityHashes(assets) { var self = this; @@ -256,7 +269,7 @@ SubresourceIntegrityPlugin.prototype.afterOptimizeAssets = function afterOptimizeAssets(compilation, assets) { var self = this; - compilation.chunks.filter(util.isRuntimeChunk).forEach(function forEachChunk(chunk) { + Array.from(compilation.chunks).filter(util.isRuntimeChunk).forEach(function forEachChunk(chunk) { self.processChunk(chunk, compilation, assets); }); @@ -343,40 +356,77 @@ SubresourceIntegrityPlugin.prototype.registerHwpHooks = } }; -SubresourceIntegrityPlugin.prototype.thisCompilation = - function thisCompilation(compiler, compilation) { - var afterOptimizeAssets = this.afterOptimizeAssets.bind(this, compilation); - var beforeChunkAssets = this.beforeChunkAssets.bind(this, compilation); - var alterAssetTags = this.alterAssetTags.bind(this, compilation); - var beforeHtmlGeneration = this.beforeHtmlGeneration.bind(this, compilation); +SubresourceIntegrityPlugin.prototype.thisCompilation = function thisCompilation( + compiler, + compilation +) { + this.validateOptions(compilation); - this.validateOptions(compilation); + if (!this.options.enabled) { + return; + } - if (!this.options.enabled) { - return; - } + this.registerJMTP(compilation); - this.registerJMTP(compilation); + // FIXME: refactor into separate per-compilation state + // eslint-disable-next-line no-param-reassign + compilation.sriChunkAssets = {}; - // FIXME: refactor into separate per-compilation state - // eslint-disable-next-line no-param-reassign - compilation.sriChunkAssets = {}; + /* + * html-webpack support: + * Modify the asset tags before webpack injects them for anything with an integrity value. + */ + if (compiler.hooks) { + this.setupHooks(compiler, compilation); + } else { + this.setupLegacyHooks(compiler, compilation); + } +}; - /* - * html-webpack support: - * Modify the asset tags before webpack injects them for anything with an integrity value. - */ - if (compiler.hooks) { - compilation.hooks.afterOptimizeAssets.tap('SriPlugin', afterOptimizeAssets); - compilation.hooks.beforeChunkAssets.tap('SriPlugin', beforeChunkAssets); - compiler.hooks.compilation.tap('HtmlWebpackPluginHooks', this.registerHwpHooks.bind(this, alterAssetTags, beforeHtmlGeneration)); - } else { - compilation.plugin('after-optimize-assets', afterOptimizeAssets); - compilation.plugin('before-chunk-assets', beforeChunkAssets); - compilation.plugin('html-webpack-plugin-alter-asset-tags', alterAssetTags); - compilation.plugin('html-webpack-plugin-before-html-generation', beforeHtmlGeneration); - } - }; +SubresourceIntegrityPlugin.prototype.setupHooks = function setupHooks( + compiler, + compilation +) { + var afterOptimizeAssets = this.afterOptimizeAssets.bind(this, compilation); + var beforeChunkAssets = this.beforeChunkAssets.bind(this, compilation); + var alterAssetTags = this.alterAssetTags.bind(this, compilation); + var beforeHtmlGeneration = this.beforeHtmlGeneration.bind(this, compilation); + + if (compilation.hooks.processAssets) { + compilation.hooks.processAssets.tap( + { + name: 'SriPlugin', + stage: webpack.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_HASH + }, + afterOptimizeAssets + ); + } else { + compilation.hooks.afterOptimizeAssets.tap('SriPlugin', afterOptimizeAssets); + } + compilation.hooks.beforeChunkAssets.tap('SriPlugin', beforeChunkAssets); + compiler.hooks.compilation.tap( + 'HtmlWebpackPluginHooks', + this.registerHwpHooks.bind(this, alterAssetTags, beforeHtmlGeneration) + ); +}; + +SubresourceIntegrityPlugin.prototype.setupLegacyHooks = function setupLegacyHooks( + compiler, + compilation +) { + var afterOptimizeAssets = this.afterOptimizeAssets.bind(this, compilation); + var beforeChunkAssets = this.beforeChunkAssets.bind(this, compilation); + var alterAssetTags = this.alterAssetTags.bind(this, compilation); + var beforeHtmlGeneration = this.beforeHtmlGeneration.bind(this, compilation); + + compilation.plugin('after-optimize-assets', afterOptimizeAssets); + compilation.plugin('before-chunk-assets', beforeChunkAssets); + compilation.plugin('html-webpack-plugin-alter-asset-tags', alterAssetTags); + compilation.plugin( + 'html-webpack-plugin-before-html-generation', + beforeHtmlGeneration + ); +}; SubresourceIntegrityPlugin.prototype.beforeChunkAssets = function afterPlugins(compilation) { var chunkAsset = this.chunkAsset.bind(this, compilation); @@ -390,6 +440,13 @@ SubresourceIntegrityPlugin.prototype.beforeChunkAssets = function afterPlugins(c SubresourceIntegrityPlugin.prototype.afterPlugins = function afterPlugins(compiler) { if (compiler.hooks) { compiler.hooks.thisCompilation.tap('SriPlugin', this.thisCompilation.bind(this, compiler)); + + compiler.hooks.compilation.tap("DefaultStatsFactoryPlugin", compilation => { + if (compilation.hooks.statsFactory) { + compilation.hooks.statsFactory.tap('SriPlugin', this.statsFactory.bind(this, compilation)); + } + }); + } else { compiler.plugin('this-compilation', this.thisCompilation.bind(this, compiler)); } diff --git a/jmtp.js b/jmtp.js index 3da48b7..79c99c8 100644 --- a/jmtp.js +++ b/jmtp.js @@ -19,10 +19,10 @@ WebIntegrityJsonpMainTemplatePlugin.prototype.addSriHashes = var includedChunks = chunk.getChunkMaps().hash; var hashFuncNames = this.sriPlugin.options.hashFuncNames; - if (allChunks.size > 0) { + if (Object.keys(includedChunks).length > 0) { return (Template.asString || mainTemplate.asString)([ source, - 'var sriHashes = ' + + '__webpack_require__.sriHashes = ' + JSON.stringify( Array.from(allChunks).reduce(function chunkIdReducer( sriHashes, @@ -47,8 +47,9 @@ WebIntegrityJsonpMainTemplatePlugin.prototype.addSriHashes = * Patch jsonp-script code to add the integrity attribute. */ WebIntegrityJsonpMainTemplatePlugin.prototype.addAttribute = - function addAttribute(mainTemplate, elName, source) { - if (!mainTemplate.outputOptions.crossOriginLoading) { + function addAttribute(mainTemplate, elName, source, chunk) { + const outputOptions = this.compilation.outputOptions || mainTemplate.outputOptions; + if (!outputOptions.crossOriginLoading) { this.sriPlugin.errorOnce( this.compilation, 'webpack option output.crossOriginLoading not set, code splitting will not work!' @@ -56,8 +57,8 @@ WebIntegrityJsonpMainTemplatePlugin.prototype.addAttribute = } return (Template.asString || mainTemplate.asString)([ source, - elName + '.integrity = sriHashes[chunkId];', - elName + '.crossOrigin = ' + JSON.stringify(mainTemplate.outputOptions.crossOriginLoading) + ';', + elName + '.integrity = __webpack_require__.sriHashes[' + (chunk ? `'${chunk.id}'` : 'chunkId') + '];', + elName + '.crossOrigin = ' + JSON.stringify(outputOptions.crossOriginLoading) + ';', ]); }; @@ -68,18 +69,21 @@ WebIntegrityJsonpMainTemplatePlugin.prototype.apply = function apply( var linkPreloadPlugin = this.addAttribute.bind(this, mainTemplate, "link"); var addSriHashes = this.addSriHashes.bind(this, mainTemplate); - if (!mainTemplate.hooks) { - mainTemplate.plugin('jsonp-script', jsonpScriptPlugin); - 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 { + if (this.compilation.compiler.options.target !== 'web') { this.sriPlugin.warnOnce( this.compilation, 'This plugin is not useful for non-web targets.' ); + return; + } + + if (mainTemplate.hooks) { + mainTemplate.hooks.jsonpScript.tap('SriPlugin', jsonpScriptPlugin); + mainTemplate.hooks.linkPreload.tap('SriPlugin', linkPreloadPlugin); + mainTemplate.hooks.localVars.tap('SriPlugin', addSriHashes); + } else { + mainTemplate.plugin('jsonp-script', jsonpScriptPlugin); + mainTemplate.plugin('local-vars', addSriHashes); } }; diff --git a/package.json b/package.json index 7600d5e..0ba6065 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "webpack-subresource-integrity", - "version": "1.4.1", + "version": "1.5.0", "description": "Webpack plugin for enabling Subresource Integrity", "engines": { "node": ">=4" @@ -9,8 +9,8 @@ "scripts": { "codeclimate": "docker run --interactive --tty --rm --env CODECLIMATE_CODE=\"$PWD\" --volume \"$PWD\":/code --volume /var/run/docker.sock:/var/run/docker.sock --volume /tmp/cc:/tmp/cc codeclimate/codeclimate", "coverage": "nyc $(npm bin)/mocha --exit --timeout 20000", - "test": "karma start --single-run && mocha --exit --timeout 20000", - "mocha": "mocha --exit --timeout 20000", + "karma": "karma start --single-run", + "test": "mocha --exit --timeout 20000", "lint": "eslint .", "prettier": "prettier --write '**/*.js'" }, @@ -76,8 +76,8 @@ "webpack-fix-style-only-entries": "^0.4.0" }, "peerDependencies": { - "html-webpack-plugin": "^2.21.0 || ~3 || >=4.0.0-alpha.2 <5", - "webpack": "^1.12.11 || ~2 || ~3 || ~4" + "html-webpack-plugin": ">= 2.21.0 < 5", + "webpack": ">= 1.12.11 < 6" }, "peerDependenciesMeta": { "html-webpack-plugin": { @@ -93,7 +93,12 @@ "jmtp.js" ], "nyc": { - "exclude": ["coverage/**", "test/**", "examples/**", "**/node_modules/**"] + "exclude": [ + "coverage/**", + "test/**", + "examples/**", + "**/node_modules/**" + ] }, "prettier": { "singleQuote": true