From 31563109399165c49d4ec0164300a62299c9c2d1 Mon Sep 17 00:00:00 2001 From: Jonghakseo Date: Sat, 11 Nov 2023 19:02:25 +0900 Subject: [PATCH 01/10] feat: Modified to let the plugin do the build completion detection. --- utils/plugins/watch-rebuild.ts | 14 ++++++++++- utils/reload/constant.ts | 3 --- utils/reload/initReloadClient.ts | 13 +++------- utils/reload/initReloadServer.ts | 41 ++++++++----------------------- utils/reload/injections/script.ts | 2 -- utils/reload/interpreter/index.ts | 6 ++--- utils/reload/interpreter/types.ts | 17 +++++++------ 7 files changed, 39 insertions(+), 57 deletions(-) diff --git a/utils/plugins/watch-rebuild.ts b/utils/plugins/watch-rebuild.ts index 14a960565..b06c10b76 100644 --- a/utils/plugins/watch-rebuild.ts +++ b/utils/plugins/watch-rebuild.ts @@ -1,16 +1,28 @@ import type { PluginOption } from 'vite'; import { resolve } from 'path'; +import { WebSocket } from 'ws'; +import MessageInterpreter from '../reload/interpreter'; +import { LOCAL_RELOAD_SOCKET_URL } from '../reload/constant'; const rootDir = resolve(__dirname, '..', '..'); const manifestFile = resolve(rootDir, 'manifest.ts'); const viteConfigFile = resolve(rootDir, 'vite.config.ts'); +const ws = new WebSocket(LOCAL_RELOAD_SOCKET_URL); + export default function watchRebuild(): PluginOption { return { name: 'watch-rebuild', - async buildStart() { + buildStart() { this.addWatchFile(manifestFile); this.addWatchFile(viteConfigFile); }, + writeBundle() { + /** + * When the build is complete, send a message to the reload server. + * The reload server will send a message to the client to reload or refresh the extension. + */ + ws.send(MessageInterpreter.send({ type: 'build_complete' })); + }, }; } diff --git a/utils/reload/constant.ts b/utils/reload/constant.ts index 548669d80..de2d84fba 100644 --- a/utils/reload/constant.ts +++ b/utils/reload/constant.ts @@ -1,5 +1,2 @@ export const LOCAL_RELOAD_SOCKET_PORT = 8081; export const LOCAL_RELOAD_SOCKET_URL = `ws://localhost:${LOCAL_RELOAD_SOCKET_PORT}`; -export const UPDATE_PENDING_MESSAGE = 'wait_update'; -export const UPDATE_REQUEST_MESSAGE = 'do_update'; -export const UPDATE_COMPLETE_MESSAGE = 'done_update'; diff --git a/utils/reload/initReloadClient.ts b/utils/reload/initReloadClient.ts index 656266244..75d5bde16 100644 --- a/utils/reload/initReloadClient.ts +++ b/utils/reload/initReloadClient.ts @@ -1,9 +1,4 @@ -import { - LOCAL_RELOAD_SOCKET_URL, - UPDATE_COMPLETE_MESSAGE, - UPDATE_PENDING_MESSAGE, - UPDATE_REQUEST_MESSAGE, -} from './constant'; +import { LOCAL_RELOAD_SOCKET_URL } from './constant'; import MessageInterpreter from './interpreter'; let needToUpdate = false; @@ -18,14 +13,14 @@ export default function initReloadClient({ const socket = new WebSocket(LOCAL_RELOAD_SOCKET_URL); function sendUpdateCompleteMessage() { - socket.send(MessageInterpreter.send({ type: UPDATE_COMPLETE_MESSAGE })); + socket.send(MessageInterpreter.send({ type: 'done_update' })); } socket.addEventListener('message', event => { const message = MessageInterpreter.receive(String(event.data)); switch (message.type) { - case UPDATE_REQUEST_MESSAGE: { + case 'do_update': { if (needToUpdate) { sendUpdateCompleteMessage(); needToUpdate = false; @@ -33,7 +28,7 @@ export default function initReloadClient({ } return; } - case UPDATE_PENDING_MESSAGE: { + case 'wait_update': { if (!needToUpdate) { needToUpdate = message.path.includes(watchPath); } diff --git a/utils/reload/initReloadServer.ts b/utils/reload/initReloadServer.ts index 335918288..357a03642 100644 --- a/utils/reload/initReloadServer.ts +++ b/utils/reload/initReloadServer.ts @@ -1,13 +1,7 @@ import { WebSocket, WebSocketServer } from 'ws'; import chokidar from 'chokidar'; import { debounce } from './utils'; -import { - LOCAL_RELOAD_SOCKET_PORT, - LOCAL_RELOAD_SOCKET_URL, - UPDATE_COMPLETE_MESSAGE, - UPDATE_PENDING_MESSAGE, - UPDATE_REQUEST_MESSAGE, -} from './constant'; +import { LOCAL_RELOAD_SOCKET_PORT, LOCAL_RELOAD_SOCKET_URL } from './constant'; import MessageInterpreter from './interpreter'; const clientsThatNeedToUpdate: Set = new Set(); @@ -22,10 +16,16 @@ function initReloadServer() { ws.addEventListener('close', () => clientsThatNeedToUpdate.delete(ws)); ws.addEventListener('message', event => { - const message = MessageInterpreter.receive(String(event.data)); - if (message.type === UPDATE_COMPLETE_MESSAGE) { + if (typeof event.data !== 'string') return; + + const message = MessageInterpreter.receive(event.data); + + if (message.type === 'do_update') { ws.close(); } + if (message.type === 'build_complete') { + clientsThatNeedToUpdate.forEach((ws: WebSocket) => ws.send(MessageInterpreter.send({ type: 'do_update' }))); + } }); }); } @@ -35,31 +35,10 @@ const debounceSrc = debounce(function (path: string) { // Normalize path on Windows const pathConverted = path.replace(/\\/g, '/'); clientsThatNeedToUpdate.forEach((ws: WebSocket) => - ws.send( - MessageInterpreter.send({ - type: UPDATE_PENDING_MESSAGE, - path: pathConverted, - }), - ), + ws.send(MessageInterpreter.send({ type: 'wait_update', path: pathConverted })), ); // Delay waiting for public assets to be copied }, 400); chokidar.watch('src', { ignorePermissionErrors: true }).on('all', (_, path) => debounceSrc(path)); -/** CHECK:: build was completed **/ -const debounceDist = debounce(() => { - clientsThatNeedToUpdate.forEach((ws: WebSocket) => { - ws.send(MessageInterpreter.send({ type: UPDATE_REQUEST_MESSAGE })); - }); -}, 100); -chokidar.watch('dist', { ignorePermissionErrors: true }).on('all', event => { - // Ignore unlink, unlinkDir and change events - // that happen in beginning of build:watch and - // that will cause ws.send() if it takes more than 400ms - // to build (which it might). This fixes: - // https://github.com/Jonghakseo/chrome-extension-boilerplate-react-vite/issues/100 - if (event !== 'add' && event !== 'addDir') return; - debounceDist(); -}); - initReloadServer(); diff --git a/utils/reload/injections/script.ts b/utils/reload/injections/script.ts index d02ac7da1..46278f65b 100644 --- a/utils/reload/injections/script.ts +++ b/utils/reload/injections/script.ts @@ -4,8 +4,6 @@ export default function addHmrIntoScript(watchPath: string) { initReloadClient({ watchPath, onUpdate: () => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore chrome.runtime.reload(); }, }); diff --git a/utils/reload/interpreter/index.ts b/utils/reload/interpreter/index.ts index 2ef2318de..b9811c1f3 100644 --- a/utils/reload/interpreter/index.ts +++ b/utils/reload/interpreter/index.ts @@ -1,13 +1,13 @@ -import type { ReloadMessage, SerializedMessage } from './types'; +import type { WebSocketMessage, SerializedMessage } from './types'; export default class MessageInterpreter { // eslint-disable-next-line @typescript-eslint/no-empty-function private constructor() {} - static send(message: ReloadMessage): SerializedMessage { + static send(message: WebSocketMessage): SerializedMessage { return JSON.stringify(message); } - static receive(serializedMessage: SerializedMessage): ReloadMessage { + static receive(serializedMessage: SerializedMessage): WebSocketMessage { return JSON.parse(serializedMessage); } } diff --git a/utils/reload/interpreter/types.ts b/utils/reload/interpreter/types.ts index 831010a45..48dd345e5 100644 --- a/utils/reload/interpreter/types.ts +++ b/utils/reload/interpreter/types.ts @@ -1,15 +1,16 @@ -import { UPDATE_COMPLETE_MESSAGE, UPDATE_PENDING_MESSAGE, UPDATE_REQUEST_MESSAGE } from '../constant'; - type UpdatePendingMessage = { - type: typeof UPDATE_PENDING_MESSAGE; + type: 'wait_update'; path: string; }; - type UpdateRequestMessage = { - type: typeof UPDATE_REQUEST_MESSAGE; + type: 'do_update'; }; - -type UpdateCompleteMessage = { type: typeof UPDATE_COMPLETE_MESSAGE }; +type UpdateCompleteMessage = { type: 'done_update' }; +type BuildCompletionMessage = { type: 'build_complete' }; export type SerializedMessage = string; -export type ReloadMessage = UpdateCompleteMessage | UpdateRequestMessage | UpdatePendingMessage; +export type WebSocketMessage = + | UpdateCompleteMessage + | UpdateRequestMessage + | UpdatePendingMessage + | BuildCompletionMessage; From 37f064543c812ef167215a938e8cdbb4a431b596 Mon Sep 17 00:00:00 2001 From: Jonghakseo Date: Sat, 11 Nov 2023 19:03:07 +0900 Subject: [PATCH 02/10] chore: make-manifest plugin --- utils/plugins/make-manifest.ts | 15 +++------------ vite.config.ts | 1 - 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/utils/plugins/make-manifest.ts b/utils/plugins/make-manifest.ts index 9088c05af..722f558c1 100644 --- a/utils/plugins/make-manifest.ts +++ b/utils/plugins/make-manifest.ts @@ -7,11 +7,10 @@ import type { PluginOption } from 'vite'; const { resolve } = path; const distDir = resolve(__dirname, '..', '..', 'dist'); -const publicDir = resolve(__dirname, '..', '..', 'public'); export default function makeManifest( manifest: chrome.runtime.ManifestV3, - config: { isDev: boolean; contentScriptCssKey?: string }, + config: { contentScriptCssKey?: string }, ): PluginOption { function makeManifest(to: string) { if (!fs.existsSync(to)) { @@ -33,16 +32,8 @@ export default function makeManifest( return { name: 'make-manifest', - buildStart() { - if (config.isDev) { - makeManifest(distDir); - } - }, - buildEnd() { - if (config.isDev) { - return; - } - makeManifest(publicDir); + writeBundle() { + makeManifest(distDir); }, }; } diff --git a/vite.config.ts b/vite.config.ts index 46f2f7e18..da20928f1 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -32,7 +32,6 @@ export default defineConfig({ plugins: [ react(), makeManifest(manifest, { - isDev, contentScriptCssKey: regenerateCacheInvalidationKey(), }), customDynamicImport(), From 38267c6b526205e882bc930f55dcbe09f273737b Mon Sep 17 00:00:00 2001 From: Jonghakseo Date: Sat, 11 Nov 2023 19:05:35 +0900 Subject: [PATCH 03/10] chore: run chmod husky files --- .husky/commit-msg | 0 .husky/pre-commit | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 .husky/commit-msg mode change 100644 => 100755 .husky/pre-commit diff --git a/.husky/commit-msg b/.husky/commit-msg old mode 100644 new mode 100755 diff --git a/.husky/pre-commit b/.husky/pre-commit old mode 100644 new mode 100755 From 43c8c392bc5f4cd9bdbb8d14c014a5b1422290c0 Mon Sep 17 00:00:00 2001 From: Jonghakseo Date: Sat, 11 Nov 2023 19:11:51 +0900 Subject: [PATCH 04/10] fix: disable rebuild plugin when production build --- utils/plugins/watch-rebuild.ts | 3 +-- vite.config.ts | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/utils/plugins/watch-rebuild.ts b/utils/plugins/watch-rebuild.ts index b06c10b76..4513ab7b0 100644 --- a/utils/plugins/watch-rebuild.ts +++ b/utils/plugins/watch-rebuild.ts @@ -8,9 +8,8 @@ const rootDir = resolve(__dirname, '..', '..'); const manifestFile = resolve(rootDir, 'manifest.ts'); const viteConfigFile = resolve(rootDir, 'vite.config.ts'); -const ws = new WebSocket(LOCAL_RELOAD_SOCKET_URL); - export default function watchRebuild(): PluginOption { + const ws = new WebSocket(LOCAL_RELOAD_SOCKET_URL); return { name: 'watch-rebuild', buildStart() { diff --git a/vite.config.ts b/vite.config.ts index da20928f1..3c892ed34 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -36,7 +36,7 @@ export default defineConfig({ }), customDynamicImport(), addHmr({ background: enableHmrInBackgroundScript, view: true }), - watchRebuild(), + isDev && watchRebuild(), ], publicDir, build: { From 088a15a819c2b00ad5acd0ec9e804a4cf732ada9 Mon Sep 17 00:00:00 2001 From: Jonghakseo Date: Sat, 11 Nov 2023 21:24:01 +0900 Subject: [PATCH 05/10] fix: disable emptyOutDir --- vite.config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/vite.config.ts b/vite.config.ts index 3c892ed34..589a95aca 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -46,6 +46,7 @@ export default defineConfig({ minify: isProduction, modulePreload: false, reportCompressedSize: isProduction, + emptyOutDir: false, rollupOptions: { input: { devtools: resolve(pagesDir, 'devtools', 'index.html'), From e494a69aff1db04fa698b0750c1673f859dddac7 Mon Sep 17 00:00:00 2001 From: Jonghakseo Date: Sat, 11 Nov 2023 21:25:16 +0900 Subject: [PATCH 06/10] fix: remove debounce --- utils/reload/initReloadServer.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/utils/reload/initReloadServer.ts b/utils/reload/initReloadServer.ts index 357a03642..b05ecc10c 100644 --- a/utils/reload/initReloadServer.ts +++ b/utils/reload/initReloadServer.ts @@ -1,6 +1,5 @@ import { WebSocket, WebSocketServer } from 'ws'; import chokidar from 'chokidar'; -import { debounce } from './utils'; import { LOCAL_RELOAD_SOCKET_PORT, LOCAL_RELOAD_SOCKET_URL } from './constant'; import MessageInterpreter from './interpreter'; @@ -31,14 +30,13 @@ function initReloadServer() { } /** CHECK:: src file was updated **/ -const debounceSrc = debounce(function (path: string) { +const watchSrc = function (path: string) { // Normalize path on Windows const pathConverted = path.replace(/\\/g, '/'); clientsThatNeedToUpdate.forEach((ws: WebSocket) => ws.send(MessageInterpreter.send({ type: 'wait_update', path: pathConverted })), ); - // Delay waiting for public assets to be copied -}, 400); -chokidar.watch('src', { ignorePermissionErrors: true }).on('all', (_, path) => debounceSrc(path)); +}; +chokidar.watch('src', { ignorePermissionErrors: true }).on('all', (_, path) => watchSrc(path)); initReloadServer(); From 58c9802c730f2c56d63b1f0bb3fa037d442a758f Mon Sep 17 00:00:00 2001 From: Jonghakseo Date: Sat, 11 Nov 2023 21:30:15 +0900 Subject: [PATCH 07/10] fix: logging disconnected not warn --- utils/reload/initReloadClient.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/reload/initReloadClient.ts b/utils/reload/initReloadClient.ts index 75d5bde16..422aee3e8 100644 --- a/utils/reload/initReloadClient.ts +++ b/utils/reload/initReloadClient.ts @@ -38,7 +38,7 @@ export default function initReloadClient({ }); socket.onclose = () => { - console.warn( + console.log( `Reload server disconnected.\nPlease check if the WebSocket server is running properly on ${LOCAL_RELOAD_SOCKET_URL}. This feature detects changes in the code and helps the browser to reload the extension or refresh the current tab.`, ); }; From 3b7f51927e3c6e13f242fb4a97c3efb00012eba0 Mon Sep 17 00:00:00 2001 From: Jonghakseo Date: Sat, 11 Nov 2023 21:31:21 +0900 Subject: [PATCH 08/10] feat: add automatic reconnection logic every second --- utils/reload/initReloadClient.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/utils/reload/initReloadClient.ts b/utils/reload/initReloadClient.ts index 422aee3e8..de93d65fa 100644 --- a/utils/reload/initReloadClient.ts +++ b/utils/reload/initReloadClient.ts @@ -41,6 +41,9 @@ export default function initReloadClient({ console.log( `Reload server disconnected.\nPlease check if the WebSocket server is running properly on ${LOCAL_RELOAD_SOCKET_URL}. This feature detects changes in the code and helps the browser to reload the extension or refresh the current tab.`, ); + setInterval(() => { + initReloadClient({ watchPath, onUpdate }); + }, 1000); }; return socket; From c13b735a329094b6efcf0276c0842653e0b4932e Mon Sep 17 00:00:00 2001 From: Jonghakseo Date: Sat, 11 Nov 2023 22:39:17 +0900 Subject: [PATCH 09/10] fix: bug on HRR --- utils/reload/initReloadClient.ts | 2 +- utils/reload/initReloadServer.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/reload/initReloadClient.ts b/utils/reload/initReloadClient.ts index de93d65fa..509ac8aa3 100644 --- a/utils/reload/initReloadClient.ts +++ b/utils/reload/initReloadClient.ts @@ -41,7 +41,7 @@ export default function initReloadClient({ console.log( `Reload server disconnected.\nPlease check if the WebSocket server is running properly on ${LOCAL_RELOAD_SOCKET_URL}. This feature detects changes in the code and helps the browser to reload the extension or refresh the current tab.`, ); - setInterval(() => { + setTimeout(() => { initReloadClient({ watchPath, onUpdate }); }, 1000); }; diff --git a/utils/reload/initReloadServer.ts b/utils/reload/initReloadServer.ts index b05ecc10c..03ac5f350 100644 --- a/utils/reload/initReloadServer.ts +++ b/utils/reload/initReloadServer.ts @@ -19,7 +19,7 @@ function initReloadServer() { const message = MessageInterpreter.receive(event.data); - if (message.type === 'do_update') { + if (message.type === 'done_update') { ws.close(); } if (message.type === 'build_complete') { From c3d8618df07eb5c954dcd7c4e396f31fdca6010b Mon Sep 17 00:00:00 2001 From: Jonghakseo Date: Sat, 11 Nov 2023 22:42:31 +0900 Subject: [PATCH 10/10] fix: rollback debounce --- utils/reload/initReloadServer.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/utils/reload/initReloadServer.ts b/utils/reload/initReloadServer.ts index 03ac5f350..8001afd7d 100644 --- a/utils/reload/initReloadServer.ts +++ b/utils/reload/initReloadServer.ts @@ -2,6 +2,7 @@ import { WebSocket, WebSocketServer } from 'ws'; import chokidar from 'chokidar'; import { LOCAL_RELOAD_SOCKET_PORT, LOCAL_RELOAD_SOCKET_URL } from './constant'; import MessageInterpreter from './interpreter'; +import { debounce } from './utils'; const clientsThatNeedToUpdate: Set = new Set(); @@ -30,13 +31,13 @@ function initReloadServer() { } /** CHECK:: src file was updated **/ -const watchSrc = function (path: string) { +const debounceSrc = debounce(function (path: string) { // Normalize path on Windows const pathConverted = path.replace(/\\/g, '/'); clientsThatNeedToUpdate.forEach((ws: WebSocket) => ws.send(MessageInterpreter.send({ type: 'wait_update', path: pathConverted })), ); -}; -chokidar.watch('src', { ignorePermissionErrors: true }).on('all', (_, path) => watchSrc(path)); +}, 100); +chokidar.watch('src', { ignorePermissionErrors: true }).on('all', (_, path) => debounceSrc(path)); initReloadServer();