跨多个站点的可复用组件:从设计系统到部署 🔥
由 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>
网站上显示的结果如下:
现在,假设有两个网站需要使用相同的组件。我们暂且称它们为 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);
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>
这里我们通过一个与我们两个站点都不相连的站点来连接模块。这个站点可以是同一个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>
之后,我们需要将这个文件传输到服务器。后端假设使用 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);
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);
之后,我们将拥有一个可以轻松访问该组件的路径。我们在网站上连接了 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>
通过进口
import hmpl from "hmpl-js";
我们使用方法 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>
这里我们做的几乎和第一种方法一样,但诀窍在于现在你可以安全地重用该组件。比如说,你可以这样做:
const btnWrapper1 = templateFn().response;
const btnWrapper2 = templateFn().response;
此外,该模块还提供了许多附加功能——指示器、请求错误处理等等。由于该模块基于 fetch,因此您可以有效地自定义请求并执行更多操作。
特点(优势):
- 组件重用
- 适用于包含数千个组件的小型和大型应用。
- 大量功能专门针对这种面向服务器的客户端组件显示方式。
- 使用灵活
缺点:
- 连接两个脚本文件
- 创建额外的 API
这种方法某种程度上实现了 SSR 方法,但在客户端缺少了关键要素——机器人可见性,但除此之外,它是一种很棒的方法,可以简化问题的解决。
✅ 结论
根据具体情况,您可以选择第一种方法或第二种方法。第一种方法可以让您完全掌控整个过程,但如果您需要处理多个组件,这种方法就不太合适了,因为您需要不断地导入文件,这并不理想。
感谢大家的阅读!希望这篇文章对你们有所帮助❤️!
PS:也别忘了帮我给HMPL点赞哦!
文章来源:https://dev.to/anthonymax/reusable-components-across-multiple-sites-from-design-system-to-deployment-21mp

