Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add batch for watcher change event #662

Merged
merged 1 commit into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/sharp-starfishes-eat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@ice/pkg': minor
---

feat: add batch for watcher change event
22 changes: 13 additions & 9 deletions packages/pkg/src/commands/start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@ import consola from 'consola';
import { RollupOptions } from 'rollup';
import { getBuildTasks } from '../helpers/getBuildTasks.js';
import { getRollupOptions } from '../helpers/getRollupOptions.js';
import { createWatcher } from '../helpers/watcher.js';
import { createBatchChangeHandler, createWatcher } from '../helpers/watcher.js';
import { watchBundleTasks } from '../tasks/bundle.js';
import { watchTransformTasks } from '../tasks/transform.js';

import type {
OutputResult,
Context,
WatchEvent,
TaskRunnerContext,
TaskRunnerContext, WatchChangedFile,
} from '../types.js';

export default async function start(context: Context) {
Expand All @@ -34,9 +33,12 @@ export default async function start(context: Context) {
});

const watcher = createWatcher(taskConfigs);
watcher.on('add', async (id) => await handleChange(id, 'create'));
watcher.on('change', async (id) => await handleChange(id, 'update'));
watcher.on('unlink', async (id) => await handleChange(id, 'delete'));
const batchHandler = createBatchChangeHandler(runChangedCompile);
batchHandler.beginBlock();

watcher.on('add', (id) => batchHandler.onChange(id, 'create'));
watcher.on('change', (id) => batchHandler.onChange(id, 'update'));
watcher.on('unlink', (id) => batchHandler.onChange(id, 'delete'));
watcher.on('error', (error) => consola.error(error));

const transformOptions = buildTasks
Expand Down Expand Up @@ -83,14 +85,16 @@ export default async function start(context: Context) {

await applyHook('after.start.compile', outputResults);

async function handleChange(id: string, event: WatchEvent) {
batchHandler.endBlock();

async function runChangedCompile(changedFiles: WatchChangedFile[]) {
const newOutputResults = [];
try {
const newTransformOutputResults = transformWatchResult.handleChange ?
await transformWatchResult.handleChange(id, event) :
await transformWatchResult.handleChange(changedFiles) :
[];
const newBundleOutputResults = bundleWatchResult.handleChange ?
await bundleWatchResult.handleChange(id, event) :
await bundleWatchResult.handleChange(changedFiles) :
[];
newOutputResults.push(
...newTransformOutputResults,
Expand Down
65 changes: 64 additions & 1 deletion packages/pkg/src/helpers/watcher.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import * as chokidar from 'chokidar';
import { unique } from '../utils.js';
import type { TaskConfig } from '../types.js';
import type { TaskConfig, WatchChangedFile, WatchEvent } from '../types.js';

const WATCH_INTERVAL = 250;

type WatchCallback = (changedFiles: WatchChangedFile[]) => (Promise<void>);

export const createWatcher = (taskConfigs: TaskConfig[]) => {
const outputs = unique(taskConfigs.map((taskConfig) => taskConfig.outputDir));
Expand All @@ -17,3 +21,62 @@ export const createWatcher = (taskConfigs: TaskConfig[]) => {

return watcher;
};

export function createBatchChangeHandler(changeCallback: WatchCallback) {
let nextChangedFiles: WatchChangedFile[] = [];
let runningTask: Promise<void> | null = null;
let enableBatch = false;
let timer: any = 0;

async function onChange(id: string, event: WatchEvent) {
nextChangedFiles.push({ path: id, event });
if (enableBatch) {
return;
}
tryRunTask();
}

function tryRunTask() {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
runTask();
timer = null;
}, WATCH_INTERVAL);
}

function runTask() {
if (!nextChangedFiles.length) {
return;
}

if (!runningTask) {
const changedFiles = nextChangedFiles;
nextChangedFiles = [];
const task = changeCallback(changedFiles);
runningTask = task.finally(() => {
runningTask = null;
tryRunTask();
});
}
}


return {
/**
* Block and cache file changes event, do not trigger change handler
*/
beginBlock() {
enableBatch = true;
},
/**
* Trigger change handler since beginBlock
*/
endBlock() {
enableBatch = false;
tryRunTask();
},
onChange,
};
}
16 changes: 9 additions & 7 deletions packages/pkg/src/tasks/bundle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ export const watchBundleTasks: RunTasks = async (taskOptionsList, context, watch
handleChangeFunctions.push(handleChange);
}

const handleChange: HandleChange<OutputResult[]> = async (id, event) => {
const handleChange: HandleChange<OutputResult[]> = async (changedFiles) => {
const newOutputResults: OutputResult[] = [];
for (const handleChangeFunction of handleChangeFunctions) {
const newOutputResult = await handleChangeFunction(id, event);
const newOutputResult = await handleChangeFunction(changedFiles);
newOutputResults.push(newOutputResult);
}

Expand Down Expand Up @@ -215,16 +215,18 @@ async function rawWatch(
}
};

const handleChange: HandleChange = async (id: string, event: string) => {
const handleChange: HandleChange = async (changedFiles) => {
const changeStart = performance.now();

logger.debug('Bundle start...');

for (const task of watcher.tasks) {
task.invalidate(id, {
event,
isTransformDependency: false,
});
for (const file of changedFiles) {
task.invalidate(file.path, {
event: file.event,
isTransformDependency: false,
});
}
}

const outputResult = await getOutputResult();
Expand Down
24 changes: 13 additions & 11 deletions packages/pkg/src/tasks/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,17 @@ export const watchTransformTasks: RunTasks = async (taskOptionsList, context, wa
}
outputResults.push(outputResult);

handleChangeFunctions.push(async (id, event) => {
if (event === 'update' || event === 'create') {
return await runTransform(rollupOptions, taskRunnerContext, context, id);
handleChangeFunctions.push(async (changedFiles) => {
if (changedFiles.some((file) => file.event === 'update' || file.event === 'create')) {
return await runTransform(rollupOptions, taskRunnerContext, context, changedFiles.map((file) => file.path));
}
});
}

const handleChange: HandleChange<OutputResult[]> = async (id, event) => {
const handleChange: HandleChange<OutputResult[]> = async (changedFiles) => {
const newOutputResults: OutputResult[] = [];
for (const handleChangeFunction of handleChangeFunctions) {
const newOutputResult = await handleChangeFunction(id, event);
const newOutputResult = await handleChangeFunction(changedFiles);
newOutputResults.push(newOutputResult);
}

Expand Down Expand Up @@ -81,7 +81,7 @@ async function runTransform(
rollupOptions: RollupOptions,
taskRunnerContext: TaskRunnerContext,
context: Context,
updatedFile?: string,
updatedFiles?: string[],
): Promise<OutputResult> {
let isDistContainingSWCHelpers = false;
let isDistContainingJSXRuntime = false;
Expand All @@ -100,11 +100,13 @@ async function runTransform(

const files: OutputFile[] = [];

if (updatedFile) {
for (const entryDir of entryDirs) {
if (updatedFile.startsWith(entryDir)) {
files.push(getFileInfo(updatedFile, entryDir));
break;
if (updatedFiles) {
for (const updatedFile of updatedFiles) {
for (const entryDir of entryDirs) {
if (updatedFile.startsWith(entryDir)) {
files.push(getFileInfo(updatedFile, entryDir));
break;
}
}
}
} else {
Expand Down
8 changes: 7 additions & 1 deletion packages/pkg/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,13 @@ export interface OutputResult {
export type NodeEnvMode = 'development' | 'production' | string;

export type WatchEvent = 'create' | 'update' | 'delete';
export type HandleChange<R = OutputResult> = (id: string, event: WatchEvent) => Promise<R>;

export interface WatchChangedFile {
path: string;
event: WatchEvent;
}

export type HandleChange<R = OutputResult> = (changedFiles: WatchChangedFile[]) => Promise<R>;

export interface TaskResult {
handleChange?: HandleChange<OutputResult[]>;
Expand Down
Loading