diff --git a/templates/webpack.angular.js b/templates/webpack.angular.js index e8de5173..64d6087e 100644 --- a/templates/webpack.angular.js +++ b/templates/webpack.angular.js @@ -51,7 +51,7 @@ module.exports = env => { const externals = nsWebpack.getConvertedExternals(env.externals); const appFullPath = resolve(projectRoot, appPath); const appResourcesFullPath = resolve(projectRoot, appResourcesPath); - + const tsConfigName = "tsconfig.tns.json"; const entryModule = `${nsWebpack.getEntryModule(appFullPath)}.ts`; const entryPath = `.${sep}${entryModule}`; const ngCompilerTransformers = []; @@ -68,7 +68,7 @@ module.exports = env => { // directly from node_modules and the Angular modules loader won't be able to resolve the lazy routes // fixes https://github.com/NativeScript/nativescript-cli/issues/4024 if (env.externals && env.externals.indexOf("@angular/core") > -1) { - const appModuleRelativePath = getMainModulePath(resolve(appFullPath, entryModule)); + const appModuleRelativePath = getMainModulePath(resolve(appFullPath, entryModule), tsConfigName); if (appModuleRelativePath) { const appModuleFolderPath = dirname(resolve(appFullPath, appModuleRelativePath)); // include the lazy loader inside app module @@ -82,7 +82,7 @@ module.exports = env => { hostReplacementPaths: nsWebpack.getResolver([platform, "tns"]), platformTransformers: ngCompilerTransformers.map(t => t(() => ngCompilerPlugin, resolve(appFullPath, entryModule))), mainPath: resolve(appPath, entryModule), - tsConfigPath: join(__dirname, "tsconfig.tns.json"), + tsConfigPath: join(__dirname, tsConfigName), skipCodeGeneration: !aot, sourceMap: !!sourceMap, additionalLazyModuleResources: additionalLazyModuleResources diff --git a/utils/ast-utils.ts b/utils/ast-utils.ts index a98c53de..88660b86 100644 --- a/utils/ast-utils.ts +++ b/utils/ast-utils.ts @@ -14,19 +14,62 @@ // example of a working workaround by searching for content in each parent. // 4) Always test your transformer both single and in combinations with the other ones. -import { dirname, join } from "path"; +import { dirname, join, relative } from "path"; import * as ts from "typescript"; import { readFileSync, existsSync } from "fs"; import { collectDeepNodes } from "@ngtools/webpack/src/transformers"; -export function getMainModulePath(entryFilePath) { +export function getMainModulePath(entryFilePath: string, tsConfigName: string) { try { - return findBootstrappedModulePath(entryFilePath); + // backwards compatibility + tsConfigName = tsConfigName || "tsconfig.tns.json"; + + const tsModuleName = findBootstrappedModulePath(entryFilePath); + const result = tsResolve(tsModuleName, entryFilePath, tsConfigName); + + return result; } catch (e) { return null; } } +/** + * Returns the real path to the ts/d.ts of the specified `moduleName` relative to the specified `containingFilePath`. (e.g. `~/app/file` -> `./app/file.ts`) + * @param moduleName The name of the module to be resolved (e.g. `~/config.js`, `lodash`, `./already-relative.js`, `@custom-path/file`). + * @param containingFilePath An absolute path to the file where the `moduleName` is imported. The relative result will be based on this file. + * @param tsConfigName The name of the tsconfig which will be used during the module resolution (e.g. `tsconfig.json`). + * We need this config in order to get its compiler options into account (e.g. resolve any custom `paths` like `~` or `@src`). + */ +function tsResolve(moduleName: string, containingFilePath: string, tsConfigName: string) { + let result = moduleName; + try { + const parseConfigFileHost: ts.ParseConfigFileHost = { + getCurrentDirectory: ts.sys.getCurrentDirectory, + useCaseSensitiveFileNames: false, + readDirectory: ts.sys.readDirectory, + fileExists: ts.sys.fileExists, + readFile: ts.sys.readFile, + onUnRecoverableConfigFileDiagnostic: undefined + }; + + const tsConfig = ts.getParsedCommandLineOfConfigFile(tsConfigName, ts.getDefaultCompilerOptions(), parseConfigFileHost); + + const compilerOptions: ts.CompilerOptions = tsConfig.options || ts.getDefaultCompilerOptions(); + const moduleResolutionHost: ts.ModuleResolutionHost = { + fileExists: ts.sys.fileExists, + readFile: ts.sys.readFile + }; + + const resolutionResult = ts.resolveModuleName(moduleName, containingFilePath, compilerOptions, moduleResolutionHost); + + if (resolutionResult && resolutionResult.resolvedModule && resolutionResult.resolvedModule.resolvedFileName) { + result = relative(dirname(containingFilePath), resolutionResult.resolvedModule.resolvedFileName); + } + } catch (err) { } + + return result; +} + export function findBootstrapModuleCall(mainPath: string): ts.CallExpression | null { const source = getSourceFile(mainPath);