简介

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。我浏览了网站的所有页面,修复了所有报告的问题。

接下来发生了什么?事情开始好转。我能够反转图表。在接下来的几个月里,有机增长翻了一番。快乐的客户。

[Google Search Console 趋势](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 用于软件包有很多好处。我个人最喜欢的是它可以让我轻松地为你的包隔离逻辑和依赖关系,让你编写更简单的代码。允许最终用户提取他们想要使用的包的任何特定部分。

[Unlighthouse 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以了解最新信息。

Logo

ModelScope旨在打造下一代开源的模型即服务共享平台,为泛AI开发者提供灵活、易用、低成本的一站式模型服务产品,让模型应用更简单!

更多推荐