基于 inertia-go + Svelte 的简单示例

基于 inertia-go + Svelte 的简单示例

这个示例实现一个基础的 "欢迎页面 + 计数器" 功能,包含后端 Go 服务(inertia-go)和前端 Svelte 页面,完整流程如下:


一、项目结构

inertia-svelte-demo/
├── go.mod
├── go.sum
├── main.go          # Go 后端(inertia-go)
├── frontend/        # Svelte 前端
│   ├── package.json
│   ├── vite.config.js
│   ├── src/
│   │   ├── app.js
│   │   ├── pages/
│   │   │   ├── Welcome.svelte  # 欢迎页(含计数器)
│   │   ├── inertia.js          # Inertia Svelte 适配器

二、后端实现(Go + inertia-go)

1. 初始化 Go 模块

mkdir inertia-svelte-demo && cd inertia-svelte-demo
go mod init inertia-svelte-demo
go get github.com/petaki/inertia-go
go get github.com/labstack/echo/v4  # 用 Echo 作为 Web 框架(inertia-go 兼容任意框架)

2. main.go 代码

package main

import (
	"embed"
	"strconv"

	"github.com/labstack/echo/v4"
	"github.com/petaki/inertia-go"
)

//go:embed frontend/dist
var templates embed.FS

func main() {
	// 初始化 Echo
	e := echo.New()

	// 配置 Inertia
	assetVersion := "1.0.0"                    // 前端资源版本(更新时触发重新加载)
	rootTemplate := "frontend/dist/index.html" // Inertia Go 模板(使用 Go template 语法)
	assetsPath := "./frontend/dist"            // 前端静态资源目录

	// 创建 Inertia 实例(适配 Echo 框架)
	// New(url, rootTemplate, version string, templateFS ...fs.FS)
	inertiaManager := inertia.New("http://localhost:3000", rootTemplate, assetVersion, templates)

	// 静态文件服务(提供前端构建后的 JS/CSS)
	e.Static("/assets", assetsPath+"/assets")

	// 测试端点
	e.GET("/test", func(c echo.Context) error {
		return c.String(200, "Hello from test endpoint!")
	})

	// 核心:Inertia 处理器(处理前端页面渲染 + 数据传输)
	e.GET("/", func(c echo.Context) error {
		// 从请求参数获取 count(默认 0)
		countStr := c.QueryParam("count")
		count, _ := strconv.Atoi(countStr)
		if count < 0 {
			count = 0
		}

		// 向前端传递数据(Inertia 共享数据)
		err := inertiaManager.Render(c.Response(), c.Request(), "Welcome", map[string]any{
			"message": "Hello Inertia + Svelte!",
			"count":   count,
		})
		if err != nil {
			c.Logger().Error("Inertia Render error:", err)
		}
		return err
	})

	// 启动服务
	e.Logger.Fatal(e.Start(":3000"))
}

三、前端实现(Svelte + Inertia)

1. 初始化 Svelte 项目

mkdir -p frontend && cd frontend
npm init vite@latest . -- --template svelte
npm install @inertiajs/svelte @inertiajs/core

2. 配置 Vite(vite.config.js)

确保构建路径匹配后端的 assetsPath

import path from "node:path";
import { svelte } from "@sveltejs/vite-plugin-svelte";
import { defineConfig } from "vite";

export default defineConfig({
	plugins: [svelte()],
	build: {
		outDir: "./dist",
		assetsDir: "assets",
		manifest: true,
	},
	resolve: {
		alias: {
			"@": path.resolve(__dirname, "./src"),
		},
	},
	server: {
		proxy: {
			"/": {
				target: "http://localhost:3000",
				changeOrigin: true,
			},
		},
	},
});

3. Inertia 入口(src/inertia.js)

import "./app.css";
import { createInertiaApp } from "@inertiajs/svelte";
import { mount } from "svelte";

// 使用Vite的import.meta.glob动态导入所有页面组件
const pages = import.meta.glob("./pages/**/*.svelte");

createInertiaApp({
	resolve: async (name) => {
		const pagePath = `./pages/${name}.svelte`;

		if (!(pagePath in pages)) {
			console.error(
				`Page not found: ${name}. Available pages:`,
				Object.keys(pages).map((p) =>
					p.replace("./pages/", "").replace(".svelte", ""),
				),
			);
			throw new Error(`Page not found: ${name}`);
		}

		const page = await pages[pagePath]();
		return page;
	},
	setup({ el, App, props }) {
		mount(App, { target: el, props });
	},
});

5. Svelte 页面(src/pages/Welcome.svelte)

实现计数器功能,通过 Inertia 与后端交互:

<script>
import { router } from "@inertiajs/svelte";

// 接收后端传递的 props
export let message;
export let count;

// 计数器增加
function increment() {
	// 通过 Inertia 导航(不刷新页面)
	router.visit(`/?count=${count + 1}`, {
		preserveState: false,
	});
}

// 计数器减少
function decrement() {
	router.visit(`/?count=${Math.max(0, count - 1)}`, {
		preserveState: false,
	});
}
</script>

<main class="container">
    <h1>{message}</h1>

    <div class="counter">
        <button on:click={decrement}>-</button>
        <span>Count: {count}</span>
        <button on:click={increment}>+</button>
    </div>
</main>

<style>
    .container {
        max-width: 800px;
        margin: 50px auto;
        text-align: center;
        font-family: Arial, sans-serif;
    }

    .counter {
        margin-top: 30px;
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 20px;
        font-size: 24px;
    }

    button {
        padding: 10px 20px;
        font-size: 24px;
        cursor: pointer;
        border: none;
        border-radius: 5px;
        background: #007bff;
        color: white;
    }

    button:hover {
        background: #0056b3;
    }
</style>

6. 调整 index.html(根目录)

修改前端根模板,适配 Inertia 渲染:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <link rel="icon" type="image/svg+xml" href="/assets/favicon.svg" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Inertia + Svelte + Go</title>
</head>
<body>
  <!-- Inertia 挂载点 -->
  <div id="app" data-page="{{ .page | marshal }}"></div>
  <!-- 前端构建后的 JS -->
  <script type="module" src="/src/main.js"></script>
</body>
</html>

四、运行项目

1. 构建前端

cd frontend
npm run build  # 生成 dist 目录(后端会读取此目录)

2. 启动后端

cd ..  # 回到项目根目录
go run main.go

3. 访问页面

打开浏览器访问 http://localhost:3000,即可看到:

  • 欢迎语(来自后端传递的 message
  • 计数器(点击 +/- 按钮,通过 Inertia 无刷新更新 count,数据由后端处理)

核心说明

  1. Inertia 核心逻辑

    • 后端通过 inertiaManager.Render 传递页面名称(Welcome)和 props(message/count
    • 前端通过 createInertiaApp 解析页面组件,并接收后端 props
    • 前端导航使用 router.visit 实现无刷新页面跳转,替代传统的页面刷新
  2. 开发优化

    • 前端开发时可运行 npm run dev,通过 Vite 代理请求到后端,实现热更新
    • 后端修改后重启 go run main.go 即可
  3. 扩展方向:

    • 添加更多页面(如 About.svelte),后端新增路由并渲染对应页面
    • 使用 Inertia 共享数据(inertiaManager.Share)实现全局 props
    • 集成表单提交(router.post/router.put)实现数据提交

注意:
前端的@inertiajs/core@inertiajs/progress@inertiajs/svelte版本不能太高,否则总是运行失败!我调试了大半天才找出问题所在。

{
	"name": "frontend",
	"private": true,
	"version": "0.0.0",
	"type": "module",
	"scripts": {
		"dev": "vite",
		"build": "vite build",
		"preview": "vite preview"
	},
	"devDependencies": {
		"@sveltejs/vite-plugin-svelte": "^7.0.0",
		"@tailwindcss/vite": "4.2.2",
		"svelte": "^5.55.3",
		"tailwindcss": "4.2.2",
		"vite": "^8.0.8"
	},
	"dependencies": {
		"@inertiajs/core": "^1.0.13",
		"@inertiajs/progress": "^0.2.7",
		"@inertiajs/svelte": "^1.0.9"
	},
	"packageManager": "pnpm@10.33.0+sha512.10568bb4a6afb58c9eb3630da90cc9516417abebd3fabbe6739f0ae795728da1491e9db5a544c76ad8eb7570f5c4bb3d6c637b2cb41bfdcdb47fa823c8649319"
}
posted @ 2026-04-11 21:20  卓能文  阅读(2)  评论(0)    收藏  举报