@@ -29,7 +29,8 @@ function createWorkedEnvironment(
2929 dev: {
3030 createEnvironment(name , config ) {
3131 return createWorkerdDevEnvironment (name , config , {
32- hot: customHotChannel (),
32+ hot: true ,
33+ transport: customHotChannel (),
3334 })
3435 },
3536 },
@@ -82,29 +83,26 @@ Vite モジュールランナーは、最初に Vite プラグインで処理す
8283この機能の目的の 1 つは、コードを処理および実行するためのカスタマイズ可能な API を提供することです。ユーザーは、公開されたプリミティブを使用して新しい環境ファクトリーを作成できます。
8384
8485``` ts
85- import { DevEnvironment , RemoteEnvironmentTransport } from ' vite'
86+ import { DevEnvironment , HotChannel } from ' vite'
8687
8788function createWorkerdDevEnvironment(
8889 name : string ,
8990 config : ResolvedConfig ,
9091 context : DevEnvironmentContext
9192) {
92- const hot = /* ... */
9393 const connection = /* ... */
94- const transport = new RemoteEnvironmentTransport ({
94+ const transport: HotChannel = {
95+ on : (listener ) => { connection .on (' message' , listener ) },
9596 send : (data ) => connection .send (data ),
96- onMessage : (listener ) => connection .on (' message' , listener ),
97- })
97+ }
9898
9999 const workerdDevEnvironment = new DevEnvironment (name , config , {
100100 options: {
101101 resolve: { conditions: [' custom' ] },
102102 ... context .options ,
103103 },
104- hot ,
105- remoteRunner: {
106- transport ,
107- },
104+ hot: true ,
105+ transport ,
108106 })
109107 return workerdDevEnvironment
110108}
@@ -152,13 +150,12 @@ export class ModuleRunner {
152150
153151``` js
154152import { ModuleRunner , ESModulesEvaluator } from ' vite/module-runner'
155- import { root , fetchModule } from ' ./rpc-implementation.js'
153+ import { root , transport } from ' ./rpc-implementation.js'
156154
157155const moduleRunner = new ModuleRunner (
158156 {
159157 root,
160- fetchModule,
161- // HMR をサポートするために hmr.connection を提供することもできます
158+ transport,
162159 },
163160 new ESModulesEvaluator (),
164161)
@@ -177,7 +174,7 @@ export interface ModuleRunnerOptions {
177174 /**
178175 * サーバーと通信するための一連のメソッド。
179176 */
180- transport: RunnerTransport
177+ transport: ModuleRunnerTransport
181178 /**
182179 * ソースマップの解決方法を設定します。
183180 * `process.setSourceMapsEnabled` が使用可能な場合は `node` を優先します。
@@ -197,10 +194,6 @@ export interface ModuleRunnerOptions {
197194 hmr ?:
198195 | false
199196 | {
200- /**
201- * HMR がクライアントとサーバー間で通信する方法を設定します。
202- */
203- connection: ModuleRunnerHMRConnection
204197 /**
205198 * HMR ロガーを設定します。
206199 */
@@ -245,59 +238,91 @@ export interface ModuleEvaluator {
245238
246239Vite はデフォルトでこのインターフェイスを実装した ` ESModulesEvaluator ` をエクスポートします。コードの評価には ` new AsyncFunction ` を使用するので、インライン化されたソースマップがある場合は、新しい行が追加されたことを考慮して [ 2 行分のオフセット] ( https://tc39.es/ecma262/#sec-createdynamicfunction ) を追加する必要があります。これは ` ESModulesEvaluator ` によって自動的に実行されます。カスタムの Evaluator は行を追加しません。
247240
248- ## RunnerTransport
241+ ## ` ModuleRunnerTransport `
249242
250243** 型シグネチャー:**
251244
252245``` ts
253- interface RunnerTransport {
254- /**
255- * モジュールに関する情報を取得するメソッド。
256- */
257- fetchModule: FetchFunction
246+ interface ModuleRunnerTransport {
247+ connect? (handlers : ModuleRunnerTransportHandlers ): Promise <void > | void
248+ disconnect? (): Promise <void > | void
249+ send? (data : HotPayload ): Promise <void > | void
250+ invoke? (
251+ data : HotPayload ,
252+ ): Promise <{ /** result */ r: any } | { /** error */ e: any }>
253+ timeout? : number
258254}
259255```
260256
261- RPC 経由または関数を直接呼び出して環境と通信するトランスポートオブジェクト。デフォルトでは、` fetchModule ` メソッドでオブジェクトを渡す必要があります。このメソッド内ではどのようなタイプの RPC も使用できますが、Vite では設定を簡単にするために ` RemoteRunnerTransport ` クラスを使用して双方向のトランスポートインターフェースを公開しています。モジュールランナーがワーカースレッドで作成される次の例のように、サーバー上の ` RemoteEnvironmentTransport ` インスタンスと合わせる必要があります:
257+ RPC 経由または関数を直接呼び出して環境と通信するトランスポートオブジェクト。` invoke ` メソッドが実装されていない場合、` send ` メソッドと ` connect ` メソッドの実装が必須となります。Vite は内部で ` invoke ` を構築します。
258+
259+ 次の例のように、モジュールランナーがワーカー スレッドで作成されるサーバー上の ` HotChannel ` インスタンスと結合する必要があります:
262260
263261::: code-group
264262
265- ``` ts [worker.js]
263+ ``` js [worker.js]
266264import { parentPort } from ' node:worker_threads'
267265import { fileURLToPath } from ' node:url'
268- import {
269- ESModulesEvaluator ,
270- ModuleRunner ,
271- RemoteRunnerTransport ,
272- } from ' vite/module-runner'
266+ import { ESModulesEvaluator , ModuleRunner } from ' vite/module-runner'
267+
268+ /** @type {import('vite/module-runner').ModuleRunnerTransport} */
269+ const transport = {
270+ connect ({ onMessage, onDisconnection }) {
271+ parentPort .on (' message' , onMessage)
272+ parentPort .on (' close' , onDisconnection)
273+ },
274+ send (data ) {
275+ parentPort .postMessage (data)
276+ },
277+ }
273278
274279const runner = new ModuleRunner (
275280 {
276281 root: fileURLToPath (new URL (' ./' , import .meta.url)),
277- transport: new RemoteRunnerTransport ({
278- send : (data ) => parentPort .postMessage (data ),
279- onMessage : (listener ) => parentPort .on (' message' , listener ),
280- timeout: 5000 ,
281- }),
282+ transport,
282283 },
283284 new ESModulesEvaluator (),
284285)
285286` ` `
286287
287- ``` ts [server.js]
288+ ` ` ` js [server .js ]
288289import { BroadcastChannel } from ' node:worker_threads'
289290import { createServer , RemoteEnvironmentTransport , DevEnvironment } from ' vite'
290291
291292function createWorkerEnvironment (name , config , context ) {
292293 const worker = new Worker (' ./worker.js' )
293- return new DevEnvironment (name , config , {
294- hot: /* custom hot channel */ ,
295- remoteRunner: {
296- transport: new RemoteEnvironmentTransport ({
297- send : (data ) => worker .postMessage (data ),
298- onMessage : (listener ) => worker .on (' message' , listener ),
299- }),
294+ const handlerToWorkerListener = new WeakMap ()
295+
296+ const workerHotChannel = {
297+ send : (data ) => w .postMessage (data),
298+ on : (event , handler ) => {
299+ if (event === ' connection' ) return
300+
301+ const listener = (value ) => {
302+ if (value .type === ' custom' && value .event === event ) {
303+ const client = {
304+ send (payload ) {
305+ w .postMessage (payload)
306+ },
307+ }
308+ handler (value .data , client)
309+ }
310+ }
311+ handlerToWorkerListener .set (handler, listener)
312+ w .on (' message' , listener)
313+ },
314+ off : (event , handler ) => {
315+ if (event === ' connection' ) return
316+ const listener = handlerToWorkerListener .get (handler)
317+ if (listener) {
318+ w .off (' message' , listener)
319+ handlerToWorkerListener .delete (handler)
320+ }
300321 },
322+ }
323+
324+ return new DevEnvironment (name, config, {
325+ transport: workerHotChannel,
301326 })
302327}
303328
@@ -314,7 +339,7 @@ await createServer({
314339
315340:::
316341
317- ` RemoteRunnerTransport ` と ` RemoteEnvironmentTransport ` は一緒に使うことを想定していますが、必ずしも使う必要はありません。独自の関数を定義して、ランナーとサーバー間の通信を行えます。例えば、 HTTP リクエストで環境に接続する場合、 ` fetchModule ` 関数で ` fetch().json() ` を呼び出せます :
342+ HTTP リクエストを使用してランナーとサーバー間で通信する別の例 :
318343
319344` ` ` ts
320345import { ESModulesEvaluator , ModuleRunner } from ' vite/module-runner'
@@ -323,10 +348,11 @@ export const runner = new ModuleRunner(
323348 {
324349 root: fileURLToPath (new URL (' ./' , import .meta.url)),
325350 transport: {
326- async fetchModule(id , importer ) {
327- const response = await fetch (
328- ` http://my-vite-server/fetch?id=${id }&importer=${importer } ` ,
329- )
351+ async invoke (data ) {
352+ const response = await fetch (` http://my-vite-server/invoke` , {
353+ method: ' POST' ,
354+ body: JSON .stringify (data),
355+ })
330356 return response .json ()
331357 },
332358 },
@@ -337,37 +363,22 @@ export const runner = new ModuleRunner(
337363await runner .import (' /entry.js' )
338364` ` `
339365
340- ## ModuleRunnerHMRConnection
341-
342- ** 型シグネチャー:**
366+ この場合、` NormalizedHotChannel` の ` handleInvoke` メソッドを使用できます:
343367
344368` ` ` ts
345- export interface ModuleRunnerHMRConnection {
346- /**
347- * サーバーにメッセージを送信する前にチェックされます。
348- */
349- isReady(): boolean
350- /**
351- * サーバーにメッセージを送信します。
352- */
353- send(payload : HotPayload ): void
354- /**
355- * この接続が更新をトリガーしたときに HMR がどのように処理されるかを設定します。
356- * このメソッドは、接続が HMR 更新のリッスンを開始し、受信時にこのコールバックを
357- * 呼び出すことを想定しています。
358- */
359- onUpdate(callback : (payload : HotPayload ) => void ): void
360- }
369+ const customEnvironment = new DevEnvironment (name, config, context)
370+
371+ server .onRequest ((request : Request ) => {
372+ const url = new URL (request .url )
373+ if (url .pathname === ' /invoke' ) {
374+ const payload = (await request .json ()) as HotPayload
375+ const result = customEnvironment .hot .handleInvoke (payload)
376+ return new Response (JSON .stringify (result))
377+ }
378+ return Response .error ()
379+ })
361380` ` `
362381
363- このインターフェイスは HMR 通信の確立方法を定義します。Vite の SSR 中に HMR をサポートするために、Vite は ` ServerHMRConnector ` をメインエントリーからエクスポートします。` isReady ` と ` send ` メソッドは通常、カスタムイベントがトリガーされたときに呼び出されます(` import.meta.hot.send("my-event") ` のように)。
364-
365- ` onUpdate ` は、新しいモジュールランナーが初期化されたときに一度だけ呼ばれます。接続が HMR イベントをトリガーしたときに呼び出されるメソッドを渡します。実装は接続の種類(例として、` WebSocket ` /` EventEmitter ` /` MessageChannel ` )に依存しますが、通常は以下のようになります:
366-
367- ``` js
368- function onUpdate (callback ) {
369- this .connection .on (' hmr' , (event ) => callback (event .data ))
370- }
371- ```
382+ ただし、HMR をサポートするためには ` send` メソッドと ` connect` メソッドが必要です。` send` メソッドは通常、カスタムイベントがトリガーされたときに呼び出されます(` import .meta.hot.send(" my-event" )` のように)。
372383
373- コールバックはキューに入れられ、次の更新を処理する前に現在の更新が解決されるのを待ちます。ブラウザーの実装とは異なり、モジュールランナーにおける HMR の更新は、モジュールを更新する前に、すべてのリスナー( ` vite:beforeUpdate ` / ` vite:beforeFullReload ` など)が終了するまで待機します 。
384+ Vite は SSR 中の HMR をサポートするために、メインエントリーポイントから ` createServerHotChannel ` をエクスポートします 。
0 commit comments