Building Unlighthouse:用于站点范围内 Google Lighthouse 扫描的开源软件包
简介
Unlighthouse是一个开源软件包,用于使用 Google Lighthouse 扫描您的整个站点。具有现代 UI、最少的配置和智能采样。
创意之旅
作为一名自由职业者,我使用 Google Search Console 保持客户的有机增长。
和其他任何一天一样,看着我的一个客户的仪表板。似乎不知从何而来,我看到了自由落体的页面位置、点击量和页面浏览量的趋势。我的客户的收入是基于自然流量,不好。
[
](https://res.cloudinary.com/practicaldev/image/fetch/s--2r_z1zhN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev -to-uploads.s3.amazonaws.com/uploads/articles/n4ajn7qv5iir7kmido0p.png)
找出页面排名下降的原因并不容易。该站点存在问题,但是是什么导致了自由落体。没有办法知道。
为了诊断问题,我使用了 Google Lighthouse。我浏览了网站的所有页面,修复了所有报告的问题。
接下来发生了什么?事情开始好转。我能够反转图表。在接下来的几个月里,有机增长翻了一番。快乐的客户。
[
](https://res.cloudinary.com/practicaldev/image/fetch/s--WPORlJlu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev -to-uploads.s3.amazonaws.com/uploads/articles/wh6s6kjiy5y8ilv8pzeq.png)
现在已经不碍事了,我怎样才能更轻松地掌握我管理的网站的健康状况?
开始构建
所以我知道我想构建一个只需要主页 URL 就可以在整个网站上运行 Google Lighthouse 的东西。
当需要将一些东西放在一起时,我对堆栈有了一个粗略的了解。 Typescript、Vue、Vite 等
还有无数漂亮的软件包来自我想玩的UnJS生态系统。
这样,该软件包将被称为 Un(受 Unjs 启发)Lighthouse。
无灯塔建筑
构建包的代码。
查看3 / 快速客户
心爱的Vite将用于使客户端的开发尽可能简单和快速。
Vue v3 曾经使用VueUse上提供的大量实用程序。
灯塔二进制
如果 Google 没有将 Lighthouse 发布为自己的NPM 二进制,那么 Unlighthouse 就不可能实现。
为了使 Unlighthouse 更快,我将二进制文件与包puppeteer-cluster结合起来,它允许多线程灯塔扫描。
PNPM Monorepo
PNPM是节点包管理器中的新手,并且有充分的理由迅速获得大量追随者。它是性能最高的包管理器,并为 monorepos 提供一流的支持。
将 monorepo 用于软件包有很多好处。我个人最喜欢的是它可以让我轻松地为你的包隔离逻辑和依赖关系,让你编写更简单的代码。允许最终用户提取他们想要使用的包的任何特定部分。
[
](https://res.cloudinary.com/practicaldev/image/fetch/s--qvawN7e1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to- uploads.s3.amazonaws.com/uploads/articles/3hfzz5ik3fa9qtzmmmz9.png)
齿轮检测
Vitest也是测试中的新手。它最初的目标是成为一个专门针对 Vite 的测试框架,但它最终可能完全替代了 Jest。
Vitest 让编写逻辑和测试变得轻而易举,我建议在任何项目中检查它。
取消构建
这个包被描述为“一个统一的 javascript 构建系统”。
实际上,这是将包代码构建为 ESM 和 CJS 的最小配置方式。
unbuild 的惊人功能之一是存根。这使您可以从 dist 文件夹运行源代码,这意味着它可以即时转换。
当您在包上迭代和测试集成时,这允许您完全取消构建步骤。
它就像unbuild --stub一样简单。
import { defineBuildConfig } from 'unbuild'
export default defineBuildConfig({
entries: [
{ input: 'src/index' },
{ input: 'src/process', outDir: 'dist/process', builder: 'mkdist', declaration: false },
],
})
进入全屏模式 退出全屏模式
unctx
令人惊讶的是,像组合这样的简单模式已经避开 Node 包这么久了。
随着 Vue 3 的引入,组合变得很酷。有了这个,unctx 就是你自己的包的组合。
unctx 允许您定义一个范围,其中只有一个全局可访问的实例。这对于构建包非常有用,因为您不再需要处理核心状态。您可以将逻辑构建为与核心交互的可组合项。
import { createContext } from 'unctx'
const engineContext = createContext<UnlighthouseContext>()
export const useUnlighthouse = engineContext.use as () => UnlighthouseContext
export const createUnlighthouse = async(userConfig: UserConfig, provider?: Provider) => {
// ...
engineContext.set(ctx, true)
}
进入全屏模式 退出全屏模式
未布线
我需要一个 API 供客户端与 Node 服务器通信以获取扫描状态并提交重新扫描。
当前的 JS 产品有点乏善可陈。我想要一些可以正常工作并且有很好的使用方法的东西。
我最终构建了 unrouted 来解决这个问题。
group('/api', () => {
group('/reports', () => {
post('/rescan', () => {
const { worker } = useUnlighthouse()
const reports = [...worker.routeReports.values()]
logger.info(`Doing site rescan, clearing ${reports.length} reports.`)
worker.routeReports.clear()
reports.forEach((route) => {
const dir = route.artifactPath
if (fs.existsSync(dir))
fs.rmSync(dir, { recursive: true })
})
worker.queueRoutes(reports.map(report => report.route))
return true
})
post('/:id/rescan', () => {
const report = useReport()
const { worker } = useUnlighthouse()
if (report)
worker.requeueReport(report)
})
})
get('__launch', () => {
const { file } = useQuery<{ file: string }>()
if (!file) {
setStatusCode(400)
return false
}
const path = file.replace(resolvedConfig.root, '')
const resolved = join(resolvedConfig.root, path)
logger.info(`Launching file in editor: \`${path}\``)
launch(resolved)
})
get('ws', req => ws.serve(req))
get('reports', () => {
const { worker } = useUnlighthouse()
return worker.reports().filter(r => r.tasks.inspectHtmlTask === 'completed')
})
get('scan-meta', () => createScanMeta())
})
进入全屏模式 退出全屏模式
可钩式
对于 Nuxt.js 用户,您可能熟悉框架钩子的概念。一种让您修改或使用 Nuxt 内部逻辑的方法。
构建一个包,我知道这是一个有用的功能,不仅对最终用户,而且对我来说是一种组织逻辑的方式。
拥有一个可挂钩的核心意味着您可以避免烘焙逻辑,因为它可能更适合其他地方。
例如,我想确保 Unlighthouse 在访问页面之前不会开始进行集成。
我只是设置了一个钩子,让它只有在他们访问客户端时才启动。
hooks.hookOnce('visited-client', () => {
ctx.start()
})
进入全屏模式 退出全屏模式
取消配置
Unconfig 是加载配置的通用解决方案。这让我允许包从unlighthouse.config.ts或自定义路径的配置中加载,几乎没有任何代码。
import { loadConfig } from 'unconfig'
const configDefinition = await loadConfig<UserConfig>({
cwd: userConfig.root,
sources: [
{
files: [
'unlighthouse.config',
// may provide the config file as an argument
...(userConfig.configFile ? [userConfig.configFile] : []),
],
// default extensions
extensions: ['ts', 'js'],
},
],
})
if (configDefinition.sources?.[0]) {
configFile = configDefinition.sources[0]
userConfig = defu(configDefinition.config, userConfig)
}
进入全屏模式 退出全屏模式
不明飞行物
用于人类的 URL 实用程序
在 Node 中处理 URL 不是很好。对于 Unlighthouse,我需要处理许多 URL,无论它们是如何形成的,我都需要确保它们是标准化的。
这意味着大量使用 ufo 包。斜线修剪非常方便和原点检测。
export const trimSlashes = (s: string) => withoutLeadingSlash(withoutTrailingSlash(s))
进入全屏模式 退出全屏模式
const site = new $URL(url).origin
进入全屏模式 退出全屏模式
放在一起 - 第 2 部分
本文的第 2 部分即将发布,我将介绍一些将上述软件包组合在一起的技术壮举。
结论
感谢您阅读第 1 部分。我希望您至少觉得它很有趣或其中的一些链接很有用。
您可以关注我@harlan_zw以了解最新信息。
更多推荐


所有评论(0)