@ishibashi0112/webview2-bridge-gen 0.2.0 → 0.3.0

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.
Files changed (44) hide show
  1. package/README.md +12 -0
  2. package/dist/cli.js +62 -6
  3. package/dist/cli.js.map +1 -1
  4. package/dist/generate.d.ts +1 -0
  5. package/dist/generate.d.ts.map +1 -1
  6. package/dist/generate.js +1 -0
  7. package/dist/generate.js.map +1 -1
  8. package/dist/init.d.ts +32 -0
  9. package/dist/init.d.ts.map +1 -0
  10. package/dist/init.js +93 -0
  11. package/dist/init.js.map +1 -0
  12. package/package.json +6 -3
  13. package/template/README.md +10 -0
  14. package/template/myapp/README.md +91 -0
  15. package/template/myapp/_gitignore +6 -0
  16. package/template/myapp/contract/contract.schema.json +66 -0
  17. package/template/myapp/contract/contract.ts +8 -0
  18. package/template/myapp/dotnet/Directory.Build.props +10 -0
  19. package/template/myapp/dotnet/MyApp.Contract/Generated/Dispatcher.Generated.vb +30 -0
  20. package/template/myapp/dotnet/MyApp.Contract/Generated/Dto.vb +39 -0
  21. package/template/myapp/dotnet/MyApp.Contract/Generated/Events.vb +32 -0
  22. package/template/myapp/dotnet/MyApp.Contract/Generated/Interfaces.vb +20 -0
  23. package/template/myapp/dotnet/MyApp.Contract/MyApp.Contract.vbproj +9 -0
  24. package/template/myapp/dotnet/MyApp.Contract/Runtime/Dispatcher.vb +151 -0
  25. package/template/myapp/dotnet/MyApp.Contract/Runtime/IBridgeEmitter.vb +22 -0
  26. package/template/myapp/dotnet/MyApp.Contract/Runtime/JsonRpc.vb +130 -0
  27. package/template/myapp/dotnet/MyApp.Host/Bridge/WebViewBridge.vb +106 -0
  28. package/template/myapp/dotnet/MyApp.Host/MainForm.vb +90 -0
  29. package/template/myapp/dotnet/MyApp.Host/MyApp.Host.vbproj +28 -0
  30. package/template/myapp/dotnet/MyApp.Host/Program.vb +12 -0
  31. package/template/myapp/dotnet/MyApp.Impl/CustomersApi.vb +38 -0
  32. package/template/myapp/dotnet/MyApp.Impl/MyApp.Impl.vbproj +9 -0
  33. package/template/myapp/dotnet/MyApp.sln +34 -0
  34. package/template/myapp/package.json +16 -0
  35. package/template/myapp/pnpm-workspace.yaml +6 -0
  36. package/template/myapp/web/index.html +13 -0
  37. package/template/myapp/web/package.json +23 -0
  38. package/template/myapp/web/src/bridge.ts +29 -0
  39. package/template/myapp/web/src/generated/contract-types.ts +33 -0
  40. package/template/myapp/web/src/main.tsx +37 -0
  41. package/template/myapp/web/src/vite-env.d.ts +6 -0
  42. package/template/myapp/web/tsconfig.json +8 -0
  43. package/template/myapp/web/vite.config.ts +17 -0
  44. package/template/myapp/webview2-bridge.gen.json +11 -0
@@ -0,0 +1,32 @@
1
+ ' <auto-generated>
2
+ ' This code was generated by @ishibashi0112/webview2-bridge-gen from contract.schema.json.
3
+ ' DO NOT EDIT. Changes will be lost when `pnpm gen` runs.
4
+ ' </auto-generated>
5
+ Option Strict On
6
+ Option Explicit On
7
+ Option Infer On
8
+
9
+ Imports System
10
+ Imports WebView2Bridge.Runtime
11
+
12
+ Namespace Global.MyApp.Contract
13
+
14
+ ''' <summary>Host → Web の型付きイベント発行ヘルパ。内部で IBridgeEmitter.Emit("event.&lt;name&gt;", payload) を呼ぶ</summary>
15
+ Public Class BridgeEvents
16
+ Private ReadOnly _emitter As IBridgeEmitter
17
+
18
+ Public Sub New(emitter As IBridgeEmitter)
19
+ If emitter Is Nothing Then Throw New ArgumentNullException(NameOf(emitter))
20
+ _emitter = emitter
21
+ End Sub
22
+
23
+ ''' <summary>契約に含まれる全イベント名</summary>
24
+ Public Shared ReadOnly EventNames As String() = {"event.progress"}
25
+
26
+ ''' <summary>JSON-RPC notification "event.progress"</summary>
27
+ Public Sub Progress(payload As ProgressEvent)
28
+ _emitter.Emit("event.progress", payload)
29
+ End Sub
30
+ End Class
31
+
32
+ End Namespace
@@ -0,0 +1,20 @@
1
+ ' <auto-generated>
2
+ ' This code was generated by @ishibashi0112/webview2-bridge-gen from contract.schema.json.
3
+ ' DO NOT EDIT. Changes will be lost when `pnpm gen` runs.
4
+ ' </auto-generated>
5
+ Option Strict On
6
+ Option Explicit On
7
+ Option Infer On
8
+
9
+ Imports System
10
+ Imports System.Threading.Tasks
11
+
12
+ Namespace Global.MyApp.Contract
13
+
14
+ ''' <summary>"customers.*" メソッドの実装。人間が Implements して WebView2Bridge.Impl に置く</summary>
15
+ Public Interface ICustomersApi
16
+ ''' <summary>JSON-RPC method "customers.list"</summary>
17
+ Function List(req As CustomersListRequest) As Task(Of CustomersListResponse)
18
+ End Interface
19
+
20
+ End Namespace
@@ -0,0 +1,9 @@
1
+ <Project Sdk="Microsoft.NET.Sdk">
2
+ <PropertyGroup>
3
+ <TargetFramework>netstandard2.0</TargetFramework>
4
+ <RootNamespace>MyApp.Contract</RootNamespace>
5
+ </PropertyGroup>
6
+ <ItemGroup>
7
+ <PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
8
+ </ItemGroup>
9
+ </Project>
@@ -0,0 +1,151 @@
1
+ ' <auto-generated>
2
+ ' webview2-bridge VB JSON-RPC runtime (namespace WebView2Bridge.Runtime; needs Newtonsoft.Json)
3
+ ' copied by @ishibashi0112/webview2-bridge-gen 0.3.0 from its bundled vb-runtime/runtime/.
4
+ ' DO NOT EDIT. Changes will be lost when `pnpm gen` runs.
5
+ ' To update, upgrade the npm package and run the generator again.
6
+ ' </auto-generated>
7
+ Option Strict On
8
+
9
+ Imports System
10
+ Imports System.Collections.Generic
11
+ Imports System.Threading.Tasks
12
+ Imports Newtonsoft.Json
13
+ Imports Newtonsoft.Json.Linq
14
+
15
+ Namespace Global.WebView2Bridge.Runtime
16
+
17
+ ''' <summary>
18
+ ''' JSON-RPC 要求文字列を受け取り、登録されたハンドラへ振り分けて応答文字列を返す。
19
+ ''' 手書き側(このファイル)は契約に依存しない汎用部分。
20
+ ''' 生成側(Dispatcher.Generated.vb)が Register(api As IXxxApi) を提供し、RegisterHandler を呼ぶ。
21
+ ''' WebView2 には依存しない。
22
+ ''' </summary>
23
+ Partial Public Class Dispatcher
24
+
25
+ ''' <summary>型消去したハンドラ。params(JToken) → 結果(Object)</summary>
26
+ Private Interface IHandler
27
+ Function InvokeAsync(params As JToken) As Task(Of Object)
28
+ End Interface
29
+
30
+ Private NotInheritable Class TypedHandler(Of TReq, TRes)
31
+ Implements IHandler
32
+
33
+ Private ReadOnly _handler As Func(Of TReq, Task(Of TRes))
34
+ Private ReadOnly _serializer As JsonSerializer
35
+
36
+ Public Sub New(handler As Func(Of TReq, Task(Of TRes)), serializer As JsonSerializer)
37
+ _handler = handler
38
+ _serializer = serializer
39
+ End Sub
40
+
41
+ Public Async Function InvokeAsync(params As JToken) As Task(Of Object) Implements IHandler.InvokeAsync
42
+ Dim req As TReq
43
+ Try
44
+ ' params 省略時は {} として扱う(全プロパティ optional な入力を許す)
45
+ Dim source As JToken = If(params Is Nothing OrElse params.Type = JTokenType.Null, New JObject(), params)
46
+ If source.Type <> JTokenType.Object Then
47
+ Throw New JsonRpcException(JsonRpcErrorCodes.InvalidParams, "Invalid params: expected an object")
48
+ End If
49
+ req = source.ToObject(Of TReq)(_serializer)
50
+ Catch ex As JsonException
51
+ Throw New JsonRpcException(JsonRpcErrorCodes.InvalidParams, "Invalid params: " & ex.Message, ex.GetType().FullName)
52
+ End Try
53
+ Dim result As TRes = Await _handler(req).ConfigureAwait(False)
54
+ Return result
55
+ End Function
56
+ End Class
57
+
58
+ Private ReadOnly _handlers As New Dictionary(Of String, IHandler)(StringComparer.Ordinal)
59
+ Private ReadOnly _serializer As JsonSerializer
60
+
61
+ Public Sub New()
62
+ Me.New(JsonRpc.CreateSerializerSettings())
63
+ End Sub
64
+
65
+ Public Sub New(settings As JsonSerializerSettings)
66
+ If settings Is Nothing Then Throw New ArgumentNullException(NameOf(settings))
67
+ _serializer = JsonSerializer.Create(settings)
68
+ End Sub
69
+
70
+ ''' <summary>JSON の読み書きに使うシリアライザ。Host 側の通知にも同じものを使う</summary>
71
+ Public ReadOnly Property Serializer As JsonSerializer
72
+ Get
73
+ Return _serializer
74
+ End Get
75
+ End Property
76
+
77
+ ''' <summary>登録済みメソッド名</summary>
78
+ Public ReadOnly Property RegisteredMethods As IEnumerable(Of String)
79
+ Get
80
+ Return _handlers.Keys
81
+ End Get
82
+ End Property
83
+
84
+ ''' <summary>
85
+ ''' 型付きハンドラを登録する。通常は生成側の Register(api) から呼ばれる。
86
+ ''' 同名メソッドは後勝ち。
87
+ ''' </summary>
88
+ Public Sub RegisterHandler(Of TReq, TRes)(method As String, handler As Func(Of TReq, Task(Of TRes)))
89
+ If String.IsNullOrEmpty(method) Then Throw New ArgumentException("method is required", NameOf(method))
90
+ If handler Is Nothing Then Throw New ArgumentNullException(NameOf(handler))
91
+ _handlers(method) = New TypedHandler(Of TReq, TRes)(handler, _serializer)
92
+ End Sub
93
+
94
+ ''' <summary>
95
+ ''' 要求 JSON を処理し、応答 JSON を返す。例外は投げず、必ず JSON-RPC エラー応答にする。
96
+ ''' 要求に id が無い(通知)場合は処理だけ行い Nothing を返す。
97
+ ''' </summary>
98
+ Public Async Function HandleAsync(requestJson As String) As Task(Of String)
99
+ Dim id As JToken = Nothing
100
+ Dim hasId As Boolean = False
101
+ Try
102
+ Dim token As JToken
103
+ Try
104
+ token = JsonRpc.ParseToken(If(requestJson, String.Empty))
105
+ Catch ex As JsonException
106
+ Return JsonRpc.BuildError(Nothing, JsonRpcErrorCodes.ParseError, "Parse error: " & ex.Message, Nothing, _serializer)
107
+ End Try
108
+
109
+ Dim request = TryCast(token, JObject)
110
+ If request Is Nothing Then
111
+ Return JsonRpc.BuildError(Nothing, JsonRpcErrorCodes.InvalidRequest, "Invalid Request: expected an object", Nothing, _serializer)
112
+ End If
113
+
114
+ Dim idToken As JToken = Nothing
115
+ If request.TryGetValue("id", idToken) AndAlso idToken.Type <> JTokenType.Null Then
116
+ id = idToken
117
+ hasId = True
118
+ End If
119
+
120
+ Dim methodToken As JToken = Nothing
121
+ If Not request.TryGetValue("method", methodToken) OrElse methodToken.Type <> JTokenType.String Then
122
+ Return If(hasId, JsonRpc.BuildError(id, JsonRpcErrorCodes.InvalidRequest, "Invalid Request: method is required", Nothing, _serializer), Nothing)
123
+ End If
124
+ Dim method As String = methodToken.Value(Of String)()
125
+
126
+ Dim handler As IHandler = Nothing
127
+ If Not _handlers.TryGetValue(method, handler) Then
128
+ Return If(hasId, JsonRpc.BuildError(id, JsonRpcErrorCodes.MethodNotFound, "Method not found: " & method, Nothing, _serializer), Nothing)
129
+ End If
130
+
131
+ Dim params As JToken = Nothing
132
+ request.TryGetValue("params", params)
133
+
134
+ Dim result As Object = Await handler.InvokeAsync(params).ConfigureAwait(False)
135
+ Return If(hasId, JsonRpc.BuildResult(id, result, _serializer), Nothing)
136
+
137
+ Catch ex As JsonRpcException
138
+ Return If(hasId, JsonRpc.BuildError(id, ex.Code, ex.Message, ex.ErrorData, _serializer), Nothing)
139
+ Catch ex As Exception
140
+ ' 実装側の未処理例外: -32000、message に例外メッセージ、data に例外型名(HANDOFF.md §5)
141
+ Return If(hasId, JsonRpc.BuildError(id, JsonRpcErrorCodes.ServerError, ex.Message, ex.GetType().FullName, _serializer), Nothing)
142
+ End Try
143
+ End Function
144
+
145
+ ''' <summary>Host → Web の通知 JSON を作る(送信は Host 側)</summary>
146
+ Public Function BuildNotification(method As String, params As Object) As String
147
+ Return JsonRpc.BuildNotification(method, params, _serializer)
148
+ End Function
149
+ End Class
150
+
151
+ End Namespace
@@ -0,0 +1,22 @@
1
+ ' <auto-generated>
2
+ ' webview2-bridge VB JSON-RPC runtime (namespace WebView2Bridge.Runtime; needs Newtonsoft.Json)
3
+ ' copied by @ishibashi0112/webview2-bridge-gen 0.3.0 from its bundled vb-runtime/runtime/.
4
+ ' DO NOT EDIT. Changes will be lost when `pnpm gen` runs.
5
+ ' To update, upgrade the npm package and run the generator again.
6
+ ' </auto-generated>
7
+ Option Strict On
8
+
9
+ Namespace Global.WebView2Bridge.Runtime
10
+
11
+ ''' <summary>
12
+ ''' Host → Web の通知(JSON-RPC notification)を送る口。
13
+ ''' Contract は WebView2 に依存しないので、実体は Host 側(WebViewBridge)が実装する。
14
+ ''' 生成される BridgeEvents はこれを通して "event.&lt;name&gt;" を発行する。
15
+ ''' </summary>
16
+ Public Interface IBridgeEmitter
17
+ ''' <param name="method">"event.progress" のような通知名</param>
18
+ ''' <param name="params">ペイロード(生成 DTO)。Nothing 可</param>
19
+ Sub Emit(method As String, params As Object)
20
+ End Interface
21
+
22
+ End Namespace
@@ -0,0 +1,130 @@
1
+ ' <auto-generated>
2
+ ' webview2-bridge VB JSON-RPC runtime (namespace WebView2Bridge.Runtime; needs Newtonsoft.Json)
3
+ ' copied by @ishibashi0112/webview2-bridge-gen 0.3.0 from its bundled vb-runtime/runtime/.
4
+ ' DO NOT EDIT. Changes will be lost when `pnpm gen` runs.
5
+ ' To update, upgrade the npm package and run the generator again.
6
+ ' </auto-generated>
7
+ Option Strict On
8
+
9
+ Imports System
10
+ Imports System.IO
11
+ Imports Newtonsoft.Json
12
+ Imports Newtonsoft.Json.Linq
13
+
14
+ Namespace Global.WebView2Bridge.Runtime
15
+
16
+ ''' <summary>JSON-RPC 2.0 のエラーコード(HANDOFF.md §5)</summary>
17
+ Public NotInheritable Class JsonRpcErrorCodes
18
+ Private Sub New()
19
+ End Sub
20
+
21
+ Public Const ParseError As Integer = -32700
22
+ Public Const InvalidRequest As Integer = -32600
23
+ Public Const MethodNotFound As Integer = -32601
24
+ Public Const InvalidParams As Integer = -32602
25
+ Public Const InternalError As Integer = -32603
26
+ ''' <summary>アプリ定義エラーの既定値。実装側の未処理例外はこのコードになる</summary>
27
+ Public Const ServerError As Integer = -32000
28
+ End Class
29
+
30
+ ''' <summary>
31
+ ''' 実装(IXxxApi)から意図的に JSON-RPC エラーを返したいときに投げる。
32
+ ''' Code は -32000 以下のアプリ定義コードを使う。
33
+ ''' </summary>
34
+ Public Class JsonRpcException
35
+ Inherits Exception
36
+
37
+ Public ReadOnly Property Code As Integer
38
+ Public ReadOnly Property ErrorData As Object
39
+
40
+ Public Sub New(code As Integer, message As String)
41
+ Me.New(code, message, Nothing)
42
+ End Sub
43
+
44
+ Public Sub New(code As Integer, message As String, data As Object)
45
+ MyBase.New(message)
46
+ Me.Code = code
47
+ Me.ErrorData = data
48
+ End Sub
49
+ End Class
50
+
51
+ ''' <summary>JSON-RPC 封筒の組み立て・解釈。Dispatcher と Host(WebViewBridge)が共用する</summary>
52
+ Public NotInheritable Class JsonRpc
53
+ Private Sub New()
54
+ End Sub
55
+
56
+ Public Const Version As String = "2.0"
57
+
58
+ ''' <summary>
59
+ ''' ブリッジ全体で使う Newtonsoft の設定。
60
+ ''' DateParseHandling.None: "2024-01-01T00:00:00Z" のような文字列を Date に変換せず、文字列のまま往復させる。
61
+ ''' </summary>
62
+ Public Shared Function CreateSerializerSettings() As JsonSerializerSettings
63
+ Return New JsonSerializerSettings() With {
64
+ .DateParseHandling = DateParseHandling.None,
65
+ .NullValueHandling = NullValueHandling.Include,
66
+ .Formatting = Formatting.None
67
+ }
68
+ End Function
69
+
70
+ ''' <summary>JSON 文字列 → JToken。日付文字列を自動変換しない</summary>
71
+ Public Shared Function ParseToken(json As String) As JToken
72
+ Using sr As New StringReader(json)
73
+ Using reader As New JsonTextReader(sr)
74
+ reader.DateParseHandling = DateParseHandling.None
75
+ Dim token = JToken.ReadFrom(reader)
76
+ ' 末尾にゴミが無いことを確認する("{}{}" のような入力を弾く)
77
+ If reader.Read() Then
78
+ Throw New JsonReaderException("Additional text found after JSON root")
79
+ End If
80
+ Return token
81
+ End Using
82
+ End Using
83
+ End Function
84
+
85
+ ''' <summary>成功応答 {"jsonrpc":"2.0","id":...,"result":...}</summary>
86
+ Public Shared Function BuildResult(id As JToken, result As Object, serializer As JsonSerializer) As String
87
+ Dim resultToken As JToken = If(result Is Nothing, CType(JValue.CreateNull(), JToken), JToken.FromObject(result, serializer))
88
+ Dim o As New JObject() From {
89
+ {"jsonrpc", Version},
90
+ {"id", NormalizeId(id)},
91
+ {"result", resultToken}
92
+ }
93
+ Return o.ToString(Formatting.None)
94
+ End Function
95
+
96
+ ''' <summary>エラー応答 {"jsonrpc":"2.0","id":...,"error":{"code","message","data"}}</summary>
97
+ Public Shared Function BuildError(id As JToken, code As Integer, message As String, data As Object, serializer As JsonSerializer) As String
98
+ Dim dataToken As JToken = If(data Is Nothing, CType(JValue.CreateNull(), JToken), JToken.FromObject(data, serializer))
99
+ Dim err As New JObject() From {
100
+ {"code", code},
101
+ {"message", If(message, String.Empty)},
102
+ {"data", dataToken}
103
+ }
104
+ Dim o As New JObject() From {
105
+ {"jsonrpc", Version},
106
+ {"id", NormalizeId(id)},
107
+ {"error", err}
108
+ }
109
+ Return o.ToString(Formatting.None)
110
+ End Function
111
+
112
+ ''' <summary>通知 {"jsonrpc":"2.0","method":...,"params":...}(id なし)</summary>
113
+ Public Shared Function BuildNotification(method As String, params As Object, serializer As JsonSerializer) As String
114
+ If String.IsNullOrEmpty(method) Then Throw New ArgumentException("method is required", NameOf(method))
115
+ Dim paramsToken As JToken = If(params Is Nothing, CType(JValue.CreateNull(), JToken), JToken.FromObject(params, serializer))
116
+ Dim o As New JObject() From {
117
+ {"jsonrpc", Version},
118
+ {"method", method},
119
+ {"params", paramsToken}
120
+ }
121
+ Return o.ToString(Formatting.None)
122
+ End Function
123
+
124
+ Private Shared Function NormalizeId(id As JToken) As JToken
125
+ If id Is Nothing Then Return JValue.CreateNull()
126
+ Return id.DeepClone()
127
+ End Function
128
+ End Class
129
+
130
+ End Namespace
@@ -0,0 +1,106 @@
1
+ ' <auto-generated>
2
+ ' webview2-bridge VB WinForms bridge (namespace WebView2Bridge.WinForms; needs Microsoft.Web.WebView2 and the runtime)
3
+ ' copied by @ishibashi0112/webview2-bridge-gen 0.3.0 from its bundled vb-runtime/winforms/.
4
+ ' DO NOT EDIT. Changes will be lost when `pnpm gen` runs.
5
+ ' To update, upgrade the npm package and run the generator again.
6
+ ' </auto-generated>
7
+ Option Strict On
8
+
9
+ Imports System
10
+ Imports System.Diagnostics
11
+ Imports System.Windows.Forms
12
+ Imports Microsoft.Web.WebView2.Core
13
+ Imports Microsoft.Web.WebView2.WinForms
14
+ Imports WebView2Bridge.Runtime
15
+
16
+ Namespace Global.WebView2Bridge.WinForms
17
+
18
+ ''' <summary>
19
+ ''' WebView2 コントロールと Dispatcher をつなぐ。
20
+ ''' Web → Host: WebMessageReceived → Dispatcher.HandleAsync → PostWebMessageAsJson
21
+ ''' Host → Web: Emit(method, payload) → 通知 JSON → PostWebMessageAsJson(UI スレッドへマーシャリング)
22
+ ''' AddHostObjectToScript は使わない(HANDOFF.md §5)。
23
+ ''' </summary>
24
+ Public NotInheritable Class WebViewBridge
25
+ Implements IBridgeEmitter
26
+ Implements IDisposable
27
+
28
+ Private ReadOnly _webView As WebView2
29
+ Private ReadOnly _dispatcher As Dispatcher
30
+ Private _core As CoreWebView2
31
+ Private _attached As Boolean
32
+
33
+ Public Sub New(webView As WebView2, dispatcher As Dispatcher)
34
+ If webView Is Nothing Then Throw New ArgumentNullException(NameOf(webView))
35
+ If dispatcher Is Nothing Then Throw New ArgumentNullException(NameOf(dispatcher))
36
+ _webView = webView
37
+ _dispatcher = dispatcher
38
+ End Sub
39
+
40
+ Public ReadOnly Property Dispatcher As Dispatcher
41
+ Get
42
+ Return _dispatcher
43
+ End Get
44
+ End Property
45
+
46
+ ''' <summary>EnsureCoreWebView2Async の後に呼ぶ。WebMessageReceived を購読する</summary>
47
+ Public Sub Attach()
48
+ If _attached Then Return
49
+ If _webView.CoreWebView2 Is Nothing Then
50
+ Throw New InvalidOperationException("Call EnsureCoreWebView2Async before Attach")
51
+ End If
52
+ _core = _webView.CoreWebView2
53
+ AddHandler _core.WebMessageReceived, AddressOf OnWebMessageReceived
54
+ _attached = True
55
+ End Sub
56
+
57
+ Private Async Sub OnWebMessageReceived(sender As Object, e As CoreWebView2WebMessageReceivedEventArgs)
58
+ ' Web 側は postMessage(obj) で送るので WebMessageAsJson で受ける(TryGetWebMessageAsString は使わない)
59
+ Dim requestJson As String = e.WebMessageAsJson
60
+ Dim responseJson As String
61
+ Try
62
+ ' HandleAsync は例外を投げず JSON-RPC エラーに変換する。ここは UI スレッドに戻ってくる
63
+ responseJson = Await _dispatcher.HandleAsync(requestJson)
64
+ Catch ex As Exception
65
+ Debug.WriteLine($"[WebViewBridge] unexpected: {ex}")
66
+ Return
67
+ End Try
68
+ If responseJson Is Nothing Then Return ' 通知(id なし)には応答しない
69
+ Post(responseJson)
70
+ End Sub
71
+
72
+ ''' <summary>Host → Web の通知。どのスレッドから呼んでもよい</summary>
73
+ Public Sub Emit(method As String, params As Object) Implements IBridgeEmitter.Emit
74
+ Dim json As String = _dispatcher.BuildNotification(method, params)
75
+ Post(json)
76
+ End Sub
77
+
78
+ Private Sub Post(json As String)
79
+ If _core Is Nothing OrElse _webView.IsDisposed Then Return
80
+ If _webView.InvokeRequired Then
81
+ _webView.BeginInvoke(New Action(Sub() PostOnUiThread(json)))
82
+ Else
83
+ PostOnUiThread(json)
84
+ End If
85
+ End Sub
86
+
87
+ Private Sub PostOnUiThread(json As String)
88
+ If _core Is Nothing OrElse _webView.IsDisposed Then Return
89
+ Try
90
+ _core.PostWebMessageAsJson(json)
91
+ Catch ex As Exception
92
+ ' ナビゲーション中・破棄中など。ブリッジ自体は落とさない
93
+ Debug.WriteLine($"[WebViewBridge] PostWebMessageAsJson failed: {ex.Message}")
94
+ End Try
95
+ End Sub
96
+
97
+ Public Sub Dispose() Implements IDisposable.Dispose
98
+ If _attached AndAlso _core IsNot Nothing Then
99
+ RemoveHandler _core.WebMessageReceived, AddressOf OnWebMessageReceived
100
+ End If
101
+ _attached = False
102
+ _core = Nothing
103
+ End Sub
104
+ End Class
105
+
106
+ End Namespace
@@ -0,0 +1,90 @@
1
+ Option Strict On
2
+
3
+ Imports System
4
+ Imports System.IO
5
+ Imports System.Windows.Forms
6
+ Imports Microsoft.Web.WebView2.Core
7
+ Imports Microsoft.Web.WebView2.WinForms
8
+ Imports MyApp.Contract
9
+ Imports MyApp.Impl
10
+ Imports WebView2Bridge.Runtime
11
+ Imports WebView2Bridge.WinForms
12
+
13
+ ''' <summary>
14
+ ''' 窓 + WebView2 + Dispatcher。人間が書くホスト側はこのファイルだけ(WebViewBridge は gen が Bridge/ に書く)。
15
+ ''' Debug かつ環境変数 WEBVIEW2_BRIDGE_DEV_URL があれば Vite dev server へ(通常 http://localhost:5173)
16
+ ''' それ以外は exe 隣の wwwroot を https://app.local/ にマッピングして index.html を開く
17
+ ''' VS のフォームデザイナは使っていない(コードで WebView2 を Dock=Fill している)。
18
+ ''' デザイナで部品を足したくなったら MainForm.Designer.vb に分離する。
19
+ ''' </summary>
20
+ Public Class MainForm
21
+ Inherits Form
22
+
23
+ Public Const VirtualHost As String = "app.local"
24
+ Public Const DevUrlEnvVar As String = "WEBVIEW2_BRIDGE_DEV_URL"
25
+
26
+ Private ReadOnly WebView As New WebView2() With {.Dock = DockStyle.Fill}
27
+ Private _bridge As WebViewBridge
28
+
29
+ Public Sub New()
30
+ Text = "MyApp"
31
+ Width = 1000
32
+ Height = 700
33
+ Controls.Add(WebView)
34
+ End Sub
35
+
36
+ Private Async Sub MainForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
37
+ Try
38
+ ' ユーザーデータは exe 隣ではなく LocalAppData に置く(Program Files 配下でも動くように)
39
+ Dim userDataFolder = Path.Combine(
40
+ Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "MyApp")
41
+ Dim env = Await CoreWebView2Environment.CreateAsync(Nothing, userDataFolder)
42
+ Await WebView.EnsureCoreWebView2Async(env)
43
+
44
+ Dim core = WebView.CoreWebView2
45
+ core.Settings.AreDevToolsEnabled = True ' F12 で DevTools
46
+ core.Settings.IsStatusBarEnabled = False
47
+
48
+ ' 契約の実装を Dispatcher に登録する(API を増やしたらここに Register を足す)
49
+ Dim dispatcher As New Dispatcher()
50
+ _bridge = New WebViewBridge(WebView, dispatcher)
51
+ Dim events As New BridgeEvents(_bridge)
52
+ dispatcher.Register(New CustomersApi(events))
53
+ _bridge.Attach()
54
+
55
+ Dim devUrl = DevServerUrl()
56
+ If devUrl IsNot Nothing Then
57
+ Text = $"MyApp - dev ({devUrl})"
58
+ core.Navigate(devUrl)
59
+ Else
60
+ Dim wwwroot = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "wwwroot")
61
+ If Not File.Exists(Path.Combine(wwwroot, "index.html")) Then
62
+ ' 無いフォルダを SetVirtualHostNameToFolderMapping に渡すと DirectoryNotFoundException になるので、ここで止める
63
+ MessageBox.Show(
64
+ $"wwwroot が見つかりません: {wwwroot}{Environment.NewLine}" &
65
+ "`pnpm build:web` の後に Host をビルドすると web/dist がコピーされます。" & Environment.NewLine &
66
+ $"開発中は環境変数 {DevUrlEnvVar}=http://localhost:5173 を設定して起動してください。",
67
+ Text, MessageBoxButtons.OK, MessageBoxIcon.Warning)
68
+ Return
69
+ End If
70
+ core.SetVirtualHostNameToFolderMapping(VirtualHost, wwwroot, CoreWebView2HostResourceAccessKind.Allow)
71
+ core.Navigate($"https://{VirtualHost}/index.html")
72
+ End If
73
+ Catch ex As Exception
74
+ MessageBox.Show(ex.ToString(), "WebView2 の初期化に失敗しました", MessageBoxButtons.OK, MessageBoxIcon.Error)
75
+ End Try
76
+ End Sub
77
+
78
+ ''' <summary>Debug ビルドで WEBVIEW2_BRIDGE_DEV_URL が設定されていればその URL、それ以外は Nothing</summary>
79
+ Private Shared Function DevServerUrl() As String
80
+ #If DEBUG Then
81
+ Dim url = Environment.GetEnvironmentVariable(DevUrlEnvVar)
82
+ If Not String.IsNullOrWhiteSpace(url) Then Return url.Trim()
83
+ #End If
84
+ Return Nothing
85
+ End Function
86
+
87
+ Private Sub MainForm_FormClosed(sender As Object, e As FormClosedEventArgs) Handles MyBase.FormClosed
88
+ _bridge?.Dispose()
89
+ End Sub
90
+ End Class
@@ -0,0 +1,28 @@
1
+ <Project Sdk="Microsoft.NET.Sdk">
2
+ <PropertyGroup>
3
+ <OutputType>WinExe</OutputType>
4
+ <TargetFramework>net48</TargetFramework>
5
+ <UseWindowsForms>true</UseWindowsForms>
6
+ <RootNamespace>MyApp.Host</RootNamespace>
7
+ <MyType>WindowsForms</MyType>
8
+ <StartupObject>MyApp.Host.Program</StartupObject>
9
+ <!--
10
+ AnyCPU のままだと Windows の dotnet build で exe は 64 ビット、WebView2Loader.dll は x86 だけ出力されて
11
+ 起動時に BadImageFormatException になる(SDK が .NET Framework exe に win7-x86 を仮定し、WebView2 の
12
+ ローダーコピーと食い違う)。x64 に固定して揃える。32 ビット専用の DB ドライバ等が要るなら x86 にする。
13
+ -->
14
+ <PlatformTarget>x64</PlatformTarget>
15
+ <WebDistDir>$(MSBuildProjectDirectory)\..\..\web\dist</WebDistDir>
16
+ </PropertyGroup>
17
+ <ItemGroup>
18
+ <PackageReference Include="Microsoft.Web.WebView2" Version="1.0.4191.47" />
19
+ <PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
20
+ <ProjectReference Include="..\MyApp.Contract\MyApp.Contract.vbproj" />
21
+ <ProjectReference Include="..\MyApp.Impl\MyApp.Impl.vbproj" />
22
+ </ItemGroup>
23
+ <Target Name="CopyWebDist" AfterTargets="Build" Condition="Exists('$(WebDistDir)\index.html')">
24
+ <ItemGroup><WebDistFiles Include="$(WebDistDir)\**\*" /></ItemGroup>
25
+ <RemoveDir Directories="$(OutDir)wwwroot" />
26
+ <Copy SourceFiles="@(WebDistFiles)" DestinationFiles="@(WebDistFiles->'$(OutDir)wwwroot\%(RecursiveDir)%(Filename)%(Extension)')" />
27
+ </Target>
28
+ </Project>
@@ -0,0 +1,12 @@
1
+ Option Strict On
2
+ Imports System
3
+ Imports System.Windows.Forms
4
+
5
+ Friend Module Program
6
+ <STAThread>
7
+ Friend Sub Main()
8
+ Application.EnableVisualStyles()
9
+ Application.SetCompatibleTextRenderingDefault(False)
10
+ Application.Run(New MainForm())
11
+ End Sub
12
+ End Module
@@ -0,0 +1,38 @@
1
+ Option Strict On
2
+
3
+ Imports System
4
+ Imports System.Collections.Generic
5
+ Imports System.Linq
6
+ Imports System.Threading.Tasks
7
+ Imports MyApp.Contract
8
+
9
+ ''' <summary>
10
+ ''' "customers.*" の実装。人間が書く VB はこのようなクラスと MainForm だけ。
11
+ ''' ここで SqlClient / Oracle.ManagedDataAccess 等を使い DB と話す。
12
+ ''' 振る舞いは web/src/bridge.ts のモックと揃えておく(ブラウザ単体と WebView2 内で同じ動きにする)。
13
+ ''' </summary>
14
+ Public Class CustomersApi
15
+ Implements ICustomersApi
16
+
17
+ Private ReadOnly _events As BridgeEvents
18
+
19
+ Private Shared ReadOnly Data As Customer() = {
20
+ New Customer With {.Id = "1", .Name = "山田商事"},
21
+ New Customer With {.Id = "2", .Name = "佐藤工業"},
22
+ New Customer With {.Id = "3", .Name = "鈴木電機"}
23
+ }
24
+
25
+ ''' <param name="events">進捗などのイベント発行先。Nothing なら発行しない</param>
26
+ Public Sub New(events As BridgeEvents)
27
+ _events = events
28
+ End Sub
29
+
30
+ Public Async Function List(req As CustomersListRequest) As Task(Of CustomersListResponse) Implements ICustomersApi.List
31
+ _events?.Progress(New ProgressEvent With {.Percent = 0})
32
+ Await Task.Delay(100).ConfigureAwait(False)
33
+ Dim kw = If(req.Keyword, "")
34
+ Dim hit = Data.Where(Function(c) c.Name.Contains(kw)).ToList()
35
+ _events?.Progress(New ProgressEvent With {.Percent = 100})
36
+ Return New CustomersListResponse With {.Items = hit}
37
+ End Function
38
+ End Class
@@ -0,0 +1,9 @@
1
+ <Project Sdk="Microsoft.NET.Sdk">
2
+ <PropertyGroup>
3
+ <TargetFramework>net48</TargetFramework>
4
+ <RootNamespace>MyApp.Impl</RootNamespace>
5
+ </PropertyGroup>
6
+ <ItemGroup>
7
+ <ProjectReference Include="..\MyApp.Contract\MyApp.Contract.vbproj" />
8
+ </ItemGroup>
9
+ </Project>