diff --git a/index.js b/index.js index 20f86ed7..5557ec39 100644 --- a/index.js +++ b/index.js @@ -12,7 +12,7 @@ var isAngular = Object.keys(packageJson.dependencies).filter(function (dependenc if (isAngular) { - exports.StyleUrlResolvePlugin = require("./resource-resolver-plugins/StyleUrlResolvePlugin"); + exports.UrlResolvePlugin = require("./resource-resolver-plugins/UrlResolvePlugin"); } //HACK: changes the JSONP chunk eval function to `global["nativescriptJsonp"]` diff --git a/installer.js b/installer.js index 9cb2e197..386f74db 100644 --- a/installer.js +++ b/installer.js @@ -13,6 +13,7 @@ function install() { let packageJson = helpers.getPackageJson(PROJECT_DIR); projectFilesManager.addProjectFiles(PROJECT_DIR, APP_DIR); + projectFilesManager.editExistingProjectFiles(PROJECT_DIR); let scripts = packageJson.scripts || {}; scripts = npmScriptsManager.removeDeprecatedNpmScripts(scripts); diff --git a/prepublish/angular/plugins.js b/prepublish/angular/plugins.js index a09d8105..6d6402d0 100644 --- a/prepublish/angular/plugins.js +++ b/prepublish/angular/plugins.js @@ -6,6 +6,10 @@ module.exports = ` typeChecking: false }), - // Resolve .ios.css and .android.css component stylesheets - new nsWebpack.StyleUrlResolvePlugin({platform}), + // Resolve .ios.css and .android.css component stylesheets, and .ios.html and .android component views + new nsWebpack.UrlResolvePlugin({ + platform: platform, + resolveStylesUrls: true, + resolveTemplateUrl: true + }), `; diff --git a/projectFilesManager.js b/projectFilesManager.js index a2ce223e..b7c298ea 100644 --- a/projectFilesManager.js +++ b/projectFilesManager.js @@ -91,6 +91,29 @@ function getFullTemplatesPath(projectDir, templates) { return updatedTemplates; } +function editExistingProjectFiles(projectDir) { + const webpackConfigPath = getFullPath(projectDir, "webpack.config.js"); + const webpackCommonPath = getFullPath(projectDir, "webpack.common.js"); + + editWebpackConfig(webpackConfigPath, replaceStyleUrlResolvePlugin); + editWebpackConfig(webpackCommonPath, replaceStyleUrlResolvePlugin); +} + +function editWebpackConfig(path, fn) { + if (!fs.existsSync(path)) { + return; + } + + const config = fs.readFileSync(path, "utf8"); + const newConfig = fn(config); + + fs.writeFileSync(path, newConfig, "utf8"); +} + +function replaceStyleUrlResolvePlugin(config) { + return config.replace(/StyleUrlResolvePlugin/g, "UrlResolvePlugin"); +} + function getFullPath(projectDir, filePath) { return path.resolve(projectDir, filePath); } @@ -103,4 +126,5 @@ function tsOrJs(projectDir, name) { module.exports = { addProjectFiles, removeProjectFiles, + editExistingProjectFiles, }; diff --git a/resource-resolver-plugins/StyleUrlResolvePlugin.js b/resource-resolver-plugins/StyleUrlResolvePlugin.js deleted file mode 100644 index ee110adb..00000000 --- a/resource-resolver-plugins/StyleUrlResolvePlugin.js +++ /dev/null @@ -1,97 +0,0 @@ -const ts = require("typescript"); -const fs = require("fs"); -const path = require("path"); - -const StyleUrlResolvePlugin = (function() { - function StyleUrlResolvePlugin(options) { - if (!options || !options.platform) { - throw new Error(`Target platform must be specified!`); - } - - this.platform = options.platform; - } - - StyleUrlResolvePlugin.prototype.apply = function (compiler) { - compiler.plugin("make", (compilation, callback) => { - const aotPlugin = getAotPlugin(compilation); - aotPlugin._program.getSourceFiles() - .forEach(sf => this.usePlatformStyleUrl(sf)); - - callback(); - }) - }; - - function getAotPlugin(compilation) { - let maybeAotPlugin = compilation._ngToolsWebpackPluginInstance; - if (!maybeAotPlugin) { - throw new Error(`This plugin must be used with the AotPlugin!`); - } - - return maybeAotPlugin; - } - - StyleUrlResolvePlugin.prototype.usePlatformStyleUrl = function(sourceFile) { - this.setCurrentDirectory(sourceFile); - ts.forEachChild(sourceFile, node => this.traverseDecorators(node)); - } - - StyleUrlResolvePlugin.prototype.setCurrentDirectory = function(sourceFile) { - this.currentDirectory = path.resolve(sourceFile.path, ".."); - } - - StyleUrlResolvePlugin.prototype.traverseDecorators = function(node) { - if (node.kind !== ts.SyntaxKind.ClassDeclaration || !node.decorators) { - return; - } - - node.decorators.forEach(decorator => { - this.traverseDecoratorArguments(decorator.expression.arguments); - }); - } - - StyleUrlResolvePlugin.prototype.traverseDecoratorArguments = function(args) { - args.forEach(arg => arg.properties && this.traverseProperties(arg.properties)); - } - - StyleUrlResolvePlugin.prototype.traverseProperties = function(properties) { - properties.filter(isStyleUrls) - .forEach(prop => this.traversePropertyElements(prop)); - } - - function isStyleUrls(property) { - return property.name.text === "styleUrls"; - } - - StyleUrlResolvePlugin.prototype.traversePropertyElements = function(property) { - property.initializer.elements - .filter(el => !!el.text) - .filter(el => this.notPlatformUrl(el.text)) - .filter(el => this.noMultiplatformFile(el.text)) - .forEach(el => this.replaceStyleUrlsValue(el)); - } - - StyleUrlResolvePlugin.prototype.notPlatformUrl = function(styleUrl) { - let extensionStartIndex = styleUrl.lastIndexOf("."); - let extension = styleUrl.slice(extensionStartIndex); - - return !styleUrl.endsWith(`.${this.platform}${extension}`); - } - - StyleUrlResolvePlugin.prototype.noMultiplatformFile = function(styleUrl) { - let stylePath = path.resolve(this.currentDirectory, styleUrl); - - return !fs.existsSync(stylePath); - } - - StyleUrlResolvePlugin.prototype.replaceStyleUrlsValue = function(element) { - const extensionStartIndex = element.text.lastIndexOf("."); - const prefix = element.text.slice(0, extensionStartIndex); - const currentExtension = element.text.slice(extensionStartIndex); - - element.text = `${prefix}.${this.platform}${currentExtension}`; - } - - return StyleUrlResolvePlugin; -})(); - -module.exports = StyleUrlResolvePlugin; diff --git a/resource-resolver-plugins/UrlResolvePlugin.js b/resource-resolver-plugins/UrlResolvePlugin.js new file mode 100644 index 00000000..1222d695 --- /dev/null +++ b/resource-resolver-plugins/UrlResolvePlugin.js @@ -0,0 +1,109 @@ +const ts = require("typescript"); +const fs = require("fs"); +const path = require("path"); + +const UrlResolvePlugin = (function() { + function UrlResolvePlugin(options) { + if (!options || !options.platform) { + throw new Error(`Target platform must be specified!`); + } + + this.platform = options.platform; + + // these are true by default + this.resolveStylesUrls = options.resolveStylesUrls === undefined || options.resolveStylesUrls; + this.resolveTemplateUrl = options.resolveTemplateUrl === undefined || options.resolveTemplateUrl; + + if (!this.resolveStylesUrls && !this.resolveTemplateUrl) { + throw new Error(`resolveStylesUrls and resolveTemplateUrl mustn't both be false`); + } + } + + UrlResolvePlugin.prototype.apply = function (compiler) { + compiler.plugin("make", (compilation, callback) => { + const aotPlugin = getAotPlugin(compilation); + aotPlugin._program.getSourceFiles() + .forEach(sf => this.usePlatformUrl(sf)); + + callback(); + }) + }; + + function getAotPlugin(compilation) { + let maybeAotPlugin = compilation._ngToolsWebpackPluginInstance; + if (!maybeAotPlugin) { + throw new Error(`This plugin must be used with the AotPlugin!`); + } + + return maybeAotPlugin; + } + + UrlResolvePlugin.prototype.usePlatformUrl = function(sourceFile) { + this.setCurrentDirectory(sourceFile); + ts.forEachChild(sourceFile, node => this.traverseDecorators(node)); + } + + UrlResolvePlugin.prototype.setCurrentDirectory = function(sourceFile) { + this.currentDirectory = path.resolve(sourceFile.path, ".."); + } + + UrlResolvePlugin.prototype.traverseDecorators = function(node) { + if (node.kind !== ts.SyntaxKind.ClassDeclaration || !node.decorators) { + return; + } + + node.decorators.forEach(decorator => { + this.traverseDecoratorArguments(decorator.expression.arguments); + }); + } + + UrlResolvePlugin.prototype.traverseDecoratorArguments = function(args) { + args.forEach(arg => arg.properties && this.traverseProperties(arg.properties)); + } + + UrlResolvePlugin.prototype.traverseProperties = function(properties) { + properties + .filter(prop => this.isRelevantNode(prop)) + .forEach(prop => this.traversePropertyElements(prop)); + } + + UrlResolvePlugin.prototype.isRelevantNode = function(property) { + return this.resolveStylesUrls && property.name.text === "styleUrls" || + this.resolveTemplateUrl && property.name.text === "templateUrl" + } + + UrlResolvePlugin.prototype.traversePropertyElements = function(property) { + const elements = property.initializer.elements === undefined ? [property.initializer] : property.initializer.elements; + + elements + .filter(el => !!el.text) + .filter(el => this.notPlatformUrl(el.text)) + .filter(el => this.noMultiplatformFile(el.text)) + .forEach(el => this.replaceUrlsValue(el)); + } + + UrlResolvePlugin.prototype.notPlatformUrl = function(url) { + let extensionStartIndex = url.lastIndexOf("."); + let extension = url.slice(extensionStartIndex); + + return !url.endsWith(`.${this.platform}${extension}`); + } + + UrlResolvePlugin.prototype.noMultiplatformFile = function(url) { + let filePath = path.resolve(this.currentDirectory, url); + + return !fs.existsSync(filePath); + } + + UrlResolvePlugin.prototype.replaceUrlsValue = function(element) { + const extensionStartIndex = element.text.lastIndexOf("."); + const prefix = element.text.slice(0, extensionStartIndex); + const currentExtension = element.text.slice(extensionStartIndex); + + element.text = `${prefix}.${this.platform}${currentExtension}`; + } + + return UrlResolvePlugin; +})(); + +module.exports = UrlResolvePlugin; diff --git a/templates/webpack.angular.js b/templates/webpack.angular.js index c1069373..51590bb6 100644 --- a/templates/webpack.angular.js +++ b/templates/webpack.angular.js @@ -160,9 +160,12 @@ function getPlugins(platform, env) { typeChecking: false }), - // Resolve .ios.css and .android.css component stylesheets - new nsWebpack.StyleUrlResolvePlugin({platform}), - + // // Resolve .ios.css and .android.css component stylesheets, and .ios.html and .android component views + new nsWebpack.UrlResolvePlugin({ + platform: platform, + resolveStylesUrls: true, + resolveTemplateUrl: true + }), ]; if (env.uglify) {