dev.to 的前端:一次性完成头脑风暴添加关于 JavaScript 前端的开发人员文档 #2507 @ 在评论框中提及自动完成功能 #354 部署 Storybook #338 主题

2025-06-07

dev.to 的前端:一次性头脑风暴

添加有关 JavaScript 前端的开发人员文档 #2507

@提及评论框中的自动完成功能 #354

部署 Storybook #338

主题

目前有一个问题需要改进前端文档(参见前端 · 开发文档),以便用户更快地上手前端。非常感谢@rhymes提出这个问题!

添加有关 JavaScript 前端的开发人员文档 #2507

您的功能请求是否与问题相关?请描述。

在关于迁移到 TypeScript 并提高前端 DEV 代码库整体质量的想法DEV 注意事项:不要忘记清除缓存!https://github.com/thepracticaldev/dev.to/issues/2499之后,我认为如果有某种关于前端部分(特别是 JavaScript 层)如何组合在一起的概述会很好并且很有用。

我知道有两组 JS 代码库,由 Rails 的 sprockets 管理的app/assets/javascripts中的“遗留”代码库和由 webpack 管理的app/javascript中的“遗留”代码库

除此之外,我不确定一切是如何运作的(我承认除了偶尔修复错误或小功能外,我没有在前端花费太多时间)。

可能会回答以下几个问题docs/frontend/javascript.md

  • 初始化如何工作?
  • Preact 层是否完全忽略了原始 JS 层?
  • 两个 JS 代码库是否相互交互/调用?
  • 它们是如何附加到模板页面的?每个网页是否提供两组打包/压缩后的 JS 文件?
  • 在 dev.to 上下文中,Service Worker 做了什么?它在整个页面上都注册了吗?有多个 Service Worker 吗?
  • 边缘缓存如何适应这一切?
  • 即时点击如何适应这一切?

以及其他任何被认为重要的内容。不必非常深入,只需一张藏宝图,了解各个部分的功能以及它们如何组合在一起即可。

描述您想要的解决方案

包含 JS 前端工作原理描述的文档文件

描述你考虑过的替代方案

老实说,我还没有考虑过其他选择,现状还可以,只是如果有一些关于代码库的入职文档,对贡献者来说会更容易一些,特别是如果目标是重构它、使其现代化,甚至适应 TypeScript 或其他解决方案。

我决定写这篇文章,是因为我想为这个文档问题贡献一份力量,并认为它对包括我自己在内的所有人都有益。我希望大家能在评论区提问,或者补充文章中遗漏的内容。

香草 JS

该文件夹中包含大量前端代码库app/assets/javascripts。这部分代码库不使用ES 模块。它负责加载脚本,在 DOM 加载完成后运行代码,在全局范围内运行代码,并为 dev.to 提供大量客户端功能。

资源通过标准的rails / fastly方法加载,这些方法添加了<script />标签来加载前端代码。大多数(如果不是全部)脚本都会被延迟加载(请参阅<script>defer中的属性:Script 元素 - HTML)。

Preact、webpacker 和 webpack

该应用程序也包含更现代的 JavaScript 部分,但它并非单页应用程序(SPA)。它是一组分散在关键位置的组件,例如搜索、v2 编辑器、用户引导等。

Preact 组件使用webpacker gemwebpack进行管理。如果你对 webpacker 感兴趣,可以联系团队中的@maestromac 。

Webpack 入口点的脚本已添加到 Ruby ERB 模板中,但它们使用 Webpackerjavascript_pack_tag在服务器端添加脚本。有一个 Webpack 配置文件,但它是 yaml 格式的。该配置中包含一些设置,用于确定代码的位置以及如何定义入口点。

dev.to/webpacker.yml at master · thepracticaldev/dev.to · GitHub

...
default: &default
  source_path: app/javascript
  source_entry_path: packs
...
Enter fullscreen mode Exit fullscreen mode

查看上面的配置,这部分前端代码库可以在app/javascript文件夹中找到,并在文件夹中找到 webpack 入口点app/javascript/packs

这代表了 webpack 的基础配置。如果某个环境需要额外的配置,webpacker 允许你通过 webpack 配置导出来增强配置。

dev.to/development.js at master · thepracticaldev/dev.to · GitHub

const environment = require('./environment');
const config = environment.toWebpackConfig();

// For more information, see https://webpack.js.org/configuration/devtool/#devtool
config.devtool = 'eval-source-map';

module.exports = config;
Enter fullscreen mode Exit fullscreen mode

随着项目的不断推进,希望看到客户端的更多东西变得预先实现(这是我刚刚编造的,轰!)。

@提及评论框中的自动完成功能 #354

功能请求或任务

作为用户,我希望能够输入 @ 并弹出下拉菜单。在这种情况下,这是预期的行为。

这意味着该框必须变成一个可编辑内容的 div,并且代码应该附加到每个框上。要实现这一部分,可能得费点功夫。

这应该用 Preact 编写,如果您觉得包含其他库有意义,欢迎讨论。我们对每个依赖项都要求严格,因为我们希望在这方面提高效率。这并不意味着您绝对不能使用库,但我们只想讨论一下如果这样做会有什么影响。

下拉菜单将使用 Algolia 搜索,我们可能需要在User模型上添加适当的新自定义索引来实现这一点。

完成的定义

当所有内容框都包含下拉菜单,并且其行为在 GitHub 和 Twitter 等网站上正常运作时,即可实现此目的。核心团队会协助您解决此问题的细微之处。

Preact 在前端代码库中如何工作的示例

  1. 搜索入口点脚本通过 webpacker 加载javascript_pack_tag,例如<%= javascript_pack_tag "Search", defer: true %>

dev.to/application.html.erb at master · thepracticaldev/dev.to · GitHub

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <% title = yield(:title) %>
    <title><%= title || "#{ApplicationConfig['COMMUNITY_NAME']} Community" %></title>
    <% if internal_navigation? %>
      <style>
            ...
      </style>
    <% else %>
      ...
      <style>
        ..
      </style>
      ...
      <%= javascript_pack_tag "Search", defer: true %>
...
Enter fullscreen mode Exit fullscreen mode
  1. 搜索栏在页面初始加载时也会在服务器端渲染。这就是我目前所说的 Preact 的 ghetto 服务器端渲染 (SSR)。我知道@ben曾经想过添加 Preact SSR,但当时优先级并不高。也许现在随着越来越多的组件使用 Preact 创建,它的排名会更高。

dev.to/_top_bar.html.erb at master · thepracticaldev/dev.to · GitHub

...
    <div id="nav-search-form-root">
      <div class="nav-search-form">
        <form acceptCharset="UTF-8" method="get">
          <input class="nav-search-form__input" type="text" name="q" id="nav-search" placeholder="search" autoComplete="off" />
        </form>
      </div>
    </div>
...
Enter fullscreen mode Exit fullscreen mode
  1. 在客户端,一旦 DOM 内容加载完毕,Preact 就会接管。

dev.to/Search.jsx at master · thepracticaldev/dev.to · GitHub

import { h, render } from preact;
import { Search } from ../src/components/Search;

document.addEventListener(DOMContentLoaded, () => {
  const root = document.getElementById(nav-search-form-root);

  render(<Search />, root, root.firstElementChild);
});
Enter fullscreen mode Exit fullscreen mode
  1. 从那时起,与搜索框的所有交互都是客户端的。

即时点击

正如其宣传语所说,“ InstantClick是一个 JavaScript 库,可以显著提升您的网站速度,在大多数情况下实现即时导航。” 它的工作原理是,当用户将鼠标悬停在超链接上时,他们很可能是想点击它。InstantClick 会在用户悬停在超链接上时开始预加载页面,这样当他们真正点击时,页面加载就已经是即时的了。请注意,在移动设备上,预加载从“ touchstart ”开始。

除了预取页面之外,InstantClick 还允许您自定义 InstantClick 页面发生变化时发生的情况。

dev.to/githubRepos.jsx at master · thepracticaldev/dev.to · GitHub

...
window.InstantClick.on('change', () => {
  loadElement();
});
...
Enter fullscreen mode Exit fullscreen mode

您还可以通过该属性决定是否在 InstantClick 加载的页面中重新执行脚本data-no-instant。我认为代码库中没有任何示例将脚本重新执行列入黑名单。您也可以将链接列入黑名单。以下是代码库中的一个示例。

dev.to/buildCommentHTML.js.erb at master · thepracticaldev/dev.to · GitHub

...

function actions(comment) {
  if (comment.newly_created) {
    return '<div class="actions" data-comment-id="'+comment.id+'" data-path="'+comment.url+'">\
              <span class="current-user-actions" style="display: '+ (comment.newly_created ? 'inline-block' : 'none') +';">\
                <a data-no-instant="" href="'+comment.url+'/delete_confirm" class="edit-butt" rel="nofollow">DELETE</a>\
                <a href="'+comment.url+'/edit" class="edit-butt" rel="nofollow">EDIT</a>\
              </span>\
                <a href="#" class="toggle-reply-form" rel="nofollow">REPLY</a>\
            </div>';
  } else {
...
Enter fullscreen mode Exit fullscreen mode

有关更多信息,请参阅InstantClick 文档中的事件和脚本重新评估

代码检查/代码格式化

eslint 和 prettier

该项目使用带有 Prettier 插件的 eslint。这意味着所有与代码格式化相关的 eslint 规则都由 Prettier 处理。在大多数情况下,我们使用扩展配置提供的开箱即用规则,但也进行了一些调整。

另外,如上所述,有些对象存在于全局作用域中,例如Pusher。我们需要告诉 eslint 它已定义,否则它会抱怨它未定义。这时 eslintglobals部分就派上用场了。

...
  globals: {
    InstantClick: false,
    filterXSS: false,
    Pusher: false,
    algoliasearch: false,
  }
...
Enter fullscreen mode Exit fullscreen mode

哈士奇,棉绒阶段

代码库自带预提交钩子,允许我们在提交代码之前执行一些操作,例如运行 eslint。如果列表中存在可以修复的问题,它们将自动修复并提交。如果存在无法解决的问题,则提交失败,需要手动处理更改。

故事书

dev.to 前端代码库使用Storybook。它用于开发/展示组件。它的自定义配置可以在master · thepracticaldev/dev.to · GitHub 的 dev.to/app/javascript/.storybook中找到。

写故事书故事

Storybook 文档非常好,但如果您正在寻找一些示例,请参阅master · thepracticaldev/dev.to · GitHub 上的dev.to/app/javascript/src/components/stories

Storybook 的用途

目前尚未部署到 Netlify,但存在一个未解决的问题。

部署 Storybook #338

任务

Storybook 可以在本地运行,但我也编写了一个脚本来为其生成静态网站。在执行此操作之前,我一直在等待项目开源。运行npm run build-storybook,它将为 dev.to 的 Storybook 生成一个静态网站。它目前构建到./storybook-static文件夹。您可以将该文件夹部署到任何位置。我假设是 Netlify,因为 dev.to 文档就在那里。

此外,您还需要为故事书网站的名称添加 DNS 记录,例如 storybook.dev.to

我还采取了预防措施,将此文件夹添加到.gitignore

完成的定义

作为 CI 的一部分npm run build-storybook,它应该运行,如果失败(很可能是因为有人忘记更新),构建也应该失败。当 PR 合并到主分支时,上述情况仍然会发生,但./storybook-static静态文件夹也应该部署到像 Netlify 这样的服务上,该服务会解析为网站 URL,例如https://storybook.dev.to

如果您需要讨论其中任何内容,请随时联系我@maestromac或@benhalpern。

这部分代码库可能需要一些改进。对于有兴趣贡献代码的前端开发者来说,这里可能有很多唾手可得的成果,因为我相信其中有几个组件是 Storybook 中没有的。

主题

我没有参与这个项目,但我知道它大量使用 CSS 变量来设置主题,并提供了回退机制。这真是实现现代主题的好方法。

因此,所有可主题化的内容始终会应用 CSS 变量及其当前值(除非由于浏览器不支持 CSS 变量而只能采用后备)。

CSS 代码快照

主题切换的神奇之处在于用户配置。在这里,我们可以看到夜间主题或粉色主题的样式应用情况。

dev.to/_user_config.html.erb at master · thepracticaldev/dev.to · GitHub

<script>
  try {
    var bodyClass = localStorage.getItem('config_body_class');
    document.body.className = bodyClass;
    if (bodyClass.includes('night-theme')) {
            document.getElementById('body-styles').innerHTML = '<style>\
              :root {\
        --theme-background: #0d1219;\
        --theme-color: #fff;\
        --theme-logo-background: #0a0a0a;\
            ...
        --theme-social-icon-invert: invert(100)</style>'
    } else if (bodyClass.includes('pink-theme')) {
      document.getElementById('body-styles').innerHTML = '<style>\
      :root {\
      --theme-background: #FFF7F9;\
      --theme-color: #333;\
      --theme-logo-background: #fff7f9;\
            ...
      --theme-social-icon-invert: invert(0)</style>'
    }
  } catch(e) {
      console.log(e)
  }
</script>
Enter fullscreen mode Exit fullscreen mode

所以,如果你正在为项目中任何 CSS 相关的内容做贡献,请记得在工作中是否需要应用主题。别害羞,如果问题中没有明确提到,可以直接询问。@venarius在这方面做了很多工作,所以他可能是个不错的主题相关咨询对象。

未知数

服务人员

我完全没有在代码库中开发过任何与 Service Worker 相关的功能,所以如果有人能分享一下它的使用情况就太好了😺。我知道它支持离线页面,画图会很有趣。感谢@aspittel在离线页面上的出色工作!另外,我相信它也做了很多缓存工作,但同样,我不太了解这部分代码库的所有细节。

边缘缓存和前端

我没有做过任何关于边缘缓存的工作,但我知道 dev.to 使用的是Fastly。我猜想所有前端都会在全球的 CDN 上进行大量缓存。@ben我觉得你可以更详细地解释一下这部分。😺

![我会功夫](https://media.giphy.com/media/3o7btNhMBytxAM6YBa/giphy.gif)

希望这能为大家提供更多关于 dev.to 前端的说明。👋

其他资源:

照片由Milad FakurianUnsplash上拍摄

文章来源:https://dev.to/nickytonline/dev-to-s-frontend-a-brain-dump-in-one-act-7mg
PREV
正则表达式入门
NEXT
我对 Node.js 感到遗憾的 10 件事