构建一个与框架无关的 Ruby gem(并确保它不会损坏)
Building a framework-agnostic Ruby gem (and making sure it doesn't break)

原始链接: https://newsletter.masilotti.com/p/on-building-a-framework-agnostic

Ruby Native 旨在将 Rails 应用连接到原生移动体验,同时支持 ERB、React 和 Vue。管理这种复杂性的关键在于一种与框架无关的方法:原生应用读取带有 `data-native-*` 属性的简单 HTML 元素,避免直接的框架依赖。 这允许每个框架(ERB、React、Vue)以其自然的方式生成必要的 HTML——在 ERB 中使用块,在 React 中使用组件和 props 等——而无需对原生端进行更改。精简的组件可以最大限度地减少特定于框架的逻辑,从而减少潜在问题。 为了防止跨框架的回归,作者为使用每个框架构建的演示应用实施了 XCUITest 测试。这些测试验证*用户可见的*原生 UI,而不是底层的 HTML 或 JavaScript,确保更改不会无意中破坏其他环境中的功能。 有趣的是,这种方法也为在 Rails 之外的框架中使用 Ruby Native 提供了可能性,例如 Sinatra,因为其核心机制仅依赖于标准的 HTML。来自积极使用每个框架的开发者的持续反馈对于完善 API 并确保其“感觉正确”至关重要。

黑客新闻 新的 | 过去的 | 评论 | 提问 | 展示 | 招聘 | 提交 登录 构建一个与框架无关的 Ruby gem (以及确保它不会损坏) (masilotti.com) 10 分,joemasilotti 发表于 1 小时前 | 隐藏 | 过去的 | 收藏 | 1 条评论 帮助 vmsp 发表于 19 分钟前 [–] 有趣的库。有点像 Hotwire Native 回复 指南 | 常见问题 | 列表 | API | 安全 | 法律 | 申请 YC | 联系 搜索:
相关文章

原文

Ruby Native needs to work with ERB, React, and Vue. That’s three frameworks, three sets of conventions, and three ways developers expect an API to feel. And every new feature needs to ship across all of them without breaking the others.

This week I added a native navbar, and it was the first real test of whether this approach scales. Here’s what I’ve learned about keeping an API clean across frameworks, and how I’m catching regressions.

When I started Ruby Native, it was ERB-only. The tab bar, push notifications, and forms all used the same pattern: render a hidden HTML element with data-native-* attributes. The native app detects these “signal elements” via a MutationObserver and translates them into real native UI.

For example, the native navbar is just this:

Hidden divs, that’s it! The native app doesn’t know what generated them. It just reads the DOM.

This turned out to be the most important decision in the entire project. Because when it came time to support React and Vue, I didn’t have to change anything on the native side. I just needed new ways to produce the same HTML.

ERB developers expect blocks and builders. React developers expect components and props. If you force one framework’s patterns onto another, the API feels wrong even if it works.

Here’s the same navbar in ERB:

And in React:

Different syntax. Same output. The ERB version uses Ruby’s block pattern with a builder that yields menu items. The React version uses component composition with props. Both feel right in their own context.

The React components themselves are intentionally thin. Here’s NativeButton:

No state or effects, just a function that turns props into data attributes. The less framework-specific logic lives in these components, the less can go wrong.

I’m a Rails and ERB developer. I don’t reach for React or Vue on my own projects. When I built the Inertia support, I leaned heavily on early Ruby Native adopters who use Inertia every day. They told me when something felt off, when a prop name was confusing, or when a pattern didn’t match how they structure their apps.

This is something I think library authors underestimate. You can read the docs and follow the conventions, but there’s a feel to a framework that only comes from daily use. Having people who live in that framework test your API is the difference between “technically works” and “feels right.”

Supporting multiple frameworks creates a real regression problem. A change to the JavaScript bridge could break React but not ERB. A new signal element might work in Hotwire but lead to a race condition in Inertia. And I don’t want to manually check every combination on every change.

So I set up XCUITest tests for each of the three demo apps: Beervana (Hotwire/ERB), Coffee (React/Inertia), and Habits (Vue/Inertia). Each test suite boots the real Rails server and exercises the actual native UI.

The tests don’t assert on HTML or JavaScript. They assert on what the user sees:

  • Does the tab bar appear after sign-in?

  • Does the navbar title update when I switch tabs?

  • Does the menu button open with the right items?

Here’s what the Coffee (React) test looks like for the navbar menu:

And the equivalent Beervana (Hotwire) test for tab navigation:

Both tests are framework-agnostic. They have no idea what’s rendering the HTML. They just verify the native UI works. If I break something in the JavaScript bridge, these tests catch it regardless of which framework exposed the problem.

I haven’t tried it yet, but someone recently asked if Ruby Native works outside of Rails. With Sinatra, for example. And the honest answer is: it should. The signal elements are just HTML. The native app reads the DOM. There’s nothing Rails-specific about the data attributes themselves.

The Ruby gem’s helpers are Rails-specific, sure. But the React and Vue components aren’t. And you could render the raw HTML from any templating language.

That question made me realize the early decision to build on data attributes rather than framework hooks is paying off in ways I didn’t plan for. It’s one more framework to think about. But the fact that it’s even plausible tells me the abstraction is at the right layer.

If you’re using Inertia with Rails and want to try Ruby Native, I’d love your feedback. The people who use these frameworks daily are the ones who make the API better.

联系我们 contact @ memedata.com