油猴脚本创建webworker踩坑记录

作者:天平日期:2026/7/4

起因是我在使用vite-plugin-monkey编写油猴脚本,用ts编写webworker脚本,然后在一些网站创建webworker准备做一些耗时任务时,webworker一直没生效。我一直以为new Worker()梭哈就好了,没想到里面的门道这么多,整理了一些问题。

1.webworker不能直接使用非同源

假设谷歌有一个w.js脚本,在你的网站里面,不能直接new Worker('https://www.google.com/w.js'))去加载。注意,这里是限制非同源,和跨域CORS没关系。

2.worker导入方式

1.new Worker()

传统worker的导入方式是new Worker(''), new Worker做了什么?它会发起一个http请求,请求自身站点的这个worker文件。(要求这个文件真实存在)

2.new Worker(BlobURL)

传统worker导入方式又有另一种变体,就是获取到js的字符串,通过new Blob([jsCodeString], { type: "application/javascript" })得到blob,然后再通过URL.createObjectURL(blob)生成blob url,最后new Worker(blob url), 就不需要文件真实存在了。

1const jsContent = [`const a = 1;console.log(a)`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.a.md)
2const blob = new Blob([jsCodeString], { type: "application/javascript" })
3const url = URL.createObjectURL(blob)
4new Worker(url)
5

3.new Worker(new URL('./w.js', import.meta.url).href, { type: 'module' })

new Worker('')是以浏览器地址栏页面 URL为基准解析,可是在vue/react等应用出现后,这些SPA的History 多层路由(/user/detail/123)会拼接错误路径,导致找不到这个worker文件,所以Chrome在2020年推出用import.meta.url来查找worker文件,无论页面路由多深、页面在哪一级,永远以当前脚本文件目录查找 worker。但是一定要在script module里面执行

1<script type="module">
2new Worker(new URL('./w.js', import.meta.url).href, { type: 'module' })
3</script>
4

4.import Worker from './worker?worker&inline'

这是vite的语法,用来支持将外部worker文件内联到代码中的场景。

原理就是第二种方式,先把外部js文件转成code strig,再用Blob内联,只不过这个过程不用你手动处理了,vite帮你处理了。

3.代码实战

按照以上顺序,我让AI写了4组代码,并且分js/ts来测试。

代码具体实现如下:

A-js

1const w = new Worker('./fib-worker.js');
2

A-ts

1const w = new Worker('./fib-worker.ts');
2

B-js

1import jsWorkerCode from './fib-worker.js?raw';
2
3const blob = new Blob([jsWorkerCode], { type: 'text/javascript' });
4const url = URL.createObjectURL(blob);
5const w = new Worker(url);
6URL.revokeObjectURL(url);
7

B-ts

1import tsWorkerCode from './fib-worker.ts?raw';
2
3const blob = new Blob([tsWorkerCode], { type: 'text/javascript' });
4const url = URL.createObjectURL(blob);
5const w = new Worker(url);
6URL.revokeObjectURL(url);
7

C-js

1const url = new URL('./fib-worker.js', import.meta.url).href;
2const w = new Worker(url, { type: 'module' });
3

C-ts

1const url = new URL('./fib-worker.ts', import.meta.url).href;
2const w = new Worker(url, { type: 'module' });
3

D-js

1import FibWorkerJS from './fib-worker.js?worker&inline';
2
3const w = new FibWorkerJS();
4

D-ts

1import FibWorkerTS from './fib-worker.ts?worker&inline';
2
3const w = new FibWorkerTS();
4

以下是用vite-plugin-monkey掘金的页面开发环境下跑的:

然后来解释一下:

A-js是向掘金发起了一个http请求,去请求这个worker文件,而这个文件不存在,掘金返回了一个200的html <!DOCTYPE html><html>。然后Worker尝试去执行,发现第一行是<,于是报出具体的语法错误:

注意,不是说worker文件不存在就会返回html,是要看网站的处理,如果面对资源不存在,网站返回html,那就是这个。如果网站不处理,那么这个请求就会一直pending等待中,然后触发浏览器的报错。

A-ts和A-js一样

B-js就是标准的内联js worker,所以可以运行

B-ts是因为导入了ts源码,里面含有一些类型,而浏览器不支持解析这些类型,所以报错了。(有时候有人导入ts也成功,是因为里面不含类型,浏览器按js来解析了)

C-js和A-js差不多都是new Worker(), 为什么报错不一样呢?问题在于这个import.meta.url,此时worker不是向掘金发起http请求,而是向vite-plugin-monkey本地的vite服务器发起请求,实际上是new Worker('http://127.0.0.1:5173/src/fib-worker.js')),违反了第一条规则webworker不能直接使用非同源

C-ts同上

D-js不是说会内联worker吗?为什么还是和A-js一样,请求不存在的worker?我们可以打开面板,看到这条请求

里面的内容是这样的

也就是说,因为vite在开发环境下是不打包的,所以只是对其简单的包装了一下,由于这样写,实际上还是向掘金发起了http请求,然后由于掘金对这个请求没有处理,一直pending,所以触发了浏览器的错误事件。

4.打包结果

我们可以看到CD变了,C-js是因为tampermonkey打包出来的是普通script,通过iife运行,所以外层script没有module,导致import.meta.url在这里是undefined,从而构造URL失败。

而D则是正确的内联在code里面,所以在打包后能够正常运行。

5.怎么在开发环境下使用ts+webworker?

我们可以看到,在开发环境下,只有一种方式,那就是使用js内联。但是我就是想让它支持ts丰富的类型提示,总不能每次修改一点,就打包测试吧?这样调试起来太麻烦了,我之前试过,每次改一点->打包->删除旧的油猴脚本->替换新的脚本,非常繁琐。

其实也有看到社区自己写了一些plugin,在检测到?worker&inline时,就先打包,直接内联,这样就ok了,但是感觉还是不够优雅。

终于被我找到了另一种方式:

1const url = new URL('./fib-worker.ts', import.meta.url).href
2const res = await fetch(url)
3const jsCodeString = await res.text()
4const blob = new Blob([jsCodeString], { type: 'application/javascript' })
5const blobUrl = URL.createObjectURL(blob)
6const w = new Worker(blobUrl)
7

这里涉及到vite的服务器原理了。我们在开发vue/react项目的时候,在开发环境下,你会发现浏览器发起了很多请求,像vue,ts,tsx等等。

可是浏览器怎么会认识vue、ts呢?那是因为浏览器向vite请求vue文件,先不直接返回vue文件,而是通过@vue/compiler-sfc先把vue文件转成js文件,再返回。

同样的,浏览器向vite请求ts文件时,vite会先做一遍类型擦除,类型擦除后不就是js文件吗?所以也不用编译,直接返回。

那么回到刚才的问题,const url = new URL('./fib-worker.ts', import.meta.url).href,这里得到的其实就是vite服务器的ts文件的地址: http://127.0.0.1:5173/src/fib-worker.ts

而刚才说了,向vite服务器请求ts,vite会自动做一次类型擦除,所以得到的是纯净的js文件

既然能得到纯净的js文件,那么我们就要得到它。通过fetch去获取,而vite服务器设置的是允许跨域,所以我们就得到了纯净的jsCodeString。既然得到了jsCodeString,上面开发环境演示的几个demo中,只有B-js是成功的,那么就只需要转Blob url,就能在开发环境下使用webworker了。

完整封装如下:

1import TSWorker from './worker?worker&inline'
2
3async function createWorker(): Promise<Worker> {
4    if (import.meta.env.DEV) {
5        const url = new URL('./worker.ts', import.meta.url).href
6        const res = await fetch(url)
7        if (!res.ok) throw new Error('获取worker代码失败')
8        const jsCodeString = await res.text()
9        const blob = new Blob([jsCodeString], { type: 'application/javascript' })
10        return new Worker(URL.createObjectURL(blob))
11    }
12    return new TSWorker()
13}
14
15await createWorker()
16

开发环境下走fetch,打包时走vite的worker inline


油猴脚本创建webworker踩坑记录》 是转载文章,点击查看原文


相关推荐


WorkBuddy 上手实战:打造一个可用的本地 AI 工作台
倔强的石头_2026/6/26

WorkBuddy 上手实战:打造一个可用的本地 AI 工作台 很多 AI 产品看上去都能聊天,但真正进到日常使用里,最常见的需求并不是闲聊,而是整理一段零散记录、起草一段通知、输出一份周报,或者把一个任务拆成清单。而WorkBuddy 更像一个本地工作台,而不是单一聊天框:它把任务输入、专家角色、技能扩展和自动化模板放在同一个界面里,适合把办公动作收拢到一处完成。 和只做对话的产品相比,WorkBuddy 的优势很明显: 任务入口更集中,不用在多个页面之间来回切换。 专家、技能、自动化是分层


Ubuntu 26.04 完整安装 Fcitx5 中文拼音输入法指南(适配默认Wayland)
Oneslide2026/6/17

前言 Ubuntu 26.04 默认采用 Wayland 显示服务,传统 IBus 输入法存在光标跟随、软件兼容性问题;搜狗输入法依赖老旧 Fcitx4 框架,安装会破坏桌面依赖、造成登录循环。 本文使用系统原生 Fcitx5 输入法框架,完美适配 Wayland,浏览器、VSCode、办公软件均可正常输入中文,附带界面美化、候选框遮挡问题全套解决方案。 一、前置准备:安装中文语言包&中文字体 终端执行以下命令,完成中文本地化环境部署,解决汉字方框乱码问题: # 更新软件源 sudo apt u


Flink-HBase生产问题排查:NoClassDefFoundError
大大大大晴天️2026/6/10

一、背景与问题 我们生产环境上有一个Flink实时作业近期出现写入 HBase 失败,日志频繁打印Exception日志,但作业的运行状态却一直健康正常;进行应急手动重启作业后恢复正常,HBase正常写入,未再复现。 环境信息:Flink(1.16)、HBase(2.4)、Kafka(2.8) 作业的计算链路DAG大致如下: 算子链路:Source → Filter/FlatMap → Process → HBaseSink 二、问题排查 此Flink作业是一个Flink-Java作


别再把“做个H5”挂嘴边了:这个词,官方压根就没有定义过
知航驿站2026/6/2

别再把“H5”当正式术语了 前言 做前端这些年,我一直觉得中文互联网里有个词特别有意思,就是“H5”。 这个词几乎人人都在用。产品说“做个 H5”,运营说“我要一个 H5 活动页”,甲方也会说“你们能不能先出个 H5 版本”。说得多了,很多人就默认:这一定是个很正式、很标准、很官方的技术词。 但真要较真一点看,这事其实不是这样。 HTML5 当然是标准里的正式说法,H5 却不是一个被官方单独定义出来、专门指代“活动页”“移动端网页”“营销页面”的术语。今天大家口中的“H5”,更像是中文互联网行业


构建无障碍组件之Toolbar Pattern
anOnion2026/5/25

Toolbar Pattern 详解:构建无障碍的工具栏组件 Toolbar(工具栏)是一种用于组合一组控件的容器,例如按钮、菜单按钮或复选框。本文基于 W3C WAI-ARIA Toolbar Pattern 规范,详解如何构建无障碍的工具栏组件。 一、Toolbar 的定义与核心概念 1.1 什么是 Toolbar Toolbar 是一种控件分组容器,具有以下特征: 将一组相关控件(按钮、菜单、复选框等)视觉上分组 通过 role="toolbar" 向屏幕阅读器用户传达分组的存在和目的


Android 窗口容器树(一)—— 窗口和窗口容器树
无限进化2026/5/4

窗口容器树系列文章: Android 窗口容器树(一)—— 窗口和窗口容器树 Android 窗口容器树(二)—— 窗口容器树的构建 1. 什么是窗口? 在 Android 中,窗口不是 View,也不是某个单独的界面控件,而是系统层面对一块可显示 UI 内容的抽象管理单元。 它至少有 3 个核心特征: 它有独立的 WindowManager.LayoutParams,用来描述类型、位置、大小、标志位等。 它最终会对应到 SurfaceControl / Surface,并交给 Surfa


【从0开始学设计模式-11| 外观模式】
我爱cope2026/4/24

概念 外观模式(Facade Pattern) 是一种使用频率非常高的结构型设计模式,它通过引入一个外观角色来简化客户端与子系统之间的交互,为复杂的子系统调用提供一个统一的入口,降低子系统与客户端的耦合度,且客户端调用非常方便。 定义: 为子系统中的一组接口提供一个统一的入口。外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。 外观模式又称为门面模式,它是一种对象结构型模式。外观模式是迪米特法则的一种具体实现,通过引入一个新的外观角色可以降低原有系统的复杂度,同时降低客户类与子


VPS 买回来第一天该干什么?我的开机必做清单
小墨同学boy2026/4/16

很多人买来第一台VPS可能不知道干什么,是到手之后直接装宝塔,然后部署一个WordPress 博客丢上去跑了两天。可能过几天你就会发现 auth.log 里全是暴力破解记录,SSH 端口没有改还是默认的 22,root 密码没有做修改还是简单的 8 数字。最离谱的是你没有一开始测试号,最后发现那台机器的网络在晚高峰根本不能用,到最后可以部署完了才发现的,前面装的东西全白费功夫。 所以我才要写这篇文章,介绍我的流程:新机器到手,不要一上来就按照服务,先按照我的固定流程把去设置一遍服务器。整个过程其


# KubeBlocks for MSSQL 高可用实现
小猿姐2026/4/8

背景 Microsoft SQL Server(MSSQL)是由微软开发的一款关系型数据库管理系统。最初仅支持在 Windows 平台上运行,自 2017 版本起开始支持 Linux 系统,这一变化为 MSSQL 的容器化部署提供了可能。 MSSQL 提供了名为 Availability Group(可用性组,下文简称AG) 的多数据库复制管理特性,该特性支持在多个节点上实现数据库的多副本冗余,从而提升数据可靠性和服务连续性。在 Windows 平台上,MSSQL 通过与 Windows Ser


AI时代,我们的任务不应沉溺于与 AI 聊天 - 🤔 从“对话式编程”迈向“数字软件工厂”
阿文WUTAI感话2026/3/31

2026年,AI辅助开发的正确打开方式 在 2026 年的今天,研发工程师已经意识到,AI 辅助开发不应只是零散的提示词,而是一套 有标准、有性能、有角色、有流程 的系统工程 。通过 OpenSpec、Everything Claude Code (ECC)、gstack 以及新增的 superpowers 的深度协同,我们可以构建起一套现代化的"数字软件工厂",让研发协作工作流与状态流转更加符合项目的确定性需求 一、核心概念:先对齐术语,避免鸡同鸭讲 要驾驭这套工厂,首先需要对齐底层的专业概

首页编辑器站点地图

本站内容在 CC BY-SA 4.0 协议下发布

Copyright © 2026 聚合阅读