Skip to content
This repository was archived by the owner on Aug 7, 2021. It is now read-only.

Commit 2ccf55b

Browse files
EddyVerbruggensis0k0
authored andcommitted
feat: add UrlResolvePlugin for platform-specific template/style urls (#155)
fixes #75
1 parent 30e9c97 commit 2ccf55b

File tree

7 files changed

+147
-103
lines changed

7 files changed

+147
-103
lines changed

Diff for: index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ var isAngular = Object.keys(packageJson.dependencies).filter(function (dependenc
1212

1313

1414
if (isAngular) {
15-
exports.StyleUrlResolvePlugin = require("./resource-resolver-plugins/StyleUrlResolvePlugin");
15+
exports.UrlResolvePlugin = require("./resource-resolver-plugins/UrlResolvePlugin");
1616
}
1717

1818
//HACK: changes the JSONP chunk eval function to `global["nativescriptJsonp"]`

Diff for: installer.js

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ function install() {
1313
let packageJson = helpers.getPackageJson(PROJECT_DIR);
1414

1515
projectFilesManager.addProjectFiles(PROJECT_DIR, APP_DIR);
16+
projectFilesManager.editExistingProjectFiles(PROJECT_DIR);
1617

1718
let scripts = packageJson.scripts || {};
1819
scripts = npmScriptsManager.removeDeprecatedNpmScripts(scripts);

Diff for: prepublish/angular/plugins.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ module.exports = `
66
typeChecking: false
77
}),
88
9-
// Resolve .ios.css and .android.css component stylesheets
10-
new nsWebpack.StyleUrlResolvePlugin({platform}),
9+
// Resolve .ios.css and .android.css component stylesheets, and .ios.html and .android component views
10+
new nsWebpack.UrlResolvePlugin({
11+
platform: platform,
12+
resolveStylesUrls: true,
13+
resolveTemplateUrl: true
14+
}),
1115
`;

Diff for: projectFilesManager.js

+24
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,29 @@ function getFullTemplatesPath(projectDir, templates) {
9191
return updatedTemplates;
9292
}
9393

94+
function editExistingProjectFiles(projectDir) {
95+
const webpackConfigPath = getFullPath(projectDir, "webpack.config.js");
96+
const webpackCommonPath = getFullPath(projectDir, "webpack.common.js");
97+
98+
editWebpackConfig(webpackConfigPath, replaceStyleUrlResolvePlugin);
99+
editWebpackConfig(webpackCommonPath, replaceStyleUrlResolvePlugin);
100+
}
101+
102+
function editWebpackConfig(path, fn) {
103+
if (!fs.existsSync(path)) {
104+
return;
105+
}
106+
107+
const config = fs.readFileSync(path, "utf8");
108+
const newConfig = fn(config);
109+
110+
fs.writeFileSync(path, newConfig, "utf8");
111+
}
112+
113+
function replaceStyleUrlResolvePlugin(config) {
114+
return config.replace(/StyleUrlResolvePlugin/g, "UrlResolvePlugin");
115+
}
116+
94117
function getFullPath(projectDir, filePath) {
95118
return path.resolve(projectDir, filePath);
96119
}
@@ -103,4 +126,5 @@ function tsOrJs(projectDir, name) {
103126
module.exports = {
104127
addProjectFiles,
105128
removeProjectFiles,
129+
editExistingProjectFiles,
106130
};

Diff for: resource-resolver-plugins/StyleUrlResolvePlugin.js

-97
This file was deleted.

Diff for: resource-resolver-plugins/UrlResolvePlugin.js

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
const ts = require("typescript");
2+
const fs = require("fs");
3+
const path = require("path");
4+
5+
const UrlResolvePlugin = (function() {
6+
function UrlResolvePlugin(options) {
7+
if (!options || !options.platform) {
8+
throw new Error(`Target platform must be specified!`);
9+
}
10+
11+
this.platform = options.platform;
12+
13+
// these are true by default
14+
this.resolveStylesUrls = options.resolveStylesUrls === undefined || options.resolveStylesUrls;
15+
this.resolveTemplateUrl = options.resolveTemplateUrl === undefined || options.resolveTemplateUrl;
16+
17+
if (!this.resolveStylesUrls && !this.resolveTemplateUrl) {
18+
throw new Error(`resolveStylesUrls and resolveTemplateUrl mustn't both be false`);
19+
}
20+
}
21+
22+
UrlResolvePlugin.prototype.apply = function (compiler) {
23+
compiler.plugin("make", (compilation, callback) => {
24+
const aotPlugin = getAotPlugin(compilation);
25+
aotPlugin._program.getSourceFiles()
26+
.forEach(sf => this.usePlatformUrl(sf));
27+
28+
callback();
29+
})
30+
};
31+
32+
function getAotPlugin(compilation) {
33+
let maybeAotPlugin = compilation._ngToolsWebpackPluginInstance;
34+
if (!maybeAotPlugin) {
35+
throw new Error(`This plugin must be used with the AotPlugin!`);
36+
}
37+
38+
return maybeAotPlugin;
39+
}
40+
41+
UrlResolvePlugin.prototype.usePlatformUrl = function(sourceFile) {
42+
this.setCurrentDirectory(sourceFile);
43+
ts.forEachChild(sourceFile, node => this.traverseDecorators(node));
44+
}
45+
46+
UrlResolvePlugin.prototype.setCurrentDirectory = function(sourceFile) {
47+
this.currentDirectory = path.resolve(sourceFile.path, "..");
48+
}
49+
50+
UrlResolvePlugin.prototype.traverseDecorators = function(node) {
51+
if (node.kind !== ts.SyntaxKind.ClassDeclaration || !node.decorators) {
52+
return;
53+
}
54+
55+
node.decorators.forEach(decorator => {
56+
this.traverseDecoratorArguments(decorator.expression.arguments);
57+
});
58+
}
59+
60+
UrlResolvePlugin.prototype.traverseDecoratorArguments = function(args) {
61+
args.forEach(arg => arg.properties && this.traverseProperties(arg.properties));
62+
}
63+
64+
UrlResolvePlugin.prototype.traverseProperties = function(properties) {
65+
properties
66+
.filter(prop => this.isRelevantNode(prop))
67+
.forEach(prop => this.traversePropertyElements(prop));
68+
}
69+
70+
UrlResolvePlugin.prototype.isRelevantNode = function(property) {
71+
return this.resolveStylesUrls && property.name.text === "styleUrls" ||
72+
this.resolveTemplateUrl && property.name.text === "templateUrl"
73+
}
74+
75+
UrlResolvePlugin.prototype.traversePropertyElements = function(property) {
76+
const elements = property.initializer.elements === undefined ? [property.initializer] : property.initializer.elements;
77+
78+
elements
79+
.filter(el => !!el.text)
80+
.filter(el => this.notPlatformUrl(el.text))
81+
.filter(el => this.noMultiplatformFile(el.text))
82+
.forEach(el => this.replaceUrlsValue(el));
83+
}
84+
85+
UrlResolvePlugin.prototype.notPlatformUrl = function(url) {
86+
let extensionStartIndex = url.lastIndexOf(".");
87+
let extension = url.slice(extensionStartIndex);
88+
89+
return !url.endsWith(`.${this.platform}${extension}`);
90+
}
91+
92+
UrlResolvePlugin.prototype.noMultiplatformFile = function(url) {
93+
let filePath = path.resolve(this.currentDirectory, url);
94+
95+
return !fs.existsSync(filePath);
96+
}
97+
98+
UrlResolvePlugin.prototype.replaceUrlsValue = function(element) {
99+
const extensionStartIndex = element.text.lastIndexOf(".");
100+
const prefix = element.text.slice(0, extensionStartIndex);
101+
const currentExtension = element.text.slice(extensionStartIndex);
102+
103+
element.text = `${prefix}.${this.platform}${currentExtension}`;
104+
}
105+
106+
return UrlResolvePlugin;
107+
})();
108+
109+
module.exports = UrlResolvePlugin;

Diff for: templates/webpack.angular.js

+6-3
Original file line numberDiff line numberDiff line change
@@ -160,9 +160,12 @@ function getPlugins(platform, env) {
160160
typeChecking: false
161161
}),
162162

163-
// Resolve .ios.css and .android.css component stylesheets
164-
new nsWebpack.StyleUrlResolvePlugin({platform}),
165-
163+
// // Resolve .ios.css and .android.css component stylesheets, and .ios.html and .android component views
164+
new nsWebpack.UrlResolvePlugin({
165+
platform: platform,
166+
resolveStylesUrls: true,
167+
resolveTemplateUrl: true
168+
}),
166169
];
167170

168171
if (env.uglify) {

0 commit comments

Comments
 (0)