Merge pull request #977 from themohammadsa/feat-hot-reload

feature: hot-reloading for static web files
This commit is contained in:
Mohammad S 2023-06-16 19:56:06 +05:30 committed by GitHub
commit 4d5eb63089
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 75 additions and 4 deletions

View file

@ -27,6 +27,8 @@ export const IPC_MAIN_CHANNELS = {
AUTH_RESPONSE: 'auth-response',
OPEN_EXTERNAL: 'open-external',
OPEN_URL: 'open-url',
START_WATCHING_FILE: 'start-watching-file',
STOP_WATCHER: 'stop-watcher',
} as const;
export type Channels = typeof IPC_MAIN_CHANNELS[keyof typeof IPC_MAIN_CHANNELS];

View file

@ -1,4 +1,6 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
import BrowserSync, { BrowserSyncInstance } from 'browser-sync';
import fs from 'fs-extra';
export const BROWSER_SYNC_PORT = 12719;
export const BROWSER_SYNC_HOST = `localhost:${BROWSER_SYNC_PORT}`;
@ -7,6 +9,8 @@ export const BROWSER_SYNC_URL = `https://${BROWSER_SYNC_HOST}/browser-sync/brows
const browserSyncEmbed: BrowserSyncInstance = BrowserSync.create('embed');
let created = false;
let filesWatcher: ReturnType<BrowserSyncInstance['watch']> | null = null;
let cssWatcher: ReturnType<BrowserSyncInstance['watch']> | null = null;
export async function initInstance(): Promise<BrowserSyncInstance> {
if (created) {
@ -32,3 +36,35 @@ export async function initInstance(): Promise<BrowserSyncInstance> {
);
});
}
export function watchFiles(filePath: string) {
if (filePath && fs.existsSync(filePath)) {
const fileDir = filePath.substring(0, filePath.lastIndexOf('/'));
filesWatcher = browserSyncEmbed
// @ts-expect-error
.watch([filePath, `${fileDir}/**/**.js`])
.on('change', browserSyncEmbed.reload);
cssWatcher = browserSyncEmbed.watch(
`${fileDir}/**/**.css`,
// @ts-expect-error
(event: string, file: string) => {
if (event === 'change') {
browserSyncEmbed.reload(file);
}
}
);
}
}
export async function stopWatchFiles() {
if (filesWatcher) {
// @ts-expect-error
await filesWatcher.close();
}
if (cssWatcher) {
// @ts-expect-error
await cssWatcher.close();
}
}

View file

@ -9,14 +9,19 @@
* `./src/main.js` using webpack. This gives us some performance wins.
*/
import path from 'path';
import { app, BrowserWindow, shell, screen } from 'electron';
import { app, BrowserWindow, shell, screen, ipcMain } from 'electron';
import { autoUpdater } from 'electron-updater';
import log from 'electron-log';
import cli from './cli';
import { PROTOCOL } from '../common/constants';
import MenuBuilder from './menu';
import { isValidCliArgURL, resolveHtmlPath } from './util';
import { BROWSER_SYNC_HOST, initInstance } from './browser-sync';
import { resolveHtmlPath } from './util';
import {
BROWSER_SYNC_HOST,
initInstance,
stopWatchFiles,
watchFiles,
} from './browser-sync';
import store from '../store';
import { initWebviewContextMenu } from './webview-context-menu/register';
import { initScreenshotHandlers } from './screenshot';
@ -197,6 +202,19 @@ const createWindow = async () => {
return { action: 'deny' };
});
ipcMain.on('start-watching-file', async (event, fileInfo) => {
let filePath = fileInfo.path.replace('file://', '');
if (process.platform === 'win32') {
filePath = filePath.replace(/^\//, '');
}
app.addRecentDocument(filePath);
await stopWatchFiles();
watchFiles(filePath);
});
ipcMain.on('stop-watcher', async () => {
await stopWatchFiles();
});
// Remove this if your app does not use auto updates
// eslint-disable-next-line
new AppUpdater();

View file

@ -1,6 +1,6 @@
import { createSlice } from '@reduxjs/toolkit';
import type { PayloadAction } from '@reduxjs/toolkit';
import { PreviewLayout } from 'common/constants';
import { IPC_MAIN_CHANNELS, PreviewLayout } from 'common/constants';
import type { RootState } from '../..';
export interface RendererState {
@ -34,12 +34,27 @@ const initialState: RendererState = {
isCapturingScreenshot: false,
};
export const updateFileWatcher = (newURL: string) => {
if (
newURL.startsWith('file://') &&
(newURL.endsWith('.html') || newURL.endsWith('.htm'))
)
window.electron.ipcRenderer.sendMessage(
IPC_MAIN_CHANNELS.START_WATCHING_FILE,
{
path: newURL,
}
);
else window.electron.ipcRenderer.sendMessage(IPC_MAIN_CHANNELS.STOP_WATCHER);
};
export const rendererSlice = createSlice({
name: 'renderer',
initialState,
reducers: {
setAddress: (state, action: PayloadAction<string>) => {
if (action.payload !== state.address) {
updateFileWatcher(action.payload);
state.address = action.payload;
}
},