发布于 2026-01-05 10 阅读
0

跨多个站点的可重用组件:从设计系统到部署 🔥 由 Mux 呈现的 DEV 全球展示挑战赛:展示你的项目!

跨多个站点的可复用组件:从设计系统到部署 🔥

由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!

太长不看

当一个开发者长时间开发一个网站时,显然很少有人会想到这样的功能,但想象一下,如果你的服务变得受欢迎,你想扩展业务。

乍一看,一个代码仓库似乎就足够了,但如果一个服务(公司)旗下有 10 个网站,那么所有网站都必须使用相同的组件,因为创建新的设计根本不划算。像 GitHub 和 YouTube 这样的服务的用户根本无法想象会有多少个子网站。

2010 年和 2025 年的 Web 开发几乎截然不同。因此,了解当今的现代实践至关重要。组件共享就是其中之一。本文将对此进行探讨!


🔩 组件

例如,我们可以取一个按钮组件,我们将在各个组件之间传递这个组件。它看起来会像这样:

<button class="button">Click Me</button>
<style>
  .button {
    background-color: #4caf50;
    color: white;
    border: none;
    padding: 12px 24px;
    text-align: center;
    text-decoration: none;
    font-size: 16px;
    border-radius: 5px;
    cursor: pointer;
    transition: background-color 0.3s, transform 0.2s;
  }

  .button:hover {
    background-color: #45a049;
  }

  .button:active {
    transform: scale(0.95);
  }
</style>
Enter fullscreen mode Exit fullscreen mode

网站上显示的结果如下:

按钮

现在,假设有两个网站需要使用相同的组件。我们暂且称它们为 example1 和 example2。它们可以托管在不同的服务器上。假设一个网站部署在 GitHub 上,另一个网站部署在本地服务器上。

现在,主要问题来了——如何分享?


🛤️ 多种分享方式

我将介绍几种常用的方法,从最普通的到最实用的。

共享组件

这两种方法看起来都差不多是这样的。


🔗 1. 通过脚本输出到文件并建立连接

此方法假设存在一个返回 HTML 标记的函数。并且,该函数可以通过远程文件连接。该文件位于何处并不重要,您只需从该文件处连接即可。

createButton.js

// buttonModule.js
(function (global) {
  // Define the createButton function
  function createButton() {
    // Create a <style> element and add styles
    const style = document.createElement('style');
    style.textContent = `
      .button {
        background-color: #4caf50;
        color: white;
        border: none;
        padding: 12px 24px;
        text-align: center;
        text-decoration: none;
        font-size: 16px;
        border-radius: 5px;
        cursor: pointer;
        transition: background-color 0.3s, transform 0.2s;
      }
      .button:hover {
        background-color: #45a049;
      }
      .button:active {
        transform: scale(0.95);
      }
    `;

    // Create the button element
    const button = document.createElement('button');
    button.className = 'button';
    button.textContent = 'Click Me';

    // Return the elements (style and button)
    return { style, button };
  }

  // Expose the function to the global scope
  global.buttonModule = {
    createButton,
  };
})(window);
Enter fullscreen mode Exit fullscreen mode

example1/root/index.html,
example2/root/index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Button Module</title>
  <script src="https://.../buttonModule.js"></script>
</head>
<body>
  <div id="wrapper"></div>
  <script>
    // Use the buttonModule
    const { style, button } = buttonModule.createButton();
    const wrapper = document.getElementById("wrapper");
    wrapper.append(style); // Attach styles to the document
    wrapper.append(button); // Add the button to the page
  </script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

这里我们通过一个与我们两个站点都不相连的站点来连接模块。这个站点可以是同一个GitHub仓库。

特点(优势):

  • <script>无需额外设置,即可使用HTML标准标签轻松实现。
  • 无需像 Webpack 或 Vite 那样的现代工具或配置。
  • 适用于小型单页应用程序或快速实验。
  • 设置简单,开发速度更快。
  • 可以无缝集成到已经依赖全局变量的现有项目中。

缺点:

  • 如果组件很多,就会有上千个脚本,这使得该方法只适合单次使用。
  • 将变量或对象添加到全局作用域,增加了命名冲突的风险。
  • 使用多个脚本时很难避免冲突。
  • 这使得项目更难扩展或重构。
  • 脚本的运行依赖于正确的加载顺序,这需要手动管理。
  • 维护性较差,且不符合当前的最佳实践。

🌐 2. 使用第三方库并将组件迁移到 API

对于这种方法,我们将使用像HTML这样的模块。它允许您使用基于对象的简单模板从服务器连接组件。首先,让我们将组件发送到服务器。创建一个单独的文件HTML并通过 API 请求将其送达。该文件将.html如下所示:

button.html

<button class="button">Click Me</button>
<style>
  .button {
    background-color: #4caf50;
    color: white;
    border: none;
    padding: 12px 24px;
    text-align: center;
    text-decoration: none;
    font-size: 16px;
    border-radius: 5px;
    cursor: pointer;
    transition: background-color 0.3s, transform 0.2s;
  }

  .button:hover {
    background-color: #45a049;
  }

  .button:active {
    transform: scale(0.95);
  }
</style>
Enter fullscreen mode Exit fullscreen mode

之后,我们需要将这个文件传输到服务器。后端假设使用 Node.js。我们将使用 express.js,它是目前最流行的 API 开发框架之一。首先,我们需要设置接收组件的路由:

buttonController.js

const express = require("express");
const expressRouter = express.Router();
const path = require("path");

const buttonController = (req, res) => {
  res.sendFile(path.join(__dirname, "../button.html"));
};

expressRouter.use("/getButton", buttonController);
Enter fullscreen mode Exit fullscreen mode

app.js

const express = require("express");
const path = require("path");
const bodyParser = require("body-parser");
const cors = require("cors");
const PORT = 8000;
const app = express();
const routes = require("./routes/buttonController");

app.use(bodyParser.urlencoded({ extended: false }));
app.use(cors({ origin: true, credentials: true }));

app.set(express.static(path.join(__dirname, "src")));

app.use("/api", routes);

app.listen(PORT);
Enter fullscreen mode Exit fullscreen mode

之后,我们将拥有一个可以轻松访问该组件的路径。我们在网站上连接了 HTML。连接方式有多种,我们来看几种主要的:

通过脚本

<script src="https://unpkg.com/json5/dist/index.js"></script>
<script src="https://unpkg.com/hmpl-js/dist/hmpl.min.js"></script>
<script src="https://unpkg.com/dompurify/dist/purify.min.js"></script>
Enter fullscreen mode Exit fullscreen mode

通过进口

import hmpl from "hmpl-js";
Enter fullscreen mode Exit fullscreen mode

我们使用方法 1,因为 index.html 是我们网站的默认文件。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Button Module</title>
  </head>
  <body>
    <script src="https://unpkg.com/json5/dist/index.js"></script>
    <script src="https://unpkg.com/hmpl-js/dist/hmpl.min.js">
    <script src="https://unpkg.com/dompurify/dist/purify.min.js"> 
    </script>
</script>
    <script>
      const templateFn = hmpl.compile(
        `<div id="wrapper">
          {{#request src="https://.../api/getButton"}}
          {{/request}}
        </div>`
      );
      const btnWrapper = templateFn().response;
      document.body.append(btnWrapper);
    </script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

这里我们做的几乎和第一种方法一样,但诀窍在于现在你可以安全地重用该组件。比如说,你可以这样做:

const btnWrapper1 = templateFn().response;
const btnWrapper2 = templateFn().response;
Enter fullscreen mode Exit fullscreen mode

此外,该模块还提供了许多附加功能——指示器、请求错误处理等等。由于该模块基于 fetch,因此您可以有效地自定义请求并执行更多操作。

特点(优势):

  • 组件重用
  • 适用于包含数千个组件的小型和大型应用。
  • 大量功能专门针对这种面向服务器的客户端组件显示方式。
  • 使用灵活

缺点:

  • 连接两个脚本文件
  • 创建额外的 API

这种方法某种程度上实现了 SSR 方法,但在客户端缺少了关键要素——机器人可见性,但除此之外,它是一种很棒的方法,可以简化问题的解决。


✅ 结论

根据具体情况,您可以选择第一种方法或第二种方法。第一种方法可以让您完全掌控整个过程,但如果您需要处理多个组件,这种方法就不太合适了,因为您需要不断地导入文件,这并不理想。


感谢大家的阅读!希望这篇文章对你们有所帮助❤️!

PS:也别忘了帮我给HMPL点赞哦!

🌱 星级 HMPL

文章来源:https://dev.to/anthonymax/reusable-components-across-multiple-sites-from-design-system-to-deployment-21mp