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

客户端服务器端渲染:10 分钟内构建组件化落地页⏱️

客户端服务器端渲染:10 分钟内构建组件化落地页⏱️

如今,如果没有使用 Next.js 或 Nuxt.js,就无法想象一个现代大型项目会是什么样子。

但是,如果任务是快速创建这样的结构,那么这里描述的这种方法就非常适合。

今天,我们将创建一个包含 5 个组件的小型落地页应用程序,这些组件位于服务器上。

我们开始吧!

着陆页


📦 应用结构

我们的应用程序将具有与现代 SSR 应用程序类似的结构(当然,没有 BFF 等),但渲染将在客户端进行,并通过浏览器显示。

图表

我们的架构中没有数据库的概念,因为数据将存储在 HTML 文件中。但是,如果我们要在着陆页上进行注册,我们可能需要一个.json符合现代数据库要求的文件,但这个示例需要在 10 分钟内完成,因此没有必要扩展功能。

此外,为了将客户端连接到服务器,我们将连接一个模块,例如 HMPL:

🌱 查看 HMPL ★


👀 如何开始开发一款应用?

首先,我们创建两个文件global.cssglobal.js它们将包含那些不依赖于服务器返回的内容的样式和脚本。

global.css

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: Roboto, sans-serif;
}

body {
  line-height: 1.6;
  color: #333;
}

.container {
  width: 100%;
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 20px;
}

.section {
  padding: 80px 0;
  text-align: center;
}

.section h2 {
  font-size: 36px;
  margin-bottom: 30px;
}
Enter fullscreen mode Exit fullscreen mode

global.js

console.log("Global scripts loaded");
Enter fullscreen mode Exit fullscreen mode

因此,虽然可以不连接 global.js,但总的来说,如果我们有一些共同的 JavaScript 知识点,比如配置常量、实用函数等等,那将是一个很好的示例。

现在,我们将创建index.html 文件,并在其中连接着陆页所需的所有模块。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>My Landing Page</title>
    <link rel="stylesheet" href="global.css" />
  </head>
  <body>
    <script src="https://unpkg.com/json5/dist/index.min.js"></script>
    <script src="https://unpkg.com/dompurify/dist/purify.min.js"></script>
    <script src="https://unpkg.com/hmpl-js/dist/hmpl.min.js"></script>
    <script src="global.js"></script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

网站目前看起来是空的,所以我们来创建组件吧!


⚙️ 服务器配置

服务器端我们当然会选择 Node.js 平台。当然,你也可以选择其他平台,这对网站来说并非必要条件。框架方面,我们会使用 Express.js。

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 getRoutes = require("./routes/get");

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

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

app.get("/", (_, res) => {
  res.sendFile(path.join(__dirname, "src/index.html"));
});

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

app.listen(PORT, () => {
  console.log(`Server is running on http://localhost:${PORT}`);
});
Enter fullscreen mode Exit fullscreen mode

routes/get.js

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

const components = {
  title: "CTA",
  header: "Header",
  features: "Features",
  promo: "Promo",
  cta: "CTA",
  footer: "Footer",
};

Object.entries(components).forEach(([name, folder]) => {
  expressRouter.get(`/get-${name}-component`, (_, res) => {
    res.type("text/html");
    res.sendFile(path.join(__dirname, `../components/${folder}/index.html`));
  });
});

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

在介绍了几个 js 文件之后,我们现在可以在components文件夹中创建应用程序的各个部分了。

这些路线可以随意命名,但为了方便起见,我给它们起了名字。/api/get-${name}-component


⌨️ 编写第一个组件

我们先从横幅广告开始,因为这是我们在着陆页上的第一个内容模块。我们将直接从服务器路由的 URL 上添加它http://localhost:8000/api/get-features-component

components/Features/index.html

<div id="features-component">
  <section id="features" class="section features">
    <div class="container">
      <h2>Our Amazing Features</h2>
      <div class="features-grid">
        <div class="feature-card">
          <h3>Fast</h3>
          <p>Lightning fast performance that saves you time.</p>
        </div>
        <div class="feature-card">
          <h3>Simple</h3>
          <p>Easy to use interface with no learning curve.</p>
        </div>
        <div class="feature-card">
          <h3>Reliable</h3>
          <p>99.9% uptime guaranteed for your business.</p>
        </div>
      </div>
    </div>
  </section>
  <style>
    .features {
      background: #f9f9f9;
      padding: 80px 0;
      text-align: center;
    }
    .features h2 {
      font-size: 36px;
      margin-bottom: 30px;
    }
    .features-grid {
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      gap: 30px;
      margin-top: 50px;
    }
    .feature-card {
      background: white;
      padding: 30px;
      border-radius: 8px;
      box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
      opacity: 0;
      transform: translateY(20px);
      transition: all 0.6s ease;
    }
    .feature-card h3 {
      margin-bottom: 15px;
      font-size: 22px;
    }
    @media (max-width: 768px) {
      .features-grid {
        grid-template-columns: 1fr;
      }
    }
  </style>
  <script>
    const animateFeatures = function () {
      const elements = document.querySelectorAll(
        "#features-component .feature-card"
      );
      elements.forEach((element) => {
        const elementPosition = element.getBoundingClientRect().top;
        const screenPosition = window.innerHeight / 1.3;

        if (elementPosition < screenPosition) {
          element.style.opacity = "1";
          element.style.transform = "translateY(0)";
        }
      });
    };

    window.addEventListener("load", animateFeatures);
    window.addEventListener("scroll", animateFeatures);
  </script>
</div>
Enter fullscreen mode Exit fullscreen mode

现在,让我们看看它会是什么样子:

特征

是的,服务器端的组件看起来不会很好,因为我们编写的样式仅针对它。但是当我们把所有这些部署到生产网站时,所有字体和其他元素都会同步,网站看起来就会很好。


✅ 让我们把剩下的部分写完。

一切运行正常,现在我们可以完成所有组件的编写,并使用 HTML 将它们连接到我们的系统中index.html。我们还将完成以下组件的编写:

  1. 标题:http://localhost:8000/api/get-header-component
  2. 促销:http://localhost:8000/api/get-promo-component
  3. 行动号召:http://localhost:8000/api/get-cta-component
  4. 页脚:http://localhost:8000/api/get-footer-component

你可以在本站的代码仓库中找到完整的列表,我不会直接复制粘贴代码,因为那样文章篇幅会非常长。代码仓库的链接如下。


🔗 将所有内容连接到我们的网站

让我们将服务器请求的组成部分添加到我们的 html 中,并将生成的 html 附加到其中。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>My Landing Page</title>
    <link rel="stylesheet" href="global.css" />
  </head>
  <body>
    <script src="https://unpkg.com/json5/dist/index.min.js"></script>
    <script src="https://unpkg.com/dompurify/dist/purify.min.js"></script>
    <script src="https://unpkg.com/hmpl-js/dist/hmpl.min.js"></script>
    <script src="global.js"></script>
    <script>
      const body = document.querySelector("body");
      const template = `
        <main>
            <!-- Header Component -->
            {{#request src="http://localhost:8000/api/get-header-component"}}{{/request}}
            <!-- Features Component -->
            {{#request src="http://localhost:8000/api/get-features-component"}}{{/request}}
            <!-- Promo Component -->
            {{#request src="http://localhost:8000/api/get-promo-component"}}{{/request}}
            <!-- CTA Component -->
            {{#request src="http://localhost:8000/api/get-cta-component"}}{{/request}}
            <!-- Footer Component -->
            {{#request src="http://localhost:8000/api/get-footer-component"}}{{/request}}
        </main>
      `;
      const { response } = hmpl.compile(template)();
      body.append(response);
    </script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

值得注意的是,您可以通过interval属性为我们的组件添加加载器,或者为促销活动添加间隔请求。


🖥️结果

现在,让我们来看看我们花了十分钟(稍微多一点)的时间完成了什么:

结果

在我看来,考虑到设计风格等方面并没有特别讲究,这看起来非常不错。


🖋️结论

在本文中,我们仅用 10 分钟就创建了一个小巧但非常酷炫且功能强大的应用程序,而且只使用了客户端的 SSR 技术。虽然使用 Next.js 也能实现同样的功能,但问题在于我们需要集成整个框架并完全依赖其结构,而在这里,我们只需集成一个模块就能获得相同的结果(无需搜索引擎爬虫)。

另外,如果您能用星星支持一下这个项目就太好了!谢谢❤️!

💎 星级 HMPL ★


🗄️ 仓库链接

您可以在这里找到完整的代码:https://github.com/hmpl-language/examples/tree/main/landing


非常感谢大家阅读这篇文章!

谢谢

文章来源:https://dev.to/hmpljs/client-side-ssr-build-a-component-based-landing-page-in-10-minutes-2784