跳到主要内容

Docusaurus scripts 添加 inline 脚本构建失败?只支持 src 不接受 content

· 阅读需 5 分钟

docusaurus.config.tsscripts 数组里用 { content: '...' } 注入 inline 脚本(例如百度统计的 IIFE),执行 npm run build 直接报错。

在开发 CCLEE Docusaurus Theme 时遇到此问题——基于 Docusaurus 3.x 的高级文档主题,紫色主题 + 深色模式 + Tailwind 排版增强,开箱即用的生产级文档站点模板。

TL;DR

Docusaurus 的 scripts 配置只接受 src,不支持 inline content。把 inline 脚本挪到 static/js/ 下,用 { src: '/js/xxx.js', async: true } 引用即可;若脚本加载外部域名,还要同步更新 CSP。

问题现象

按百度统计官方代码,本能地想直接塞进 scripts

// docusaurus.config.ts
const config: Config = {
scripts: [
{
content: `var _hmt=_hmt||[];(function(){var hm=document.createElement("script");hm.src="https://hm.baidu.com/hm.js?XXXX";var s=document.getElementsByTagName("script")[0];s.parentNode.insertBefore(hm,s);})();`,
},
],
};

构建立刻失败:

[ERROR] Error: "scripts[1]" is invalid.
A script must be a plain string (the src), or an object with at least a "src" property.
at validateConfig (.../configValidation.js:397:15)

根因

Docusaurus 的 scripts 配置在构建期被 validateScripts 逐条校验,每条只允许两种形态:

  1. 纯字符串:直接当作 src 处理
  2. 对象:必须包含 src 属性,可选 asyncdeferdata-*

设计上 scripts 只生成形如 <script src="..." /> 的标签,没有为 inline 脚本保留 content / innerHTML 字段。所以无论 inline 内容多短,校验都会在 src 缺失时直接抛错,本地构建、Vercel 远端构建同样失败。

想注入带构建期变量的 inline 脚本,应改用顶层的 headTags 配置(tagName: 'script' + innerHTML),而不是 scripts

解决方案

1. 把 inline 脚本放进 static/js/

// static/js/baidu-tongji.js
var _hmt = _hmt || [];
(function () {
var hm = document.createElement('script');
hm.src = 'https://hm.baidu.com/hm.js?XXXX';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(hm, s);
})();

static/ 目录下的文件会被原样拷贝到站点根目录,最终 URL 即 /js/baidu-tongji.js

2. 在 scriptssrc 引用

// docusaurus.config.ts
scripts: [
// 已有的 Umami(参见 /blog/docusaurus-umami-analytics)
{
src: 'https://tj.ccleeai.com/script.js',
async: true,
'data-website-id': 'xxxx',
},
// 百度统计:走静态文件
{
src: '/js/baidu-tongji.js',
async: true,
},
],

3. 同步更新 CSP

如果站点启用了 Content-Security-Policy(推荐做法,参见我们之前总结的 Umami 集成与 CSP 配置),新加的外部域名必须放行,否则脚本会被浏览器拦截:

themeConfig: {
metadata: [
{
'http-equiv': 'Content-Security-Policy',
// script-src 加 https://hm.baidu.com
// connect-src、img-src 同步放行(hm.js 会发图片像素和 fetch 上报)
content: "default-src 'self'; " +
"script-src 'self' 'unsafe-inline' 'unsafe-eval' https://tj.ccleeai.com https://hm.baidu.com; " +
"connect-src 'self' https://tj.ccleeai.com https://hm.baidu.com; " +
"img-src 'self' data: https://hm.baidu.com; " +
"style-src 'self' 'unsafe-inline'; " +
"object-src 'none'; base-uri 'self'",
},
],
},

百度统计的 IIFE 内部用 document.createElement('script') 动态注入 <script src="hm.baidu.com/...">,所以光放 'unsafe-inline' 不够,必须把 hm.baidu.com 加进 script-src

注意事项

  • scripts 数组里的纯字符串和 src 是等价的:'https://x/a.js'{ src: 'https://x/a.js' } 等效
  • 路径以 / 开头时是相对站点根目录(static/ 拷贝产物),不是文件系统根
  • 若脚本依赖运行期变量、必须 inline,请用顶层 headTags 而非 scriptsheadTags 支持 innerHTML
  • 多套统计(Umami + 百度 + GA)可以共存,但每个外部域名都要单独加进 CSP,否则该域名上报被静默拦截

常见问题

如何在 Docusaurus 配置自定义 scripts?

docusaurus.config.ts 顶层的 scripts 数组中添加条目,每条要么是字符串(视作 src),要么是带 src 属性的对象。inline 内容不能用 content 字段——把脚本放进 static/js/ 目录后用 src: '/js/xxx.js' 引用即可。如果还需要 asyncdefer 或自定义 data-* 属性,把它们和 src 放在同一个对象里。

Docusaurus scripts 为什么不支持 inline content?

Docusaurus 的 scripts 配置在构建期生成的是 <script src="..."> 标签,本身没有为 inline 脚本设计字段。校验器(configValidation.ts 中的 validateScripts)逐条检查,只要对象缺少 src 就抛出 A script must be a plain string, or an object with at least a "src" property,无论你的 content 写得多完整。这是刻意的 API 边界,把 inline 注入的能力交给了 headTags

Docusaurus 如何注入 inline JavaScript(如百度统计)?

最稳的方式是「静态文件 + 内部动态注入」:把官方那段 IIFE 脚本完整保存到 static/js/baidu-tongji.jsscripts{ src: '/js/baidu-tongji.js', async: true } 引用;脚本内部再 document.createElement('script') 加载 hm.baidu.com/hm.js。最后别忘了在 CSP 的 script-srcconnect-srcimg-src 都加上 https://hm.baidu.com,否则上报会被浏览器拦截。

CCLEE

独立开发者,24年电商行业实战经验,专注将AI能力落地于真实商业场景。

合作咨询