diff --git a/CHANGELOG.md b/CHANGELOG.md
index 304ac1af..f0a5941b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,21 @@
+
+# [0.4.0](https://github.com/NativeScript/nativescript-dev-webpack/compare/v0.3.7...v0.4.0) (2017-04-20)
+
+
+### Bug Fixes
+
+* add webpack.common template for JS projects ([7451545](https://github.com/NativeScript/nativescript-dev-webpack/commit/7451545)), closes [#113](https://github.com/NativeScript/nativescript-dev-webpack/issues/113)
+* **installer:** show helper message for new dependencies ([#122](https://github.com/NativeScript/nativescript-dev-webpack/issues/122)) ([5c7ebeb](https://github.com/NativeScript/nativescript-dev-webpack/commit/5c7ebeb))
+* **ns-bundle:** use remove/add platform instead of clean-app ([#116](https://github.com/NativeScript/nativescript-dev-webpack/issues/116)) ([6609370](https://github.com/NativeScript/nativescript-dev-webpack/commit/6609370))
+* **tsconfig:** add "exclude" property to aot config ([#120](https://github.com/NativeScript/nativescript-dev-webpack/issues/120)) ([d28dba1](https://github.com/NativeScript/nativescript-dev-webpack/commit/d28dba1)), closes [#101](https://github.com/NativeScript/nativescript-dev-webpack/issues/101)
+
+
+### Features
+
+* detect required devDeps versions ([9b102c3](https://github.com/NativeScript/nativescript-dev-webpack/commit/9b102c3))
+
+
+
## [0.3.7](https://github.com/NativeScript/nativescript-dev-webpack/compare/v0.3.6...v0.3.7) (2017-03-31)
diff --git a/README.md b/README.md
index 49dc18a7..530d6b48 100644
--- a/README.md
+++ b/README.md
@@ -6,15 +6,67 @@ A package to help with webpacking NativeScript apps.
* webpack config templates.
* helper functions that place files at the correct locations before packaging apps.
-* loaders and plugins for vanilla NativeScript and Angular 2 apps.
+* loaders and plugins for vanilla NativeScript and Angular apps.
# Usage
```sh
$ npm install --save-dev nativescript-dev-webpack
+$ npm install
+
$ npm run start-android-bundle
+or
+$ npm run start-ios-bundle
```
# Documentation
For details, see the [NativeScript docs](http://docs.nativescript.org/angular/tooling/bundling-with-webpack.html).
+
+# Note about dependencies.
+
+The `nativescript-dev-webpack` plugin adds a few devDependencies to the project. Make sure to run either `npm install` or `yarn` after installing the plugin.
+The versions of the newly added packages depend on the versions of some of your already added packages. More specifically - `tns-core-modules` and all packages from the `@angular` scope. Since version 0.4.0, nativescript-dev-webpack will automatically add the correct development dependencies, based on what you already have installed.
+You can force update your `package.json` using the `update-ns-webpack` script which you can find in `PROJECT_DIR/node_modules/.bin`.
+If the bundling process fails, please make sure you have the correct versions of the packages.
+
+If you are targetting:
+```
+ "tns-core-modules": "^3.0.0" or "^3.0.0-rc.1" or "rc"
+ "@angular/": "^4.0.0"
+```
+Then you should use:
+```
+ "nativescript-angular": "rc" or "internal-preview"
+ "@ngtools/webpack": "1.3.0"
+ "typescript": "~2.2.2"
+```
+
+
+If you are targetting:
+```
+ "tns-core-modules": "~2.5.0"
+ "@angular/": "^4.0.0"
+```
+Then you should use:
+```
+ "nativescript-angular": "~1.5.1"
+ "@ngtools/webpack": "1.2.13"
+ "typescript": "~2.1.6"
+```
+
+
+If you are targetting:
+```
+ "tns-core-modules": "~2.5.0"
+ "@angular/": "~2.4.0"
+```
+Then you should use:
+```
+ "nativescript-angular": "~1.4.1"
+ "@ngtools/webpack": "1.2.10"
+ "typescript": "~2.1.6"
+```
+
+
+P.S. Also please make sure you are using the same version of all `@angular/` packages, including the devDependency of `@angular/compiler-cli`.
\ No newline at end of file
diff --git a/bin/install-ns-webpack b/bin/install-ns-webpack
index 7b330b80..e8445188 100644
--- a/bin/install-ns-webpack
+++ b/bin/install-ns-webpack
@@ -1,7 +1,3 @@
#!/usr/bin/env node
-var installer = require("../installer");
-
-installer.addProjectFiles();
-installer.removeDeprecatedNpmScripts();
-installer.addNpmScripts();
-installer.addProjectDependencies();
+const installer = require("../installer");
+installer.install();
diff --git a/bin/ns-bundle b/bin/ns-bundle
index 72008625..9e28ffd3 100644
--- a/bin/ns-bundle
+++ b/bin/ns-bundle
@@ -37,7 +37,11 @@ function execute(options) {
];
if (options.bundle) {
- commands.unshift(() => webpack(options.platform));
+ commands = [
+ () => prepare(options.platform),
+ () => webpack(options.platform),
+ ...commands
+ ];
}
return commands.reduce((current, next) => current.then(next), Promise.resolve());
@@ -47,17 +51,42 @@ function webpack(platform) {
return new Promise(function (resolve, reject) {
console.log(`Running webpack for ${platform}...`);
- spawnChildProcess("tns", "clean-app", platform)
- .then(() => spawnChildProcess("webpack", `--config=webpack.${platform}.js`, "--progress"))
+ spawnChildProcess(true, "webpack", `--config=webpack.${platform}.js`, "--progress")
.then(resolve)
.catch(throwError);
});
}
+function prepare(platform) {
+ return removePlatform(platform)
+ .then(() => addPlatform(platform));
+}
+
+function removePlatform(platform) {
+ return new Promise(function (resolve, reject) {
+ console.log(`Removing platform ${platform}...`);
+
+ spawnChildProcess(false, "tns", "platform", "remove", platform)
+ .then(resolve)
+ .catch(resolve);
+ });
+}
+
+function addPlatform(platform) {
+ return new Promise(function (resolve, reject) {
+ console.log(`Adding platform ${platform}...`);
+
+ spawnChildProcess(false, "tns", "platform", "add", platform)
+ .then(resolve)
+ .catch(resolve);
+ });
+}
+
function runTns(command, platform) {
- console.log(`Running tns ${command}...`);
return new Promise((resolve, reject) => {
- spawnChildProcess("tns", command, platform, "--bundle", "--disable-npm-install", ...tnsArgs)
+ console.log(`Running tns ${command}...`);
+
+ spawnChildProcess(true, "tns", command, platform, "--bundle", "--disable-npm-install", ...tnsArgs)
.then(resolve)
.catch(throwError);
});
@@ -100,9 +129,11 @@ function getCommand(flags) {
}
}
-function spawnChildProcess(command, ...args) {
+function spawnChildProcess(shouldPrintOutput, command, ...args) {
+ const stdio = shouldPrintOutput ? "inherit" : "ignore";
+
return new Promise((resolve, reject) => {
- const childProcess = spawn(command, args, { stdio: "inherit", pwd: PROJECT_DIR, shell: true });
+ const childProcess = spawn(command, args, { stdio, pwd: PROJECT_DIR, shell: true });
childProcess.on("close", (code) => {
if (code === 0) {
diff --git a/bin/ns-verify-bundle b/bin/ns-verify-bundle
index c423e746..695767c4 100644
--- a/bin/ns-verify-bundle
+++ b/bin/ns-verify-bundle
@@ -4,7 +4,6 @@ const path = require("path");
const fs = require("fs");
const PROJECT_DIR = path.resolve(__dirname, "../../../");
-console.log(PROJECT_DIR);
const APP_ID = require(path.resolve(PROJECT_DIR, "./package.json")).nativescript.id;
const APP_NAME = APP_ID.substring(APP_ID.lastIndexOf(".") + 1);
const PROJECT_PATHS = {
diff --git a/bin/ns-webpack-update.cmd b/bin/ns-webpack-update.cmd
new file mode 100644
index 00000000..135558e7
--- /dev/null
+++ b/bin/ns-webpack-update.cmd
@@ -0,0 +1 @@
+@node %~dp0\ns-webpack-update %*
diff --git a/bin/remove-ns-webpack b/bin/remove-ns-webpack
index b7677950..88ea2bfa 100644
--- a/bin/remove-ns-webpack
+++ b/bin/remove-ns-webpack
@@ -1,7 +1,3 @@
#!/usr/bin/env node
-var installer = require("../installer");
-
-installer.removeProjectFiles();
-installer.removeDeprecatedNpmScripts();
-installer.removeNpmScripts();
-installer.removeProjectDependencies();
+const installer = require("../installer");
+installer.uninstall();
diff --git a/bin/remove-ns-webpack.cmd b/bin/remove-ns-webpack.cmd
index 5de779b8..311f4ecf 100644
--- a/bin/remove-ns-webpack.cmd
+++ b/bin/remove-ns-webpack.cmd
@@ -1 +1 @@
-@node %~dp0\install-ns-webpack %*
+@node %~dp0\remove-ns-webpack %*
diff --git a/bin/update-ns-webpack b/bin/update-ns-webpack
new file mode 100644
index 00000000..6a2c47c8
--- /dev/null
+++ b/bin/update-ns-webpack
@@ -0,0 +1,13 @@
+#!/usr/bin/env node
+const path = require("path");
+const fs = require("fs");
+
+const helpers = require("../projectHelpers");
+const forceUpdateProjectDeps = require("../dependencyManager").forceUpdateProjectDeps;
+
+const PROJECT_DIR = path.resolve(__dirname, "../../../");
+const packageJson = helpers.getPackageJson(PROJECT_DIR);
+
+packageJson.devDependencies = forceUpdateProjectDeps(packageJson);
+
+helpers.writePackageJson(packageJson, PROJECT_DIR);
diff --git a/dependencyManager.js b/dependencyManager.js
new file mode 100644
index 00000000..7e455a9e
--- /dev/null
+++ b/dependencyManager.js
@@ -0,0 +1,115 @@
+const helpers = require("./projectHelpers");
+
+const NEW_DEPS_MESSAGE = `
+A few development dependencies were added. \
+Install them before bundling your project.`;
+
+const ALREADY_ADDED_MESSAGE = `\
+Some dependencies may have already been added. \
+If you want to force update them, please run "node_modules/.bin/update-ns-webpack".`;
+
+function forceUpdateProjectDeps(packageJson) {
+ return addProjectDeps(packageJson, true);
+}
+
+function addProjectDeps(packageJson, force = false) {
+ const depsToAdd = getRequiredDeps(packageJson);
+ packageJson.devDependencies = packageJson.devDependencies || {};
+ let deps = Object.assign({}, packageJson.devDependencies);
+
+ Object.keys(depsToAdd).forEach(function(name) {
+ const version = depsToAdd[name];
+ deps = addDependency(deps, name, version, force);
+ });
+
+ logHelperMessages();
+
+ return deps;
+}
+
+function addDependency(deps, name, version, force) {
+ if (!deps[name] || force) {
+ deps[name] = version;
+ console.info(`Adding dev dependency: ${name}@${version}`);
+ } else if (deps[name] !== version) {
+ console.info(`Dev dependency: ${name} already added. Leaving version: ${deps[name]}`);
+ }
+
+ return deps;
+}
+
+function getRequiredDeps(packageJson) {
+ let deps = {
+ "webpack": "~2.3.3",
+ "webpack-sources": "~0.2.3",
+ "copy-webpack-plugin": "~4.0.1",
+ "raw-loader": "~0.5.1",
+ "nativescript-css-loader": "~0.26.0",
+ "resolve-url-loader": "~2.0.2",
+ "extract-text-webpack-plugin": "~2.1.0",
+ };
+
+ if (helpers.isAngular({packageJson})) {
+ const angularDeps = resolveAngularDeps(packageJson.dependencies);
+ deps = Object.assign(deps, angularDeps);
+ } else if (helpers.isTypeScript({packageJson})) {
+ deps["awesome-typescript-loader"] = "~3.1.2";
+ }
+
+ return deps;
+}
+
+function resolveAngularDeps(usedDependencies) {
+ let depsToAdd = {
+ "@angular/compiler-cli": usedDependencies["@angular/core"],
+ };
+ const tnsModulesVersion = getVersionWithoutPatch(usedDependencies["tns-core-modules"]);
+ const angularCoreVersion = getVersionWithoutPatch(usedDependencies["@angular/core"]);
+
+ if (angularCoreVersion.startsWith("2.")) {
+ Object.assign(depsToAdd, {
+ "typescript": "~2.1.6",
+ "@ngtools/webpack": "1.2.10",
+ });
+ } else if (tnsModulesVersion.startsWith("2.")) {
+ Object.assign(depsToAdd, {
+ "typescript": "~2.1.6",
+ "@ngtools/webpack": "1.2.13",
+ });
+ } else {
+ Object.assign(depsToAdd, {
+ "typescript": "~2.2.2",
+ "@ngtools/webpack": "1.3.0",
+ });
+ }
+
+ return depsToAdd;
+}
+
+function getVersionWithoutPatch(version) {
+ if (!version) {
+ return "";
+ }
+
+ if (version === "next" || version === "latest" || version === "rc") {
+ return version;
+ }
+
+ version = version.substring(0, version.lastIndexOf("."));
+
+ if (version.startsWith("~") || version.startsWith("^")) {
+ return version.substring(1);
+ } else {
+ return version;
+ }
+}
+
+function logHelperMessages(someAlreadyAdded) {
+ console.info(NEW_DEPS_MESSAGE);
+ console.info(ALREADY_ADDED_MESSAGE);
+}
+
+module.exports = {
+ forceUpdateProjectDeps,
+ addProjectDeps,
+};
diff --git a/installer.js b/installer.js
index 725f0c32..9cb2e197 100644
--- a/installer.js
+++ b/installer.js
@@ -1,276 +1,43 @@
-var path = require("path");
-var fs = require("fs");
-var childProcess = require("child_process");
+const path = require("path");
+const fs = require("fs");
-var projectDir = path.dirname(path.dirname(__dirname));
-var appDir = path.join(projectDir, "app");
+const helpers = require("./projectHelpers");
+const projectFilesManager = require("./projectFilesManager");
+const npmScriptsManager = require("./npmScriptsManager");
+const dependencyManager = require("./dependencyManager");
-var packageJsonPath = path.join(projectDir, "package.json");
-var packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
+const PROJECT_DIR = path.dirname(path.dirname(__dirname));
+const APP_DIR = path.resolve(PROJECT_DIR, "app");
-var isAngular = Object.keys(packageJson.dependencies).filter(function (dependency) {
- return /^@angular\b/.test(dependency);
-}).length > 0;
+function install() {
+ let packageJson = helpers.getPackageJson(PROJECT_DIR);
-var isTypeScript = fs.existsSync(path.join(projectDir, "tsconfig.json"));
-if (isAngular) {
- isTypeScript = true;
-}
-
-function getProjectTemplates() {
- var templates = {
- "webpack.android.js.template": "webpack.android.js",
- "webpack.ios.js.template": "webpack.ios.js",
- };
-
- if (isAngular) {
- templates["webpack.common.js.angular.template"] = "webpack.common.js";
- templates["tsconfig.aot.json.template"] = "tsconfig.aot.json";
- } else {
- templates["webpack.common.js.nativescript.template"] = "webpack.common.js";
- }
- return templates;
-}
-
-function getAppTemplates() {
- var templates = {
- "vendor-platform.android.ts.template": tsOrJs("vendor-platform.android"),
- "vendor-platform.ios.ts.template": tsOrJs("vendor-platform.ios"),
- };
-
- if (isAngular) {
- templates["vendor.ts.angular.template"] = tsOrJs("vendor");
- } else {
- templates["vendor.ts.nativescript.template"] = tsOrJs("vendor");
- }
- return templates;
-}
-
-function addProjectFiles() {
- var projectTemplates = getProjectTemplates();
- Object.keys(projectTemplates).forEach(function(templateName) {
- var templateDestination = projectTemplates[templateName];
- copyProjectTemplate(templateName, templateDestination);
- });
-
- var appTemplates = getAppTemplates();
- Object.keys(appTemplates).forEach(function(templateName) {
- var templateDestination = appTemplates[templateName];
- copyAppTemplate(templateName, templateDestination);
- });
-}
-exports.addProjectFiles = addProjectFiles;
-
-function removeProjectFiles() {
- var projectTemplates = getProjectTemplates();
- Object.keys(projectTemplates).forEach(function(templateName) {
- var templateDestination = projectTemplates[templateName];
- deleteProjectFile(templateDestination);
- });
-
- var appTemplates = getAppTemplates();
- Object.keys(appTemplates).forEach(function(templateName) {
- var templateDestination = appTemplates[templateName];
- deleteAppFile(templateDestination);
- });
-}
-exports.removeProjectFiles = removeProjectFiles;
-
-function getScriptTemplates() {
- return {
- "ns-bundle": "ns-bundle",
- "start-[PLATFORM]-bundle": "npm run ns-bundle --[PLATFORM] --start-app",
- "build-[PLATFORM]-bundle": "npm run ns-bundle --[PLATFORM] --build-app",
- };
-}
-
-function getDeprecatedScriptTemplates() {
- return [
- "clean-[PLATFORM]",
- "prewebpack-[PLATFORM]",
- "webpack-[PLATFORM]",
- "prestart-[PLATFORM]-bundle",
- "start-[PLATFORM]-bundle",
- "prebuild-[PLATFORM]-bundle",
- "build-[PLATFORM]-bundle",
- ]
-}
-
-function addNpmScripts() {
- var scriptTemplates = getScriptTemplates();
- Object.keys(scriptTemplates).forEach(function(templateName) {
- addPlatformScript(packageJson, templateName, scriptTemplates[templateName]);
- });
-}
-exports.addNpmScripts = addNpmScripts;
+ projectFilesManager.addProjectFiles(PROJECT_DIR, APP_DIR);
-function removeDeprecatedNpmScripts() {
- removeNpmScripts(getDeprecatedScriptTemplates());
-}
+ let scripts = packageJson.scripts || {};
+ scripts = npmScriptsManager.removeDeprecatedNpmScripts(scripts);
+ scripts = npmScriptsManager.addNpmScripts(scripts);
+ packageJson.scripts = scripts;
-exports.removeDeprecatedNpmScripts = removeDeprecatedNpmScripts;
+ packageJson.devDependencies = dependencyManager.addProjectDeps(packageJson);
-function removeNpmScripts(scriptTemplates) {
- var scriptTemplates = scriptTemplates || Object.keys(getScriptTemplates());
- scriptTemplates.forEach(function(templateName) {
- removePlatformScripts(packageJson, templateName);
- });
+ helpers.writePackageJson(packageJson, PROJECT_DIR);
}
-exports.removeNpmScripts = removeNpmScripts;
-function getProjectDependencies() {
- var dependencies = {
- "webpack": "2.2.0",
- "webpack-sources": "~0.1.3",
- "copy-webpack-plugin": "~3.0.1",
- "raw-loader": "~0.5.1",
- "nativescript-css-loader": "~0.26.0",
- "resolve-url-loader": "~1.6.0",
- "extract-text-webpack-plugin": "~2.0.0-beta.4",
- };
+function uninstall() {
+ let packageJson = helpers.getPackageJson(PROJECT_DIR);
- if (isAngular) {
- dependencies["@angular/compiler-cli"] = "~4.0.0";
- dependencies["@ngtools/webpack"] = "1.2.13";
- dependencies["typescript"] = "^2.1.0";
- } else {
- dependencies["awesome-typescript-loader"] = "~3.0.0-beta.9";
- }
- return dependencies;
-}
+ projectFilesManager.removeProjectFiles(PROJECT_DIR, APP_DIR);
+ npmScriptsManager.removeDeprecatedNpmScripts(packageJson);
-function addProjectDependencies() {
- configureDevDependencies(packageJson, function (add) {
- var dependencies = getProjectDependencies();
- Object.keys(dependencies).forEach(function(dependencyName) {
- add(dependencyName, dependencies[dependencyName]);
- });
- });
-}
-exports.addProjectDependencies = addProjectDependencies;
+ let scripts = packageJson.scripts;
+ scripts = npmScriptsManager.removeNpmScripts(scripts);
+ packageJson.scripts = scripts;
-function removeProjectDependencies() {
- configureDevDependencies(packageJson, function (add, remove) {
- var dependencies = getProjectDependencies();
- Object.keys(dependencies).forEach(function(dependencyName) {
- remove(dependencyName);
- });
- });
+ helpers.writePackageJson(packageJson, PROJECT_DIR);
}
-exports.removeProjectDependencies = removeProjectDependencies;
-
-
-function addPlatformScript(packageJson, nameTemplate, commandTemplate) {
- if (!packageJson.scripts) {
- packageJson.scripts = {};
- }
- var scripts = packageJson.scripts;
- ["android", "ios"].forEach(function (platform) {
- var name = nameTemplate.replace(/\[PLATFORM\]/g, platform);
- var command = commandTemplate.replace(/\[PLATFORM\]/g, platform);
- if (!scripts[name]) {
- console.log("Registering script: " + name);
- scripts[name] = command;
- }
- });
-}
-
-function removePlatformScripts(packageJson, nameTemplate) {
- if (!packageJson.scripts) {
- return;
- }
-
- var scripts = packageJson.scripts;
- ["android", "ios"].forEach(function (platform) {
- var name = nameTemplate.replace(/\[PLATFORM\]/g, platform);
- console.log("Removing script: " + name);
- delete scripts[name];
- });
-}
-
-function configureDevDependencies(packageJson, adderCallback) {
- var pendingNpmInstall = false;
- if (!packageJson.devDependencies) {
- packageJson.devDependencies = {};
- }
- var dependencies = packageJson.devDependencies;
-
- adderCallback(function (name, version) {
- if (!dependencies[name]) {
- dependencies[name] = version;
- console.info("Adding dev dependency: " + name + "@" + version);
- pendingNpmInstall = true;
- } else {
- console.info("Dev dependency: '" + name + "' already added. Leaving version: " + dependencies[name]);
- }
- }, function(name) {
- console.info("Removing dev dependency: " + name);
- delete dependencies[name];
- });
-
- fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
-
- if (pendingNpmInstall) {
- console.info("Installing new dependencies...");
- //Run `npm install` after everything else.
- setTimeout(function () {
- var spawnArgs = [];
- if (/^win/.test(process.platform)) {
- spawnArgs = ["cmd.exe", ["/c", "npm", "install"]];
- } else {
- spawnArgs = ["npm", ["install"]];
- }
- spawnArgs.push({ cwd: projectDir, stdio: "inherit" });
- var npm = childProcess.spawn.apply(null, spawnArgs);
- npm.on("close", function (code) {
- process.exit(code);
- });
- }, 100);
- }
-}
-
-function tsOrJs(name) {
- if (isTypeScript) {
- return name + ".ts";
- } else {
- return name + ".js";
- }
-}
-
-function copyProjectTemplate(templateName, projectPath) {
- var destinationPath = path.join(projectDir, projectPath);
- copyTemplate(templateName, destinationPath);
-}
-
-function deleteProjectFile(projectPath) {
- var destinationPath = path.join(projectDir, projectPath);
- deleteFile(destinationPath);
-}
-
-function copyAppTemplate(templateName, appPath) {
- var destinationPath = path.join(appDir, appPath);
- copyTemplate(templateName, destinationPath);
-}
-
-function deleteAppFile(appPath) {
- var destinationPath = path.join(appDir, appPath);
- deleteFile(destinationPath);
-}
-
-function deleteFile(destinationPath) {
- if (fs.existsSync(destinationPath)) {
- console.log("Deleting file: " + destinationPath);
- fs.unlink(destinationPath);
- }
-}
-
-function copyTemplate(templateName, destinationPath) {
- var templatePath = path.join(__dirname, templateName);
- // Create destination file, only if not present.
- if (!fs.existsSync(destinationPath)) {
- console.log("Creating file: " + destinationPath);
- var content = fs.readFileSync(templatePath, "utf8");
- fs.writeFileSync(destinationPath, content);
- }
-}
+module.exports = {
+ install,
+ uninstall,
+};
diff --git a/npmScriptsManager.js b/npmScriptsManager.js
new file mode 100644
index 00000000..7ed09a15
--- /dev/null
+++ b/npmScriptsManager.js
@@ -0,0 +1,74 @@
+const SCRIPT_TEMPLATES = Object.freeze({
+ "ns-bundle": "ns-bundle",
+ "start-[PLATFORM]-bundle": "npm run ns-bundle --[PLATFORM] --start-app",
+ "build-[PLATFORM]-bundle": "npm run ns-bundle --[PLATFORM] --build-app",
+});
+
+const DEPRECATED_SCRIPT_TEMPLATES = Object.freeze([
+ "clean-[PLATFORM]",
+ "prewebpack-[PLATFORM]",
+ "webpack-[PLATFORM]",
+ "prestart-[PLATFORM]-bundle",
+ "start-[PLATFORM]-bundle",
+ "prebuild-[PLATFORM]-bundle",
+ "build-[PLATFORM]-bundle",
+]);
+
+const PLATFORMS = Object.freeze(["android", "ios"]);
+
+function addNpmScripts(scripts) {
+ Object.keys(SCRIPT_TEMPLATES).forEach(name => {
+ packageJson = addPlatformScript(scripts, name, SCRIPT_TEMPLATES[name]);
+ });
+
+ return scripts;
+}
+
+function removeDeprecatedNpmScripts(scripts) {
+ return removeNpmScripts(scripts, DEPRECATED_SCRIPT_TEMPLATES);
+}
+
+function removeNpmScripts(scripts, scriptTemplates = Object.keys(SCRIPT_TEMPLATES)) {
+ scriptTemplates.forEach(function(templateName) {
+ scripts = removePlatformScripts(scripts, templateName);
+ });
+
+ return scripts;
+}
+
+function addPlatformScript(scripts, nameTemplate, commandTemplate) {
+ PLATFORMS.forEach(function (platform) {
+ const name = nameTemplate.replace(/\[PLATFORM\]/g, platform);
+ const command = commandTemplate.replace(/\[PLATFORM\]/g, platform);
+
+ if (!scripts[name]) {
+ console.info(`Registering script: ${name}`);
+ scripts[name] = command;
+ }
+ });
+
+ return scripts;
+}
+
+function removePlatformScripts(scripts, nameTemplate) {
+ if (!scripts) {
+ return;
+ }
+
+ PLATFORMS.forEach(function (platform) {
+ const name = nameTemplate.replace(/\[PLATFORM\]/g, platform);
+
+ if (scripts[name]) {
+ console.info(`Removing script: ${name}`);
+ delete scripts[name];
+ }
+ });
+
+ return scripts;
+}
+
+module.exports = {
+ addNpmScripts,
+ removeDeprecatedNpmScripts,
+ removeNpmScripts,
+};
diff --git a/package.json b/package.json
index 42843d5b..df28686e 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "nativescript-dev-webpack",
- "version": "0.3.7",
+ "version": "0.4.0",
"main": "index",
"description": "",
"homepage": "http://www.telerik.com",
@@ -19,6 +19,7 @@
"bin": {
"install-ns-webpack": "./bin/install-ns-webpack",
"remove-ns-webpack": "./bin/remove-ns-webpack",
+ "update-ns-webpack": "./bin/update-ns-webpack",
"ns-bundle": "./bin/ns-bundle",
"ns-verify-bundle": "./bin/ns-verify-bundle"
},
diff --git a/postinstall.js b/postinstall.js
index e252b2b6..9b839ad2 100644
--- a/postinstall.js
+++ b/postinstall.js
@@ -1,6 +1,2 @@
-var installer = require("./installer");
-
-installer.addProjectFiles();
-installer.removeDeprecatedNpmScripts();
-installer.addNpmScripts();
-installer.addProjectDependencies();
+const installer = require("./installer");
+installer.install();
diff --git a/projectFilesManager.js b/projectFilesManager.js
new file mode 100644
index 00000000..e4e58ba3
--- /dev/null
+++ b/projectFilesManager.js
@@ -0,0 +1,109 @@
+const path = require("path");
+const fs = require("fs");
+
+const helpers = require("./projectHelpers");
+
+function addProjectFiles(projectDir, appDir) {
+ const projectTemplates = getProjectTemplates(projectDir);
+ Object.keys(projectTemplates).forEach(function(templateName) {
+ const templateDestination = projectTemplates[templateName];
+ templateName = path.resolve(templateName)
+ copyTemplate(templateName, templateDestination);
+ });
+
+ const appTemplates = getAppTemplates(projectDir, appDir);
+ Object.keys(appTemplates).forEach(function(templateName) {
+ const templateDestination = appTemplates[templateName];
+ copyTemplate(templateName, templateDestination)
+ });
+}
+
+function removeProjectFiles(projectDir, appDir) {
+ const projectTemplates = getProjectTemplates(projectDir);
+ Object.keys(projectTemplates).forEach(function(templateName) {
+ const templateDestination = projectTemplates[templateName];
+ deleteFile(templateDestination);
+ });
+
+ const appTemplates = getAppTemplates(projectDir, appDir);
+ Object.keys(appTemplates).forEach(function(templateName) {
+ const templateDestination = appTemplates[templateName];
+ deleteFile(templateDestination);
+ });
+}
+
+function deleteFile(destinationPath) {
+ if (fs.existsSync(destinationPath)) {
+ console.info(`Deleting file: ${destinationPath}`);
+ fs.unlink(destinationPath);
+ }
+}
+
+function copyTemplate(templateName, destinationPath) {
+ // Create destination file, only if not present.
+ if (!fs.existsSync(destinationPath)) {
+ console.info(`Creating file: ${destinationPath}`);
+ const content = fs.readFileSync(templateName, "utf8");
+ fs.writeFileSync(destinationPath, content);
+ }
+}
+
+function getProjectTemplates(projectDir) {
+ let templates = {
+ "webpack.android.js.template": "webpack.android.js",
+ "webpack.ios.js.template": "webpack.ios.js",
+ };
+
+ if (helpers.isAngular({projectDir})) {
+ templates["webpack.common.js.angular.template"] = "webpack.common.js";
+ templates["tsconfig.aot.json.template"] = "tsconfig.aot.json";
+ } else if (helpers.isTypeScript({projectDir})) {
+ templates["webpack.common.js.typescript.template"] = "webpack.common.js";
+ } else {
+ templates["webpack.common.js.javascript.template"] = "webpack.common.js";
+ }
+
+ return getFullTemplatesPath(projectDir, templates);
+}
+
+function getAppTemplates(projectDir, appDir) {
+ const templates = {
+ "vendor-platform.android.ts.template": tsOrJs(projectDir, "vendor-platform.android"),
+ "vendor-platform.ios.ts.template": tsOrJs(projectDir, "vendor-platform.ios"),
+ };
+
+ if (helpers.isAngular({projectDir})) {
+ templates["vendor.ts.angular.template"] = tsOrJs(projectDir, "vendor");
+ } else {
+ templates["vendor.ts.nativescript.template"] = tsOrJs(projectDir, "vendor");
+ }
+
+ return getFullTemplatesPath(appDir, templates);
+}
+
+function getFullTemplatesPath(projectDir, templates) {
+ let updatedTemplates = {};
+
+ Object.keys(templates).forEach(key => {
+ const updatedKey = getFullPath(__dirname, key);
+ const updatedValue = getFullPath(projectDir, templates[key])
+
+ updatedTemplates[updatedKey] = updatedValue;
+ });
+
+ return updatedTemplates;
+}
+
+function getFullPath(projectDir, filePath) {
+ return path.resolve(projectDir, filePath);
+}
+
+function tsOrJs(projectDir, name) {
+ const extension = helpers.isTypeScript({projectDir}) ? "ts" : "js";
+ return `${name}.${extension}`;
+}
+
+module.exports = {
+ addProjectFiles,
+ removeProjectFiles,
+};
diff --git a/projectHelpers.js b/projectHelpers.js
new file mode 100644
index 00000000..903cb384
--- /dev/null
+++ b/projectHelpers.js
@@ -0,0 +1,36 @@
+const path = require("path");
+const fs = require("fs");
+
+const isTypeScript = ({projectDir, packageJson} = {}) => {
+ packageJson = packageJson || getPackageJson(projectDir);
+
+ return packageJson.dependencies.hasOwnProperty("typescript") ||
+ packageJson.devDependencies.hasOwnProperty("typescript") ||
+ isAngular({packageJson});
+};
+
+const isAngular = ({projectDir, packageJson} = {}) => {
+ packageJson = packageJson || getPackageJson(projectDir);
+
+ return Object.keys(packageJson.dependencies)
+ .some(dependency => /^@angular\b/.test(dependency));
+};
+
+const getPackageJson = projectDir => {
+ const packageJsonPath = getPackageJsonPath(projectDir);
+ return JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
+};
+
+const writePackageJson = (content, projectDir) => {
+ const packageJsonPath = getPackageJsonPath(projectDir);
+ fs.writeFileSync(packageJsonPath, JSON.stringify(content, null, 2))
+}
+
+const getPackageJsonPath = projectDir => path.resolve(projectDir, "package.json");
+
+module.exports = {
+ isTypeScript,
+ isAngular,
+ getPackageJson,
+ writePackageJson,
+};
diff --git a/should-not-be-here b/should-not-be-here
new file mode 100644
index 00000000..e69de29b
diff --git a/tsconfig.aot.json.template b/tsconfig.aot.json.template
index b1221e9a..23e3021c 100644
--- a/tsconfig.aot.json.template
+++ b/tsconfig.aot.json.template
@@ -1,5 +1,5 @@
{
- "extend": "./tsconfig",
+ "extends": "./tsconfig",
"compilerOptions": {
"baseUrl": ".",
"paths": {
@@ -28,6 +28,10 @@
"globals": ["node_modules/tns-core-modules/globals"]
}
},
+ "exclude": [
+ "node_modules",
+ "platforms"
+ ],
"angularCompilerOptions": {
"skipMetadataEmit": true,
"genDir": "./"
diff --git a/webpack.common.js.angular.template b/webpack.common.js.angular.template
index b05c860e..0d017ebd 100644
--- a/webpack.common.js.angular.template
+++ b/webpack.common.js.angular.template
@@ -12,24 +12,24 @@ module.exports = function (platform, destinationApp) {
destinationApp = nsWebpack.getAppPath(platform);
}
var entry = {};
- //Discover entry module from package.json
+ // Discover entry module from package.json
entry.bundle = "./" + nsWebpack.getEntryModule();
//Vendor entry with third party libraries.
entry.vendor = "./vendor";
- //app.css bundle
+ // app.css bundle
entry["app.css"] = "./app.css";
var plugins = [
new ExtractTextPlugin("app.css"),
- //Vendor libs go to the vendor.js chunk
+ // Vendor libs go to the vendor.js chunk
new webpack.optimize.CommonsChunkPlugin({
name: ["vendor"]
}),
- //Define useful constants like TNS_WEBPACK
+ // Define useful constants like TNS_WEBPACK
new webpack.DefinePlugin({
"global.TNS_WEBPACK": "true",
}),
- //Copy assets to out dir. Add your own globs as needed.
+ // Copy assets to out dir. Add your own globs as needed.
new CopyWebpackPlugin([
{ from: "app.css" },
{ from: "css/**" },
@@ -38,13 +38,13 @@ module.exports = function (platform, destinationApp) {
{ from: "**/*.png" },
{ from: "**/*.xml" },
], { ignore: ["App_Resources/**"] }),
- //Generate a bundle starter script and activate it in package.json
+ // Generate a bundle starter script and activate it in package.json
new nsWebpack.GenerateBundleStarterPlugin([
"./vendor",
"./bundle",
]),
- //Angular AOT compiler
+ // Angular AOT compiler
new AotPlugin({
tsConfigPath: "tsconfig.aot.json",
entryModule: path.resolve(__dirname, "app/app.module#AppModule"),
@@ -58,7 +58,7 @@ module.exports = function (platform, destinationApp) {
minimize: true
}));
- //Work around an Android issue by setting compress = false
+ // Work around an Android issue by setting compress = false
var compress = platform !== "android";
plugins.push(new webpack.optimize.UglifyJsPlugin({
mangle: {
@@ -79,7 +79,7 @@ module.exports = function (platform, destinationApp) {
filename: "[name].js",
},
resolve: {
- //Resolve platform-specific modules like module.android.js
+ // Resolve platform-specific modules like module.android.js
extensions: [
".aot.ts",
".ts",
@@ -89,14 +89,14 @@ module.exports = function (platform, destinationApp) {
"." + platform + ".js",
"." + platform + ".css",
],
- //Resolve {N} system modules from tns-core-modules
+ // Resolve {N} system modules from tns-core-modules
modules: [
"node_modules/tns-core-modules",
- "node_modules"
+ "node_modules",
]
},
node: {
- //Disable node shims that conflict with NativeScript
+ // Disable node shims that conflict with NativeScript
"http": false,
"timers": false,
"setImmediate": false,
@@ -141,7 +141,7 @@ module.exports = function (platform, destinationApp) {
loaders: [
"raw-loader",
"resolve-url-loader",
- "sass-loader"
+ "sass-loader",
]
},
]
diff --git a/webpack.common.js.javascript.template b/webpack.common.js.javascript.template
new file mode 100644
index 00000000..7f44fda8
--- /dev/null
+++ b/webpack.common.js.javascript.template
@@ -0,0 +1,129 @@
+var webpack = require("webpack");
+var nsWebpack = require("nativescript-dev-webpack");
+var nativescriptTarget = require("nativescript-dev-webpack/nativescript-target");
+var path = require("path");
+var CopyWebpackPlugin = require("copy-webpack-plugin");
+var ExtractTextPlugin = require("extract-text-webpack-plugin");
+
+module.exports = function (platform, destinationApp) {
+ if (!destinationApp) {
+ // Default destination inside platforms//...
+ destinationApp = nsWebpack.getAppPath(platform);
+ }
+ var entry = {};
+ // Discover entry module from package.json
+ entry.bundle = "./" + nsWebpack.getEntryModule();
+ // Vendor entry with third party libraries.
+ entry.vendor = "./vendor";
+ // app.css bundle
+ entry["app.css"] = "./app.css";
+
+ var plugins = [
+ new ExtractTextPlugin("app.css"),
+ // Vendor libs go to the vendor.js chunk
+ new webpack.optimize.CommonsChunkPlugin({
+ name: ["vendor"]
+ }),
+ // Define useful constants like TNS_WEBPACK
+ new webpack.DefinePlugin({
+ "global.TNS_WEBPACK": "true",
+ }),
+ // Copy assets to out dir. Add your own globs as needed.
+ new CopyWebpackPlugin([
+ { from: "app.css" },
+ { from: "css/**" },
+ { from: "fonts/**" },
+ { from: "**/*.jpg" },
+ { from: "**/*.png" },
+ { from: "**/*.xml" },
+ ], { ignore: ["App_Resources/**"] }),
+ // Generate a bundle starter script and activate it in package.json
+ new nsWebpack.GenerateBundleStarterPlugin([
+ "./vendor",
+ "./bundle",
+ ]),
+ ];
+
+ if (process.env.npm_config_uglify) {
+ plugins.push(new webpack.LoaderOptionsPlugin({
+ minimize: true
+ }));
+
+ // Work around an Android issue by setting compress = false
+ var compress = platform !== "android";
+ plugins.push(new webpack.optimize.UglifyJsPlugin({
+ mangle: {
+ except: nsWebpack.uglifyMangleExcludes,
+ },
+ compress: compress,
+ }));
+ }
+
+ return {
+ context: path.resolve("./app"),
+ target: nativescriptTarget,
+ entry: entry,
+ output: {
+ pathinfo: true,
+ path: path.resolve(destinationApp),
+ libraryTarget: "commonjs2",
+ filename: "[name].js",
+ },
+ resolve: {
+ // Resolve platform-specific modules like module.android.js
+ extensions: [
+ ".js",
+ ".css",
+ "." + platform + ".js",
+ "." + platform + ".css",
+ ],
+ // Resolve {N} system modules from tns-core-modules
+ modules: [
+ "node_modules/tns-core-modules",
+ "node_modules",
+ ]
+ },
+ node: {
+ // Disable node shims that conflict with NativeScript
+ "http": false,
+ "timers": false,
+ "setImmediate": false,
+ "fs": "empty",
+ },
+ module: {
+ loaders: [
+ {
+ test: /\.html$/,
+ loader: "raw-loader"
+ },
+ // Root app.css file gets extracted with bundled dependencies
+ {
+ test: /app\.css$/,
+ loader: ExtractTextPlugin.extract([
+ "resolve-url-loader",
+ "nativescript-css-loader",
+ "nativescript-dev-webpack/platform-css-loader",
+ ]),
+ },
+ // Other CSS files get bundled using the raw loader
+ {
+ test: /\.css$/,
+ exclude: /app\.css$/,
+ loaders: [
+ "raw-loader",
+ ]
+ },
+ // SASS support
+ {
+ test: /\.scss$/,
+ loaders: [
+ "raw-loader",
+ "resolve-url-loader",
+ "sass-loader",
+ ]
+ },
+ ]
+ },
+ plugins: plugins,
+ };
+};
diff --git a/webpack.common.js.nativescript.template b/webpack.common.js.typescript.template
similarity index 82%
rename from webpack.common.js.nativescript.template
rename to webpack.common.js.typescript.template
index 531f7327..8427c542 100644
--- a/webpack.common.js.nativescript.template
+++ b/webpack.common.js.typescript.template
@@ -7,28 +7,28 @@ var ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = function (platform, destinationApp) {
if (!destinationApp) {
- //Default destination inside platforms//...
+ // Default destination inside platforms//...
destinationApp = nsWebpack.getAppPath(platform);
}
var entry = {};
- //Discover entry module from package.json
+ // Discover entry module from package.json
entry.bundle = "./" + nsWebpack.getEntryModule();
- //Vendor entry with third party libraries.
+ // Vendor entry with third party libraries.
entry.vendor = "./vendor";
- //app.css bundle
+ // app.css bundle
entry["app.css"] = "./app.css";
var plugins = [
new ExtractTextPlugin("app.css"),
- //Vendor libs go to the vendor.js chunk
+ // Vendor libs go to the vendor.js chunk
new webpack.optimize.CommonsChunkPlugin({
name: ["vendor"]
}),
- //Define useful constants like TNS_WEBPACK
+ // Define useful constants like TNS_WEBPACK
new webpack.DefinePlugin({
"global.TNS_WEBPACK": "true",
}),
- //Copy assets to out dir. Add your own globs as needed.
+ // Copy assets to out dir. Add your own globs as needed.
new CopyWebpackPlugin([
{ from: "app.css" },
{ from: "css/**" },
@@ -37,7 +37,7 @@ module.exports = function (platform, destinationApp) {
{ from: "**/*.png" },
{ from: "**/*.xml" },
], { ignore: ["App_Resources/**"] }),
- //Generate a bundle starter script and activate it in package.json
+ // Generate a bundle starter script and activate it in package.json
new nsWebpack.GenerateBundleStarterPlugin([
"./vendor",
"./bundle",
@@ -49,7 +49,7 @@ module.exports = function (platform, destinationApp) {
minimize: true
}));
- //Work around an Android issue by setting compress = false
+ // Work around an Android issue by setting compress = false
var compress = platform !== "android";
plugins.push(new webpack.optimize.UglifyJsPlugin({
mangle: {
@@ -70,7 +70,7 @@ module.exports = function (platform, destinationApp) {
filename: "[name].js",
},
resolve: {
- //Resolve platform-specific modules like module.android.js
+ // Resolve platform-specific modules like module.android.js
extensions: [
".ts",
".js",
@@ -79,14 +79,14 @@ module.exports = function (platform, destinationApp) {
"." + platform + ".js",
"." + platform + ".css",
],
- //Resolve {N} system modules from tns-core-modules
+ // Resolve {N} system modules from tns-core-modules
modules: [
"node_modules/tns-core-modules",
- "node_modules"
+ "node_modules",
]
},
node: {
- //Disable node shims that conflict with NativeScript
+ // Disable node shims that conflict with NativeScript
"http": false,
"timers": false,
"setImmediate": false,
@@ -119,7 +119,7 @@ module.exports = function (platform, destinationApp) {
{
test: /\.ts$/,
loaders: [
- "awesome-typescript-loader"
+ "awesome-typescript-loader",
]
},
// SASS support
@@ -128,7 +128,7 @@ module.exports = function (platform, destinationApp) {
loaders: [
"raw-loader",
"resolve-url-loader",
- "sass-loader"
+ "sass-loader",
]
},
]