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
feat: support Trusted Types for client overlay #4404
Changes from all commits
7db36ec
55a2805
efa9248
57cd5a6
b2fb287
eb652fa
e12147e
acca22a
8a9754e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,10 +23,25 @@ let iframeContainerElement; | |
let containerElement; | ||
/** @type {Array<(element: HTMLDivElement) => void>} */ | ||
let onLoadQueue = []; | ||
/** @type {TrustedTypePolicy | undefined} */ | ||
let overlayTrustedTypesPolicy; | ||
|
||
ansiHTML.setColors(colors); | ||
|
||
function createContainer() { | ||
/** | ||
* @param {string | null} trustedTypesPolicyName | ||
*/ | ||
function createContainer(trustedTypesPolicyName) { | ||
// Enable Trusted Types if they are available in the current browser. | ||
if (window.trustedTypes) { | ||
overlayTrustedTypesPolicy = window.trustedTypes.createPolicy( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In case there is an error creating a Trusted Types policy the overlay is not shown at all. A different approach would be to capture the exception outside this function (same place we define However I think having an error in the console is sufficient, since this is a development only feature so we can assume the console is opened anyways. |
||
trustedTypesPolicyName || "webpack-dev-server#overlay", | ||
{ | ||
createHTML: (value) => value, | ||
} | ||
); | ||
} | ||
|
||
iframeContainerElement = document.createElement("iframe"); | ||
iframeContainerElement.id = "webpack-dev-server-client-overlay"; | ||
iframeContainerElement.src = "about:blank"; | ||
|
@@ -109,8 +124,9 @@ function createContainer() { | |
|
||
/** | ||
* @param {(element: HTMLDivElement) => void} callback | ||
* @param {string | null} trustedTypesPolicyName | ||
*/ | ||
function ensureOverlayExists(callback) { | ||
function ensureOverlayExists(callback, trustedTypesPolicyName) { | ||
if (containerElement) { | ||
// Everything is ready, call the callback right away. | ||
callback(containerElement); | ||
|
@@ -124,7 +140,7 @@ function ensureOverlayExists(callback) { | |
return; | ||
} | ||
|
||
createContainer(); | ||
createContainer(trustedTypesPolicyName); | ||
} | ||
|
||
// Successful compilation. | ||
|
@@ -178,8 +194,9 @@ function formatProblem(type, item) { | |
/** | ||
* @param {string} type | ||
* @param {Array<string | { file?: string, moduleName?: string, loc?: string, message?: string }>} messages | ||
* @param {string | null} trustedTypesPolicyName | ||
*/ | ||
function show(type, messages) { | ||
function show(type, messages, trustedTypesPolicyName) { | ||
ensureOverlayExists(() => { | ||
messages.forEach((message) => { | ||
const entryElement = document.createElement("div"); | ||
|
@@ -193,7 +210,9 @@ function show(type, messages) { | |
const text = ansiHTML(encode(body)); | ||
const messageTextNode = document.createElement("div"); | ||
|
||
messageTextNode.innerHTML = text; | ||
messageTextNode.innerHTML = overlayTrustedTypesPolicy | ||
? overlayTrustedTypesPolicy.createHTML(text) | ||
: text; | ||
|
||
entryElement.appendChild(typeElement); | ||
entryElement.appendChild(document.createElement("br")); | ||
|
@@ -205,7 +224,7 @@ function show(type, messages) { | |
/** @type {HTMLDivElement} */ | ||
(containerElement).appendChild(entryElement); | ||
}); | ||
}); | ||
}, trustedTypesPolicyName); | ||
} | ||
|
||
export { formatProblem, show, hide }; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
# client.overlay.trustedTypesPolicyName option | ||
|
||
**webpack.config.js** | ||
|
||
```js | ||
module.exports = { | ||
// ... | ||
output: { | ||
trustedTypes: { policyName: "webpack" }, | ||
}, | ||
devServer: { | ||
client: { | ||
overlay: { | ||
trustedTypesPolicyName: "webpack#dev-overlay", | ||
}, | ||
}, | ||
}, | ||
}; | ||
``` | ||
|
||
Usage via CLI: | ||
|
||
```shell | ||
npx webpack serve --open | ||
``` | ||
|
||
## What Should Happen | ||
|
||
1. The script should open `http://localhost:8080/` in your default browser. | ||
2. You should see an overlay in browser for compilation errors. | ||
3. Modify `devServer.client.overlay.trustedTypesPolicyName` in webpack.config.js to `disallowed-policy` and save. | ||
4. Restart the command and you should not see an overlay at all. In the console you should see the following error: | ||
|
||
``` | ||
Refused to create a TrustedTypePolicy named 'disallowed-policy' because it violates the following Content Security Policy directive: "trusted-types webpack webpack#dev-overlay". | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
"use strict"; | ||
|
||
const target = document.querySelector("#target"); | ||
|
||
target.classList.add("pass"); | ||
target.textContent = "Success!"; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
<!-- Originally copied from "../../.assets/layout.html" --> | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<!-- Enable Trusted Types --> | ||
<meta | ||
http-equiv="Content-Security-Policy" | ||
content="require-trusted-types-for 'script'; trusted-types webpack webpack#dev-overlay;" | ||
/> | ||
|
||
<title>WDS ▻ <%= htmlWebpackPlugin.options.title %></title> | ||
<meta charset="utf-8" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1" /> | ||
<link rel="shortcut icon" href=".assets/favicon.ico" /> | ||
<link | ||
rel="stylesheet" | ||
href="https://fonts.googleapis.com/css?family=Source+Code+Pro:400,600|Source+Sans+Pro:400,400i,500,600" | ||
/> | ||
<link rel="stylesheet" href=".assets/style.css" /> | ||
</head> | ||
<body> | ||
<main> | ||
<header> | ||
<h1> | ||
<img | ||
src=".assets/icon-square.svg" | ||
style="width: 35px; height: 35px" | ||
/> | ||
webpack-dev-server | ||
</h1> | ||
</header> | ||
<section> | ||
<h2><%= htmlWebpackPlugin.options.title %></h2> | ||
<div id="target"></div> | ||
</section> | ||
</main> | ||
</body> | ||
</html> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
"use strict"; | ||
|
||
const path = require("path"); | ||
const HtmlWebpackPlugin = require("html-webpack-plugin"); | ||
// our setup function adds behind-the-scenes bits to the config that all of our | ||
// examples need | ||
const { setup } = require("../../util"); | ||
|
||
const config = setup({ | ||
context: __dirname, | ||
// create error for overlay | ||
entry: "./invalid.js", | ||
output: { | ||
trustedTypes: { policyName: "webpack" }, | ||
}, | ||
devServer: { | ||
client: { | ||
overlay: { | ||
trustedTypesPolicyName: "webpack#dev-overlay", | ||
}, | ||
}, | ||
}, | ||
}); | ||
|
||
// overwrite the index.html with our own to enable Trusted Types | ||
config.plugins[0] = new HtmlWebpackPlugin({ | ||
filename: "index.html", | ||
template: path.join(__dirname, "./layout.html"), | ||
title: "trusted types overlay", | ||
}); | ||
|
||
module.exports = config; |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could optionally check whether the
policyName
is notnull
. However, I think using trustedTypes whenever they are available is better because: