Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/WebpackConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ class WebpackConfig {
this.configuredFilenames = {};
this.aliases = {};
this.externals = [];
this.useIntegrity = false;
this.integrityAlgorithms = [];
this.shouldUseSingleRuntimeChunk = null;
this.shouldSplitEntryChunks = false;
Expand Down Expand Up @@ -1067,6 +1068,7 @@ class WebpackConfig {
}
}

this.useIntegrity = enabled;
this.integrityAlgorithms = enabled ? algorithms : [];
}

Expand Down
35 changes: 33 additions & 2 deletions lib/config-generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,8 @@
// will use the CDN path (if one is available) so that split
// chunks load internally through the CDN.
publicPath: this.webpackConfig.getRealPublicPath(),
pathinfo: !this.webpackConfig.isProduction()
pathinfo: !this.webpackConfig.isProduction(),
crossOriginLoading: this.webpackConfig.useIntegrity ? 'anonymous' : false,
};
}

Expand All @@ -274,7 +275,33 @@
return false;
}

return applyOptionsCallback(this.webpackConfig.cleanOptionsCallback, {});
const cleanConfig = applyOptionsCallback(this.webpackConfig.cleanOptionsCallback, {});

// TODO: add tests for this
const cleanConfigKeep = cleanConfig.keep;
if (cleanConfigKeep) {
cleanConfig.keep = function (asset) {

Check failure on line 283 in lib/config-generator.js

View workflow job for this annotation

GitHub Actions / ESLint

Unexpected space before function parentheses
// We always want to keep the entrypoints.json file, as it's used by the Webpack Encore Bundle.
if (asset === 'entrypoints.json') {
return true;
}

if (typeof cleanConfigKeep === 'function') {
return cleanConfigKeep(asset);
} else if (typeof cleanConfigKeep === 'string') {
return asset === cleanConfigKeep;
} else if (cleanConfigKeep instanceof RegExp) {
return cleanConfigKeep.test(asset);
}

return false;
}

Check failure on line 298 in lib/config-generator.js

View workflow job for this annotation

GitHub Actions / ESLint

Missing semicolon
} else {
// We always want to keep the entrypoints.json file, as it's used by the Webpack Encore Bundle.
cleanConfig.keep = 'entrypoints.json';
}

return cleanConfig;
}

buildRulesConfig() {
Expand Down Expand Up @@ -558,6 +585,10 @@
splitChunks
);

if (this.webpackConfig.useIntegrity > 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why > 0 while it is a boolean ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bad search/replace, before introducing webpackConfig.useIntegrity, I've used webpackConfig.integrityAlgorithms.length > 0 to check if integrity was enabled.

optimization.realContentHash = true;
}

return optimization;
}

Expand Down
7 changes: 7 additions & 0 deletions lib/features.js
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,13 @@ const features = {
],
description: 'run the Webpack development server'
},
integrity: {
method: 'enableIntegrityHashes()',
packages: [
{ name: 'webpack-subresource-integrity', enforce_version: true }
],
description: 'enable Subresource Integrity hashes'
},
};

function getFeatureConfig(featureName) {
Expand Down
85 changes: 19 additions & 66 deletions lib/plugins/entry-files-manifest.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,90 +14,43 @@
*/

const PluginPriorities = require('./plugin-priorities');
const copyEntryTmpName = require('../utils/copyEntryTmpName');

Check failure on line 17 in lib/plugins/entry-files-manifest.js

View workflow job for this annotation

GitHub Actions / ESLint

'copyEntryTmpName' is assigned a value but never used
const AssetsPlugin = require('assets-webpack-plugin');
const fs = require('fs');

Check failure on line 19 in lib/plugins/entry-files-manifest.js

View workflow job for this annotation

GitHub Actions / ESLint

'fs' is assigned a value but never used
const path = require('path');

Check failure on line 20 in lib/plugins/entry-files-manifest.js

View workflow job for this annotation

GitHub Actions / ESLint

'path' is assigned a value but never used
const crypto = require('crypto');

function processOutput(webpackConfig) {
return (assets) => {
// Remove temporary entry added by the copyFiles feature
delete assets[copyEntryTmpName];

// with --watch or dev-server, subsequent calls will include
// the original assets (so, assets.entrypoints) + the new
// assets (which will have their original structure). We
// delete the entrypoints key, and then process the new assets
// like normal below. The same reasoning applies to the
// integrity key.
delete assets.entrypoints;
delete assets.integrity;

// This will iterate over all the entry points and convert the
// one file entries into an array of one entry since that was how the entry point file was before this change.
const integrity = {};
const integrityAlgorithms = webpackConfig.integrityAlgorithms;
const publicPath = webpackConfig.getRealPublicPath();

for (const asset in assets) {
for (const fileType in assets[asset]) {
if (!Array.isArray(assets[asset][fileType])) {
assets[asset][fileType] = [assets[asset][fileType]];
}

if (integrityAlgorithms.length) {
for (const file of assets[asset][fileType]) {
if (file in integrity) {
continue;
}

const filePath = path.resolve(
webpackConfig.outputPath,
file.replace(publicPath, '')
);

if (fs.existsSync(filePath)) {
const fileHashes = [];

for (const algorithm of webpackConfig.integrityAlgorithms) {
const hash = crypto.createHash(algorithm);
const fileContent = fs.readFileSync(filePath, 'utf8');
hash.update(fileContent, 'utf8');

fileHashes.push(`${algorithm}-${hash.digest('base64')}`);
}

integrity[file] = fileHashes.join(' ');
}
}
}
}
}

const manifestContent = { entrypoints: assets };
if (integrityAlgorithms.length) {
manifestContent.integrity = integrity;
}

return JSON.stringify(manifestContent, null, 2);
};
}
const featuresHelper = require("../features");

Check failure on line 21 in lib/plugins/entry-files-manifest.js

View workflow job for this annotation

GitHub Actions / ESLint

Strings must use singlequote

/**
* @param {Array} plugins
* @param {WebpackConfig} webpackConfig
* @returns {void}
*/
module.exports = function(plugins, webpackConfig) {
if (webpackConfig.useIntegrity) {
featuresHelper.ensurePackagesExistAndAreCorrectVersion('integrity')

Check failure on line 30 in lib/plugins/entry-files-manifest.js

View workflow job for this annotation

GitHub Actions / ESLint

Missing semicolon
}

plugins.push({
plugin: new AssetsPlugin({
path: webpackConfig.outputPath,
filename: 'entrypoints.json',
includeAllFileTypes: true,
entrypoints: true,
processOutput: processOutput(webpackConfig)
integrity: webpackConfig.useIntegrity,
prettyPrint: true,
}),
priority: PluginPriorities.AssetsPlugin
});

if (webpackConfig.useIntegrity) {
const {SubresourceIntegrityPlugin} = require('webpack-subresource-integrity');

Check failure on line 46 in lib/plugins/entry-files-manifest.js

View workflow job for this annotation

GitHub Actions / ESLint

A space is required after '{'

Check failure on line 46 in lib/plugins/entry-files-manifest.js

View workflow job for this annotation

GitHub Actions / ESLint

A space is required before '}'

Check failure on line 46 in lib/plugins/entry-files-manifest.js

View workflow job for this annotation

GitHub Actions / ESLint

"webpack-subresource-integrity" is not published

plugins.push({
plugin: new SubresourceIntegrityPlugin({
hashFuncNames: webpackConfig.integrityAlgorithms,
enabled: true,
}),
priority: PluginPriorities.SubresourceIntegrityPlugin
});
}
};
1 change: 1 addition & 0 deletions lib/plugins/plugin-priorities.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ module.exports = {
AssetOutputDisplayPlugin: 30,
ForkTsCheckerWebpackPlugin: 10,
AssetsPlugin: -10,
SubresourceIntegrityPlugin: -20,
};
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"homepage": "https://github.com/symfony/webpack-encore",
"dependencies": {
"@nuxt/friendly-errors-webpack-plugin": "^2.5.1",
"assets-webpack-plugin": "7.0.*",
"assets-webpack-plugin": "^7.1.1",
"babel-loader": "^9.1.3",
"css-loader": "^6.7.0",
"css-minimizer-webpack-plugin": "^7.0.0",
Expand Down Expand Up @@ -97,7 +97,8 @@
"webpack": "^5.72",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^5.0.4",
"webpack-notifier": "^1.15.0"
"webpack-notifier": "^1.15.0",
"webpack-subresource-integrity": "^5.1.0"
},
"peerDependencies": {
"@babel/core": "^7.17.0",
Expand Down Expand Up @@ -216,6 +217,9 @@
},
"webpack-notifier": {
"optional": true
},
"webpack-subresource-integrity": {
"optional": true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

listing it here without putting it in peerDependencies does not make sense.

}
},
"files": [
Expand Down
22 changes: 17 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2091,14 +2091,14 @@ assertion-error@^1.1.0:
resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b"
integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==

assets-webpack-plugin@7.0.*:
version "7.0.0"
resolved "https://registry.yarnpkg.com/assets-webpack-plugin/-/assets-webpack-plugin-7.0.0.tgz#c61ed7466f35ff7a4d90d7070948736f471b8804"
integrity sha512-DMZ9r6HFxynWeONRMhSOFTvTrmit5dovdoUKdJgCG03M6CC7XiwNImPH+Ad1jaVrQ2n59e05lBhte52xPt4MSA==
assets-webpack-plugin@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/assets-webpack-plugin/-/assets-webpack-plugin-7.1.1.tgz#0b988bf904a1895cae5820957ad82aa402673894"
integrity sha512-HwsDcu9UR9kv7AtiyMpUO9fARn94SbrLzw5+aQ59RnOZJeet+EVHmOrMwXl8fZ8cZmdZ9Sbl1/l+fn7ymiyfMg==
dependencies:
camelcase "^6.0.0"
escape-string-regexp "^4.0.0"
lodash "^4.17.20"
lodash "^4.17.21"

ast-types@^0.13.4:
version "0.13.4"
Expand Down Expand Up @@ -6927,6 +6927,11 @@ typed-array-length@^1.0.6:
is-typed-array "^1.1.13"
possible-typed-array-names "^1.0.0"

typed-assert@^1.0.8:
version "1.0.9"
resolved "https://registry.yarnpkg.com/typed-assert/-/typed-assert-1.0.9.tgz#8af9d4f93432c4970ec717e3006f33f135b06213"
integrity sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==

typed-query-selector@^2.12.0:
version "2.12.0"
resolved "https://registry.yarnpkg.com/typed-query-selector/-/typed-query-selector-2.12.0.tgz#92b65dbc0a42655fccf4aeb1a08b1dddce8af5f2"
Expand Down Expand Up @@ -7177,6 +7182,13 @@ webpack-sources@^3.2.3:
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde"
integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==

webpack-subresource-integrity@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/webpack-subresource-integrity/-/webpack-subresource-integrity-5.1.0.tgz#8b7606b033c6ccac14e684267cb7fb1f5c2a132a"
integrity sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q==
dependencies:
typed-assert "^1.0.8"

webpack@^5.72:
version "5.94.0"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.94.0.tgz#77a6089c716e7ab90c1c67574a28da518a20970f"
Expand Down
Loading