From 1c73cbae6a9a608ec0086a477c2854600232165b Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Sun, 22 Apr 2018 18:24:00 +0300 Subject: [PATCH 1/3] fix: Allow using the plugin via symlink Currently when the plugin is used with symlink, the execution fails as the project dir is calculated incorrectly. Instead of trying to find the project dir, pass it wherever it is required. This leads to changes in the way NativeScriptAngularCompilerPlugin is loaded - currently it uses the projectDir directly when the plugin is loaded. However, at this point we do no know the exact location of the project directory. So change the require of the NativeScriptAngularCompilerPlugin to return a function, which accepts projectDir as argument. Expose the loading through a new method in the nativescript-dev-webpack plugin - `loadAdditionalPlugins`. BREAKING CHANGE: The current code changes the way NativeScriptAngularCompilerPlugin is loaded. This means that all projects that already have webpack.config.js and just upgrade the version of nativescript-dev-webpack, will not be able to use the plugin (NativeScriptAngularCompilerPlugin). They will have to modify their webpack.config.js files. --- index.js | 25 ++- plugins/NativeScriptAngularCompilerPlugin.ts | 167 ++++++++++--------- plugins/angular.js | 4 +- templates/webpack.angular.js | 2 + templates/webpack.javascript.js | 2 + templates/webpack.typescript.js | 2 + 6 files changed, 109 insertions(+), 93 deletions(-) diff --git a/index.js b/index.js index bc4fe058..6b59ae1f 100644 --- a/index.js +++ b/index.js @@ -11,13 +11,12 @@ const { resolveAndroidAppPath, } = require("./projectHelpers"); -const PROJECT_DIR = getProjectDir(); -const APP_PATH = path.join(PROJECT_DIR, APP_DIR); - Object.assign(exports, require('./plugins')); -if (isAngular({ projectDir: PROJECT_DIR })) { - Object.assign(exports, require('./plugins/angular')); +exports.loadAdditionalPlugins = function (projectSettings) { + if (isAngular(projectSettings)) { + Object.assign(exports, require('./plugins/angular')(projectSettings.projectDir)); + } } exports.getAotEntryModule = function (appDirectory = APP_PATH) { @@ -36,7 +35,15 @@ exports.getAotEntryModule = function (appDirectory = APP_PATH) { // Exported for backwards compatibility with {N} 3 exports.uglifyMangleExcludes = require("./mangle-excludes"); -exports.getEntryModule = function (appDirectory = APP_PATH) { +exports.getEntryModule = function (appDirectory) { + if (!appDirectory) { + throw new Error("Path to app directory is not specified. Unable to find entry module."); + } + + if (!existsSync(appDirectory)) { + throw new Error(`The specified path to app directory ${appDirectory} does not exist. Unable to find entry module.`); + } + const entry = getPackageJsonEntry(appDirectory); const tsEntryPath = path.resolve(appDirectory, `${entry}.ts`); @@ -49,14 +56,14 @@ exports.getEntryModule = function (appDirectory = APP_PATH) { return entry; }; -exports.getAppPath = platform => { +exports.getAppPath = (platform, projectDir) => { if (isIos(platform)) { - const appName = path.basename(PROJECT_DIR); + const appName = path.basename(projectDir); const sanitizedName = sanitize(appName); return `platforms/ios/${sanitizedName}/app`; } else if (isAndroid(platform)) { - return resolveAndroidAppPath(PROJECT_DIR); + return resolveAndroidAppPath(projectDir); } else { throw new Error(`Invalid platform: ${platform}`); } diff --git a/plugins/NativeScriptAngularCompilerPlugin.ts b/plugins/NativeScriptAngularCompilerPlugin.ts index 7554e022..a8fb8323 100644 --- a/plugins/NativeScriptAngularCompilerPlugin.ts +++ b/plugins/NativeScriptAngularCompilerPlugin.ts @@ -1,101 +1,104 @@ import * as path from "path"; import { PlatformFSPlugin, PlatformFSPluginOptions, mapFileSystem } from "./PlatformFSPlugin"; -import * as hook from "nativescript-hook"; import * as ngToolsWebpack from "@ngtools/webpack"; +module.exports = (projectDir) => { + // During development the nativescript-dev-webpack plugin may have @ngtools/webpack installed locally as dev-dependency, + // we want to make sure we are using the one installed in the actual app + const ngToolsWebpackDir = path.join(projectDir, "node_modules", "@ngtools", "webpack"); + const appNgToolsWebpack: typeof ngToolsWebpack = require(ngToolsWebpackDir); + const AngularCompilerPlugin: typeof ngToolsWebpack.AngularCompilerPlugin = appNgToolsWebpack.AngularCompilerPlugin; -// During development the nativescript-dev-webpack plugin may have @ngtools/webpack installed locally as dev-dependency, -// we want to make sure we are using the one installed in the actual app -const projectDir = hook(path.join(__dirname, "..")).findProjectDir(); -const ngToolsWebpackDir = path.join(projectDir, "node_modules", "@ngtools", "webpack"); -const appNgToolsWebpack: typeof ngToolsWebpack = require(ngToolsWebpackDir); + class NativeScriptAngularCompilerPlugin extends AngularCompilerPlugin { + readonly options: NativeScriptAngularCompilerPluginOptions; + readonly platform: string; -export const AngularCompilerPlugin: typeof ngToolsWebpack.AngularCompilerPlugin = appNgToolsWebpack.AngularCompilerPlugin; - -export interface NativeScriptAngularCompilerPluginOptions extends ngToolsWebpack.AngularCompilerPluginOptions { - platformOptions?: PlatformFSPluginOptions; -} - -export interface CompiledFile { - outputText: string; - sourceMap: string; - errorDependencies: string[]; -} - -export class NativeScriptAngularCompilerPlugin extends AngularCompilerPlugin { - readonly options: NativeScriptAngularCompilerPluginOptions; - readonly platform: string; - - get __compilerHost() { - // Accessing private API of the AngularCompilerPlugin - // We need this to augment at least the "resourceNameToFileName" so we can map - // component.css to component.android.css etc. for platform specific css and html resources. - return (this)._compilerHost; - } + get __compilerHost() { + // Accessing private API of the AngularCompilerPlugin + // We need this to augment at least the "resourceNameToFileName" so we can map + // component.css to component.android.css etc. for platform specific css and html resources. + return (this)._compilerHost; + } - constructor(options: NativeScriptAngularCompilerPluginOptions) { - super(options); + constructor(options: NativeScriptAngularCompilerPluginOptions) { + super(options); - this.platform = (this.options.platformOptions && this.options.platformOptions.platform) || undefined; - const platform = this.platform; + this.platform = (this.options.platformOptions && this.options.platformOptions.platform) || undefined; + const platform = this.platform; - if (platform) { - // https://github.com/angular/angular/blob/7bfeac746e717d02e062fe4a65c008060b8b662c/packages/compiler-cli/src/transformers/api.ts - const resourceNameToFileName = this.__compilerHost.resourceNameToFileName || function(file, relativeTo) { - const resolved = path.resolve(path.dirname(relativeTo), file); - if (this.fileExists(resolved)) { + if (platform) { + // https://github.com/angular/angular/blob/7bfeac746e717d02e062fe4a65c008060b8b662c/packages/compiler-cli/src/transformers/api.ts + const resourceNameToFileName = this.__compilerHost.resourceNameToFileName || function (file, relativeTo) { + const resolved = path.resolve(path.dirname(relativeTo), file); + if (this.fileExists(resolved)) { + return resolved; + } else { + return null; + } + }; + this.__compilerHost.resourceNameToFileName = function (file, relativeTo) { + const parsed = path.parse(file); + const platformFile = parsed.name + "." + platform + parsed.ext; + let resolved; + try { + resolved = resourceNameToFileName.call(this, platformFile, relativeTo); + } catch (e) { + } + resolved = resolved || resourceNameToFileName.call(this, file, relativeTo); + resolved = resolved && resolved.replace(/\\/g, "/"); return resolved; - } else { - return null; - } - }; - this.__compilerHost.resourceNameToFileName = function(file, relativeTo) { - const parsed = path.parse(file); - const platformFile = parsed.name + "." + platform + parsed.ext; - let resolved; - try { - resolved = resourceNameToFileName.call(this, platformFile, relativeTo); - } catch(e) { - } - resolved = resolved || resourceNameToFileName.call(this, file, relativeTo); - resolved = resolved && resolved.replace(/\\/g, "/"); - return resolved; - }; + }; + } } - } - getCompiledFile(this: NativeScriptAngularCompilerPlugin, file: string): CompiledFile { - try { - if (this.platform) { - const parsed = path.parse(file); - const platformFile = parsed.dir + path.sep + parsed.name + "." + this.platform + parsed.ext; - const result = super.getCompiledFile(platformFile); - return result; + getCompiledFile(this: NativeScriptAngularCompilerPlugin, file: string): CompiledFile { + try { + if (this.platform) { + const parsed = path.parse(file); + const platformFile = parsed.dir + path.sep + parsed.name + "." + this.platform + parsed.ext; + const result = super.getCompiledFile(platformFile); + return result; + } + } catch (e) { } - } catch(e) { + return super.getCompiledFile(file); } - return super.getCompiledFile(file); - } - apply(compiler) { - super.apply(compiler); - if (this.options.platformOptions && this.options.platformOptions.platform && this.options.platformOptions.platforms) { - compiler.plugin('environment', () => { - compiler.inputFileSystem = mapFileSystem({ - fs: compiler.inputFileSystem, - context: compiler.context, - platform: this.options.platformOptions.platform, - platforms: this.options.platformOptions.platforms, - ignore: this.options.platformOptions.ignore - }); + apply(compiler) { + super.apply(compiler); + if (this.options.platformOptions && this.options.platformOptions.platform && this.options.platformOptions.platforms) { + compiler.plugin('environment', () => { + compiler.inputFileSystem = mapFileSystem({ + fs: compiler.inputFileSystem, + context: compiler.context, + platform: this.options.platformOptions.platform, + platforms: this.options.platformOptions.platforms, + ignore: this.options.platformOptions.ignore + }); - compiler.watchFileSystem = mapFileSystem({ - fs: compiler.watchFileSystem, - context: compiler.context, - platform: this.options.platformOptions.platform, - platforms: this.options.platformOptions.platforms, - ignore: this.options.platformOptions.ignore + compiler.watchFileSystem = mapFileSystem({ + fs: compiler.watchFileSystem, + context: compiler.context, + platform: this.options.platformOptions.platform, + platforms: this.options.platformOptions.platforms, + ignore: this.options.platformOptions.ignore + }); }); - }); + } } } + + return { + AngularCompilerPlugin, + NativeScriptAngularCompilerPlugin + }; +} + +export interface NativeScriptAngularCompilerPluginOptions extends ngToolsWebpack.AngularCompilerPluginOptions { + platformOptions?: PlatformFSPluginOptions; +} + +export interface CompiledFile { + outputText: string; + sourceMap: string; + errorDependencies: string[]; } diff --git a/plugins/angular.js b/plugins/angular.js index 59d4e29b..ddfe1288 100644 --- a/plugins/angular.js +++ b/plugins/angular.js @@ -1,3 +1,3 @@ -module.exports = Object.assign({}, - require("./NativeScriptAngularCompilerPlugin") +module.exports = (projectDir) => Object.assign({}, + require("./NativeScriptAngularCompilerPlugin")(projectDir) ); diff --git a/templates/webpack.angular.js b/templates/webpack.angular.js index 401ff1f6..2e8152fa 100644 --- a/templates/webpack.angular.js +++ b/templates/webpack.angular.js @@ -17,6 +17,8 @@ module.exports = env => { const platforms = ["ios", "android"]; const projectRoot = __dirname; + nsWebpack.loadAdditionalPlugins({ projectDir: projectRoot }); + // Default destination inside platforms//... const dist = resolve(projectRoot, nsWebpack.getAppPath(platform)); const appResourcesPlatformDir = platform === "android" ? "Android" : "iOS"; diff --git a/templates/webpack.javascript.js b/templates/webpack.javascript.js index 780806ee..d9886677 100644 --- a/templates/webpack.javascript.js +++ b/templates/webpack.javascript.js @@ -17,6 +17,8 @@ module.exports = env => { const platforms = ["ios", "android"]; const projectRoot = __dirname; + nsWebpack.loadAdditionalPlugins({ projectDir: projectRoot }); + // Default destination inside platforms//... const dist = resolve(projectRoot, nsWebpack.getAppPath(platform)); const appResourcesPlatformDir = platform === "android" ? "Android" : "iOS"; diff --git a/templates/webpack.typescript.js b/templates/webpack.typescript.js index e7467903..76ce0554 100644 --- a/templates/webpack.typescript.js +++ b/templates/webpack.typescript.js @@ -17,6 +17,8 @@ module.exports = env => { const platforms = ["ios", "android"]; const projectRoot = __dirname; + nsWebpack.loadAdditionalPlugins({ projectDir: projectRoot }); + // Default destination inside platforms//... const dist = resolve(projectRoot, nsWebpack.getAppPath(platform)); const appResourcesPlatformDir = platform === "android" ? "Android" : "iOS"; From 335585d9b68775fe1d8cf3066dfce88a7e44105c Mon Sep 17 00:00:00 2001 From: Manol Donev Date: Mon, 23 Apr 2018 13:21:28 +0300 Subject: [PATCH 2/3] fix: webpack getAppPath with projectRoot --- templates/webpack.angular.js | 2 +- templates/webpack.javascript.js | 2 +- templates/webpack.typescript.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/templates/webpack.angular.js b/templates/webpack.angular.js index 2e8152fa..5bfe6e85 100644 --- a/templates/webpack.angular.js +++ b/templates/webpack.angular.js @@ -20,7 +20,7 @@ module.exports = env => { nsWebpack.loadAdditionalPlugins({ projectDir: projectRoot }); // Default destination inside platforms//... - const dist = resolve(projectRoot, nsWebpack.getAppPath(platform)); + const dist = resolve(projectRoot, nsWebpack.getAppPath(platform, projectRoot)); const appResourcesPlatformDir = platform === "android" ? "Android" : "iOS"; const { diff --git a/templates/webpack.javascript.js b/templates/webpack.javascript.js index d9886677..aa51a4fe 100644 --- a/templates/webpack.javascript.js +++ b/templates/webpack.javascript.js @@ -20,7 +20,7 @@ module.exports = env => { nsWebpack.loadAdditionalPlugins({ projectDir: projectRoot }); // Default destination inside platforms//... - const dist = resolve(projectRoot, nsWebpack.getAppPath(platform)); + const dist = resolve(projectRoot, nsWebpack.getAppPath(platform, projectRoot)); const appResourcesPlatformDir = platform === "android" ? "Android" : "iOS"; const { diff --git a/templates/webpack.typescript.js b/templates/webpack.typescript.js index 76ce0554..cfc2be63 100644 --- a/templates/webpack.typescript.js +++ b/templates/webpack.typescript.js @@ -20,7 +20,7 @@ module.exports = env => { nsWebpack.loadAdditionalPlugins({ projectDir: projectRoot }); // Default destination inside platforms//... - const dist = resolve(projectRoot, nsWebpack.getAppPath(platform)); + const dist = resolve(projectRoot, nsWebpack.getAppPath(platform, projectRoot)); const appResourcesPlatformDir = platform === "android" ? "Android" : "iOS"; const { From c9d1853a9dfeb60d863e3f39990313ec1710eb00 Mon Sep 17 00:00:00 2001 From: Manol Donev Date: Mon, 23 Apr 2018 14:19:38 +0300 Subject: [PATCH 3/3] refactor: verify entry module directory --- index.js | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/index.js b/index.js index 6b59ae1f..faeb625e 100644 --- a/index.js +++ b/index.js @@ -2,9 +2,7 @@ const path = require("path"); const { existsSync } = require("fs"); const { - APP_DIR, getPackageJson, - getProjectDir, isAngular, isAndroid, isIos, @@ -19,7 +17,9 @@ exports.loadAdditionalPlugins = function (projectSettings) { } } -exports.getAotEntryModule = function (appDirectory = APP_PATH) { +exports.getAotEntryModule = function (appDirectory) { + verifyEntryModuleDirectory(appDirectory); + const entry = getPackageJsonEntry(appDirectory); const aotEntry = `${entry}.aot.ts`; @@ -36,13 +36,7 @@ exports.getAotEntryModule = function (appDirectory = APP_PATH) { exports.uglifyMangleExcludes = require("./mangle-excludes"); exports.getEntryModule = function (appDirectory) { - if (!appDirectory) { - throw new Error("Path to app directory is not specified. Unable to find entry module."); - } - - if (!existsSync(appDirectory)) { - throw new Error(`The specified path to app directory ${appDirectory} does not exist. Unable to find entry module.`); - } + verifyEntryModuleDirectory(appDirectory); const entry = getPackageJsonEntry(appDirectory); @@ -84,3 +78,13 @@ function getPackageJsonEntry(appDirectory) { return entry.replace(/\.js$/i, ""); } + +function verifyEntryModuleDirectory(appDirectory) { + if (!appDirectory) { + throw new Error("Path to app directory is not specified. Unable to find entry module."); + } + + if (!existsSync(appDirectory)) { + throw new Error(`The specified path to app directory ${appDirectory} does not exist. Unable to find entry module.`); + } +}