picoruby-cloudflare-template 0.1.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.ja.md +183 -0
- data/README.md +183 -0
- data/exe/picoruby-cloudflare +5 -0
- data/lib/picoruby/cloudflare/build.rb +87 -0
- data/lib/picoruby/cloudflare/template/cli.rb +54 -0
- data/lib/picoruby/cloudflare/template/exporter.rb +139 -0
- data/lib/picoruby/cloudflare/template/generator.rb +44 -0
- data/lib/picoruby/cloudflare/template/project.rb +63 -0
- data/lib/picoruby/cloudflare/template/version.rb +9 -0
- data/lib/picoruby/cloudflare/template.rb +20 -0
- data/sig/picoruby/cloudflare/template.rbs +40 -0
- data/templates/project/Gemfile.erb +3 -0
- data/templates/project/README.md.erb +59 -0
- data/templates/project/Rakefile.erb +3 -0
- data/templates/project/app.rb.erb +10 -0
- data/templates/project/build_config.rb.erb +22 -0
- data/templates/project/gitignore.erb +9 -0
- data/templates/project/package.json.erb +15 -0
- data/templates/project/src/index.js.erb +5 -0
- data/templates/project/wrangler.jsonc.erb +18 -0
- data/templates/runtime/index.js +22 -0
- metadata +83 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 0514b3333048a221efffa3fa803528f1c2aafac2c14b4f545cfb59484c67ac11
|
|
4
|
+
data.tar.gz: b5db10ca44c30093aee69c5675055432e89c2761ed70279d518104408fda9c1b
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 7c0531c2e85494b47656f0b621de96bde954776951aa4ede77d8f0ce682ec8328cee3d220ffb6015002e0cbffb933326cc37292e37759b9672d36dd5cc572b77
|
|
7
|
+
data.tar.gz: e99ef3c75479ee721aa68698a72366a4d8b278385b5d663505bf8214636f5faced03e5cc5ad1cc1abad5f40d29db31df7fe7ada861ac190e362e9c98461b76f4
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Uchio Kondo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.ja.md
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# picoruby-cloudflare-template
|
|
2
|
+
|
|
3
|
+
[English](README.md) | 日本語
|
|
4
|
+
|
|
5
|
+
PicoRuby向けCloudflare Workerプロジェクトの生成、CrossBuild設定、ローカルES module出力を担当するCRuby gemです。
|
|
6
|
+
Wasm実行時には不要です。npmパッケージの公開も不要です。
|
|
7
|
+
|
|
8
|
+
## クイックスタート(未公開版の開発中)
|
|
9
|
+
|
|
10
|
+
macOSでは、まず[Homebrew](https://formulae.brew.sh/formula/emscripten)経由でEmscriptenをインストールします。
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
brew install emscripten
|
|
14
|
+
export PATH="$(brew --prefix emscripten)/bin:$PATH"
|
|
15
|
+
emcc --version
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Emscripten 5.0.0以上を使用できます。5.0.7およびHomebrew版6.0.9で動作確認済みです。
|
|
19
|
+
新しい版もバージョンチェックを通りますが、すべての版を検証済みという意味ではありません。
|
|
20
|
+
emsdkから切り替える場合は、`emsdk_env.sh`を読み込まないシェルを使い、`EMSDK`・`EM_CONFIG`・`EM_CACHE`をunsetしてツールチェーンの混在を避けてください。
|
|
21
|
+
|
|
22
|
+
続いて、このリポジトリで実行します。
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
bundle install
|
|
26
|
+
bundle exec ruby exe/picoruby-cloudflare new ../my-worker --gem-path "$PWD"
|
|
27
|
+
cd ../my-worker
|
|
28
|
+
bundle install
|
|
29
|
+
npm install
|
|
30
|
+
|
|
31
|
+
export PICORUBY_ROOT=/path/to/picoruby
|
|
32
|
+
# ビルド前に、下記の例に従ってbuild_config.rbのローカルmrbgemパスを設定
|
|
33
|
+
|
|
34
|
+
bundle exec rake doctor
|
|
35
|
+
bundle exec rake
|
|
36
|
+
npm run dev
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
PicoRubyはsubmodule初期化済みのチェックアウトを指定します。初期化・Emscripten導入はgemでは行いません。
|
|
40
|
+
`doctor` はPicoRubyの主要ファイル、emcc、emar、Node.js、jsonc-parserを確認します。
|
|
41
|
+
ビルド時にはEmscriptenが対応する版かも検査します。Node.jsはWranglerがサポートする版を使用してください。
|
|
42
|
+
上流のシェルコマンド展開の制限により、ビルド用パスでは空白やシェル特殊文字を拒否します。
|
|
43
|
+
|
|
44
|
+
配布gemを試す場合は `gem build picoruby-cloudflare-template.gemspec`、
|
|
45
|
+
`gem install ./picoruby-cloudflare-template-0.1.0.rc1.gem` の後、
|
|
46
|
+
`picoruby-cloudflare new my-worker` を使えます。生成先で未公開版を解決するには `bundle install --local` を使用します。
|
|
47
|
+
このリリース候補版を公開した後は `gem install picoruby-cloudflare-template --pre --version 0.1.0.rc1` でインストールできます。
|
|
48
|
+
`VERSION` とRubyGemsのメタデータ上のバージョンは、どちらも `0.1.0.rc1` です。
|
|
49
|
+
|
|
50
|
+
## 生成物とビルド設定
|
|
51
|
+
|
|
52
|
+
`new PATH [--name NAME] [--gem-path PATH]` はGemfile、Rakefile、build_config.rb、最小Rackアプリのapp.rb、
|
|
53
|
+
src/index.js、package.json、wrangler.jsonc、.gitignore、README.mdを生成します。
|
|
54
|
+
生成先が存在する場合は空ディレクトリでも上書きしません。Gemfile.lockとpackage-lock.jsonはアプリ側でコミットしてください。
|
|
55
|
+
|
|
56
|
+
```ruby
|
|
57
|
+
require "picoruby/cloudflare/build"
|
|
58
|
+
|
|
59
|
+
MRuby::CrossBuild.new("worker") do |conf|
|
|
60
|
+
conf.cloudflare_worker! do |cf|
|
|
61
|
+
# 任意: ローカルチェックアウトはrevision指定より優先されます。
|
|
62
|
+
# cf.picoruby_cloudflare_worker_wasm_mgem_dir = "/path/to/picoruby-cloudflare-worker-wasm"
|
|
63
|
+
# cf.mruby_rack_mgem_dir = "/path/to/mruby-rack"
|
|
64
|
+
# cf.picoruby_cloudflare_worker_wasm_revision = "<commit SHA>"
|
|
65
|
+
# cf.mruby_rack_mgem_revision = "<commit SHA>"
|
|
66
|
+
end
|
|
67
|
+
# conf.gem gemdir: File.join(__dir__, "vendor/my-gem")
|
|
68
|
+
conf.worker_export(
|
|
69
|
+
app: "app.rb",
|
|
70
|
+
output_dir: "generated/worker",
|
|
71
|
+
wrangler_config: "wrangler.jsonc",
|
|
72
|
+
environment: ENV["CLOUDFLARE_ENV"],
|
|
73
|
+
project_root: __dir__,
|
|
74
|
+
)
|
|
75
|
+
end
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
このrequireはPicoRubyのビルドシステム読込後、build_config.rb内で行います。
|
|
79
|
+
`cloudflare_worker!` はEmscripten、Wasm longjmp、Worker HAL、PicoRuby、Rackと必要なcore mrbgemを設定します。
|
|
80
|
+
Sinatra等のフレームワークはアプリ側で追加します。ABI固有の最終リンク設定(JSPI export等)は実行時ライブラリが所有します。
|
|
81
|
+
属性は `cloudflare_worker!` のブロック内で設定します。ブロックにはCrossBuild自身が渡され、検証やビルド設定の本処理より先に実行されます。
|
|
82
|
+
ブロックなしでも呼べます。その場合は事前に属性を設定してください。`!` はビルド設定を書き換えることを示します。
|
|
83
|
+
両方のディレクトリ属性はデフォルト `nil` で、その場合はrevision属性を使い、`github:` と `checksum_hash:` でgemを宣言します。
|
|
84
|
+
ディレクトリ指定はrevision指定より優先され、相対ディレクトリはbuild_configのディレクトリ基準で解決します。
|
|
85
|
+
revision属性のデフォルトはこのgemに組み込まれた値です。`nil` を代入するとデフォルトに戻ります。
|
|
86
|
+
取得先の選択で `PICORUBY_WORKER_WASM_GEM_DIR` / `MRUBY_RACK_GEM_DIR` は参照せず、`worker:` / `rack:` 引数も受け取りません。
|
|
87
|
+
|
|
88
|
+
既定のWorker revisionは `e6235bca616dbd4cec619cc0141facdea59a5541`、
|
|
89
|
+
Rackは `05ba46eb0ab490a624a5f2dcb33249670933ff6b` に固定しています。
|
|
90
|
+
revisionがリモート未公開の場合はローカル指定が必要です。gem公開前に、新規チェックアウトから固定revisionを取得できることも確認してください。
|
|
91
|
+
|
|
92
|
+
`worker_export` に渡す相対パスは `project_root` 基準(省略時はbuild_configのディレクトリ)です。
|
|
93
|
+
生成されたRakefileはPicoRubyのRakeを別プロセスで実行し、ビルドをアプリ内の `.picoruby-build/` に分離します。
|
|
94
|
+
アプリはCrossBuildが解決した `mrbcfile` でコンパイルし、既存の `build/host/bin/mrbc` には依存しません。
|
|
95
|
+
|
|
96
|
+
## ES module出力と責務
|
|
97
|
+
|
|
98
|
+
```text
|
|
99
|
+
generated/worker/
|
|
100
|
+
app.bin
|
|
101
|
+
bindings.js
|
|
102
|
+
package.json # private: true, type: module
|
|
103
|
+
manifest.json # generator版・Worker revision・成果物SHA256
|
|
104
|
+
runtime/
|
|
105
|
+
index.js # createWorker({ app, bindingTypes })
|
|
106
|
+
runtime.js
|
|
107
|
+
host-bridge.js
|
|
108
|
+
picoruby-worker.js
|
|
109
|
+
picoruby-worker.wasm
|
|
110
|
+
tools/ # binding registry生成スクリプト
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Ruby/C・HAL・共通JS bridgeは実行時ライブラリが、このgemはテンプレート・CrossBuild DSL・export処理・薄いcreateWorkerエントリを所有します。
|
|
114
|
+
共通JSとregistry生成スクリプトは、Wasmをビルドした**同じmrbgemチェックアウト**からコピーします。
|
|
115
|
+
現在の取得場所は `spike/src/` と `spike/scripts/` です。別コピーの実装をこのgemで管理しません。
|
|
116
|
+
レイアウト変更時はexporterと固定revisionを一緒に更新します。
|
|
117
|
+
|
|
118
|
+
`createWorker` はリクエストごとにVMを生成・破棄し、異なるリクエストのenvを共有しません。
|
|
119
|
+
低レベルの `createRuntime` / `dispatch` / `closeRuntime` も再exportします。
|
|
120
|
+
明示的にVMを再利用した場合、同じVMへのdispatchは実行時ライブラリが直列化します。
|
|
121
|
+
出力はWranglerでバンドルする前提です。Node.jsがそのまま `.wasm` / `.bin` importできるという意味ではありません。
|
|
122
|
+
再配布する場合は、元のmrbgemや追加依存のライセンス条件も確認してください。
|
|
123
|
+
|
|
124
|
+
アプリの再コンパイルはRakeの依存関係で判定し、exportは同じ内容なら書き直しません。
|
|
125
|
+
registryは環境変更を反映するため毎回検証・生成します。元ビルドのWasmが単独で欠けた場合も再リンクします。
|
|
126
|
+
ただし検証時のPicoRubyはsrc/version.cを毎回更新するため、無変更ビルドでもそのコンパイルと最終リンクが走ります。
|
|
127
|
+
|
|
128
|
+
## bindings・環境・Wrangler
|
|
129
|
+
|
|
130
|
+
wrangler.jsoncの `kv_namespaces` / `queues.producers` から型registryを生成します。
|
|
131
|
+
JSONCのコメント・末尾カンマに対応し、不正な設定・重複名・存在しない環境はビルドエラーにします。
|
|
132
|
+
varsの値やsecretはビルド成果物へ埋め込みません。
|
|
133
|
+
|
|
134
|
+
```ruby
|
|
135
|
+
kv = Cloudflare::KV.from_env(env, "CACHE_KV")
|
|
136
|
+
kv.put("key", "value", ttl: 60)
|
|
137
|
+
value = env["cloudflare.env"].CACHE_KV.get("key")
|
|
138
|
+
Cloudflare::Queue.from_env(env, "EVENTS").send("created")
|
|
139
|
+
token = ENV["API_TOKEN"]
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Queueは現行APIに合わせてUTF-8文字列送信のみです。secretは.dev.varsまたは `wrangler secret put` で管理し、Gitへ追加しないでください。
|
|
143
|
+
`npm run dev` / `npm run deploy` ではWranglerのcustom buildがRakeを実行します。
|
|
144
|
+
`build.watch_dir` はapp.rbとbuild_config.rbです。Rubyファイルを増やしたときは監視対象も更新してください。
|
|
145
|
+
|
|
146
|
+
```sh
|
|
147
|
+
CLOUDFLARE_ENV=staging npm run dev
|
|
148
|
+
CLOUDFLARE_ENV=staging npm run deploy
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
名前付き環境を `--env staging` だけで選ぶとcustom buildに環境名が伝わりません。
|
|
152
|
+
Wranglerとexporterが同じ `CLOUDFLARE_ENV` を参照するようにしてください。
|
|
153
|
+
リソースbindingは環境ごとに定義し、トップレベルから継承しません。
|
|
154
|
+
|
|
155
|
+
## テスト・最小再現
|
|
156
|
+
|
|
157
|
+
```sh
|
|
158
|
+
bundle exec rake test
|
|
159
|
+
|
|
160
|
+
PICORUBY_ROOT=/path/to/picoruby \
|
|
161
|
+
PICORUBY_WORKER_WASM_GEM_DIR=/path/to/picoruby-cloudflare-worker-wasm \
|
|
162
|
+
MRUBY_RACK_GEM_DIR=/path/to/mruby-rack \
|
|
163
|
+
bundle exec rake test:integration
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
このテストコマンドのmrbgem環境変数は、統合テスト用ハーネスへの入力に限定しています。
|
|
167
|
+
ハーネスは生成したbuild_configへディレクトリ属性を明示的に書き込み、ビルド実行前にこれらの環境変数を解除します。
|
|
168
|
+
|
|
169
|
+
単体テスト: CLI、非上書き、パス検証、DSL、compiler選択、増分export、欠損Wasm復旧、コンパイル失敗時の保護。
|
|
170
|
+
統合テスト: 新規生成・依存インストール・ビルド・Wrangler dry-run・ローカルHTTPとhot reload・実Wasm経由のENV/KV TTL/Queue・
|
|
171
|
+
並行リクエスト間のenv分離・環境切り替え・欠損Wasm復旧。
|
|
172
|
+
統合テスト用Node.jsはJSPI対応が必要です。デプロイやCloudflareリソースの作成はしません。
|
|
173
|
+
調査用に、表示した一時ディレクトリへ全成果物とステップ別ログを残します。
|
|
174
|
+
|
|
175
|
+
検証対象: PicoRuby `33540f66d9aba633d4d3ebd6707d5c12baebb652`、上記Worker/Rack revision、
|
|
176
|
+
Ruby 4.0.5、Emscripten 5.0.7およびHomebrew版6.0.9、Node.js 26.8.1、Wrangler 4.125.0。
|
|
177
|
+
compatibility dateは固定Wranglerと組み合わせて確認した `2026-08-22` を使います。
|
|
178
|
+
dry-runはworkerdを起動しないため、Wrangler/dateの更新時はローカルHTTP確認も必要です。
|
|
179
|
+
PicoRubyやmruby submoduleのビルドAPI変更時には統合テストを再実行してください。
|
|
180
|
+
|
|
181
|
+
## ライセンス
|
|
182
|
+
|
|
183
|
+
このgemは [MIT License](LICENSE) で公開しています。
|
data/README.md
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# picoruby-cloudflare-template
|
|
2
|
+
|
|
3
|
+
English | [日本語](README.ja.md)
|
|
4
|
+
|
|
5
|
+
A CRuby gem for generating PicoRuby Cloudflare Worker projects, configuring CrossBuild, and exporting local ES modules.
|
|
6
|
+
It is not needed at Wasm runtime, and publishing an npm package is not required.
|
|
7
|
+
|
|
8
|
+
## Quick start (before publication)
|
|
9
|
+
|
|
10
|
+
On macOS, install Emscripten via [Homebrew](https://formulae.brew.sh/formula/emscripten) first:
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
brew install emscripten
|
|
14
|
+
export PATH="$(brew --prefix emscripten)/bin:$PATH"
|
|
15
|
+
emcc --version
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Emscripten 5.0.0 or later is accepted. Versions 5.0.7 and Homebrew 6.0.9 are tested;
|
|
19
|
+
accepting newer versions does not imply they have all been tested.
|
|
20
|
+
If switching from emsdk, use a shell without `emsdk_env.sh` and unset `EMSDK`, `EM_CONFIG`, and `EM_CACHE` to avoid mixing toolchains.
|
|
21
|
+
|
|
22
|
+
Then run the following from this repository:
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
bundle install
|
|
26
|
+
bundle exec ruby exe/picoruby-cloudflare new ../my-worker --gem-path "$PWD"
|
|
27
|
+
cd ../my-worker
|
|
28
|
+
bundle install
|
|
29
|
+
npm install
|
|
30
|
+
|
|
31
|
+
export PICORUBY_ROOT=/path/to/picoruby
|
|
32
|
+
# Set local mrbgem paths in build_config.rb as shown below before building
|
|
33
|
+
|
|
34
|
+
bundle exec rake doctor
|
|
35
|
+
bundle exec rake
|
|
36
|
+
npm run dev
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Use a PicoRuby checkout with its submodules initialized. This gem does not initialize submodules or install Emscripten.
|
|
40
|
+
`doctor` checks key PicoRuby files, emcc, emar, Node.js, and jsonc-parser.
|
|
41
|
+
The build also checks that the Emscripten version is supported. Use a Node.js version supported by Wrangler.
|
|
42
|
+
Build paths containing spaces or shell metacharacters are rejected because of upstream shell command expansion limitations.
|
|
43
|
+
|
|
44
|
+
To try a packaged gem, run `gem build picoruby-cloudflare-template.gemspec`, followed by
|
|
45
|
+
`gem install ./picoruby-cloudflare-template-0.1.0.rc1.gem` and
|
|
46
|
+
`picoruby-cloudflare new my-worker`. Use `bundle install --local` in the generated project to resolve the unpublished version.
|
|
47
|
+
After this release candidate is published, install it with `gem install picoruby-cloudflare-template --pre --version 0.1.0.rc1`.
|
|
48
|
+
`VERSION` and the RubyGems metadata version are both `0.1.0.rc1`.
|
|
49
|
+
|
|
50
|
+
## Generated files and build configuration
|
|
51
|
+
|
|
52
|
+
`new PATH [--name NAME] [--gem-path PATH]` generates a Gemfile, Rakefile, build_config.rb, a minimal Rack app in app.rb,
|
|
53
|
+
src/index.js, package.json, wrangler.jsonc, .gitignore, and README.md.
|
|
54
|
+
An existing destination is never overwritten, even if it is an empty directory. Commit Gemfile.lock and package-lock.json in your application repository.
|
|
55
|
+
|
|
56
|
+
```ruby
|
|
57
|
+
require "picoruby/cloudflare/build"
|
|
58
|
+
|
|
59
|
+
MRuby::CrossBuild.new("worker") do |conf|
|
|
60
|
+
conf.cloudflare_worker! do |cf|
|
|
61
|
+
# Optional: local checkouts take precedence over revisions.
|
|
62
|
+
# cf.picoruby_cloudflare_worker_wasm_mgem_dir = "/path/to/picoruby-cloudflare-worker-wasm"
|
|
63
|
+
# cf.mruby_rack_mgem_dir = "/path/to/mruby-rack"
|
|
64
|
+
# cf.picoruby_cloudflare_worker_wasm_revision = "<commit SHA>"
|
|
65
|
+
# cf.mruby_rack_mgem_revision = "<commit SHA>"
|
|
66
|
+
end
|
|
67
|
+
# conf.gem gemdir: File.join(__dir__, "vendor/my-gem")
|
|
68
|
+
conf.worker_export(
|
|
69
|
+
app: "app.rb",
|
|
70
|
+
output_dir: "generated/worker",
|
|
71
|
+
wrangler_config: "wrangler.jsonc",
|
|
72
|
+
environment: ENV["CLOUDFLARE_ENV"],
|
|
73
|
+
project_root: __dir__,
|
|
74
|
+
)
|
|
75
|
+
end
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Place this require in build_config.rb, after PicoRuby has loaded its build system.
|
|
79
|
+
`cloudflare_worker!` configures Emscripten, Wasm longjmp, the Worker HAL, PicoRuby, Rack, and the required core mrbgems.
|
|
80
|
+
Add frameworks such as Sinatra in your application configuration. ABI-specific final link settings, such as JSPI exports, belong to the runtime library.
|
|
81
|
+
Set the attributes in the `cloudflare_worker!` block. It receives the CrossBuild object itself and runs before validation and build setup.
|
|
82
|
+
Calling without a block is also supported; in that case, set any overrides beforehand. The `!` marks its changes to the build configuration.
|
|
83
|
+
Both directory attributes default to `nil`; in that case the gem is declared with `github:` and `checksum_hash:` using its revision attribute.
|
|
84
|
+
A directory takes precedence over its revision, and relative directory paths are resolved against the build_config directory.
|
|
85
|
+
Revision attributes default to the values bundled in this gem; assigning `nil` restores those defaults.
|
|
86
|
+
Dependency source selection no longer reads `PICORUBY_WORKER_WASM_GEM_DIR` or `MRUBY_RACK_GEM_DIR`, or accepts `worker:` / `rack:` arguments.
|
|
87
|
+
|
|
88
|
+
The default Worker revision is pinned to `e6235bca616dbd4cec619cc0141facdea59a5541`,
|
|
89
|
+
and Rack to `05ba46eb0ab490a624a5f2dcb33249670933ff6b`.
|
|
90
|
+
Use a local checkout if a revision has not been published to the remote repository. Before publishing this gem, verify that a fresh checkout can fetch the pinned revisions.
|
|
91
|
+
|
|
92
|
+
Relative paths passed to `worker_export` are resolved against `project_root`, which defaults to the build_config directory.
|
|
93
|
+
The generated Rakefile runs PicoRuby's Rake in a separate process and keeps build output in the application's `.picoruby-build/` directory.
|
|
94
|
+
The application is compiled with the `mrbcfile` resolved by CrossBuild, without relying on an existing `build/host/bin/mrbc`.
|
|
95
|
+
|
|
96
|
+
## ES module output and responsibilities
|
|
97
|
+
|
|
98
|
+
```text
|
|
99
|
+
generated/worker/
|
|
100
|
+
app.bin
|
|
101
|
+
bindings.js
|
|
102
|
+
package.json # private: true, type: module
|
|
103
|
+
manifest.json # Generator version, Worker revision, artifact SHA256 hashes
|
|
104
|
+
runtime/
|
|
105
|
+
index.js # createWorker({ app, bindingTypes })
|
|
106
|
+
runtime.js
|
|
107
|
+
host-bridge.js
|
|
108
|
+
picoruby-worker.js
|
|
109
|
+
picoruby-worker.wasm
|
|
110
|
+
tools/ # Binding registry generation scripts
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The runtime library owns the Ruby/C code, HAL, and shared JS bridge. This gem owns the templates, CrossBuild DSL, export logic, and thin createWorker entry point.
|
|
114
|
+
Shared JS and registry generation scripts are copied from **the same mrbgem checkout** used to build Wasm.
|
|
115
|
+
Their current locations are `spike/src/` and `spike/scripts/`. This gem does not maintain a separate copy of those implementations.
|
|
116
|
+
If that layout changes, update the exporter and pinned revision together.
|
|
117
|
+
|
|
118
|
+
`createWorker` creates and closes a VM for each request, without sharing env between requests.
|
|
119
|
+
The low-level `createRuntime` / `dispatch` / `closeRuntime` functions are also re-exported.
|
|
120
|
+
If you explicitly reuse a VM, the runtime library serializes dispatches to that VM.
|
|
121
|
+
The output is intended to be bundled with Wrangler; it does not make `.wasm` / `.bin` imports directly usable in Node.js.
|
|
122
|
+
Check the license requirements of the original mrbgems and any additional dependencies before redistributing artifacts.
|
|
123
|
+
|
|
124
|
+
Rake dependencies determine when to recompile the application, and export leaves files unchanged when their content is identical.
|
|
125
|
+
The registry is validated and generated on every build to reflect environment changes. A missing Wasm file in the original build output also triggers relinking.
|
|
126
|
+
However, the tested PicoRuby version rewrites src/version.c on every build, so that file is recompiled and the runtime is relinked even when nothing else has changed.
|
|
127
|
+
|
|
128
|
+
## Bindings, environments, and Wrangler
|
|
129
|
+
|
|
130
|
+
The type registry is generated from `kv_namespaces` / `queues.producers` in wrangler.jsonc.
|
|
131
|
+
JSONC comments and trailing commas are supported. Invalid configuration, duplicate binding names, and nonexistent environments cause build errors.
|
|
132
|
+
Variable values and secrets are not embedded in build artifacts.
|
|
133
|
+
|
|
134
|
+
```ruby
|
|
135
|
+
kv = Cloudflare::KV.from_env(env, "CACHE_KV")
|
|
136
|
+
kv.put("key", "value", ttl: 60)
|
|
137
|
+
value = env["cloudflare.env"].CACHE_KV.get("key")
|
|
138
|
+
Cloudflare::Queue.from_env(env, "EVENTS").send("created")
|
|
139
|
+
token = ENV["API_TOKEN"]
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Queue sending currently supports UTF-8 strings only, matching the runtime API. Manage secrets through .dev.vars or `wrangler secret put`, and keep them out of Git.
|
|
143
|
+
With `npm run dev` / `npm run deploy`, Wrangler's custom build runs Rake.
|
|
144
|
+
`build.watch_dir` covers app.rb and build_config.rb. Update the watch list when adding Ruby files.
|
|
145
|
+
|
|
146
|
+
```sh
|
|
147
|
+
CLOUDFLARE_ENV=staging npm run dev
|
|
148
|
+
CLOUDFLARE_ENV=staging npm run deploy
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Selecting a named environment with only `--env staging` does not pass the environment name to the custom build.
|
|
152
|
+
Make sure Wrangler and the exporter use the same `CLOUDFLARE_ENV` value.
|
|
153
|
+
Define resource bindings for each environment; they are not inherited from the top-level configuration.
|
|
154
|
+
|
|
155
|
+
## Tests and reproduction
|
|
156
|
+
|
|
157
|
+
```sh
|
|
158
|
+
bundle exec rake test
|
|
159
|
+
|
|
160
|
+
PICORUBY_ROOT=/path/to/picoruby \
|
|
161
|
+
PICORUBY_WORKER_WASM_GEM_DIR=/path/to/picoruby-cloudflare-worker-wasm \
|
|
162
|
+
MRUBY_RACK_GEM_DIR=/path/to/mruby-rack \
|
|
163
|
+
bundle exec rake test:integration
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
The mrbgem environment variables in this test command are inputs to the integration harness only.
|
|
167
|
+
It writes explicit directory attributes into the generated build_config and clears those variables before invoking the build.
|
|
168
|
+
|
|
169
|
+
Unit tests cover the CLI, overwrite protection, path validation, DSL, compiler selection, incremental export, missing-Wasm recovery, and preservation of bytecode after compilation failures.
|
|
170
|
+
Integration tests cover project generation, dependency installation, builds, Wrangler dry-run, local HTTP and hot reload, ENV/KV TTL/Queue through actual Wasm,
|
|
171
|
+
env isolation between concurrent requests, environment switching, and missing-Wasm recovery.
|
|
172
|
+
Integration tests require a Node.js version with JSPI support. They do not deploy Workers or create Cloudflare resources.
|
|
173
|
+
All artifacts and step-by-step logs are retained in the temporary directory printed by the test for troubleshooting.
|
|
174
|
+
|
|
175
|
+
Tested with PicoRuby `33540f66d9aba633d4d3ebd6707d5c12baebb652`, the Worker/Rack revisions above,
|
|
176
|
+
Ruby 4.0.5, Emscripten 5.0.7 and Homebrew Emscripten 6.0.9, Node.js 26.8.1, and Wrangler 4.125.0.
|
|
177
|
+
The compatibility date is `2026-08-22`, tested with the pinned Wrangler version.
|
|
178
|
+
A dry-run does not start workerd, so verify local HTTP responses when updating Wrangler or the compatibility date.
|
|
179
|
+
Rerun the integration tests when PicoRuby or the mruby submodule's build API changes.
|
|
180
|
+
|
|
181
|
+
## License
|
|
182
|
+
|
|
183
|
+
This gem is available under the [MIT License](LICENSE).
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "template/exporter"
|
|
4
|
+
|
|
5
|
+
unless defined?(MRuby::CrossBuild)
|
|
6
|
+
raise Picoruby::Cloudflare::Template::Error, "Require picoruby/cloudflare/build from a PicoRuby build_config.rb, after its build system is loaded"
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
module Picoruby::Cloudflare::Template
|
|
10
|
+
module CrossBuild
|
|
11
|
+
WORKER_REVISION = "e6235bca616dbd4cec619cc0141facdea59a5541".freeze
|
|
12
|
+
RACK_REVISION = "05ba46eb0ab490a624a5f2dcb33249670933ff6b".freeze
|
|
13
|
+
CORE_GEMS = %w[mruby-array-ext mruby-catch mruby-class-ext mruby-enum-ext
|
|
14
|
+
mruby-hash-ext mruby-kernel-ext mruby-metaprog mruby-method
|
|
15
|
+
mruby-numeric-ext mruby-object-ext mruby-proc-ext mruby-sprintf
|
|
16
|
+
mruby-string-ext mruby-struct mruby-regexp].freeze
|
|
17
|
+
|
|
18
|
+
attr_accessor :picoruby_cloudflare_worker_wasm_mgem_dir, :mruby_rack_mgem_dir
|
|
19
|
+
attr_writer :picoruby_cloudflare_worker_wasm_revision, :mruby_rack_mgem_revision
|
|
20
|
+
|
|
21
|
+
def picoruby_cloudflare_worker_wasm_revision
|
|
22
|
+
@picoruby_cloudflare_worker_wasm_revision.nil? ? WORKER_REVISION : @picoruby_cloudflare_worker_wasm_revision
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def mruby_rack_mgem_revision
|
|
26
|
+
@mruby_rack_mgem_revision.nil? ? RACK_REVISION : @mruby_rack_mgem_revision
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def cloudflare_worker!
|
|
30
|
+
yield self if block_given?
|
|
31
|
+
raise Error, "cloudflare_worker! may only be configured once per target" if @cloudflare_configured
|
|
32
|
+
Picoruby::Cloudflare::Template.validate_build_path!(MRUBY_ROOT)
|
|
33
|
+
Picoruby::Cloudflare::Template.validate_build_path!(build_dir)
|
|
34
|
+
worker = cloudflare_gem_source(picoruby_cloudflare_worker_wasm_mgem_dir,
|
|
35
|
+
"udzura/picoruby-cloudflare-worker-wasm", picoruby_cloudflare_worker_wasm_revision)
|
|
36
|
+
rack = cloudflare_gem_source(mruby_rack_mgem_dir, "udzura/mruby-rack", mruby_rack_mgem_revision)
|
|
37
|
+
@cloudflare_configured = true
|
|
38
|
+
toolchain :clang
|
|
39
|
+
cc.command = linker.command = "emcc"
|
|
40
|
+
archiver.command = "emar"
|
|
41
|
+
[cc, linker].each { _1.flags.concat(%w[-sSUPPORT_LONGJMP=wasm -sWASM_LEGACY_EXCEPTIONS=0]) }
|
|
42
|
+
cc.defines.concat(%w[PICORB_PLATFORM_WASM PICORB_PLATFORM_CLOUDFLARE_WORKERS MRB_32BIT MRB_INT64 MRB_NO_BOXING MRB_UTF8_STRING])
|
|
43
|
+
ports :worker_wasm
|
|
44
|
+
picoruby(alloc_estalloc: false)
|
|
45
|
+
core_dir = File.join(MRUBY_ROOT, "mrbgems/picoruby-mruby/lib/mruby/mrbgems")
|
|
46
|
+
CORE_GEMS.each { gem gemdir: File.join(core_dir, _1) }
|
|
47
|
+
gem(rack)
|
|
48
|
+
target = self
|
|
49
|
+
gem(worker) do |spec|
|
|
50
|
+
# This runs during gems.setup, after all build_config DSL calls and mrbc resolution.
|
|
51
|
+
target.send(:setup_cloudflare_export, spec)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def worker_export(app:, output_dir:, wrangler_config:, environment: nil, project_root: nil)
|
|
56
|
+
raise Error, "Call cloudflare_worker! before worker_export" unless @cloudflare_configured
|
|
57
|
+
raise Error, "worker_export may only be configured once per target" if @cloudflare_export
|
|
58
|
+
config = cloudflare_build_config
|
|
59
|
+
@cloudflare_export = {
|
|
60
|
+
app: app, output_dir: output_dir, wrangler_config: wrangler_config,
|
|
61
|
+
environment: environment, project_root: project_root || File.dirname(config), config: config,
|
|
62
|
+
}
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
def cloudflare_gem_source(gem_dir, github, revision)
|
|
68
|
+
if gem_dir
|
|
69
|
+
path = File.expand_path(gem_dir, File.dirname(cloudflare_build_config))
|
|
70
|
+
{ gemdir: Picoruby::Cloudflare::Template.validate_build_path!(path) }
|
|
71
|
+
else
|
|
72
|
+
raise Error, "Revision for #{github} must be a nonempty String" unless revision.is_a?(String) && !revision.empty?
|
|
73
|
+
{ github: github, checksum_hash: revision }
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def cloudflare_build_config
|
|
78
|
+
File.expand_path(defined?(::MRUBY_CONFIG) ? ::MRUBY_CONFIG : ENV["MRUBY_CONFIG"] || ENV.fetch("CONFIG"))
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def setup_cloudflare_export(spec)
|
|
82
|
+
Exporter.new(self, spec.dir, **@cloudflare_export).define_tasks if @cloudflare_export
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
MRuby::CrossBuild.include(Picoruby::Cloudflare::Template::CrossBuild)
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "optparse"
|
|
4
|
+
require_relative "generator"
|
|
5
|
+
require_relative "project"
|
|
6
|
+
|
|
7
|
+
module Picoruby::Cloudflare::Template
|
|
8
|
+
class CLI
|
|
9
|
+
HELP = <<~TEXT.freeze
|
|
10
|
+
Usage: picoruby-cloudflare COMMAND [OPTIONS]
|
|
11
|
+
|
|
12
|
+
Commands:
|
|
13
|
+
new PATH Generate a PicoRuby Cloudflare Worker project
|
|
14
|
+
doctor [PROJECT] Check local Worker build prerequisites (default: current directory)
|
|
15
|
+
|
|
16
|
+
Options:
|
|
17
|
+
-h, --help Show this help
|
|
18
|
+
|
|
19
|
+
Run `picoruby-cloudflare new --help` for project generation options.
|
|
20
|
+
TEXT
|
|
21
|
+
|
|
22
|
+
def self.run(argv, out: $stdout, err: $stderr)
|
|
23
|
+
argv = argv.dup
|
|
24
|
+
command = argv.shift
|
|
25
|
+
if command.nil? || command == "-h" || command == "--help"
|
|
26
|
+
out.puts HELP
|
|
27
|
+
return 0
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
options = {}
|
|
31
|
+
parser = OptionParser.new do |opts|
|
|
32
|
+
opts.banner = "Usage: picoruby-cloudflare new PATH [--name NAME] [--gem-path PATH]\n picoruby-cloudflare doctor [PROJECT]"
|
|
33
|
+
opts.on("--name NAME", "Worker name (defaults to directory name)") { options[:name] = _1 }
|
|
34
|
+
opts.on("--gem-path PATH", "Use an unpublished local template gem") { options[:gem_path] = _1 }
|
|
35
|
+
end
|
|
36
|
+
parser.parse!(argv)
|
|
37
|
+
case command
|
|
38
|
+
when "new"
|
|
39
|
+
raise Error, parser.to_s unless argv.length == 1
|
|
40
|
+
path = Generator.new(argv.first, **options).generate
|
|
41
|
+
out.puts "Created #{path}\nNext: cd #{path}\n # On macOS: brew install emscripten (see README for PATH setup)\n bundle install\n npm install\n # Set PICORUBY_ROOT, then:\n bundle exec rake doctor\n npm run dev"
|
|
42
|
+
when "doctor"
|
|
43
|
+
raise Error, parser.to_s unless argv.length <= 1 && options.empty?
|
|
44
|
+
Project.new(root: argv.first || Dir.pwd).doctor(out: out)
|
|
45
|
+
else
|
|
46
|
+
raise Error, parser.to_s
|
|
47
|
+
end
|
|
48
|
+
0
|
|
49
|
+
rescue Error, OptionParser::ParseError => e
|
|
50
|
+
err.puts e.message
|
|
51
|
+
1
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "digest"
|
|
4
|
+
require "fileutils"
|
|
5
|
+
require "json"
|
|
6
|
+
require "open3"
|
|
7
|
+
require "rake"
|
|
8
|
+
require "tempfile"
|
|
9
|
+
require_relative "../template"
|
|
10
|
+
|
|
11
|
+
module Picoruby::Cloudflare::Template
|
|
12
|
+
class Exporter
|
|
13
|
+
include Rake::DSL
|
|
14
|
+
|
|
15
|
+
def initialize(build, gem_dir, app:, output_dir:, wrangler_config:, project_root:, config:, environment: nil)
|
|
16
|
+
@build = build
|
|
17
|
+
@gem_dir = gem_dir
|
|
18
|
+
@root = File.expand_path(project_root)
|
|
19
|
+
@app = File.expand_path(app, @root)
|
|
20
|
+
@output = File.expand_path(output_dir, @root)
|
|
21
|
+
@wrangler = File.expand_path(wrangler_config, @root)
|
|
22
|
+
@config = config
|
|
23
|
+
@environment = environment
|
|
24
|
+
unless @output.start_with?("#{@root}/") && !@output.delete_prefix("#{@root}/").split("/").include?("node_modules")
|
|
25
|
+
raise Error, "output_dir must be a subdirectory of the project, outside node_modules"
|
|
26
|
+
end
|
|
27
|
+
raise Error, "app must be outside output_dir" if @app.start_with?("#{@output}/")
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def define_tasks
|
|
31
|
+
Picoruby::Cloudflare::Template.validate_build_path!(@gem_dir)
|
|
32
|
+
check_assets!
|
|
33
|
+
verify_emscripten!
|
|
34
|
+
bytecode = File.join(@output, "app.bin")
|
|
35
|
+
check_output_path!(bytecode)
|
|
36
|
+
file bytecode => [@app, @build.mrbcfile, @config, __FILE__] do
|
|
37
|
+
check_output_path!(bytecode)
|
|
38
|
+
FileUtils.mkdir_p(@output)
|
|
39
|
+
Tempfile.create(["app", ".bin"], @output) do |temp|
|
|
40
|
+
temp.close
|
|
41
|
+
sh @build.mrbcfile, "-o#{temp.path}", @app
|
|
42
|
+
File.rename(temp.path, bytecode)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
runtime_js = File.join(@build.build_dir, "bin/picoruby-worker.js")
|
|
46
|
+
runtime_wasm = File.join(@build.build_dir, "bin/picoruby-worker.wasm")
|
|
47
|
+
# The current mrbgem emits Wasm as a side effect of linking JS. Repair a
|
|
48
|
+
# missing side output without using old artifacts or deleting the build.
|
|
49
|
+
file runtime_wasm => runtime_js do
|
|
50
|
+
Rake::Task[runtime_js].execute unless File.file?(runtime_wasm)
|
|
51
|
+
raise Error, "Linker did not produce #{runtime_wasm}" unless File.file?(runtime_wasm)
|
|
52
|
+
end
|
|
53
|
+
prepare = "cloudflare:prepare:#{@build.name}"
|
|
54
|
+
task prepare => [runtime_js, runtime_wasm, bytecode]
|
|
55
|
+
manifest = File.join(@output, "manifest.json")
|
|
56
|
+
# The task prerequisite deliberately runs export on every build: environment
|
|
57
|
+
# selection is not a file timestamp. All writes are content-aware.
|
|
58
|
+
file manifest => prepare do
|
|
59
|
+
export(runtime_js, runtime_wasm)
|
|
60
|
+
end
|
|
61
|
+
@build.products << manifest
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def export(runtime_js, runtime_wasm)
|
|
65
|
+
%w[runtime.js host-bridge.js].each do |name|
|
|
66
|
+
write(File.join("runtime", name), File.binread(File.join(@gem_dir, "spike/src", name)))
|
|
67
|
+
end
|
|
68
|
+
write("runtime/picoruby-worker.js", File.binread(runtime_js))
|
|
69
|
+
write("runtime/picoruby-worker.wasm", File.binread(runtime_wasm))
|
|
70
|
+
# Keep parser and runtime from the same mrbgem checkout. Scripts are copied
|
|
71
|
+
# below the project so Node resolves its jsonc-parser dependency there.
|
|
72
|
+
%w[cloudflare-binding-registry.mjs generate-bindings.mjs].each do |name|
|
|
73
|
+
write(File.join("tools", name), File.binread(File.join(@gem_dir, "spike/scripts", name)))
|
|
74
|
+
end
|
|
75
|
+
Tempfile.create(["bindings", ".js"], @output) do |temp|
|
|
76
|
+
temp.close
|
|
77
|
+
args = ["node", File.join(@output, "tools/generate-bindings.mjs"), "--config", @wrangler, "--output", temp.path]
|
|
78
|
+
args.concat(["--env", @environment]) if @environment
|
|
79
|
+
output, status = Open3.capture2e(*args, chdir: @root)
|
|
80
|
+
raise Error, "Binding registry generation failed:\n#{output}" unless status.success?
|
|
81
|
+
write("bindings.js", File.binread(temp.path))
|
|
82
|
+
end
|
|
83
|
+
write("runtime/index.js", File.read(File.join(templates, "runtime/index.js")))
|
|
84
|
+
write("package.json", JSON.pretty_generate({ private: true, type: "module", exports: "./runtime/index.js" }) + "\n")
|
|
85
|
+
artifacts = %w[app.bin bindings.js package.json runtime/index.js runtime/runtime.js runtime/host-bridge.js runtime/picoruby-worker.js runtime/picoruby-worker.wasm]
|
|
86
|
+
write("manifest.json", JSON.pretty_generate({
|
|
87
|
+
format_version: 1, generator_version: VERSION, environment: @environment,
|
|
88
|
+
worker_revision: worker_revision,
|
|
89
|
+
sha256: artifacts.to_h { [_1, Digest::SHA256.file(File.join(@output, _1)).hexdigest] },
|
|
90
|
+
}) + "\n")
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
private
|
|
94
|
+
|
|
95
|
+
def templates
|
|
96
|
+
File.expand_path("../../../../templates", __dir__)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def check_assets!
|
|
100
|
+
%w[spike/src/runtime.js spike/src/host-bridge.js spike/scripts/cloudflare-binding-registry.mjs spike/scripts/generate-bindings.mjs].each do |path|
|
|
101
|
+
raise Error, "Worker mrbgem is missing export asset #{path}; use the documented runtime revision" unless File.file?(File.join(@gem_dir, path))
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def verify_emscripten!
|
|
106
|
+
output, status = Open3.capture2e("emcc", "--version")
|
|
107
|
+
actual = output[/emcc.*? (\d+\.\d+\.\d+)/, 1]
|
|
108
|
+
raise Error, "Expected Emscripten >= 5.0.0, got #{actual || output.lines.first}; see README for brew install emscripten and PATH setup" unless status.success? && actual && actual.split('.').first.to_i >= 5
|
|
109
|
+
rescue Errno::ENOENT
|
|
110
|
+
raise Error, "emcc is not on PATH; on macOS, run brew install emscripten and add its bin directory to PATH (expected >= 5.0.0; see README)"
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def worker_revision
|
|
114
|
+
output, status = Open3.capture2e("git", "-C", @gem_dir, "rev-parse", "HEAD")
|
|
115
|
+
status.success? ? output.strip : nil
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def write(relative, content)
|
|
119
|
+
path = File.join(@output, relative)
|
|
120
|
+
check_output_path!(path)
|
|
121
|
+
return if File.file?(path) && File.binread(path) == content.b
|
|
122
|
+
FileUtils.mkdir_p(File.dirname(path))
|
|
123
|
+
Tempfile.create(["export", ".tmp"], File.dirname(path)) do |temp|
|
|
124
|
+
temp.binmode
|
|
125
|
+
temp.write(content)
|
|
126
|
+
temp.close
|
|
127
|
+
File.rename(temp.path, path)
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def check_output_path!(path)
|
|
132
|
+
current = path
|
|
133
|
+
while current.start_with?("#{@root}/")
|
|
134
|
+
raise Error, "Refusing to export through a symlink: #{current}" if File.symlink?(current)
|
|
135
|
+
current = File.dirname(current)
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "erb"
|
|
4
|
+
require "fileutils"
|
|
5
|
+
require_relative "../template"
|
|
6
|
+
|
|
7
|
+
module Picoruby::Cloudflare::Template
|
|
8
|
+
class Generator
|
|
9
|
+
TEMPLATES = File.expand_path("../../../../templates", __dir__)
|
|
10
|
+
|
|
11
|
+
def initialize(destination, name: nil, gem_path: nil)
|
|
12
|
+
@destination = File.expand_path(destination)
|
|
13
|
+
@name = name || File.basename(@destination)
|
|
14
|
+
@gem_path = File.expand_path(gem_path) if gem_path
|
|
15
|
+
unless @name.match?(/\A[a-z0-9][a-z0-9-]{0,62}\z/)
|
|
16
|
+
raise Error, "Worker name must be 1–63 lowercase letters, digits or hyphens, starting with a letter or digit"
|
|
17
|
+
end
|
|
18
|
+
if @gem_path && !File.file?(File.join(@gem_path, "picoruby-cloudflare-template.gemspec"))
|
|
19
|
+
raise Error, "--gem-path must point to picoruby-cloudflare-template"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def generate
|
|
24
|
+
if File.exist?(@destination) || File.symlink?(@destination)
|
|
25
|
+
raise Error, "Destination already exists: #{@destination}; choose a new directory"
|
|
26
|
+
end
|
|
27
|
+
# Render everything before creating the project. Never overwrite an existing project.
|
|
28
|
+
files = Dir[File.join(TEMPLATES, "project", "**", "*.erb")].sort.to_h do |source|
|
|
29
|
+
relative = source.delete_prefix("#{TEMPLATES}/project/").delete_suffix(".erb")
|
|
30
|
+
relative = ".gitignore" if relative == "gitignore"
|
|
31
|
+
[relative, ERB.new(File.read(source), trim_mode: "-").result(binding)]
|
|
32
|
+
end
|
|
33
|
+
raise Error, "Project templates are missing from the installed gem" if files.empty?
|
|
34
|
+
FileUtils.mkdir_p(File.dirname(@destination))
|
|
35
|
+
Dir.mkdir(@destination)
|
|
36
|
+
files.each do |relative, content|
|
|
37
|
+
path = File.join(@destination, relative)
|
|
38
|
+
FileUtils.mkdir_p(File.dirname(path))
|
|
39
|
+
File.write(path, content)
|
|
40
|
+
end
|
|
41
|
+
@destination
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "open3"
|
|
4
|
+
require "rbconfig"
|
|
5
|
+
require "rake"
|
|
6
|
+
require_relative "../template"
|
|
7
|
+
|
|
8
|
+
module Picoruby::Cloudflare::Template
|
|
9
|
+
class Project
|
|
10
|
+
include Rake::DSL
|
|
11
|
+
def initialize(root:)
|
|
12
|
+
@root = File.expand_path(root)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def picoruby_root
|
|
16
|
+
path = ENV["PICORUBY_ROOT"]
|
|
17
|
+
raise Error, "Set PICORUBY_ROOT to a PicoRuby checkout with initialized submodules" if path.nil? || path.empty?
|
|
18
|
+
Picoruby::Cloudflare::Template.validate_build_path!(@root)
|
|
19
|
+
Picoruby::Cloudflare::Template.validate_build_path!(File.expand_path(path, @root))
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def doctor(out: $stdout)
|
|
23
|
+
root = picoruby_root
|
|
24
|
+
%w[Rakefile lib/picoruby/build.rb mrbgems/picoruby-mruby/lib/mruby/lib/mruby/build.rb mrbgems/mruby-compiler/lib/prism/include/prism.h].each do |file|
|
|
25
|
+
raise Error, "Missing #{file} in #{root}; initialize PicoRuby submodules" unless File.file?(File.join(root, file))
|
|
26
|
+
end
|
|
27
|
+
%w[emcc emar node].each do |command|
|
|
28
|
+
hint = command == "node" ? "install Node.js supported by Wrangler" : "on macOS, run brew install emscripten and add its bin directory to PATH (see README)"
|
|
29
|
+
output, status = Open3.capture2e(command, "--version")
|
|
30
|
+
raise Error, "#{command} is unavailable: #{output}; #{hint}" unless status.success?
|
|
31
|
+
out.puts output.lines.first
|
|
32
|
+
rescue Errno::ENOENT
|
|
33
|
+
raise Error, "#{command} is not on PATH; #{hint}"
|
|
34
|
+
end
|
|
35
|
+
_, status = Open3.capture2e("node", "-e", "require('jsonc-parser')", chdir: @root)
|
|
36
|
+
raise Error, "jsonc-parser is missing; run npm install in #{@root}" unless status.success?
|
|
37
|
+
out.puts "PicoRuby: #{root}\nReady (compiler version and runtime assets are checked during build)."
|
|
38
|
+
true
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def build
|
|
42
|
+
config = File.join(@root, "build_config.rb")
|
|
43
|
+
raise Error, "Missing #{config}" unless File.file?(config)
|
|
44
|
+
root = picoruby_root
|
|
45
|
+
raise Error, "Missing PicoRuby Rakefile: #{root}" unless File.file?(File.join(root, "Rakefile"))
|
|
46
|
+
env = {
|
|
47
|
+
"MRUBY_CONFIG" => config, "CONFIG" => config,
|
|
48
|
+
"MRUBY_BUILD_DIR" => File.join(@root, ".picoruby-build"),
|
|
49
|
+
}
|
|
50
|
+
library = File.expand_path("../../..", __dir__)
|
|
51
|
+
command = [RbConfig.ruby, "-I", library, Gem.bin_path("rake", "rake"), "-f", File.join(root, "Rakefile"), "all"]
|
|
52
|
+
raise Error, "PicoRuby build failed" unless system(env, *command, chdir: root)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def define_tasks
|
|
56
|
+
desc "Build PicoRuby and export the Worker ES module"
|
|
57
|
+
task(:build) { build }
|
|
58
|
+
desc "Check local Worker build prerequisites"
|
|
59
|
+
task(:doctor) { doctor }
|
|
60
|
+
task default: :build
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "template/version"
|
|
4
|
+
|
|
5
|
+
module Picoruby
|
|
6
|
+
module Cloudflare
|
|
7
|
+
module Template
|
|
8
|
+
class Error < StandardError; end
|
|
9
|
+
|
|
10
|
+
# The upstream mrbgem linker still interpolates build paths into a shell
|
|
11
|
+
# command. Reject whitespace and shell metacharacters before invoking it.
|
|
12
|
+
def self.validate_build_path!(path)
|
|
13
|
+
unless path.match?(%r{\A[A-Za-z0-9_./+\-]+\z})
|
|
14
|
+
raise Error, "Build paths must use ASCII letters, digits, /, _, ., + or - (upstream shell limitation): #{path}"
|
|
15
|
+
end
|
|
16
|
+
path
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module Picoruby
|
|
2
|
+
module Cloudflare
|
|
3
|
+
module Template
|
|
4
|
+
VERSION: String
|
|
5
|
+
class Error < StandardError
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def self.validate_build_path!: (String path) -> String
|
|
9
|
+
|
|
10
|
+
module CrossBuild
|
|
11
|
+
attr_accessor picoruby_cloudflare_worker_wasm_mgem_dir: String?
|
|
12
|
+
attr_accessor mruby_rack_mgem_dir: String?
|
|
13
|
+
attr_writer picoruby_cloudflare_worker_wasm_revision: String?
|
|
14
|
+
attr_writer mruby_rack_mgem_revision: String?
|
|
15
|
+
def picoruby_cloudflare_worker_wasm_revision: () -> String
|
|
16
|
+
def mruby_rack_mgem_revision: () -> String
|
|
17
|
+
def cloudflare_worker!: () ?{ (self) -> untyped } -> untyped
|
|
18
|
+
def worker_export: (app: String, output_dir: String, wrangler_config: String,
|
|
19
|
+
?environment: String?, ?project_root: String?) -> untyped
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
class Generator
|
|
23
|
+
def initialize: (String destination, ?name: String?, ?gem_path: String?) -> void
|
|
24
|
+
def generate: () -> String
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
class CLI
|
|
28
|
+
def self.run: (Array[String] argv, ?out: untyped, ?err: untyped) -> Integer
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
class Project
|
|
32
|
+
def initialize: (root: String) -> void
|
|
33
|
+
def picoruby_root: () -> String
|
|
34
|
+
def doctor: (?out: untyped) -> bool
|
|
35
|
+
def build: () -> void
|
|
36
|
+
def define_tasks: () -> untyped
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# <%= @name %>
|
|
2
|
+
|
|
3
|
+
PicoRuby Rack application on Cloudflare Workers.
|
|
4
|
+
|
|
5
|
+
1. Install Ruby >= 3.2 and Node.js (supported by Wrangler). On macOS, install Emscripten via Homebrew as shown below.
|
|
6
|
+
2. Set `PICORUBY_ROOT` to a PicoRuby checkout with its submodules initialized.
|
|
7
|
+
3. Run `bundle install` and `npm install`.
|
|
8
|
+
4. Run `bundle exec rake doctor`, then `bundle exec rake`.
|
|
9
|
+
5. Run `npm run dev`. Wrangler's custom build also runs Rake on startup and Ruby changes.
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
brew install emscripten
|
|
13
|
+
export PATH="$(brew --prefix emscripten)/bin:$PATH"
|
|
14
|
+
emcc --version
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Emscripten 5.0.0 or later is accepted; 5.0.7 and Homebrew 6.0.9 are tested.
|
|
18
|
+
Newer versions are accepted but not necessarily tested. If switching from emsdk,
|
|
19
|
+
use a shell without `emsdk_env.sh` and unset `EMSDK`, `EM_CONFIG`, and `EM_CACHE`.
|
|
20
|
+
|
|
21
|
+
The pinned Wrangler version is paired with compatibility date `2026-08-22`.
|
|
22
|
+
Update and test them together; a dry-run alone does not start workerd.
|
|
23
|
+
|
|
24
|
+
During development of the unpublished runtime, set these attributes in the
|
|
25
|
+
`cloudflare_worker!` block in `build_config.rb`:
|
|
26
|
+
|
|
27
|
+
```ruby
|
|
28
|
+
conf.cloudflare_worker! do |cf|
|
|
29
|
+
cf.picoruby_cloudflare_worker_wasm_mgem_dir = "/path/to/picoruby-cloudflare-worker-wasm"
|
|
30
|
+
# Optional: use a local Rack checkout too.
|
|
31
|
+
cf.mruby_rack_mgem_dir = "/path/to/mruby-rack"
|
|
32
|
+
end
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The block receives the CrossBuild object itself and runs before build setup.
|
|
36
|
+
Calling without a block is also supported. Both directory attributes default to `nil`, which selects GitHub sources at the
|
|
37
|
+
revisions bundled in the template gem. Override those revisions in the same block using
|
|
38
|
+
`cf.picoruby_cloudflare_worker_wasm_revision` and `cf.mruby_rack_mgem_revision`.
|
|
39
|
+
Directory attributes take precedence over revision attributes; relative paths
|
|
40
|
+
are resolved against `build_config.rb`. These sources are not selected through
|
|
41
|
+
environment variables. See the template gem README for tested revisions.
|
|
42
|
+
|
|
43
|
+
`build_config.rb` selects mrbgems and exports an ES module to `generated/worker/`.
|
|
44
|
+
Do not edit generated files. The generated Wasm, JS and app bytecode are one unit;
|
|
45
|
+
use Wrangler to bundle them, not a plain Node.js import of `src/index.js`.
|
|
46
|
+
|
|
47
|
+
Configure bindings in `wrangler.jsonc`; the build regenerates `bindings.js`.
|
|
48
|
+
Ruby can use `env["cloudflare.env"].CACHE_KV` or
|
|
49
|
+
`Cloudflare::KV.from_env(env, "CACHE_KV")`, and similarly `Cloudflare::Queue.from_env`.
|
|
50
|
+
String/JSON vars and secrets are accessible through Ruby `ENV`.
|
|
51
|
+
|
|
52
|
+
Keep secrets in `.dev.vars` locally and use `npx wrangler secret put NAME` remotely.
|
|
53
|
+
Never put them in `app.rb`, `build_config.rb` or committed config files.
|
|
54
|
+
|
|
55
|
+
For named environments, set `CLOUDFLARE_ENV=staging npm run dev` (or `npm run deploy`)
|
|
56
|
+
so Wrangler and the binding registry select the same environment. Do not select an
|
|
57
|
+
environment using only `--env`; custom build processes need `CLOUDFLARE_ENV` too.
|
|
58
|
+
|
|
59
|
+
Commit `Gemfile.lock` and `package-lock.json`. Deploy explicitly with `npm run deploy`.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
class App
|
|
2
|
+
def self.call(env)
|
|
3
|
+
# env["cloudflare.env"].CACHE_KV and
|
|
4
|
+
# Cloudflare::KV.from_env(env, "CACHE_KV") refer to the same binding.
|
|
5
|
+
message = ENV["GREETING"] || "Hello from PicoRuby on Cloudflare!"
|
|
6
|
+
[200, { "content-type" => "text/plain; charset=utf-8" }, [message + "\n"]]
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
Rackup::Handler::CloudflareWorker.run(App)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require "picoruby/cloudflare/build"
|
|
2
|
+
|
|
3
|
+
MRuby::CrossBuild.new("worker") do |conf|
|
|
4
|
+
conf.cloudflare_worker! do |cf|
|
|
5
|
+
# Optional overrides, applied before build setup:
|
|
6
|
+
# cf.picoruby_cloudflare_worker_wasm_mgem_dir = "vendor/picoruby-cloudflare-worker-wasm"
|
|
7
|
+
# cf.mruby_rack_mgem_dir = "vendor/mruby-rack"
|
|
8
|
+
# cf.picoruby_cloudflare_worker_wasm_revision = "<commit SHA>"
|
|
9
|
+
# cf.mruby_rack_mgem_revision = "<commit SHA>"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Add application mrbgems here, for example:
|
|
13
|
+
# conf.gem gemdir: File.join(__dir__, "vendor/my-gem")
|
|
14
|
+
|
|
15
|
+
conf.worker_export(
|
|
16
|
+
app: "app.rb",
|
|
17
|
+
output_dir: "generated/worker",
|
|
18
|
+
wrangler_config: "wrangler.jsonc",
|
|
19
|
+
environment: ENV["CLOUDFLARE_ENV"],
|
|
20
|
+
project_root: __dir__,
|
|
21
|
+
)
|
|
22
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "<%= @name %>",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"build": "bundle exec rake build",
|
|
7
|
+
"generate:bindings": "bundle exec rake build",
|
|
8
|
+
"dev": "wrangler dev",
|
|
9
|
+
"deploy": "wrangler deploy"
|
|
10
|
+
},
|
|
11
|
+
"devDependencies": {
|
|
12
|
+
"jsonc-parser": "3.2.0",
|
|
13
|
+
"wrangler": "4.125.0"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { createWorker } from "../generated/worker/runtime/index.js";
|
|
2
|
+
import app from "../generated/worker/app.bin";
|
|
3
|
+
import { cloudflareBindingTypes } from "../generated/worker/bindings.js";
|
|
4
|
+
|
|
5
|
+
export default createWorker({ app, bindingTypes: cloudflareBindingTypes });
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "node_modules/wrangler/config-schema.json",
|
|
3
|
+
"name": "<%= @name %>",
|
|
4
|
+
"main": "src/index.js",
|
|
5
|
+
"compatibility_date": "2026-08-22",
|
|
6
|
+
"build": {
|
|
7
|
+
"command": "bundle exec rake build",
|
|
8
|
+
"watch_dir": ["app.rb", "build_config.rb"]
|
|
9
|
+
},
|
|
10
|
+
"rules": [
|
|
11
|
+
{ "type": "Data", "globs": ["**/*.bin"], "fallthrough": true }
|
|
12
|
+
],
|
|
13
|
+
"vars": {
|
|
14
|
+
"GREETING": "Hello from PicoRuby on Cloudflare!"
|
|
15
|
+
}
|
|
16
|
+
// Add kv_namespaces / queues.producers here, then rebuild.
|
|
17
|
+
// Keep secrets out of this file; use .dev.vars and wrangler secret put.
|
|
18
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import createPicoRuby from "./picoruby-worker.js";
|
|
2
|
+
import wasm from "./picoruby-worker.wasm";
|
|
3
|
+
import { createCloudflareBindings, handleRequest, RequestBodyTooLargeError } from "./runtime.js";
|
|
4
|
+
|
|
5
|
+
export function createWorker({ app, bindingTypes }) {
|
|
6
|
+
return {
|
|
7
|
+
async fetch(request, env) {
|
|
8
|
+
try {
|
|
9
|
+
return await handleRequest(createPicoRuby, wasm, app, request, createCloudflareBindings(env, bindingTypes));
|
|
10
|
+
} catch (error) {
|
|
11
|
+
// Do not log host error messages: upstream services may include secrets.
|
|
12
|
+
if (error instanceof RequestBodyTooLargeError) {
|
|
13
|
+
return new Response("Request body too large", { status: 413 });
|
|
14
|
+
}
|
|
15
|
+
console.error("PicoRuby Worker request failed");
|
|
16
|
+
return new Response("PicoRuby Worker runtime error", { status: 500 });
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export { createCloudflareBindings, createRuntime, dispatch, closeRuntime } from "./runtime.js";
|
metadata
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: picoruby-cloudflare-template
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0.rc1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Uchio Kondo
|
|
8
|
+
bindir: exe
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: rake
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '13.0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '13.0'
|
|
26
|
+
description: Generate Rack-based Cloudflare Worker projects and configure PicoRuby
|
|
27
|
+
cross builds. Export matching WebAssembly, ES modules, application bytecode, and
|
|
28
|
+
binding registries for Wrangler.
|
|
29
|
+
email:
|
|
30
|
+
- udzura@udzura.jp
|
|
31
|
+
executables:
|
|
32
|
+
- picoruby-cloudflare
|
|
33
|
+
extensions: []
|
|
34
|
+
extra_rdoc_files: []
|
|
35
|
+
files:
|
|
36
|
+
- LICENSE
|
|
37
|
+
- README.ja.md
|
|
38
|
+
- README.md
|
|
39
|
+
- exe/picoruby-cloudflare
|
|
40
|
+
- lib/picoruby/cloudflare/build.rb
|
|
41
|
+
- lib/picoruby/cloudflare/template.rb
|
|
42
|
+
- lib/picoruby/cloudflare/template/cli.rb
|
|
43
|
+
- lib/picoruby/cloudflare/template/exporter.rb
|
|
44
|
+
- lib/picoruby/cloudflare/template/generator.rb
|
|
45
|
+
- lib/picoruby/cloudflare/template/project.rb
|
|
46
|
+
- lib/picoruby/cloudflare/template/version.rb
|
|
47
|
+
- sig/picoruby/cloudflare/template.rbs
|
|
48
|
+
- templates/project/Gemfile.erb
|
|
49
|
+
- templates/project/README.md.erb
|
|
50
|
+
- templates/project/Rakefile.erb
|
|
51
|
+
- templates/project/app.rb.erb
|
|
52
|
+
- templates/project/build_config.rb.erb
|
|
53
|
+
- templates/project/gitignore.erb
|
|
54
|
+
- templates/project/package.json.erb
|
|
55
|
+
- templates/project/src/index.js.erb
|
|
56
|
+
- templates/project/wrangler.jsonc.erb
|
|
57
|
+
- templates/runtime/index.js
|
|
58
|
+
homepage: https://github.com/udzura/picoruby-cloudflare-template
|
|
59
|
+
licenses:
|
|
60
|
+
- MIT
|
|
61
|
+
metadata:
|
|
62
|
+
allowed_push_host: https://rubygems.org
|
|
63
|
+
source_code_uri: https://github.com/udzura/picoruby-cloudflare-template/tree/main
|
|
64
|
+
documentation_uri: https://github.com/udzura/picoruby-cloudflare-template#readme
|
|
65
|
+
bug_tracker_uri: https://github.com/udzura/picoruby-cloudflare-template/issues
|
|
66
|
+
rdoc_options: []
|
|
67
|
+
require_paths:
|
|
68
|
+
- lib
|
|
69
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
70
|
+
requirements:
|
|
71
|
+
- - ">="
|
|
72
|
+
- !ruby/object:Gem::Version
|
|
73
|
+
version: 3.2.0
|
|
74
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
75
|
+
requirements:
|
|
76
|
+
- - ">="
|
|
77
|
+
- !ruby/object:Gem::Version
|
|
78
|
+
version: '0'
|
|
79
|
+
requirements: []
|
|
80
|
+
rubygems_version: 4.0.10
|
|
81
|
+
specification_version: 4
|
|
82
|
+
summary: Generate and build PicoRuby applications for Cloudflare Workers
|
|
83
|
+
test_files: []
|