You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何检测脚本文件是被加载执行还是在浏览器标签页打开查看?

可行方案:用Service Worker区分脚本加载场景并实现语法高亮渲染

完全可以实现你的需求,核心思路是通过Service Worker拦截JS文件的请求,根据请求的特征区分「直接在标签页打开查看」和「作为脚本加载执行」两种场景,再分别处理。

一、怎么区分两种场景?

浏览器在不同场景下请求JS文件时,会带上不同的请求特征,你可以在Service Worker的fetch事件里捕捉这些差异:

  • 直接打开查看:请求的mode为navigate,同时Accept请求头会包含text/html(因为浏览器期望把文件渲染成可阅读的页面)。
  • 作为脚本执行:请求的mode是no-cors或cors(取决于脚本跨域情况),Accept头会是application/javascript或包含module(ES模块的情况),且这类请求属于子资源加载,不是页面导航。

对应的判断代码示例:

self.addEventListener('fetch', (event) => {
  const req = event.request;
  // 先过滤出JS文件请求
  if (req.url.match(/\.js(\?.*)?$/)) {
    // 判断是否是直接打开的场景
    const isDirectView = req.mode === 'navigate' || 
                         req.headers.get('Accept')?.includes('text/html');
    
    if (isDirectView) {
      // 转成带语法高亮的HTML返回
      event.respondWith(renderHighlightedHtml(req));
    } else {
      // 正常返回原始脚本,供执行使用
      event.respondWith(fetch(req));
    }
  }
});

二、实现语法高亮的HTML渲染

当判断是直接打开的场景时,你需要:

  1. 获取原始JS文件的内容;
  2. 对代码进行语法高亮处理(可以自己写轻量的正则匹配,也可以嵌入小型的高亮逻辑,不用依赖外部库);
  3. 构造完整的HTML页面返回给浏览器。

示例实现:

async function renderHighlightedHtml(request) {
  // 拉取原始JS内容
  const jsRes = await fetch(request);
  const jsCode = await jsRes.text();
  
  // 简单的语法高亮处理(可根据需求扩展规则)
  const highlightedCode = jsCode
    // 高亮关键字
    .replace(/(\bfunction\b|\bconst\b|\blet\b|\bvar\b|\bif\b|\belse\b|\breturn\b|\basync\b|\bawait\b)/g, 
             '<span style="color: #0066cc;">$1</span>')
    // 高亮字符串
    .replace(/(".*?"|'.*?')/g, '<span style="color: #009900;">$1</span>')
    // 高亮单行注释
    .replace(/(\/\/.*)/g, '<span style="color: #999999;">$1</span>')
    // 高亮多行注释
    .replace(/(\/\*[\s\S]*?\*\/)/g, '<span style="color: #999999;">$1</span>');
  
  // 构造完整的HTML页面
  const htmlPage = `
    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="UTF-8">
      <title>${new URL(request.url).pathname.split('/').pop()}</title>
      <style>
        body { margin: 0; padding: 2rem; font-family: 'Consolas', 'Monaco', monospace; background: #f5f5f5; }
        pre { white-space: pre-wrap; line-height: 1.6; background: white; padding: 1.5rem; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
      </style>
    </head>
    <body>
      <pre>${highlightedCode}</pre>
    </body>
    </html>
  `;
  
  // 返回HTML响应
  return new Response(htmlPage, {
    headers: { 'Content-Type': 'text/html; charset=utf-8' }
  });
}

三、需要注意的细节

  • Service Worker作用域:注册Service Worker时,要确保作用域覆盖所有JS文件的路径,比如根目录下的JS文件,注册时用navigator.serviceWorker.register('/sw.js', { scope: '/' })。
  • 缓存逻辑:如果需要缓存JS文件,可在「作为脚本执行」的分支里加入缓存策略,但要注意更新机制,避免用户拿到过期的脚本。
  • 兼容性:现代主流浏览器都支持Service Worker,若要兼容旧浏览器,可以在页面里做降级提示。
  • ES模块适配:ES模块的请求Accept头会包含module,同样会被归类到「执行」场景,直接返回原始内容即可,无需处理。

内容的提问来源于stack exchange,提问作者jcubic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 20:41:32