mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-15 11:01:21 +08:00
104 lines
4.8 KiB
TypeScript
104 lines
4.8 KiB
TypeScript
import { normalize } from 'path';
|
|
import * as ts from 'typescript';
|
|
import { AddNodeOperation, ReplaceNodeOperation, StandardTransform, TransformOperation, collectDeepNodes, makeTransform, insertStarImport } from '@ngtools/webpack/src/transformers';
|
|
import { AngularCompilerPlugin } from '@ngtools/webpack';
|
|
import { findBootstrappedModulePathInSource, findNativeScriptPlatformPathInSource, findBootstrapModuleCallInSource, findNativeScriptPlatformCallInSource, getExpressionName } from '../utils/ast-utils';
|
|
|
|
export function nsSupportHmrNg(getNgCompiler: () => AngularCompilerPlugin, entryPath: string): ts.TransformerFactory<ts.SourceFile> {
|
|
const standardTransform: StandardTransform = function (sourceFile: ts.SourceFile) {
|
|
let ops: TransformOperation[] = [];
|
|
|
|
if (!entryPath || normalize(sourceFile.fileName) !== normalize(entryPath)) {
|
|
return ops;
|
|
}
|
|
|
|
try {
|
|
ops = handleHmrSupport(sourceFile);
|
|
} catch (e) {
|
|
ops = [];
|
|
}
|
|
|
|
return ops;
|
|
};
|
|
|
|
return makeTransform(standardTransform, () => getNgCompiler().typeChecker);
|
|
}
|
|
|
|
export function handleHmrSupport(mainFile: ts.SourceFile): TransformOperation[] {
|
|
const importNodesInFile = collectDeepNodes(mainFile, ts.SyntaxKind.ImportDeclaration);
|
|
if (!importNodesInFile || !importNodesInFile.length) {
|
|
return [];
|
|
}
|
|
|
|
const bootstrapModuleCallNode = findBootstrapModuleCallInSource(mainFile);
|
|
if (!bootstrapModuleCallNode || !bootstrapModuleCallNode.arguments || !bootstrapModuleCallNode.arguments.length) {
|
|
return [];
|
|
}
|
|
|
|
const appModuleName = getExpressionName(bootstrapModuleCallNode.arguments[0]);
|
|
const nativeScriptPlatformCallNode = findNativeScriptPlatformCallInSource(mainFile);
|
|
if (!nativeScriptPlatformCallNode || !nativeScriptPlatformCallNode.arguments) {
|
|
return [];
|
|
}
|
|
|
|
return handleHmrSupportCore(mainFile, importNodesInFile, appModuleName, nativeScriptPlatformCallNode);
|
|
}
|
|
|
|
function handleHmrSupportCore(mainFile: ts.SourceFile, importNodesInFile: ts.Node[], appModuleName: string, nativeScriptPlatformCallNode: ts.CallExpression) {
|
|
const firstImportNode = importNodesInFile[0];
|
|
const lastImportNode = importNodesInFile[importNodesInFile.length - 1];
|
|
const appModulePath = findBootstrappedModulePathInSource(mainFile);
|
|
if (!appModuleName || !appModulePath) {
|
|
return [];
|
|
}
|
|
|
|
let currentAppOptionsInitializationNode: ts.Expression = ts.createObjectLiteral();
|
|
if (nativeScriptPlatformCallNode.arguments.length > 0) {
|
|
currentAppOptionsInitializationNode = nativeScriptPlatformCallNode.arguments[0];
|
|
}
|
|
|
|
const optionsDeclaration = ts.createVariableDeclaration(GeneratedDynamicAppOptions, undefined, ts.createObjectLiteral());
|
|
const optionsDeclarationList = ts.createVariableDeclarationList([optionsDeclaration]);
|
|
const optionsStatement = ts.createVariableStatement(undefined, optionsDeclarationList);
|
|
|
|
const setHmrOptionsNode = ts.createIdentifier(getHmrOptionsCode(appModuleName, appModulePath));
|
|
|
|
const acceptHmrNode = ts.createIdentifier(getAcceptMainModuleCode(appModulePath));
|
|
|
|
const objectAssignNode = ts.createPropertyAccess(ts.createIdentifier('Object'), ts.createIdentifier('assign'));
|
|
const extendAppOptionsNode = ts.createCall(objectAssignNode, undefined, [currentAppOptionsInitializationNode, ts.createIdentifier(GeneratedDynamicAppOptions)]);
|
|
|
|
const newNsDynamicCallArgs = ts.createNodeArray([extendAppOptionsNode, ...nativeScriptPlatformCallNode.arguments.slice(1)]);
|
|
const nsPlatformPath = findNativeScriptPlatformPathInSource(mainFile);
|
|
const nsPlatformText = getExpressionName(nativeScriptPlatformCallNode.expression);
|
|
const newNsDynamicCallNode = ts.createCall(ts.createPropertyAccess(ts.createIdentifier(NsNgPlatformStarImport), ts.createIdentifier(nsPlatformText)), [], newNsDynamicCallArgs);
|
|
|
|
return [...insertStarImport(mainFile, ts.createIdentifier(NsNgPlatformStarImport), nsPlatformPath, firstImportNode, true), new AddNodeOperation(mainFile, lastImportNode, undefined, optionsStatement), new AddNodeOperation(mainFile, lastImportNode, undefined, setHmrOptionsNode), new AddNodeOperation(mainFile, lastImportNode, undefined, acceptHmrNode), new ReplaceNodeOperation(mainFile, nativeScriptPlatformCallNode, newNsDynamicCallNode)];
|
|
}
|
|
|
|
export const GeneratedDynamicAppOptions = 'options_Generated';
|
|
const NsNgPlatformStarImport = 'nativescript_angular_platform_Generated';
|
|
|
|
export function getHmrOptionsCode(appModuleName: string, appModulePath: string) {
|
|
return `
|
|
if (module["hot"]) {
|
|
${GeneratedDynamicAppOptions} = {
|
|
hmrOptions: {
|
|
moduleTypeFactory: function () { return require("${appModulePath}").${appModuleName}; },
|
|
livesyncCallback: function (platformReboot) { setTimeout(platformReboot, 0); }
|
|
}
|
|
};
|
|
}
|
|
`;
|
|
}
|
|
|
|
export function getAcceptMainModuleCode(mainModulePath: string) {
|
|
return `
|
|
if (module["hot"]) {
|
|
module["hot"].accept(["${mainModulePath}"], function () {
|
|
global["hmrRefresh"]({});
|
|
});
|
|
}
|
|
`;
|
|
}
|