Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: First good release. #2

Merged
merged 21 commits into from
Feb 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: CI

on:
pull_request:
branches: [ main ]

jobs:
tests:
name: Run tests (Elixir ${{ matrix.elixir }}, OTP ${{ matrix.otp }})

strategy:
matrix:
include:
- os: ubuntu-latest
elixir: 1.18
otp: 27

runs-on: ${{ matrix.os }}
env:
MIX_ENV: test

steps:
- name: Checkout
uses: actions/checkout@v4

- uses: oven-sh/setup-bun@v2
with:
bun-version: latest

- name: Set up Elixir
uses: erlef/setup-beam@v1
with:
otp-version: ${{ matrix.otp }}
elixir-version: ${{ matrix.elixir }}

- name: Install dependencies
run: |
mix deps.get
bun install

- name: Check source code format
run: mix format --check-formatted

- name: Remove compiled application files
run: mix clean

- name: Compile & lint dependencies
run: mix compile --warnings-as-errors

- name: Run tests
run: mix test
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
name: test-and-release
name: manual-release
on:
workflow_dispatch:
inputs:
release-version:
required: true
description: 'The version of the release'
default: '0.1.0'
default: '0.2.0'
git-ref:
required: true
description: 'The git revison of repo, branch, tag or commit'
Expand Down Expand Up @@ -108,13 +108,15 @@ jobs:
HEX_API_KEY: ${{ secrets.HEX_API_KEY }}
run: |
mix hex.publish --yes

- uses: actions/github-script@v7
with:
script: |
github.rest.git.createRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: 'refs/tags/${{ github.event.inputs.release-version }}',
sha: context.sha
})

## maybe check tag exists and create tag
# - name: Create Git Tag
# uses: actions/github-script@v7
# with:
# script: |
# github.rest.git.createRef({
# owner: context.repo.owner,
# repo: context.repo.repo,
# ref: 'refs/tags/${{ github.event.inputs.release-version }}',
# sha: context.sha
# })
43 changes: 43 additions & 0 deletions .github/workflows/release-on-tag.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: release-on-tag

on:
push:
tags:
- '/^\d+\.\d+\.\d+$/'

# permissions:
# contents: write

jobs:
release:
name: Publish release to hex.pm
runs-on: ubuntu-latest
needs: [ tests ]
steps:
- name: ⬇️ Checkout repo
uses: actions/checkout@v4
with:
ref: ${{ github.ref }}

- name: Set up Elixir
uses: erlef/setup-beam@v1
with:
otp-version: 27
elixir-version: 1.18

- name: Install Deps and Setup Version
env:
MIX_ENV: prod
run: |
mix deps.get
echo "version: ${{ github.ref }}"
sed -i 's%@version "[0-9\.]\+"%@version "${{ github.ref }}"%' mix.exs
sed -i 's%{:phoenix_react_server, "~> [0-9\.]\+"}%{:phoenix_react_server, "~> ${{ github.ref }}"}%g' README.md

- name: Publish to hex.pm
env:
MIX_ENV: prod
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
HEX_API_KEY: ${{ secrets.HEX_API_KEY }}
run: |
mix hex.publish --yes
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ erl_crash.dump
node_modules
package-lock.json
/priv/tmp
bun.lockb
113 changes: 71 additions & 42 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ Run a `react` render server to render react component in `Phoenix` html.

**Features**

- Render to static markup
- Render to html
- Render to html and use hydrate at client side by `live_view` `hook`
- [x] Render to static markup
- [x] Render to html
- [x] Hydrate at client side

See the [docs](https://hexdocs.pm/phoenix_react_server/) for more information.

Expand All @@ -17,7 +17,7 @@ See the [docs](https://hexdocs.pm/phoenix_react_server/) for more information.
Add deps in `mix.exs`

```elixir
{:phoenix_react_server, "~> 0.1.0"},
{:phoenix_react_server, "~> #{Application.spec(:phoenix_react_server, :vsn)}"},
```

## Configuration
Expand All @@ -28,13 +28,21 @@ Set config, runtime, react components, etc.
import Config

config :phoenix_react_server, Phoenix.React,
# runtime: Path.expand("../node_modules/@babel/node/bin/babel-node.js", __DIR__)
# runtime: System.find_executable("deno"),
runtime: System.find_executable("bun"),
components_base: Path.expand("../assets/js", __DIR__),
cache_ttl: 3600
# react runtime, default to `bun`
runtime: Phoenix.React.Runtime.Bun,
# react component base path
component_base: Path.expand("../assets/component", __DIR__),
# cache ttl, default to 60 seconds
cache_ttl: 60
```

Supported `runtime`

- [x] `Phoenix.React.Runtime.Bun`
- [ ] `Phoenix.React.Runtime.Deno`
- [ ] `Phoenix.React.Runtime.Node`
- [ ] `Phoenix.React.Runtime.Lambda`

Add Render Server in your application Supervisor tree.

```elixir
Expand All @@ -44,34 +52,36 @@ Add Render Server in your application Supervisor tree.
{DNSCluster, query: Application.get_env(:react_demo, :dns_cluster_query) || :ignore},
{Phoenix.PubSub, name: ReactDemo.PubSub},
# React render service
Phoenix.React.Superviser,
Phoenix.React,
ReactDemoWeb.Endpoint
]

# See https://hexdocs.pm/elixir/Supervisor.html
# for other strategies and supported options
opts = [strategy: :one_for_one, name: ReactDemo.Supervisor]
Supervisor.start_link(children, opts)
end
```

Write React Component Module
Write Phoenix Component use `react_component`

```elixir
defmodule ReactDemoWeb.ReactComponents do
use Phoenix.Component
use Phoenix.React.Helper

def markdown(assigns) do
props = assigns.props
import Phoenix.React.Helper

def react_markdown(assigns) do
{static, props} = Map.pop(assigns, :static, true)

# path: components_base + "components/markdown.js"
react_component("components/markdown.js", props)
react_component(%{
component: "markdown",
props: props,
static: static
})
end
end
```

Import in html helpers
Import in html helpers in `react_demo_web.ex`

```elixir
defp html_helpers do
Expand All @@ -90,29 +100,48 @@ Import in html helpers
end
```

Use in html template

```heex
<.markdown
props={%{
content: """
# Hello World

Best in the world!

```elixir
defmodule Hello do
def world do
IO.puts "Hello World"
end
end
```

"""
}}
/>
## Use in otp release

Transcompile react component in release.

```shell
bun build --outdir=priv/react/component ./assets/component/**
```

## Example App
Config `runtime` to `Phoenix.React.Runtime.Bun` in `runtime.exs`

An example can be find in `react_demo` folder.
```elixir
config :phoenix_react_server, Phoenix.React,
# Change `component_base` to `priv/react/component`
component_base: :code.priv(:react_demo, "react/component")

config :phoenix_react_server, Phoenix.React.Runtime.Bun,
# include `react-dom/server` and `jsx-runtime`
cd: "/path/to/dir/include/node_modules/and/bunfig.toml",
cmd: "/path/to/bun",
env: :prod
```

## Hydrate at client side

Hydrate react component at client side.

```html
<script type="importmap">
{
"imports": {
"react-dom": "https://esm.run/react-dom@19",
"app": "https://my.web.site/app.js"
}
}
</script>
<script type="module">
import { hydrateRoot } from 'react-dom/client';
import { Component } from 'app';

hydrateRoot(
document.getElementById('app-wrapper'),
<App />
);
</script>
```
7 changes: 3 additions & 4 deletions config/config.exs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import Config

config :phoenix_react_server, Phoenix.React,
# runtime: Path.expand("../node_modules/@babel/node/bin/babel-node.js", __DIR__)
runtime: System.find_executable("bun"),
cache_ttl: 3600
# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
import_config "#{config_env()}.exs"
6 changes: 6 additions & 0 deletions config/dev.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import Config

config :phoenix_react_server, Phoenix.React,
runtime: Phoenix.React.Runtime.Bun,
component_base: Path.expand("../assets/component", __DIR__),
cache_ttl: 60
6 changes: 6 additions & 0 deletions config/prod.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import Config

config :phoenix_react_server, Phoenix.React,
runtime: Phoenix.React.Runtime.Bun,
component_base: Path.expand("../priv/react/component", __DIR__),
cache_ttl: 60 * 15
6 changes: 6 additions & 0 deletions config/test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import Config

config :phoenix_react_server, Phoenix.React,
runtime: Phoenix.React.Runtime.Bun,
component_base: Path.expand("../test/fixtures", __DIR__),
cache_ttl: 60
Loading