escapeInject
Environment: Node.js
.
The escapeInject
string template tag sanitizes HTML (to prevent so-called XSS injections security breaches).
It is usually used in the render()
hook defined in renderer/_default.page.server.js
.
// renderer/_default.page.server.js
// Environment: Node.js
import { escapeInject, dangerouslySkipEscape } from 'vite-plugin-ssr'
export { render }
async function render() {
const title = 'Hello<script src="https://devil.org/evil-code"></script>'
const pageHtml = "<div>I'm already <b>sanitized</b>, e.g. by Vue/React</div>"
// This HTML is safe thanks to the template tag `escapeInject` which sanitizes `title`
return escapeInject`<!DOCTYPE html>
<html>
<head>
<title>${title}</title>
</head>
<body>
<div id="page-root">${dangerouslySkipEscape(pageHtml)}</div>
</body>
</html>`
}
All strings, e.g. title
above, are automatically sanitized (technically speaking: HTML-escaped)
so that we can safely include untrusted strings
such as user-generated text.
The dangerouslySkipEscape(str)
function injects the string str
as-is without sanitizing.
We should use dangerouslySkipEscape()
with a lot of caution and
only for HTML strings that are guaranteed to be already sanitized.
We usually use it to include HTML generated by UI frameworks (React/Vue/...) as these always generate already-sanitized HTML.
If we find ourself using dangerouslySkipEscape()
in other situations, we should be extra careful as we run into the risk of creating a security breach.
We can assemble the overall HTML document from several pieces of HTML fragments. For example, if we want some HTML parts to be included only for certain pages:
// _default.page.server.js
// Environment: Node.js
import { escapeInject, dangerouslySkipEscape } from 'vite-plugin-ssr'
import { renderToHtml } from 'some-ui-framework'
export { render }
async function render(pageContext) {
// We only include the `<meta name="description">` tag if the page has a description.
// (Pages define `pageContext.documentProps.description` in their `onBeforeRender()` hook.)
const description = pageContext.documentProps?.description
let descriptionTag = ''
if( description ) {
// Note how we use the `escapeInject` string template tag for an HTML fragment
descriptionTag = escapeInject`<meta name="description" content="${description}">`
}
// We use the `escapeInject` template tag again for the overall HTML and we can use
// our `descriptionTag` HTML fragment.
return escapeInject`<html>
<head>
${descriptionTag}
</head>
<body>
<div id="root">
${dangerouslySkipEscape(await renderToHtml(pageContext.Page))}
</div>
</body>
</html>`
}
Example: