目录

静态站使用 Vite + EJS 实现 HTML 模板复用与变量注入

在开发多页面静态站点(如公司官网、产品文档或活动页)时,直接使用原生 HTML 常常会遇到重复劳动的问题:页眉、页脚、导航栏等公共部分需要在每个页面重复书写,如果要修改,就必须手动同步到多个文件,既费时又容易出错。

嗨,我是芦苇Z。今天说说使用 ViteEJS 模板引擎,为静态 HTML 项目引入模块化和集中管理的开发方式。

完成后,你将掌握:

  • 如何把公共 HTML 抽离为独立模板。
  • 如何集中管理页面元数据和多语言文案。
  • 如何在 Vite 中集成 EJS 并自动化配置多页面入口。
  • 如何处理 CSS、JavaScript 和图片等静态资源。
  • 如何启动开发服务器和构建生产版本。

确保你已安装:

  • Node.js(推荐 18+
  • 包管理器(npm / pnpm / yarn)
  1. 创建 Vite 项目:

    npm create vite@latest my-static-site -- --template vanilla
    cd my-static-site
  2. 安装依赖:

    npm install
  3. 安装 EJS 插件:

    npm install ejs vite-plugin-ejs -D

我们将 页面模板片段数据静态资源 分开存放,使结构更清晰:

my-static-site/
├── src/
│   ├── assets/               # CSS / JS / 图片等资源
│   │   └── main.css
│   ├── data/                 # 全站数据
│   │   └── siteData.js
│   ├── pages/                # 页面 HTML
│   │   ├── index.html
│   │   └── zh.html
│   └── partials/             # 可复用模板片段
│       ├── head.html
│       ├── footer.html
│       └── language-selector.html
├── vite.config.js
├── package.json
└── ...

vite.config.js 中,我们不仅要添加 EJS 插件,还要 自动扫描 src/pages 目录下的所有 HTML 文件作为多页面入口

import { defineConfig } from 'vite';
import { ViteEjsPlugin } from 'vite-plugin-ejs';
import { resolve } from 'path';
import fs from 'fs';
import siteData from './src/data/siteData.js';

// 自动扫描 src/pages 下的所有 HTML 文件
const pagesDir = resolve(__dirname, 'src/pages');
const entryPoints = fs.readdirSync(pagesDir)
  .filter(file => file.endsWith('.html'))
  .reduce((acc, file) => {
    const name = file.replace(/\.html$/, '');
    acc[name] = resolve(pagesDir, file);
    return acc;
  }, {});

export default defineConfig({
  root: pagesDir,
  plugins: [
    ViteEjsPlugin(siteData, {
      root: resolve(__dirname, 'src/partials'),
    }),
  ],
  build: {
    outDir: '../../dist',
    emptyOutDir: true,
    rollupOptions: {
      input: entryPoints,
    },
  },
  base: './',
});

说明

  • root: 'src/pages':Vite 的根目录,开发时直接访问 http://localhost:5173/ 对应 index.htmlhttp://localhost:5173/zh.html 对应 zh.html
  • 使用 fs 动态生成 rollupOptions.input,避免手动维护入口。
  • base: './' 确保构建后资源路径为相对路径,可部署在任意目录下。

src/data/siteData.js 中定义全站和页面数据,适合管理 SEO 元信息多语言文案

export default {
  global: {
    siteName: "My Example Site",
    author: "芦苇Z",
  },
  pages: {
    index: {
      lang: 'en',
      title: 'Home',
      description: 'Welcome to our amazing static site built with Vite and EJS!',
      keywords: 'vite, ejs, static site, homepage',
      greeting: 'Welcome',
    },
    zh: {
      lang: 'zh-CN',
      title: '首页',
      description: '欢迎来到我们用 Vite 和 EJS 构建的静态网站!',
      keywords: 'Vite, EJS, 静态站点, 首页',
      greeting: '欢迎',
    },
  },
};
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="<%= page.description %>">
<meta name="keywords" content="<%= page.keywords %>">
<title><%= page.title %> | <%= global.siteName %></title>
<link rel="stylesheet" href="../assets/main.css">
<footer>
  <p>版权所有 © 2025 - <%= global.author %></p>
</footer>
<div class="language-selector">
  <label for="language-select">Language:</label>
  <select id="language-select" onchange="location = this.value;">
    <option value="./index.html" <%= page.lang === 'en' ? 'selected' : '' %>>English</option>
    <option value="./zh.html" <%= page.lang === 'zh-CN' ? 'selected' : '' %>>简体中文</option>
  </select>
</div>
body {
  font-family: sans-serif;
  text-align: center;
  background-color: #f0f0f0;
}

footer {
  margin-top: 2rem;
  font-size: 0.9em;
  color: #666;
}
<!DOCTYPE html>
<html lang="<%= pages.index.lang %>">
<head>
  <%- include('head', { global, page: pages.index }) %>
</head>
<body>
  <h1><%= pages.index.greeting %></h1>
  <%- include('language-selector', { page: pages.index }) %>
  <%- include('footer', { global }) %>
</body>
</html>
<!DOCTYPE html>
<html lang="<%= pages.zh.lang %>">
<head>
  <%- include('head', { global, page: pages.zh }) %>
</head>
<body>
  <h1><%= pages.zh.greeting %></h1>
  <%- include('language-selector', { page: pages.zh }) %>
  <%- include('footer', { global }) %>
</body>
</html>

语法提示

  • <%- ... %>:不转义输出,适合引入模板。
  • <%= ... %>:转义输出文本,更安全。

开发模式:

npm run dev

访问:

  • http://localhost:5173/index.html
  • http://localhost:5173/zh.htmlzh.html

构建生产环境:

npm run build

产物会生成在 dist/ 文件夹,可直接部署到任意静态托管平台。

  1. 动态导航菜单
    siteData.js 定义菜单数组,在模板中循环渲染,并根据当前页面高亮。

  2. 主题变量注入
    在数据文件中定义颜色,在 <style> 标签里输出为 --primary-color 等 CSS 自定义属性,实现换肤。

  3. 更多静态资源管理

    • 图片:直接用 <img> 引入,Vite 会自动优化。
    • JS:用 <script type="module" src="../assets/main.js"></script> 引入即可。

通过 Vite + EJS,我们实现了高效的静态站点开发流程:

  • 组件化:公共 UI 片段抽离,避免重复修改。
  • 数据驱动:内容与结构分离,便于维护与多语言支持。
  • 工程化:享受 Vite 的热更新与资源优化。
  • 自动化:新增页面无需修改配置。

适合的应用场景:

  • 多语言企业官网
  • 营销落地页
  • 小型文档站点

如需更复杂的交互,可考虑 Astro / Vue / React。但对中小型静态项目,Vite + EJS 是轻量、高效、易维护的最佳选择。