Userscript × Webpack
十月 26, 2020 · 开发日记
大家好,这里是诈尸更博的轻雨酱。
之前好长一段时间没怎么出现了啦(感觉上有一年?),主要是不知道写点什么。这次转换一下身份,假装自己是一个萌萌哒的前端开发者。写点自我满足的东西,分享给大家。
好,那我们就开始吧 XD
这次想写的内容是 Userscript 相关,这大概像是所谓「极客」 向状物。原理说起来很简单,是通过一个浏览器插件(通常是 Tamper Monkey),使你自定义的 Javascript 运行在指定网页上,从而通过简短的代码实现一些有趣或是实用的功能。
比如前段日子,我给集训队作业的 OJ ioihw20.duck-ac.cn 写了个脚本。
这个 OJ 的用户名是顺序编码(形如 ioi2021_08
、ioi2021_11
);大家还有一个完成里面 150 道作业题的指标。对着数字编码人工脑补出这人是谁就很费劲,想看看谁是卷王(点名批评 @gcz)更只能一个一个点,那怎么办??
当然谁卷阿鲁巴谁当然是写个 Userscript 啦!根据内嵌的数据表,建立出用户名(形如 ioihw2021_11
)和真实姓名(xxx)的对应关系。啊这就是那个卷王 gcz 啊,怎么还没有被阿鲁巴。
至于排行榜的功能,注意到 UOJ 的前端实现中有用到 jQuery 库。这时候 Userscript 的好处就体现出来了,我们可以直接调用 UOJ 网站的 jQuery!通过 Promise.all()
和 $.get()
方法,同时取得每个人的个人信息页面 /user/profile/ioi2021_<xx>
。并用脚本处理数据,汇总到页面上。
此外,出于一些或是恶趣味,我还加了个给排行版的 rk1 带一个 卷王
的 badge 的小功能。这样无论在哪个页面,都能用红色的字写着:这就是那个卷王!!
你讲了这么多,和 Webpack 有啥关系?
欸对啊,这篇博文的标题不是 Webpack 嘛,怎么成了进来听轻雨酱扯淡吹逼啊。
注意到这么一个简简单单的脚本,我只进行了简单的函数封装,就已经有足足 10kb 了。如果我们想要完成更加复杂的脚本,这可怎么办呢?
那就请出我们的主角 webpack 吧(喂喂,这股小学生作文画风是怎么回事啊)。它是一个静态的 Javascript 打包工具。会根据你的配置和代码,生成 Javascript 代码的依赖关系,并打包成一个或多个 bundle。
这在 Vue.js 等开发工具中经常用到(他们也需要库和源代码全部打包到一个文件中),和我们的需求也十分类似。那么,或许我们就可以用类似 node.js 的方式开发我们的 Userscript,然后通过 Webpack 打包,并应用到 Tampermonkey 中?
那怎么写代码啊?
来考虑一下我们的目录结构:
./src
存放我们的脚本。其中以./src/app.js
为入口。./dist
存放自动打包生成的文件,如bundle.js
。./node_modules
存放程序运行所需要的第三方库,无需关心。./package.json
文件,存放 npm 的配置(如包的版本)。./webpack.config.js
文件,存放 webpack 的配置。
编辑 package.json
和 webpack.config.js
之前,我们先来考察一下我们开发和调试的需求。
- 开发环境(Development):在 Tampermonkey 中 @require 一个本地脚本。在 Chrome 设置中允许 Tampermonkey 访问本地文件。这样我们更新到打包更新到 bundle 文件的内容,就能实时应用到浏览器中。
- 生成环境(Production):通过 webpack 的工具进行打包和压缩。加上 Tampermonkey 所需的文件头,以作为独立的 TamperMonkey 脚本运行。进一步的,可以考虑使用 Github Action 等自动化工具部署。
webpack 支持我们分别为两个环境进行配置,并复用公共部分。
编辑 package.json
文件(请自行替换尖括号内的内容):
1 | { |
编辑 webpack.config.js
文件:
1 | const path = require('path'); |
运行 npm install
安装我们需要的库。
在当前目录新建 header.js
;新建 packer.js
,写入
1 | const fs = require("fs"); |
创建 src
文件夹,新建 app.js
文件并写入
1 | const { css } = require("./style.less"); |
新建 style.less
文件并写入
1 | * { color: red ; } |
在浏览器插件(此处以 Tampermonkey 为例)中创建一个脚本,并写入:
1 | // ==UserScript== |
运行 npm run build
进行打包,会发现自动生成了 ./dist/bundle.js
。
我们在浏览器中随便打开一个网页,会发现弹出 Hello, World! 对话框,且所有字体颜色变为了红色。
看到这个丑丑的页面,就说明我们的脚本成功运行了。
需要开发的话,可以直接修改 app.js
和 style.less
的内容。你可以在 app.js
中 import
一个别的 Javascript 文件,或者引入通过 NPM 安装的库,webpack 都会一并进行打包。
但这样做每次都要重新构建。这边选择使用 webpack 的 watch 模式监测源文件修改,并实时差量编译。前文我们已经配置好了,运行 npm run dev
即可启用该模式。
我写好了我的脚本,可怎么发布呢?
TamperMonkey 的脚本需要一个固定格式的文件头,而直接用 webpack 打包出来的 bundle.js
显然是不自带这样一段。
新建 header.js
文件,写入你配置的文件头。前文我们配置的 packer.js
可以直接把 header.js
的内容插入到 bundle.js
前面,并写入到文件 ./dist/userscript.js
中。(真是简单粗暴呢)
把 userscript.js
的内容复制到 Tampermonkey 中即可运行。
发布脚本的时候可以顺便薅一下资本主义羊毛 Github Action(@ouuan 哥哥教育我的),写入 ./.github/workflows/deploy.yml
:
1 | name: "Deploy to Artifacts" |
后话
嘛,感觉也不太适合写这种博客啊 = = ……受众范围有点小,不知道有没有人看。