UNPKG

@angular-devkit/build-angular

Version:
185 lines (184 loc) • 6.91 kB
"use strict"; /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.dev/license */ Object.defineProperty(exports, "__esModule", { value: true }); exports.default = default_1; // eslint-disable-next-line import/no-extraneous-dependencies const core_1 = require("@angular/core"); const rxjs_1 = require("rxjs"); function default_1(mod) { if (!mod['hot']) { return; } if (!(0, core_1.isDevMode)()) { console.error(`[NG HMR] Cannot use HMR when Angular is running in production mode. To prevent production mode, do not call 'enableProdMode()'.`); return; } mod['hot'].accept(); mod['hot'].dispose(() => { if (typeof ng === 'undefined') { console.warn(`[NG HMR] Cannot find global 'ng'. Likely this is caused because scripts optimization is enabled.`); return; } if (!ng.getInjector) { // View Engine return; } // Reset JIT compiled components cache (0, core_1.ɵresetCompiledComponents)(); const appRoot = getAppRoot(); if (!appRoot) { return; } const appRef = getApplicationRef(appRoot); if (!appRef) { return; } // Inputs that are hidden should be ignored const oldInputs = document.querySelectorAll('input:not([type="hidden"]), textarea'); const oldOptions = document.querySelectorAll('option'); // Create new application appRef.components.forEach((cp) => { const element = cp.location.nativeElement; const parentNode = element.parentNode; parentNode.insertBefore(document.createElement(element.tagName), element); parentNode.removeChild(element); }); // Destroy old application, injectors, <style..., etc.. const platformRef = getPlatformRef(appRoot); if (platformRef) { platformRef.destroy(); } // Restore all inputs and options const bodyElement = document.body; if (oldInputs.length + oldOptions.length === 0 || !bodyElement) { return; } // Use a `MutationObserver` to wait until the app-root element has been bootstrapped. // ie: when the ng-version attribute is added. new MutationObserver((_mutationsList, observer) => { observer.disconnect(); const newAppRoot = getAppRoot(); if (!newAppRoot) { return; } const newAppRef = getApplicationRef(newAppRoot); if (!newAppRef) { return; } // Wait until the application isStable to restore the form values newAppRef.isStable .pipe((0, rxjs_1.filter)((isStable) => !!isStable), (0, rxjs_1.take)(1)) .subscribe(() => restoreFormValues(oldInputs, oldOptions)); }).observe(bodyElement, { attributes: true, subtree: true, attributeFilter: ['ng-version'], }); }); } function getAppRoot() { const appRoot = document.querySelector('[ng-version]'); if (!appRoot) { console.warn('[NG HMR] Cannot find the application root component.'); return undefined; } return appRoot; } function getToken(appRoot, token) { return (typeof ng === 'object' && ng.getInjector(appRoot).get(token)) || undefined; } function getApplicationRef(appRoot) { const appRef = getToken(appRoot, core_1.ApplicationRef); if (!appRef) { console.warn(`[NG HMR] Cannot get 'ApplicationRef'.`); return undefined; } return appRef; } function getPlatformRef(appRoot) { const platformRef = getToken(appRoot, core_1.PlatformRef); if (!platformRef) { console.warn(`[NG HMR] Cannot get 'PlatformRef'.`); return undefined; } return platformRef; } function dispatchEvents(element) { element.dispatchEvent(new Event('input', { bubbles: true, cancelable: true, })); element.blur(); element.dispatchEvent(new KeyboardEvent('keyup', { key: 'Enter' })); } function restoreFormValues(oldInputs, oldOptions) { // Restore input that are not hidden const newInputs = document.querySelectorAll('input:not([type="hidden"]), textarea'); if (newInputs.length && newInputs.length === oldInputs.length) { console.log('[NG HMR] Restoring input/textarea values.'); for (let index = 0; index < newInputs.length; index++) { const newElement = newInputs[index]; const oldElement = oldInputs[index]; switch (oldElement.type) { case 'button': case 'image': case 'submit': case 'reset': // These types don't need any value change. continue; case 'radio': case 'checkbox': newElement.checked = oldElement.checked; break; case 'color': case 'date': case 'datetime-local': case 'email': case 'hidden': case 'month': case 'number': case 'password': case 'range': case 'search': case 'tel': case 'text': case 'textarea': case 'time': case 'url': case 'week': newElement.value = oldElement.value; break; case 'file': // Ignored due: Uncaught DOMException: Failed to set the 'value' property on 'HTMLInputElement': // This input element accepts a filename, which may only be programmatically set to the empty string. break; default: console.warn('[NG HMR] Unknown input type ' + oldElement.type + '.'); continue; } dispatchEvents(newElement); } } else if (oldInputs.length) { console.warn('[NG HMR] Cannot restore input/textarea values.'); } // Restore option const newOptions = document.querySelectorAll('option'); if (newOptions.length && newOptions.length === oldOptions.length) { console.log('[NG HMR] Restoring selected options.'); for (let index = 0; index < newOptions.length; index++) { const newElement = newOptions[index]; newElement.selected = oldOptions[index].selected; dispatchEvents(newElement); } } else if (oldOptions.length) { console.warn('[NG HMR] Cannot restore selected options.'); } }