From 124f32ed3cc9c46b666232527a9d2a753d4c6b0f Mon Sep 17 00:00:00 2001 From: tkqubo Date: Sun, 1 Nov 2015 11:39:18 +0900 Subject: [PATCH 1/3] webpack: add HMR --- webpack/webpack-env-tests.ts | 27 +++++++ webpack/webpack-env.d.ts | 135 +++++++++++++++++++++++++++++++++++ 2 files changed, 162 insertions(+) diff --git a/webpack/webpack-env-tests.ts b/webpack/webpack-env-tests.ts index b4a9693ec..25ec177d6 100644 --- a/webpack/webpack-env-tests.ts +++ b/webpack/webpack-env-tests.ts @@ -13,3 +13,30 @@ let contextModule = context('./someModule'); require(['./someModule', './otherModule'], (someModule: SomeModule, otherModule: any) => { }); + +// check if HMR is enabled +if(module.hot) { + // accept update of dependency + module.hot.accept("./handler.js", function() { + //... + }); +} + +module.exports = null; + +// check if HMR is enabled +if(module.hot) { + + // accept itself + module.hot.accept(); + + // dispose handler + module.hot.dispose(function() { + // revoke the side effect + //... + }); +} + + +var status: string = module.hot.status(); + diff --git a/webpack/webpack-env.d.ts b/webpack/webpack-env.d.ts index f67b9c5d6..07f160c5e 100644 --- a/webpack/webpack-env.d.ts +++ b/webpack/webpack-env.d.ts @@ -5,6 +5,7 @@ /** * Webpack module API - variables and global functions available inside modules + * https://webpack.github.io/docs/api-in-modules.html */ declare namespace __WebpackModuleApi { @@ -101,3 +102,137 @@ declare var __non_webpack_require__: any; * Equals the config option debug */ declare var DEBUG: boolean; + +/** + * Webpack Hot Module Replacement + * https://webpack.github.io/docs/hot-module-replacement.html + */ +declare namespace __WebpackHotModuleReplacement { + interface Module { + exports: any; + require(id: string): any; + id: string; + filename: string; + loaded: boolean; + parent: any; + children: any[]; + hot: Hot; + } + + interface Hot { + /** + * Accept code updates for the specified dependencies. The callback is called when dependencies were replaced. + * @param dependencies + * @param callback + */ + accept(dependencies: string[], callback: (updatedDependencies: string[]) => void): void; + /** + * Accept code updates for the specified dependencies. The callback is called when dependencies were replaced. + * @param dependency + * @param callback + */ + accept(dependency: string, callback: () => void): void; + /** + * Accept code updates for this module without notification of parents. + * This should only be used if the module doesn’t export anything. + * The errHandler can be used to handle errors that occur while loading the updated module. + * @param errHandler + */ + accept(errHandler?: Function): void; + /** + * Do not accept updates for the specified dependencies. If any dependencies is updated, the code update fails with code "decline". + */ + decline(dependencies: string[]): void; + /** + * Do not accept updates for the specified dependencies. If any dependencies is updated, the code update fails with code "decline". + */ + decline(dependency: string): void; + /** + * Flag the current module as not update-able. If updated the update code would fail with code "decline". + */ + decline(): void; + /** + * Add a one time handler, which is executed when the current module code is replaced. + * Here you should destroy/remove any persistent resource you have claimed/created. + * If you want to transfer state to the new module, add it to data object. + * The data will be available at module.hot.data on the new module. + * @param callback + */ + dispose(callback: (data: any) => void): void; + /** + * Add a one time handler, which is executed when the current module code is replaced. + * Here you should destroy/remove any persistent resource you have claimed/created. + * If you want to transfer state to the new module, add it to data object. + * The data will be available at module.hot.data on the new module. + * @param callback + */ + addDisposeHandler(callback: (data: any) => void): void; + /** + * Remove a handler. + * This can useful to add a temporary dispose handler. You could i. e. replace code while in the middle of a multi-step async function. + * @param callback + */ + removeDisposeHandler(callback: (data: any) => void): void; + /** + * Throws an exceptions if status() is not idle. + * Check all currently loaded modules for updates and apply updates if found. + * If no update was found, the callback is called with null. + * If autoApply is truthy the callback will be called with all modules that were disposed. + * apply() is automatically called with autoApply as options parameter. + * If autoApply is not set the callback will be called with all modules that will be disposed on apply(). + * @param autoApply + * @param callback + */ + check(autoApply: boolean, callback: (err: Error, outdatedModules: any[]) => void): void; + /** + * Throws an exceptions if status() is not idle. + * Check all currently loaded modules for updates and apply updates if found. + * If no update was found, the callback is called with null. + * The callback will be called with all modules that will be disposed on apply(). + * @param callback + */ + check(callback: (err: Error, outdatedModules: any[]) => void): void; + /** + * If status() != "ready" it throws an error. + * Continue the update process. + * @param options + * @param callback + */ + apply(options: AcceptOptions, callback: (err: Error, outdatedModules: any[]) => void): void; + /** + * If status() != "ready" it throws an error. + * Continue the update process. + * @param callback + */ + apply(callback: (err: Error, outdatedModules: any[]) => void): void; + /** + * Return one of idle, check, watch, watch-delay, prepare, ready, dispose, apply, abort or fail. + */ + status(): string; + /** Register a callback on status change. */ + status(callback: (status: string) => void): void; + /** Register a callback on status change. */ + addStatusHandler(callback: (status: string) => void): void; + /** + * Remove a registered status change handler. + * @param callback + */ + removeStatusHandler(callback: (status: string) => void): void; + + active: boolean; + data: any; + } + + interface AcceptOptions { + /** + * If true the update process continues even if some modules are not accepted (and would bubble to the entry point). + */ + ignoreUnaccepted: boolean; + /** + * Indicates that apply() is automatically called by check function + */ + autoApply: boolean; + } +} + +declare var module: __WebpackHotModuleReplacement.Module; From 15469aa4df64804a9774a53ff7d079893466227d Mon Sep 17 00:00:00 2001 From: tkqubo Date: Wed, 4 Nov 2015 02:52:07 +0900 Subject: [PATCH 2/3] Fix for stricter typings --- webpack/webpack-env.d.ts | 262 +++++++++++++++++++-------------------- 1 file changed, 128 insertions(+), 134 deletions(-) diff --git a/webpack/webpack-env.d.ts b/webpack/webpack-env.d.ts index 07f160c5e..72022c16e 100644 --- a/webpack/webpack-env.d.ts +++ b/webpack/webpack-env.d.ts @@ -5,7 +5,6 @@ /** * Webpack module API - variables and global functions available inside modules - * https://webpack.github.io/docs/api-in-modules.html */ declare namespace __WebpackModuleApi { @@ -52,6 +51,133 @@ declare namespace __WebpackModuleApi { [id: string]: any; } } + + interface Module { + exports: any; + require(id: string): any; + id: string; + filename: string; + loaded: boolean; + parent: any; + children: any[]; + hot: Hot; + } + type ModuleId = string|number; + + interface Hot { + /** + * Accept code updates for the specified dependencies. The callback is called when dependencies were replaced. + * @param dependencies + * @param callback + */ + accept(dependencies: string[], callback: (updatedDependencies: ModuleId[]) => void): void; + /** + * Accept code updates for the specified dependencies. The callback is called when dependencies were replaced. + * @param dependency + * @param callback + */ + accept(dependency: string, callback: () => void): void; + /** + * Accept code updates for this module without notification of parents. + * This should only be used if the module doesn’t export anything. + * The errHandler can be used to handle errors that occur while loading the updated module. + * @param errHandler + */ + accept(errHandler?: (err: Error) => void): void; + /** + * Do not accept updates for the specified dependencies. If any dependencies is updated, the code update fails with code "decline". + */ + decline(dependencies: string[]): void; + /** + * Do not accept updates for the specified dependencies. If any dependencies is updated, the code update fails with code "decline". + */ + decline(dependency: string): void; + /** + * Flag the current module as not update-able. If updated the update code would fail with code "decline". + */ + decline(): void; + /** + * Add a one time handler, which is executed when the current module code is replaced. + * Here you should destroy/remove any persistent resource you have claimed/created. + * If you want to transfer state to the new module, add it to data object. + * The data will be available at module.hot.data on the new module. + * @param callback + */ + dispose(callback: (data: T) => void): void; + /** + * Add a one time handler, which is executed when the current module code is replaced. + * Here you should destroy/remove any persistent resource you have claimed/created. + * If you want to transfer state to the new module, add it to data object. + * The data will be available at module.hot.data on the new module. + * @param callback + */ + addDisposeHandler(callback: (data: T) => void): void; + /** + * Remove a handler. + * This can useful to add a temporary dispose handler. You could i. e. replace code while in the middle of a multi-step async function. + * @param callback + */ + removeDisposeHandler(callback: (data: T) => void): void; + /** + * Throws an exceptions if status() is not idle. + * Check all currently loaded modules for updates and apply updates if found. + * If no update was found, the callback is called with null. + * If autoApply is truthy the callback will be called with all modules that were disposed. + * apply() is automatically called with autoApply as options parameter. + * If autoApply is not set the callback will be called with all modules that will be disposed on apply(). + * @param autoApply + * @param callback + */ + check(autoApply: boolean, callback: (err: Error, outdatedModules: ModuleId[]) => void): void; + /** + * Throws an exceptions if status() is not idle. + * Check all currently loaded modules for updates and apply updates if found. + * If no update was found, the callback is called with null. + * The callback will be called with all modules that will be disposed on apply(). + * @param callback + */ + check(callback: (err: Error, outdatedModules: ModuleId[]) => void): void; + /** + * If status() != "ready" it throws an error. + * Continue the update process. + * @param options + * @param callback + */ + apply(options: AcceptOptions, callback: (err: Error, outdatedModules: ModuleId[]) => void): void; + /** + * If status() != "ready" it throws an error. + * Continue the update process. + * @param callback + */ + apply(callback: (err: Error, outdatedModules: ModuleId[]) => void): void; + /** + * Return one of idle, check, watch, watch-delay, prepare, ready, dispose, apply, abort or fail. + */ + status(): string; + /** Register a callback on status change. */ + status(callback: (status: string) => void): void; + /** Register a callback on status change. */ + addStatusHandler(callback: (status: string) => void): void; + /** + * Remove a registered status change handler. + * @param callback + */ + removeStatusHandler(callback: (status: string) => void): void; + + active: boolean; + data: {}; + } + + interface AcceptOptions { + /** + * If true the update process continues even if some modules are not accepted (and would bubble to the entry point). + */ + ignoreUnaccepted: boolean; + /** + * Indicates that apply() is automatically called by check function + */ + autoApply: boolean; + } } declare var require: __WebpackModuleApi.RequireFunction; @@ -103,136 +229,4 @@ declare var __non_webpack_require__: any; */ declare var DEBUG: boolean; -/** - * Webpack Hot Module Replacement - * https://webpack.github.io/docs/hot-module-replacement.html - */ -declare namespace __WebpackHotModuleReplacement { - interface Module { - exports: any; - require(id: string): any; - id: string; - filename: string; - loaded: boolean; - parent: any; - children: any[]; - hot: Hot; - } - - interface Hot { - /** - * Accept code updates for the specified dependencies. The callback is called when dependencies were replaced. - * @param dependencies - * @param callback - */ - accept(dependencies: string[], callback: (updatedDependencies: string[]) => void): void; - /** - * Accept code updates for the specified dependencies. The callback is called when dependencies were replaced. - * @param dependency - * @param callback - */ - accept(dependency: string, callback: () => void): void; - /** - * Accept code updates for this module without notification of parents. - * This should only be used if the module doesn’t export anything. - * The errHandler can be used to handle errors that occur while loading the updated module. - * @param errHandler - */ - accept(errHandler?: Function): void; - /** - * Do not accept updates for the specified dependencies. If any dependencies is updated, the code update fails with code "decline". - */ - decline(dependencies: string[]): void; - /** - * Do not accept updates for the specified dependencies. If any dependencies is updated, the code update fails with code "decline". - */ - decline(dependency: string): void; - /** - * Flag the current module as not update-able. If updated the update code would fail with code "decline". - */ - decline(): void; - /** - * Add a one time handler, which is executed when the current module code is replaced. - * Here you should destroy/remove any persistent resource you have claimed/created. - * If you want to transfer state to the new module, add it to data object. - * The data will be available at module.hot.data on the new module. - * @param callback - */ - dispose(callback: (data: any) => void): void; - /** - * Add a one time handler, which is executed when the current module code is replaced. - * Here you should destroy/remove any persistent resource you have claimed/created. - * If you want to transfer state to the new module, add it to data object. - * The data will be available at module.hot.data on the new module. - * @param callback - */ - addDisposeHandler(callback: (data: any) => void): void; - /** - * Remove a handler. - * This can useful to add a temporary dispose handler. You could i. e. replace code while in the middle of a multi-step async function. - * @param callback - */ - removeDisposeHandler(callback: (data: any) => void): void; - /** - * Throws an exceptions if status() is not idle. - * Check all currently loaded modules for updates and apply updates if found. - * If no update was found, the callback is called with null. - * If autoApply is truthy the callback will be called with all modules that were disposed. - * apply() is automatically called with autoApply as options parameter. - * If autoApply is not set the callback will be called with all modules that will be disposed on apply(). - * @param autoApply - * @param callback - */ - check(autoApply: boolean, callback: (err: Error, outdatedModules: any[]) => void): void; - /** - * Throws an exceptions if status() is not idle. - * Check all currently loaded modules for updates and apply updates if found. - * If no update was found, the callback is called with null. - * The callback will be called with all modules that will be disposed on apply(). - * @param callback - */ - check(callback: (err: Error, outdatedModules: any[]) => void): void; - /** - * If status() != "ready" it throws an error. - * Continue the update process. - * @param options - * @param callback - */ - apply(options: AcceptOptions, callback: (err: Error, outdatedModules: any[]) => void): void; - /** - * If status() != "ready" it throws an error. - * Continue the update process. - * @param callback - */ - apply(callback: (err: Error, outdatedModules: any[]) => void): void; - /** - * Return one of idle, check, watch, watch-delay, prepare, ready, dispose, apply, abort or fail. - */ - status(): string; - /** Register a callback on status change. */ - status(callback: (status: string) => void): void; - /** Register a callback on status change. */ - addStatusHandler(callback: (status: string) => void): void; - /** - * Remove a registered status change handler. - * @param callback - */ - removeStatusHandler(callback: (status: string) => void): void; - - active: boolean; - data: any; - } - - interface AcceptOptions { - /** - * If true the update process continues even if some modules are not accepted (and would bubble to the entry point). - */ - ignoreUnaccepted: boolean; - /** - * Indicates that apply() is automatically called by check function - */ - autoApply: boolean; - } -} - -declare var module: __WebpackHotModuleReplacement.Module; +declare var module: __WebpackModuleApi.Module; From 37cc265e021c4bc1b99f33c68ae04df707ada618 Mon Sep 17 00:00:00 2001 From: tkqubo Date: Wed, 4 Nov 2015 03:16:48 +0900 Subject: [PATCH 3/3] add more test --- webpack/webpack-env-tests.ts | 40 +++++++++++++++++++++++++++++++++++- webpack/webpack-env.d.ts | 4 ++-- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/webpack/webpack-env-tests.ts b/webpack/webpack-env-tests.ts index 25ec177d6..f219a3e74 100644 --- a/webpack/webpack-env-tests.ts +++ b/webpack/webpack-env-tests.ts @@ -37,6 +37,44 @@ if(module.hot) { }); } +class ModuleData { + updated: boolean; +} + +if (module.hot) { + module.hot.accept((err: Error) => { + //... + }); + + module.hot.decline("./someModule"); + + module.hot.dispose((data: ModuleData) => { + data.updated = true; + // ... + }); + + let disposeHandler: ((data: ModuleData) => void) = data => { + // ... + }; + module.hot.addDisposeHandler(disposeHandler); + module.hot.removeDisposeHandler(disposeHandler); + + module.hot.check(true, (err: Error, outdatedModules: (string|number)[]) => { + // ... + }); + + module.hot.apply({ ignoreUnaccepted: true }, (err: Error, outdatedModules: (string|number)[]) => { + // ... + }); + + var status: string = module.hot.status(); + let statusHandler: ((status: string) => void) = status => { + // ... + }; + module.hot.status(statusHandler); + module.hot.addStatusHandler(statusHandler); + module.hot.removeStatusHandler(statusHandler); +} + -var status: string = module.hot.status(); diff --git a/webpack/webpack-env.d.ts b/webpack/webpack-env.d.ts index 72022c16e..04580949b 100644 --- a/webpack/webpack-env.d.ts +++ b/webpack/webpack-env.d.ts @@ -172,11 +172,11 @@ declare namespace __WebpackModuleApi { /** * If true the update process continues even if some modules are not accepted (and would bubble to the entry point). */ - ignoreUnaccepted: boolean; + ignoreUnaccepted?: boolean; /** * Indicates that apply() is automatically called by check function */ - autoApply: boolean; + autoApply?: boolean; } }