使用 vite 开发原生 html 网页

需要解决的问题

  • 打包目录结构不变
  • 可以复用 html 结构,打包结果为完整的 html
  • 打包 js、css 、图片等资源文件,文件名不能改变,代码不要拆分和拼接
  • 使用 tailwindcss
  • build 结果可直接给php后端使用

项目目录

  • src
    • components
    • style
      • js
      • css
      • images
      • lib 第三方库(jquery、swiper、video.js等)
    • ...html 文件
  • packages.json
  • build.js
  • vite.config.js

使用 vite-plugin-handlebars 插件实现开发复用 html

javascript 复制代码
import { defineConfig } from "vite";
import handlebars from "vite-plugin-handlebars";

export default defineConfig({
  root: "src",
  plugins: [
    handlebars({
      // 组件目录
      partialDirectory: "src/components",
    }),
  ],
  server: {
    port: 3000,
  },
});
html 复制代码
// componentes - header
<header>aaa</header>

// index.html - 自动导入
{{> header }}

自定义打包,解决使用 vite 打包会修改资源文件目录以及文件名

javascript 复制代码
// build.js - 简单的构建脚本
import fs from "fs";
import path from "path";
import { glob } from "glob";
import Handlebars from "handlebars";

const __dirname = path.dirname(new URL(import.meta.url).pathname);

// 注册 components
function registerComponents() {
  const partialsDir = path.resolve(__dirname, "src/components");
  if (!fs.existsSync(partialsDir)) return;

  const partialFiles = glob.sync("src/components/**/*.hbs");
  partialFiles.forEach((file) => {
    const name = path.basename(file, ".hbs");
    const content = fs.readFileSync(file, "utf8");
    Handlebars.registerPartial(name, content);
  });
}

// 编译 HTML 文件
function compileHtmlFiles() {
  const htmlFiles = glob.sync("src/*.html");
  const context = {};

  // 确保 dist 目录存在
  if (!fs.existsSync("dist")) {
    fs.mkdirSync("dist", { recursive: true });
  }

  htmlFiles.forEach((file) => {
    const content = fs.readFileSync(file, "utf8");
    const template = Handlebars.compile(content);
    const html = template(context);

    const outputFile = path.join("dist", path.basename(file));
    fs.writeFileSync(outputFile, html);
    console.log(`✓ 编译完成: ${file} -> ${outputFile}`);
  });
}

// 复制 styles 目录
function copyStyles() {
  const stylesDir = path.resolve(__dirname, "src/styles");
  const distStylesDir = path.resolve(__dirname, "dist/styles");

  if (!fs.existsSync(stylesDir)) {
    console.log("⚠️  src/styles 目录不存在");
    return;
  }

  // 递归复制目录
  function copyDir(src, dest) {
    if (!fs.existsSync(dest)) {
      fs.mkdirSync(dest, { recursive: true });
    }

    const entries = fs.readdirSync(src, { withFileTypes: true });
    entries.forEach((entry) => {
      const srcPath = path.join(src, entry.name);
      const destPath = path.join(dest, entry.name);

      if (entry.isDirectory()) {
        copyDir(srcPath, destPath);
      } else {
        fs.copyFileSync(srcPath, destPath);
      }
    });
  }

  copyDir(stylesDir, distStylesDir);
  console.log("✓ styles 目录复制完成");
}

// 清空 dist 目录
function cleanDist() {
  if (fs.existsSync("dist")) {
    fs.rmSync("dist", { recursive: true, force: true });
  }
  console.log("✓ 清空 dist 目录");
}

// 主构建函数
function build() {
  console.log("🚀 开始构建...");

  cleanDist();
  registerComponents();
  compileHtmlFiles();
  copyStyles();

  console.log("✅ 构建完成!");
}

build();

配置 packages.json 打包命令

json 复制代码
{
  "name": "phant-ai-vite",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "npx concurrently \"vite\" \"npx @tailwindcss/cli -i ./input.css -o ./src/styles/css/output.css --watch\"",
    "tw": "npx @tailwindcss/cli -i ./input.css -o ./src/styles/css/output.css --watch",
    "build": "npx @tailwindcss/cli -i ./input.css -o ./src/styles/css/output.css && node build.js"
  },
  "devDependencies": {
    "@types/jquery": "^3.5.32",
    "glob": "^11.0.2",
    "handlebars": "^4.7.8",
    "vite": "^6.3.5",
    "vite-plugin-handlebars": "^2.0.0"
  },
  "dependencies": {
    "@tailwindcss/cli": "^4.1.8",
    "tailwindcss": "^4.1.8"
  }
}
相关推荐
TA远方1 天前
【HTML】JavaScript Canvas 图像截取与保存完整指南
前端·javascript·html·canvas·截图·截取
feixing_fx1 天前
选择器的威力——深入理解优先级计算与层叠规则
开发语言·前端·css·前端框架·html
星空1 天前
html\css\js入门
javascript·css·html
ShyanZh1 天前
【skill】HTML-PPT:36主题31布局的专业HTML演示文稿工作室
ai·html·powerpoint·html-ppt
烤代码的吐司君1 天前
Redis 服务配置与使用
前端·bootstrap·html
xinhuanjieyi2 天前
html修复游戏种太阳错误
前端·游戏·html
LaughingZhu2 天前
Product Hunt 每日热榜 | 2026-06-11
人工智能·经验分享·神经网络·html·产品运营
ShyanZh2 天前
【skill】HTML PPT Skill:用 Claude Code 一句话生成专业演示文稿
前端·ai·html·powerpoint·skill
m0_547722922 天前
从零搭建乒乓球比赛管理系统——Spring Boot + 原生 HTML 实战
spring boot·后端·html
在水一缸2 天前
重塑前端开发认知:当 AI 遇见 HTML 的“不合理有效性”
前端·人工智能·html·ai编程·claude·前端开发