watch-rebuild-plugin.ts 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. import fs from 'node:fs';
  2. import path from 'node:path';
  3. import type { PluginOption } from 'vite';
  4. import { WebSocket } from 'ws';
  5. import MessageInterpreter from '../interpreter';
  6. import { BUILD_COMPLETE, LOCAL_RELOAD_SOCKET_URL } from '../constant';
  7. import type { PluginConfig } from '../types';
  8. const injectionsPath = path.resolve(__dirname, '..', '..', '..', 'build', 'injections');
  9. const refreshCode = fs.readFileSync(path.resolve(injectionsPath, 'refresh.js'), 'utf-8');
  10. const reloadCode = fs.readFileSync(path.resolve(injectionsPath, 'reload.js'), 'utf-8');
  11. export function watchRebuildPlugin(config: PluginConfig): PluginOption {
  12. const { refresh, reload, id: _id, onStart } = config;
  13. const hmrCode = (refresh ? refreshCode : '') + (reload ? reloadCode : '');
  14. let ws: WebSocket | null = null;
  15. const id = _id ?? Math.random().toString(36);
  16. let reconnectTries = 0;
  17. function initializeWebSocket() {
  18. ws = new WebSocket(LOCAL_RELOAD_SOCKET_URL);
  19. ws.onopen = () => {
  20. console.log(`[HMR] Connected to dev-server at ${LOCAL_RELOAD_SOCKET_URL}`);
  21. };
  22. ws.onerror = () => {
  23. console.error(`[HMR] Failed to connect server at ${LOCAL_RELOAD_SOCKET_URL}`);
  24. console.warn('Retrying in 3 seconds...');
  25. ws = null;
  26. if (reconnectTries <= 2) {
  27. setTimeout(() => {
  28. reconnectTries++;
  29. initializeWebSocket();
  30. }, 3_000);
  31. } else {
  32. console.error(`[HMR] Cannot establish connection to server at ${LOCAL_RELOAD_SOCKET_URL}`);
  33. }
  34. };
  35. }
  36. return {
  37. name: 'watch-rebuild',
  38. writeBundle() {
  39. onStart?.();
  40. if (!ws) {
  41. initializeWebSocket();
  42. return;
  43. }
  44. /**
  45. * When the build is complete, send a message to the reload server.
  46. * The reload server will send a message to the client to reload or refresh the extension.
  47. */
  48. ws.send(MessageInterpreter.send({ type: BUILD_COMPLETE, id }));
  49. },
  50. generateBundle(_options, bundle) {
  51. for (const module of Object.values(bundle)) {
  52. if (module.type === 'chunk') {
  53. module.code = `(function() {let __HMR_ID = "${id}";\n` + hmrCode + '\n' + '})();' + '\n' + module.code;
  54. }
  55. }
  56. },
  57. };
  58. }