
21-12-15 EDIT: 修正构建时注入css代码的字符串
如果你还没使用过油猴脚本https://greasyfork.org/zh-CN
如果你还没使用过 Vite 进行前端开发https://vitejs.dev/
开发模式下所使用的油猴脚本:
// ==UserScript==
// @name Your Script (dev mode)
// @namespace https://your.site/
// @version 0.1.0
// @description What does your script do
// @author You
// @include /https://match\.site/
// @grant GM_addElement
// @noframes
// @require https://cdn.jsdelivr.net/npm/vue@3.2.6/dist/vue.global.min.js
// ==/UserScript==
(function() {
'use strict';
// source: https://cn.vitejs.dev/guide/backend-integration.html
// 注意端口是否正确,以及是否修改了默认入口文件
GM_addElement('script', {
src: 'http://localhost:3000/@vite/client',
type: 'module'
});
GM_addElement('script', {
src: 'http://localhost:3000/src/main.ts',
type: 'module'
});
})(); 上述油猴脚本中引用的 localhost 域下脚本,一般情况下是不能在一个正常网页下运行的,会违反浏览器与网站的安全策略(CSP),安装浏览器扩展以绕过目标网页安全策略(出于安全考虑,开发结束务必关闭扩展!):
下载扩展:
https://chrome.google.com/webstore/detail/lhieoncdgamiiogcllfmboilhgoknmpi
编辑选项:
[
["https://targetsite\\.com/some/.*/url/", [
["script-src", "script-src http://localhost:3000"],
["connect-src", "connect-src ws://localhost:3000/"]
]]
] 修改HMR(默认情况下hmr会使用基于 window.location 的相对地址):
// vite.config.js
import ...
export default defineConfig({
...,
server: {
...,
hmr: {
protocol: 'ws',
host: 'localhost',
},
},
}) 项目开发像正常开发一样即可,main.ts/js 即为脚本入口(根据vite设置修改)
根据脚本功能可能需要手动添加挂载元素:
// ./src/App.vue
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
const appRoot = document.createElement('div')
appRoot.id = 'us-appRoot'
document.body.appendChild(appRoot)
app.mount('#us-appRoot') 如须对原有页面元素进行监控操作,可考虑 MutationObserver、vue 3.0 teleport 标签 等
修改设置文件在选项对象中添加以下内容:
// vite.config.js
import ...
export default defineConfig({
build: {
lib: {
entry: path.resolve(__dirname, 'src/main.ts'),
name: 'userscript',
formats: ['iife'], // 自运行打包格式,与默认模版一致
fileName: format => `yourscript.${format}.user.js`, // 非函数的常量会自动添加后缀
},
rollupOptions: {
external: ['vue'], // 分离库以降低最终代码体积
output: {
globals: {
vue: 'Vue',
GM_addStyle: 'GM_addStyle', // 油猴脚本API,用于添加样式到页面
},
inlineDynamicImports: true, // 库构建模式下不能进行代码分割,开启此功能可将本应分割的代码整合在一起避免报错(代码分割可能由其他插件引起)
},
},
minify: 'terser',
terserOptions: {
mangle: false, // 关闭名称混淆,遵守Greasefork规则
format: {
beautify: true, // 美化代码开启缩进,遵守Greasefork规则
},
},
},
...
plugins: [
...,
// custom plugin
(() => {
/**
* 如果用到了额外的 GM_functions,需要添加对应 @grant
* 虽然可以全部不添加,但只有TamperMonkey会自动推断,其他扩展不一定
* 在上面 extenral 声明的库,此处需要添加对应的 @require 要注意全局变量名称
*/
const headers = `\
// ==UserScript==
// @name Your Script (prod mode)
// @namespace https://your.site/
// @version 0.1.0
// @description What does your script do
// @author You
// @include /https://match\.site/
// @grant GM_addStyle
// @noframes
// @require https://cdn.jsdelivr.net/npm/vue@3.2.6/dist/vue.global.min.js
// ==/UserScript==
`
return {
name: 'inject-css',
apply: 'build', // 仅在构建模式下启用
enforce: 'post', // 在最后处理
generateBundle(options, bundle) {
// 从 bundle 中提取 style.css 内容,并加入到脚本中
const keyword = 'user.js'
if (!bundle['style.css'] || bundle['style.css'].type !== 'asset') return
const css = bundle['style.css'].source
const [, target] = Object.entries(bundle).find(([name]) => {
return name.includes(keyword)
}) ?? []
if (!target || target.type !== 'chunk') return
target.code = `${headers}\nGM_addStyle(\`${css}\`)\n${target.code}`
},
} as Plugin
})(),
]
}) 编译后的js文件应在 /dist 目录下,像普通油猴脚本一样使用即可
若使用了 tailwindcss/windicss 等,内置的css reset影响了原本元素,可以在对应设置文件中关闭 preflight
自动化构建+推送到greasefork (Planned)
可用作油猴脚本项目脚手架的模板库 https://github.com/antfu/vitesse-lite
EOF