ymmooot

Nuxt の WebSocket サーバーに接続してビルドの進捗を受け取る

Nuxt のビルドの完了検知がしたい

通常は、Nuxt の hook 機能を使う。
が、訳あって、Nuxt のプロセス外からビルドの完了を検知したく、ビルドの進捗を WebSocket でやってるのでそこに勝手につなぎに行くことにした。

Node.js だとこう

#!/usr/bin/env node
const http = require('http');
const { exec, spawn } = require('child_process');
const WebSocketClient = require('websocket').client;

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
const waitForNuxt = async () => {
  let count = 0;
  let resolve, reject;
  const promise = new Promise((_resolve, _reject) => {
    resolve = _resolve;
    reject = _reject;
  });

  const host = process.env.NUXT_HOST || 'localhost';
  const port = process.env.NUXT_PORT || 3000;
  const url = `ws://${host}:${port}/_loading/ws`;

  const client = new WebSocketClient();
  client.on('connect', conn => {
    console.log('Nuxt is building');
    conn.on('message', message => {
      const data = JSON.parse(message.utf8Data);
      if (data.allDone) {
        resolve();
      }
    });
    conn.on('error', error => {
      reject(error.toString());
    });
  });
  client.on('connectFailed', async error => {
    count += 1;
    if (count === 30) {
      reject('failed to connect');
    }
    await sleep(1000);
    client.connect(url, 'echo-protocol');
  });
  client.connect(url, 'echo-protocol');
  return promise;
};

const main = async () => {
  const nuxtp = spawn('npm', ['run', 'dev'], { detached: true });

  console.log('Waiting for Nuxt');
  await waitForNuxt().catch(err => {
    console.log(err);
    process.exit(1);
  });
  console.log('Nuxt is ready');

  // do something here

  process.kill(-nuxtp.pid);
};

main();

console.log や再接続の上限数を直接埋めてしまっているが、こんな感じで大体できた。
L68(// do something here) の実行結果によって終了ステータスを変えたりするのも良い。

ブラウザだとこう

ブラウザだと WebSocket API が生えているので、それを使えば良い

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
const connectWs = () => {
  const ws = new WebSocket('ws://localhost:3000/_loading/ws');
  ws.onopen = () => {
    console.log(connected);
  };
  ws.onerror = async () => {
    await sleep(1000);
    connectWs();
  };
  ws.onmessage = event => {
    const data = JSON.parse(event.data);
    const progress = Math.round(data.states.reduce((p, s) => p + s.progress, 0) / data.states.length);
    console.log(progress);
  };
};
connectWs();

大体こんな感じでできる。



参考: github.com/nuxt/nuxt.js/blob/dev/packages/vue-app/template/components/nuxt-build-indicator.vue