news 2026/9/10 5:59:01

webpack 5 如何用 output.html.csp 为内联脚本与样式生成带哈希的 CSP meta 标签

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
webpack 5 如何用 output.html.csp 为内联脚本与样式生成带哈希的 CSP meta 标签

webpack 5 如何用 output.html.csp 为内联脚本与样式生成带哈希的 CSP meta 标签

【免费下载链接】webpackA bundler for javascript and friends. Packs many modules into a few bundled assets. Code Splitting allows for loading parts of the application on demand. Through "loaders", modules can be CommonJs, AMD, ES6 modules, CSS, Images, JSON, Coffeescript, LESS, ... and your custom stuff.项目地址: https://gitcode.com/GitHub_Trending/web/webpack

如果你的 webpack 构建会产出 HTML 页面,而你想在页面上启用 Content-Security-Policy,又不想维护第三方 CSP 插件,webpack 5 的实验性 HTML 模块支持(experiments.html)提供了output.html.csp选项:它在每个 webpack 产出的 HTML 页面中注入一个<meta http-equiv="Content-Security-Policy">标签,并为页面上每一个内联<script>/<style>附上sha256哈希。本文基于仓库中的 html-csp 示例 和 WebpackOptions.json 中该字段的定义,走一遍从配置到验证的完整路径。

前提条件(均来自上述文档):

  • 使用 webpack 5,并启用实验性 HTML 模块:experiments: { html: true }
  • output.html.csp默认为false(什么都不做),只有显式配置后才会生效。
  • CSP 哈希是在内联之后计算的,因此每个哈希与浏览器实际执行的字节一一对应;这也是为什么通常需要配合output.html.inline一起使用。

准备示例文件

仓库中的 examples/html-csp 给出了完整的可复现工程。页面结构是一个入口 HTML 加上外部引用的脚本和样式,以及一个原本就写在 HTML 里的内联样式:

入口 src/index.html:

<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>CSP</title> <!-- 外部样式表:被打包后由 output.html.inline 内联成 <style>,从而被 CSP 哈希 --> <link rel="stylesheet" href="./styles.css" /> <!-- 内联 <style>:原样被哈希 --> <style> body { font-family: sans-serif; } </style> </head> <body> <h1>Content-Security-Policy</h1> <!-- 外部脚本:被打包后内联成 <script> 并被哈希 --> <script src="./app.js"></script> </body> </html>

另外两个模块文件:

// src/app.js document.querySelector("h1").classList.add("ready"); console.log("bundled + inlined script, covered by a CSP hash");
/* src/styles.css */ h1 { color: #2b3a42; } h1.ready { color: #8ed6fb; }

配置 webpack.config.js

关键是output.html下的两个选项配合(完整文件见 examples/html-csp/webpack.config.js):

"use strict"; /** @type {import("../../").Configuration} */ module.exports = { entry: { index: "./src/index.html" }, output: { html: { // 把每个产出的 chunk 内联进页面,产生供 CSP 哈希的内联 <script>/<style> // "script"/"style" 或 RegExp 数组可以收窄内联范围;未内联的部分由 'self' 覆盖 inline: true, // true = 严格基线(script-src/style-src 'self'、object-src 'none'、base-uri 'self') // 外加每个内联脚本/样式一个 sha256;传对象可以加 nonce 或通过 policy 覆盖指令 csp: true } }, experiments: { html: true } };

两个选项的作用(依据 WebpackOptions.json 的字段描述与示例 README):

  • inline: true把每个产出的 chunk 直接内联进 HTML,而不是输出单独的<script src>/<link rel="stylesheet">标签。这样原本外部的<link rel="stylesheet"><script src>会变成内联的<style>/<script>,与源文件中本来就内联的标签一起成为可哈希对象。inline的其他取值:"script"只内联 JavaScript,"style"只内联 CSS,传入RegExp数组则按 chunk 名匹配。
  • csp: true注入 CSP<meta>,基线为script-src 'self'style-src 'self'object-src 'none'base-uri 'self',并把每个内联<script>/<style>sha256哈希追加到script-src/style-src。哈希在内联完成后计算,因此与浏览器实际执行的字节一致;仍然留在页面外部的资源由'self'覆盖。

在这个示例目录下用 webpack CLI 运行一次构建(配置即上面这份),即可产出dist/index.html

验证产出页面

构建成功后(webpack 输出compiled successfully),检查dist/index.html。文档示例的产出页面开头如下(摘自 examples/html-csp/README.md,其中的哈希值是文档示例):

<!DOCTYPE html> <html lang="en"> <head><meta http-equiv="Content-Security-Policy" content="script-src 'self' 'sha256-5NlCGoSN8ETSUabbmQKYTt1H6nvYWb5OGZJTsWS8iC8='; style-src 'self' 'sha256-vp73KxgWfPhtZ9IRKOt378FrPIkD/T6FbLXnXfaktI8=' 'sha256-+Ver9ZPpEiV0Cq4WfPc7DL+LUo1ECenMRe/8IigO+wA='; object-src 'none'; base-uri 'self'"> <meta charset="utf-8" /> <title>CSP</title> <!-- 外部样式表:被打包后由 output.html.inline 内联成 <style>,从而被 CSP 哈希 --> <style>/*! ... ***! h1 { color: #2b3a42; } h1.ready { color: #8ed6fb; } </style> <!-- 内联 <style>:原样被哈希 --> <style>/*! ... ***! body { font-family: sans-serif; } </style> </head> <body> <h1>Content-Security-Policy</h1> <!-- 外部脚本:被打包后内联成 <script> 并被哈希 --> <script>/******/ (() => { // webpackBootstrap /*! ... ***! document.querySelector("h1").classList.add("ready"); console.log("bundled + inlined script, covered by a CSP hash"); /******/ })() ;</script> </body> </html>

验证要点:

  • 页面<head>中出现生成的<meta http-equiv="Content-Security-Policy">
  • style-src中出现了两个哈希(对应内联后的外部样式表 + 源文件中原本就内联的<style>),script-src中出现一个哈希(对应内联后的app.jsbundle);
  • 每个内联<script>/<style>都能在该 meta 中找到对应的哈希条目。由于哈希按内联后的字节计算,页面内容任何变动都会使旧哈希失配。

README 中还给出了该示例在 Unoptimized 与 Production mode 下两次构建的 stats 输出(同样为文档示例),可用于核对编译是否成功以及哪些资产被产出。

可选分支:nonce 与自定义 policy

csp: true改为对象即可定制(字段定义见 WebpackOptions.json 中output.html.csp的描述):

  • hashFunction:内联<script>/<style>的哈希算法,可选sha256sha384sha512
  • nonce:占位 nonce,会加到注入的<script>/<style>标签上并作为'nonce-…'源写入策略。注意它是占位符,需要服务端在每次请求时重写(rewrite it per request server-side);
  • policy:在基线之上合并的 CSP 指令,键是指令名(如"img-src"),值是单个 source 字符串或 source 数组。内联哈希和nonce仍然会被追加到script-src/style-src

示例(来自 README):

output: { html: { inline: true, csp: { policy: { "img-src": ["'self'", "data:"] } } } }

已知限制

  • 该功能依附于实验性HTML 模块支持(experiments.html),不是稳定的通用入口;output.html.inline在 schema 中标注为 5.109.0 加入。
  • 页面中已声明的 CSP 不会被触碰:schema 描述明确“Skipped when the page already declares a CSP”,即作者自己在页面里写好的 CSP meta 优先,webpack 跳过注入。
  • 只有被内联的脚本/样式才会获得哈希;仍以外链形式存在的资源依赖基线中的'self',如果你的页面需要从其他域加载脚本或样式,需要通过policy显式扩展对应指令。
  • 该机制不依赖任何 CSP 插件,全部由 webpack 在产出 HTML 时完成。

完成配置与验证后,产出页面上就会带有与内联内容逐字节对应的 CSP meta 标签;若后续需要按请求下发真实 nonce,按上面nonce字段说明在服务端做替换即可。

【免费下载链接】webpackA bundler for javascript and friends. Packs many modules into a few bundled assets. Code Splitting allows for loading parts of the application on demand. Through "loaders", modules can be CommonJs, AMD, ES6 modules, CSS, Images, JSON, Coffeescript, LESS, ... and your custom stuff.项目地址: https://gitcode.com/GitHub_Trending/web/webpack

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 5:55:46

ARM CMSIS-NN源码深度解析:嵌入式AI推理性能优化实战

1. 项目概述&#xff1a;这不是一次“读代码”&#xff0c;而是一场嵌入式AI推理引擎的解剖手术 CMSIS-NN 是 ARM 官方为 Cortex-M 系列微控制器量身打造的神经网络计算库&#xff0c;它不是教科书里的概念&#xff0c;而是你手头那块 STM32H7 或 NXP i.MX RT1060 开发板上&…

作者头像 李华
网站建设 2026/9/10 5:53:00

如何搭建 Vane 本地开发环境并用 npm run dev 启动?

如何搭建 Vane 本地开发环境并用 npm run dev 启动&#xff1f; 【免费下载链接】Vane Vane is an AI-powered answering engine. 项目地址: https://gitcode.com/GitHub_Trending/pe/Vane Vane 是一个运行在本地硬件上的 AI 回答引擎&#xff0c;基于 Next.js 构建&…

作者头像 李华
网站建设 2026/9/10 5:52:06

超帧Hyperframes:突破小包PPS瓶颈的网络性能优化实践

做了几年网络性能优化&#xff0c;我遇到最多的一个问题就是&#xff1a;服务器吞吐明明显示上去了&#xff0c;为什么PPS&#xff08;每秒转发包数&#xff09;还是上不去&#xff1f;网卡是万兆的&#xff0c;CPU核也不少&#xff0c;可一跑64字节小包压测&#xff0c;性能立…

作者头像 李华