0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Goだけでフルスタック開発する新しい選択肢 ― Marionette

0
Last updated at Posted at 2026-05-01

始めに

Webアプリ開発って、正直つらくないですか?

  • バックエンド(Go / Python / etc)
  • フロントエンド(React / Vue / etc)
  • API設計
  • 状態管理

「やりたいことはシンプルなのに、技術スタックが重すぎる」

そんな違和感から、Goだけで完結するフルスタックフレームワークを作りました。

Marionetteとは

Marionetteは、

Goコードからフロントエンドを“操る”フルスタックフレームワーク

です。

名前の由来は「操り人形(Marionette)」
GoがUIを操作する様子が、そのままコンセプトになっています。

コンセプト

Marionetteの思想はかなりシンプルです。

✅ 1. Goだけで完結

  • フロントエンド
  • バックエンド
  • 状態管理
  • 通信

すべてGoで記述できます。

👉 フロントエンド言語不要

✅ 2. 宣言的UI(React風)

GoでUIをこう書けます:

mf.Stack(
    mf.PageHeader(...),
    mf.ActionForm(...),
    mf.Region(...),
)
  • JSXなし
  • TypeScript不要
  • でも構造はReactライク

✅ 3. htmxベースの部分更新

フルSPAではない

サーバー駆動UI

必要な部分だけ更新

👉 シンプルで高速

✅ 4. Hot Reload対応

開発時は変更が即反映されます。

何が嬉しいのか?

従来

項目 技術
フロント React
API Go / Node
状態管理 Redux
通信 REST / GraphQL

👉 分断される

Marionette

項目 技術
すべて Go

👉 1つの言語で統一

サンプル:タスク管理アプリ

インストール

go get github.com/YoshihideShirai/marionette@latest

main.go

package main

import (
	"strings"

	mb "github.com/YoshihideShirai/marionette/backend"
	mf "github.com/YoshihideShirai/marionette/frontend"
)

func main() {
	app := buildApp("Simple Tasks", "Marionette end-to-end sample")
	if err := app.Run("127.0.0.1:8081"); err != nil {
		panic(err)
	}
}

type task struct {
	ID   int
	Name string
}

func buildApp(title, description string) *mb.App {
	app := mb.New()
	app.SetGlobal("tasks", []task{})
	app.SetGlobal("nextID", 1)

	app.Page("/", func(ctx *mb.Context) mf.Node {
		return page(ctx, title, description)
	}, mb.WithTitle(title))

	app.Action("tasks/create", func(ctx *mb.Context) mf.Node {
		name := strings.TrimSpace(ctx.FormValue("name"))
		if name != "" {
			nextID := ctx.IncrementGlobalInt("nextID", 1) - 1
			ctx.UpdateGlobal("tasks", func(old any) any {
				tasks := append([]task(nil), old.([]task)...)
				return append(tasks, task{ID: nextID, Name: name})
			})
		}
		return taskList(ctx.GetGlobal("tasks").([]task))
	})

	return app
}

func page(ctx *mb.Context, title, description string) mf.Node {
	tasks := ctx.GetGlobal("tasks").([]task)
	return mf.Container(mf.ContainerProps{MaxWidth: "4xl", Centered: true},
		mf.Stack(mf.StackProps{Direction: "column", Gap: "6"},
			mf.PageHeader(mf.PageHeaderProps{
				Title:       title,
				Description: description,
			}),
			mf.ActionForm(mf.ActionFormProps{
				Action: "/tasks/create",
				Target: "#task-list",
				Swap:   "innerHTML",
				Props:  mf.ComponentProps{Class: "space-y-3"},
			},
				mf.FormRow(mf.FormRowProps{
					ID:       "task-name",
					Label:    "Task",
					Required: true,
					Control: mf.TextField(mf.TextFieldProps{
						ID:          "task-name",
						Name:        "name",
						Placeholder: "Task name",
						Required:    true,
					}),
				}),
				mf.SubmitButton("Add Task", mf.ComponentProps{}),
			),
			mf.Region(mf.RegionProps{ID: "task-list"}, taskList(tasks)),
		),
	)
}

func taskList(tasks []task) mf.Node {
	if len(tasks) == 0 {
		return mf.EmptyState(mf.EmptyStateProps{Title: "No tasks yet"})
	}

	rows := make([]mf.TableComponentRow, 0, len(tasks))
	for _, t := range tasks {
		rows = append(rows, mf.TableRowValues(t.ID, t.Name))
	}
	return mf.Table(mf.TableProps{
		Columns: []mf.TableColumn{{Label: "ID"}, {Label: "Name"}},
		Rows:    rows,
	})
}

ポイント解説

🧠 状態管理

app.SetGlobal("tasks", ...)
ctx.GetGlobal("tasks")

👉 サーバー側に状態を持つ

🔁 UI更新

app.Action("tasks/create", ...)

👉 アクション実行 → 部分更新

🧩 UI構築

mf.Container(
mf.Stack(...),
)

👉 完全にGoでUI構築

どんな用途に向いているか?

👍 向いている

  • 管理画面
  • 内製ツール
  • プロトタイプ
  • 小〜中規模アプリ
  • Streamlitの代替

🤔 向いていない

  • 大規模SPA
  • 超リッチUI
  • フロント分業前提のチーム

類似技術との比較

技術 特徴
Streamlit PythonでUI、でも自由度低い
React 高機能、でも重い
HTMX シンプルだが構造管理が弱い
Marionette Goで統一 + UI DSL

今後の展望

  • コンポーネント拡張
  • テンプレート機能
  • デプロイ周りの整備
  • WebView対応強化

まとめ

Marionetteは、

「GoだけでWebアプリを書きたい」

というニーズに対する、かなりストレートな解です。

  • フロントエンド 不要
  • API設計 不要
  • 状態管理も統一

👉 思考コストが劇的に下がる

おわりに

まだまだ発展途上ですが、
コンセプトとしてはかなり面白い領域だと思っています。

ぜひ触ってみてください👇

👉 https://github.com/YoshihideShirai/marionette


フィードバック・Issue・Starお待ちしてます 🙌

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?