diff --git a/demo/AngularApp/webpack.config.js b/demo/AngularApp/webpack.config.js index 608218ff..8c81fce9 100644 --- a/demo/AngularApp/webpack.config.js +++ b/demo/AngularApp/webpack.config.js @@ -7,7 +7,7 @@ const { nsReplaceBootstrap } = require("nativescript-dev-webpack/transformers/ns const { nsReplaceLazyLoader } = require("nativescript-dev-webpack/transformers/ns-replace-lazy-loader"); const { nsSupportHmrNg } = require("nativescript-dev-webpack/transformers/ns-support-hmr-ng"); const { getMainModulePath } = require("nativescript-dev-webpack/utils/ast-utils"); -const { getNoEmitOnErrorFromTSConfig } = require("nativescript-dev-webpack/utils/tsconfig-utils"); +const { getNoEmitOnErrorFromTSConfig, getCompilerOptionsFromTSConfig } = require("nativescript-dev-webpack/utils/tsconfig-utils"); const CleanWebpackPlugin = require("clean-webpack-plugin"); const CopyWebpackPlugin = require("copy-webpack-plugin"); const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer"); @@ -61,19 +61,28 @@ module.exports = env => { const isAnySourceMapEnabled = !!sourceMap || !!hiddenSourceMap; const externals = nsWebpack.getConvertedExternals(env.externals); const appFullPath = resolve(projectRoot, appPath); + const tsConfigName = "tsconfig.tns.json"; + const tsConfigPath = join(__dirname, tsConfigName); const hasRootLevelScopedModules = nsWebpack.hasRootLevelScopedModules({ projectDir: projectRoot }); + const hasRootLevelScopedAngular = nsWebpack.hasRootLevelScopedAngular({ projectDir: projectRoot }); let coreModulesPackageName = "tns-core-modules"; const alias = { '~': appFullPath }; + const compilerOptions = getCompilerOptionsFromTSConfig(tsConfigPath); if (hasRootLevelScopedModules) { coreModulesPackageName = "@nativescript/core"; alias["tns-core-modules"] = coreModulesPackageName; + nsWebpack.processTsPathsForScopedModules({ compilerOptions }); + } + + if (hasRootLevelScopedAngular) { alias["nativescript-angular"] = "@nativescript/angular"; + nsWebpack.processTsPathsForScopedAngular({ compilerOptions }); } + const appResourcesFullPath = resolve(projectRoot, appResourcesPath); - const tsConfigName = "tsconfig.tns.json"; const entryModule = `${nsWebpack.getEntryModule(appFullPath, platform)}.ts`; const entryPath = `.${sep}${entryModule}`; const entries = { bundle: entryPath, application: "./application.android" }; @@ -110,10 +119,11 @@ module.exports = env => { hostReplacementPaths: nsWebpack.getResolver([platform, "tns"]), platformTransformers: ngCompilerTransformers.map(t => t(() => ngCompilerPlugin, resolve(appFullPath, entryModule), projectRoot)), mainPath: join(appFullPath, entryModule), - tsConfigPath: join(__dirname, tsConfigName), + tsConfigPath, skipCodeGeneration: !aot, sourceMap: !!isAnySourceMapEnabled, - additionalLazyModuleResources: additionalLazyModuleResources + additionalLazyModuleResources: additionalLazyModuleResources, + compilerOptions: { paths: compilerOptions.paths } }); let sourceMapFilename = nsWebpack.getSourceMapFilename(hiddenSourceMap, __dirname, dist); diff --git a/index.js b/index.js index f17dc47a..9036ae0c 100644 --- a/index.js +++ b/index.js @@ -10,17 +10,28 @@ const { Object.assign(exports, require("./plugins")); Object.assign(exports, require("./host/resolver")); +exports.processTsPathsForScopedModules = function ({ compilerOptions }) { + return replacePathInCompilerOptions({ + compilerOptions, + targetPath: "tns-core-modules", + replacementPath: "@nativescript/core" + }); +} + +exports.processTsPathsForScopedAngular = function ({ compilerOptions }) { + return replacePathInCompilerOptions({ + compilerOptions, + targetPath: "nativescript-angular", + replacementPath: "@nativescript/angular" + }); +} + exports.hasRootLevelScopedModules = function ({ projectDir }) { - let hasRootLevelScopedModules; - try { - const scopedModulesPackageName = '@nativescript/core'; - require.resolve(scopedModulesPackageName, { paths: [projectDir] }); - hasRootLevelScopedModules = true; - } catch (e) { - hasRootLevelScopedModules = false; - } + return hasRootLevelPackage({ projectDir, packageName: "@nativescript/core" }); +} - return hasRootLevelScopedModules; +exports.hasRootLevelScopedAngular = function ({ projectDir }) { + return hasRootLevelPackage({ projectDir, packageName: "@nativescript/angular" }); } exports.getAotEntryModule = function (appDirectory) { @@ -176,3 +187,32 @@ function verifyEntryModuleDirectory(appDirectory) { throw new Error(`The specified path to app directory ${appDirectory} does not exist. Unable to find entry module.`); } } + + +function hasRootLevelPackage({ projectDir, packageName }) { + let hasRootLevelPackage; + try { + require.resolve(packageName, { paths: [projectDir] }); + hasRootLevelPackage = true; + } catch (e) { + hasRootLevelPackage = false; + } + + return hasRootLevelPackage; +} + +function replacePathInCompilerOptions({ compilerOptions, targetPath, replacementPath }) { + const paths = (compilerOptions && compilerOptions.paths) || {}; + for (const key in paths) { + if (paths.hasOwnProperty(key)) { + const pathsForPattern = paths[key]; + if (Array.isArray(pathsForPattern)) { + for (let i = 0; i < pathsForPattern.length; ++i) { + if (typeof pathsForPattern[i] === "string") { + pathsForPattern[i] = pathsForPattern[i].replace(targetPath, replacementPath); + } + } + } + } + } +} \ No newline at end of file diff --git a/templates/webpack.angular.js b/templates/webpack.angular.js index b705a262..532fb64c 100644 --- a/templates/webpack.angular.js +++ b/templates/webpack.angular.js @@ -7,7 +7,7 @@ const { nsReplaceBootstrap } = require("nativescript-dev-webpack/transformers/ns const { nsReplaceLazyLoader } = require("nativescript-dev-webpack/transformers/ns-replace-lazy-loader"); const { nsSupportHmrNg } = require("nativescript-dev-webpack/transformers/ns-support-hmr-ng"); const { getMainModulePath } = require("nativescript-dev-webpack/utils/ast-utils"); -const { getNoEmitOnErrorFromTSConfig } = require("nativescript-dev-webpack/utils/tsconfig-utils"); +const { getNoEmitOnErrorFromTSConfig, getCompilerOptionsFromTSConfig } = require("nativescript-dev-webpack/utils/tsconfig-utils"); const CleanWebpackPlugin = require("clean-webpack-plugin"); const CopyWebpackPlugin = require("copy-webpack-plugin"); const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer"); @@ -60,19 +60,28 @@ module.exports = env => { const isAnySourceMapEnabled = !!sourceMap || !!hiddenSourceMap; const externals = nsWebpack.getConvertedExternals(env.externals); const appFullPath = resolve(projectRoot, appPath); + const tsConfigName = "tsconfig.tns.json"; + const tsConfigPath = join(__dirname, tsConfigName); const hasRootLevelScopedModules = nsWebpack.hasRootLevelScopedModules({ projectDir: projectRoot }); + const hasRootLevelScopedAngular = nsWebpack.hasRootLevelScopedAngular({ projectDir: projectRoot }); let coreModulesPackageName = "tns-core-modules"; const alias = { '~': appFullPath }; + const compilerOptions = getCompilerOptionsFromTSConfig(tsConfigPath); if (hasRootLevelScopedModules) { coreModulesPackageName = "@nativescript/core"; alias["tns-core-modules"] = coreModulesPackageName; + nsWebpack.processTsPathsForScopedModules({ compilerOptions }); + } + + if (hasRootLevelScopedAngular) { alias["nativescript-angular"] = "@nativescript/angular"; + nsWebpack.processTsPathsForScopedAngular({ compilerOptions }); } + const appResourcesFullPath = resolve(projectRoot, appResourcesPath); - const tsConfigName = "tsconfig.tns.json"; const entryModule = `${nsWebpack.getEntryModule(appFullPath, platform)}.ts`; const entryPath = `.${sep}${entryModule}`; const entries = { bundle: entryPath }; @@ -109,10 +118,11 @@ module.exports = env => { hostReplacementPaths: nsWebpack.getResolver([platform, "tns"]), platformTransformers: ngCompilerTransformers.map(t => t(() => ngCompilerPlugin, resolve(appFullPath, entryModule), projectRoot)), mainPath: join(appFullPath, entryModule), - tsConfigPath: join(__dirname, tsConfigName), + tsConfigPath, skipCodeGeneration: !aot, sourceMap: !!isAnySourceMapEnabled, - additionalLazyModuleResources: additionalLazyModuleResources + additionalLazyModuleResources: additionalLazyModuleResources, + compilerOptions: { paths: compilerOptions.paths } }); let sourceMapFilename = nsWebpack.getSourceMapFilename(hiddenSourceMap, __dirname, dist); diff --git a/templates/webpack.config.spec.ts b/templates/webpack.config.spec.ts index 392e3524..8d62b062 100644 --- a/templates/webpack.config.spec.ts +++ b/templates/webpack.config.spec.ts @@ -30,6 +30,9 @@ const nativeScriptDevWebpack = { getAppPath: () => 'app', getEntryModule: () => 'EntryModule', hasRootLevelScopedModules: () => false, + hasRootLevelScopedAngular: () => false, + processTsPathsForScopedModules: () => false, + processTsPathsForScopedAngular: () => false, getResolver: () => null, getConvertedExternals: nsWebpackIndex.getConvertedExternals, getSourceMapFilename: nsWebpackIndex.getSourceMapFilename, @@ -48,7 +51,7 @@ const webpackConfigAngular = proxyquire('./webpack.angular', { 'nativescript-dev-webpack/transformers/ns-replace-lazy-loader': { nsReplaceLazyLoader: () => { return FakeLazyTransformerFlag } }, 'nativescript-dev-webpack/transformers/ns-support-hmr-ng': { nsSupportHmrNg: () => { return FakeHmrTransformerFlag } }, 'nativescript-dev-webpack/utils/ast-utils': { getMainModulePath: () => { return "fakePath"; } }, - 'nativescript-dev-webpack/utils/tsconfig-utils': { getNoEmitOnErrorFromTSConfig: () => { return false; } }, + 'nativescript-dev-webpack/utils/tsconfig-utils': { getNoEmitOnErrorFromTSConfig: () => { return false; }, getCompilerOptionsFromTSConfig: () => { return false; } }, 'nativescript-dev-webpack/plugins/NativeScriptAngularCompilerPlugin': { getAngularCompilerPlugin: () => { return AngularCompilerStub; } }, '@ngtools/webpack': { AngularCompilerPlugin: AngularCompilerStub @@ -59,7 +62,7 @@ const webpackConfigAngular = proxyquire('./webpack.angular', { const webpackConfigTypeScript = proxyquire('./webpack.typescript', { 'nativescript-dev-webpack': nativeScriptDevWebpack, 'nativescript-dev-webpack/nativescript-target': emptyObject, - 'nativescript-dev-webpack/utils/tsconfig-utils': { getNoEmitOnErrorFromTSConfig: () => { return false; } }, + 'nativescript-dev-webpack/utils/tsconfig-utils': { getNoEmitOnErrorFromTSConfig: () => { return false; }, getCompilerOptionsFromTSConfig: () => { return false; } }, 'terser-webpack-plugin': TerserJsStub }); @@ -362,6 +365,7 @@ describe('webpack.config.js', () => { describe(`alias for webpack.${type}.js (${platform})`, () => { it('should add alias when @nativescript/core is at the root of node_modules', () => { nativeScriptDevWebpack.hasRootLevelScopedModules = () => true; + nativeScriptDevWebpack.hasRootLevelScopedAngular = () => true; const input = getInput({ platform }); const config = webpackConfig(input); expect(config.resolve.alias['tns-core-modules']).toBe('@nativescript/core'); @@ -371,6 +375,7 @@ describe('webpack.config.js', () => { }); it('shouldn\'t add alias when @nativescript/core is not at the root of node_modules', () => { nativeScriptDevWebpack.hasRootLevelScopedModules = () => false; + nativeScriptDevWebpack.hasRootLevelScopedAngular = () => false; const input = getInput({ platform }); const config = webpackConfig(input); expect(config.resolve.alias['tns-core-modules']).toBeUndefined();