diff --git a/android-app-components-loader.js b/android-app-components-loader.js
index 5e2ecfd3..9321e401 100644
--- a/android-app-components-loader.js
+++ b/android-app-components-loader.js
@@ -1,7 +1,10 @@
-module.exports = function(source) {
+const { convertSlashesInPath } = require("./projectHelpers");
+
+module.exports = function (source) {
this.cacheable();
const { modules } = this.query;
- const imports = modules.map(m => `require("${m}");`).join("\n");
+ const imports = modules.map(convertSlashesInPath)
+ .map(m => `require("${m}");`).join("\n");
const augmentedSource = `
if (!global["__snapshot"]) {
${imports}
diff --git a/demo/.gitignore b/demo/.gitignore
index 829954a9..dcdcde1a 100644
--- a/demo/.gitignore
+++ b/demo/.gitignore
@@ -16,4 +16,4 @@ tsconfig.aot.json
vendor.js
vendor.ts
-webpack.config.js
+tsconfig.esm.json
\ No newline at end of file
diff --git a/demo/AngularApp/app/App_Resources/Android/AndroidManifest.xml b/demo/AngularApp/app/App_Resources/Android/AndroidManifest.xml
index 9db83215..0bb603e9 100644
--- a/demo/AngularApp/app/App_Resources/Android/AndroidManifest.xml
+++ b/demo/AngularApp/app/App_Resources/Android/AndroidManifest.xml
@@ -19,14 +19,14 @@
diff --git a/demo/AngularApp/app/activity.android.ts b/demo/AngularApp/app/activity.android.ts
new file mode 100644
index 00000000..f04e39bd
--- /dev/null
+++ b/demo/AngularApp/app/activity.android.ts
@@ -0,0 +1,42 @@
+import {setActivityCallbacks, AndroidActivityCallbacks} from "ui/frame";
+
+@JavaProxy("org.myApp.MainActivity")
+class Activity extends android.app.Activity {
+ private _callbacks: AndroidActivityCallbacks;
+
+ protected onCreate(savedInstanceState: any): void { // android.os.Bundle
+ if (!this._callbacks) {
+ setActivityCallbacks(this);
+ }
+
+ this._callbacks.onCreate(this, savedInstanceState, super.onCreate);
+ }
+
+ protected onSaveInstanceState(outState: any): void { // android.os.Bundle
+ this._callbacks.onSaveInstanceState(this, outState, super.onSaveInstanceState);
+ }
+
+ protected onStart(): void {
+ this._callbacks.onStart(this, super.onStart);
+ }
+
+ protected onStop(): void {
+ this._callbacks.onStop(this, super.onStop);
+ }
+
+ protected onDestroy(): void {
+ this._callbacks.onDestroy(this, super.onDestroy);
+ }
+
+ public onBackPressed(): void {
+ this._callbacks.onBackPressed(this, super.onBackPressed);
+ }
+
+ public onRequestPermissionsResult(requestCode: number, permissions: Array, grantResults: Array): void {
+ this._callbacks.onRequestPermissionsResult(this, requestCode, permissions, grantResults, undefined /*TODO: Enable if needed*/);
+ }
+
+ protected onActivityResult(requestCode: number, resultCode: number, data: any): void { // android.content.Intent
+ this._callbacks.onActivityResult(this, requestCode, resultCode, data, super.onActivityResult);
+ }
+}
diff --git a/demo/AngularApp/app/application.android.ts b/demo/AngularApp/app/application.android.ts
new file mode 100644
index 00000000..4c23696f
--- /dev/null
+++ b/demo/AngularApp/app/application.android.ts
@@ -0,0 +1,10 @@
+@JavaProxy("org.myApp.Application")
+class Application extends android.app.Application {
+ onCreate(): void {
+ super.onCreate();
+ }
+
+ protected attachBaseContext(baseContext: any) { // android.content.Context
+ super.attachBaseContext(baseContext);
+ }
+}
diff --git a/demo/AngularApp/app/application.d.ts b/demo/AngularApp/app/application.d.ts
new file mode 100644
index 00000000..3cb28cfd
--- /dev/null
+++ b/demo/AngularApp/app/application.d.ts
@@ -0,0 +1 @@
+declare const android: any;
diff --git a/demo/AngularApp/package.json b/demo/AngularApp/package.json
index 27f97bbe..79551755 100644
--- a/demo/AngularApp/package.json
+++ b/demo/AngularApp/package.json
@@ -30,7 +30,7 @@
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.7.0-beta.1",
- "@angular/compiler-cli": "~6.0.0",
+ "@angular/compiler-cli": "~6.1.0-beta.1",
"@types/chai": "^4.0.2",
"@types/mocha": "^2.2.41",
"@types/node": "^7.0.5",
@@ -50,13 +50,6 @@
"typescript": "~2.7.2"
},
"scripts": {
- "ns-bundle": "ns-bundle",
- "start-android-bundle": "npm run ns-bundle --android --run-app",
- "start-ios-bundle": "npm run ns-bundle --ios --run-app",
- "build-android-bundle": "npm run ns-bundle --android --build-app",
- "build-ios-bundle": "npm run ns-bundle --ios --build-app",
- "publish-ios-bundle": "npm run ns-bundle --ios --publish-app",
- "generate-android-snapshot": "generate-android-snapshot --targetArchs arm,arm64,ia32 --install",
"e2e": "tsc -p e2e && mocha --opts ../config/mocha.opts --recursive e2e --appiumCapsLocation ../config/appium.capabilities.json",
"compile-tests": "tsc -p e2e --watch"
}
diff --git a/demo/AngularApp/webpack.config.js b/demo/AngularApp/webpack.config.js
new file mode 100644
index 00000000..04731f1a
--- /dev/null
+++ b/demo/AngularApp/webpack.config.js
@@ -0,0 +1,270 @@
+const { join, relative, resolve, sep } = require("path");
+
+const webpack = require("webpack");
+const nsWebpack = require("nativescript-dev-webpack");
+const nativescriptTarget = require("nativescript-dev-webpack/nativescript-target");
+const { PlatformReplacementHost } = require("nativescript-dev-webpack/host/platform");
+const CleanWebpackPlugin = require("clean-webpack-plugin");
+const CopyWebpackPlugin = require("copy-webpack-plugin");
+const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");
+const { NativeScriptWorkerPlugin } = require("nativescript-worker-loader/NativeScriptWorkerPlugin");
+const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
+const { AngularCompilerPlugin } = require("@ngtools/webpack");
+
+module.exports = env => {
+ // Add your custom Activities, Services and other Android app components here.
+ const appComponents = [
+ "tns-core-modules/ui/frame",
+ "tns-core-modules/ui/frame/activity",
+ resolve(__dirname, "app/activity.android.ts"),
+ ];
+
+ const platform = env && (env.android && "android" || env.ios && "ios");
+ if (!platform) {
+ throw new Error("You need to provide a target platform!");
+ }
+
+ const extensions = ["tns", platform];
+ const platformHost = new PlatformReplacementHost(extensions);
+
+ const projectRoot = __dirname;
+
+ // Default destination inside platforms//...
+ const dist = resolve(projectRoot, nsWebpack.getAppPath(platform, projectRoot));
+ const appResourcesPlatformDir = platform === "android" ? "Android" : "iOS";
+
+ const {
+ // The 'appPath' and 'appResourcesPath' values are fetched from
+ // the nsconfig.json configuration file
+ // when bundling with `tns run android|ios --bundle`.
+ appPath = "app",
+ appResourcesPath = "app/App_Resources",
+
+ // You can provide the following flags when running 'tns run android|ios'
+ aot, // --env.aot
+ snapshot, // --env.snapshot
+ uglify, // --env.uglify
+ report, // --env.report
+ } = env;
+
+ const appFullPath = resolve(projectRoot, appPath);
+ const appResourcesFullPath = resolve(projectRoot, appResourcesPath);
+
+ const entryModule = aot ?
+ nsWebpack.getAotEntryModule(appFullPath) :
+ `${nsWebpack.getEntryModule(appFullPath)}.ts`;
+ const entryPath = `.${sep}${entryModule}`;
+
+ const config = {
+ mode: uglify ? "production" : "development",
+ context: appFullPath,
+ watchOptions: {
+ ignored: [
+ appResourcesFullPath,
+ // Don't watch hidden files
+ "**/.*",
+ ]
+ },
+ target: nativescriptTarget,
+ entry: {
+ bundle: entryPath,
+ application: "./application.android",
+ },
+ output: {
+ pathinfo: false,
+ path: dist,
+ libraryTarget: "commonjs2",
+ filename: "[name].js",
+ globalObject: "global",
+ },
+ resolve: {
+ extensions: [".ts", ".js", ".scss", ".css"],
+ // Resolve {N} system modules from tns-core-modules
+ modules: [
+ resolve(__dirname, "node_modules/tns-core-modules"),
+ resolve(__dirname, "node_modules"),
+ "node_modules/tns-core-modules",
+ "node_modules",
+ ],
+ alias: {
+ '~': appFullPath
+ },
+ symlinks: true
+ },
+ resolveLoader: {
+ symlinks: false
+ },
+ node: {
+ // Disable node shims that conflict with NativeScript
+ "http": false,
+ "timers": false,
+ "setImmediate": false,
+ "fs": "empty",
+ "__dirname": false,
+ },
+ devtool: "none",
+ optimization: {
+ splitChunks: {
+ cacheGroups: {
+ vendor: {
+ name: "vendor",
+ chunks: "all",
+ test: (module, chunks) => {
+ const moduleName = module.nameForCondition ? module.nameForCondition() : '';
+ return /[\\/]node_modules[\\/]/.test(moduleName) ||
+ appComponents.some(comp => comp === moduleName);
+ },
+ enforce: true,
+ },
+ }
+ },
+ minimize: !!uglify,
+ minimizer: [
+ new UglifyJsPlugin({
+ uglifyOptions: {
+ parallel: true,
+ cache: true,
+ output: {
+ comments: false,
+ },
+ compress: {
+ // The Android SBG has problems parsing the output
+ // when these options are enabled
+ 'collapse_vars': platform !== "android",
+ sequences: platform !== "android",
+ }
+ }
+ })
+ ],
+ },
+ module: {
+ rules: [
+ {
+ test: new RegExp(entryPath),
+ use: [
+ // Require all Android app components
+ platform === "android" && {
+ loader: "nativescript-dev-webpack/android-app-components-loader",
+ options: { modules: appComponents }
+ },
+
+ {
+ loader: "nativescript-dev-webpack/bundle-config-loader",
+ options: {
+ angular: true,
+ loadCss: !snapshot, // load the application css if in debug mode
+ }
+ },
+ ].filter(loader => !!loader)
+ },
+
+ { test: /\.html$|\.xml$/, use: "raw-loader" },
+
+ // tns-core-modules reads the app.css and its imports using css-loader
+ {
+ test: /[\/|\\]app\.css$/,
+ use: {
+ loader: "css-loader",
+ options: { minimize: false, url: false },
+ }
+ },
+ {
+ test: /[\/|\\]app\.scss$/,
+ use: [
+ { loader: "css-loader", options: { minimize: false, url: false } },
+ "sass-loader"
+ ]
+ },
+
+ // Angular components reference css files and their imports using raw-loader
+ { test: /\.css$/, exclude: /[\/|\\]app\.css$/, use: "raw-loader" },
+ { test: /\.scss$/, exclude: /[\/|\\]app\.scss$/, use: ["raw-loader", "resolve-url-loader", "sass-loader"] },
+
+ // Compile TypeScript files with ahead-of-time compiler.
+ {
+ test: /.ts$/, use: [
+ "nativescript-dev-webpack/moduleid-compat-loader",
+ "@ngtools/webpack",
+ ]
+ },
+
+ // Mark files inside `@angular/core` as using SystemJS style dynamic imports.
+ // Removing this will cause deprecation warnings to appear.
+ {
+ test: /[\/\\]@angular[\/\\]core[\/\\].+\.js$/,
+ parser: { system: true },
+ },
+ ],
+ },
+ plugins: [
+ // Define useful constants like TNS_WEBPACK
+ new webpack.DefinePlugin({
+ "global.TNS_WEBPACK": "true",
+ }),
+ // Remove all files from the out dir.
+ new CleanWebpackPlugin([ `${dist}/**/*` ]),
+ // Copy native app resources to out dir.
+ new CopyWebpackPlugin([
+ {
+ from: `${appResourcesFullPath}/${appResourcesPlatformDir}`,
+ to: `${dist}/App_Resources/${appResourcesPlatformDir}`,
+ context: projectRoot
+ },
+ ]),
+ // Copy assets to out dir. Add your own globs as needed.
+ new CopyWebpackPlugin([
+ { from: "fonts/**" },
+ { from: "**/*.jpg" },
+ { from: "**/*.png" },
+ ], { ignore: [`${relative(appPath, appResourcesFullPath)}/**`] }),
+ // Generate a bundle starter script and activate it in package.json
+ new nsWebpack.GenerateBundleStarterPlugin([
+ "./vendor",
+ "./bundle",
+ ]),
+ // For instructions on how to set up workers with webpack
+ // check out https://github.com/nativescript/worker-loader
+ new NativeScriptWorkerPlugin(),
+
+ new AngularCompilerPlugin({
+ host: platformHost,
+ entryModule: resolve(appPath, "app.module#AppModule"),
+ tsConfigPath: join(__dirname, "tsconfig.esm.json"),
+ skipCodeGeneration: !aot,
+ }),
+ // Does IPC communication with the {N} CLI to notify events when running in watch mode.
+ new nsWebpack.WatchStateLoggerPlugin(),
+ ],
+ };
+
+ if (report) {
+ // Generate report files for bundles content
+ config.plugins.push(new BundleAnalyzerPlugin({
+ analyzerMode: "static",
+ openAnalyzer: false,
+ generateStatsFile: true,
+ reportFilename: resolve(projectRoot, "report", `report.html`),
+ statsFilename: resolve(projectRoot, "report", `stats.json`),
+ }));
+ }
+
+ if (snapshot) {
+ config.plugins.push(new nsWebpack.NativeScriptSnapshotPlugin({
+ chunk: "vendor",
+ angular: true,
+ requireModules: [
+ "reflect-metadata",
+ "@angular/platform-browser",
+ "@angular/core",
+ "@angular/common",
+ "@angular/router",
+ "nativescript-angular/platform-static",
+ "nativescript-angular/router",
+ ],
+ projectRoot,
+ webpackConfig: config,
+ }));
+ }
+
+ return config;
+};
diff --git a/demo/JavaScriptApp/app/App_Resources/Android/AndroidManifest.xml b/demo/JavaScriptApp/app/App_Resources/Android/AndroidManifest.xml
index 9db83215..0bb603e9 100644
--- a/demo/JavaScriptApp/app/App_Resources/Android/AndroidManifest.xml
+++ b/demo/JavaScriptApp/app/App_Resources/Android/AndroidManifest.xml
@@ -19,14 +19,14 @@
diff --git a/demo/JavaScriptApp/app/activity.android.js b/demo/JavaScriptApp/app/activity.android.js
new file mode 100644
index 00000000..c5013fd5
--- /dev/null
+++ b/demo/JavaScriptApp/app/activity.android.js
@@ -0,0 +1,32 @@
+const frame = require("ui/frame");
+
+const superProto = android.app.Activity.prototype;
+android.app.Activity.extend("org.myApp.MainActivity", {
+ onCreate: function(savedInstanceState) {
+ if(!this._callbacks) {
+ frame.setActivityCallbacks(this);
+ }
+ this._callbacks.onCreate(this, savedInstanceState, superProto.onCreate);
+ },
+ onSaveInstanceState: function(outState) {
+ this._callbacks.onSaveInstanceState(this, outState, superProto.onSaveInstanceState);
+ },
+ onStart: function() {
+ this._callbacks.onStart(this, superProto.onStart);
+ },
+ onStop: function() {
+ this._callbacks.onStop(this, superProto.onStop);
+ },
+ onDestroy: function() {
+ this._callbacks.onDestroy(this, superProto.onDestroy);
+ },
+ onBackPressed: function() {
+ this._callbacks.onBackPressed(this, superProto.onBackPressed);
+ },
+ onRequestPermissionsResult: function (requestCode, permissions, grantResults) {
+ this._callbacks.onRequestPermissionsResult(this, requestCode, permissions, grantResults, undefined);
+ },
+ onActivityResult: function (requestCode, resultCode, data) {
+ this._callbacks.onActivityResult(this, requestCode, resultCode, data, _super.prototype.onActivityResult);
+ }
+});
diff --git a/demo/JavaScriptApp/app/application.android.js b/demo/JavaScriptApp/app/application.android.js
new file mode 100644
index 00000000..858b33b6
--- /dev/null
+++ b/demo/JavaScriptApp/app/application.android.js
@@ -0,0 +1,9 @@
+const superProto = android.app.Application.prototype;
+android.app.Application.extend("org.myApp.Application", {
+ onCreate: function() {
+ superProto.onCreate.call(this);
+ },
+ attachBaseContext: function(base) {
+ superProto.attachBaseContext.call(this, base);
+ }
+});
diff --git a/demo/JavaScriptApp/package.json b/demo/JavaScriptApp/package.json
index a492ee07..32543aa0 100644
--- a/demo/JavaScriptApp/package.json
+++ b/demo/JavaScriptApp/package.json
@@ -33,13 +33,6 @@
"node-sass": "^4.7.1"
},
"scripts": {
- "ns-bundle": "ns-bundle",
- "start-android-bundle": "npm run ns-bundle --android --run-app",
- "start-ios-bundle": "npm run ns-bundle --ios --run-app",
- "build-android-bundle": "npm run ns-bundle --android --build-app",
- "build-ios-bundle": "npm run ns-bundle --ios --build-app",
- "publish-ios-bundle": "npm run ns-bundle --ios --publish-app",
- "generate-android-snapshot": "generate-android-snapshot --targetArchs arm,arm64,ia32 --install",
"e2e": "mocha --opts ../config/mocha.opts --recursive e2e --appiumCapsLocation ../config/appium.capabilities.json"
}
}
diff --git a/demo/JavaScriptApp/webpack.config.js b/demo/JavaScriptApp/webpack.config.js
new file mode 100644
index 00000000..64ea43c1
--- /dev/null
+++ b/demo/JavaScriptApp/webpack.config.js
@@ -0,0 +1,231 @@
+const { join, relative, resolve, sep } = require("path");
+
+const webpack = require("webpack");
+const nsWebpack = require("nativescript-dev-webpack");
+const nativescriptTarget = require("nativescript-dev-webpack/nativescript-target");
+const CleanWebpackPlugin = require("clean-webpack-plugin");
+const CopyWebpackPlugin = require("copy-webpack-plugin");
+const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");
+const { NativeScriptWorkerPlugin } = require("nativescript-worker-loader/NativeScriptWorkerPlugin");
+const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
+
+module.exports = env => {
+ // Add your custom Activities, Services and other android app components here.
+ const appComponents = [
+ "tns-core-modules/ui/frame",
+ "tns-core-modules/ui/frame/activity",
+ resolve(__dirname, "app/activity.android.js"),
+ ];
+
+ const platform = env && (env.android && "android" || env.ios && "ios");
+ if (!platform) {
+ throw new Error("You need to provide a target platform!");
+ }
+
+ const platforms = ["ios", "android"];
+ const projectRoot = __dirname;
+
+ // Default destination inside platforms//...
+ const dist = resolve(projectRoot, nsWebpack.getAppPath(platform, projectRoot));
+ const appResourcesPlatformDir = platform === "android" ? "Android" : "iOS";
+
+ const {
+ // The 'appPath' and 'appResourcesPath' values are fetched from
+ // the nsconfig.json configuration file
+ // when bundling with `tns run android|ios --bundle`.
+ appPath = "app",
+ appResourcesPath = "app/App_Resources",
+
+ // You can provide the following flags when running 'tns run android|ios'
+ snapshot, // --env.snapshot
+ uglify, // --env.uglify
+ report, // --env.report
+ } = env;
+
+ const appFullPath = resolve(projectRoot, appPath);
+ const appResourcesFullPath = resolve(projectRoot, appResourcesPath);
+
+ const entryModule = nsWebpack.getEntryModule(appFullPath);
+ const entryPath = `.${sep}${entryModule}.js`;
+
+ const config = {
+ mode: uglify ? "production" : "development",
+ context: appFullPath,
+ watchOptions: {
+ ignored: [
+ appResourcesFullPath,
+ // Don't watch hidden files
+ "**/.*",
+ ]
+ },
+ target: nativescriptTarget,
+ entry: {
+ bundle: entryPath,
+ application: "./application.android",
+ },
+ output: {
+ pathinfo: false,
+ path: dist,
+ libraryTarget: "commonjs2",
+ filename: "[name].js",
+ globalObject: "global",
+ },
+ resolve: {
+ extensions: [".js", ".scss", ".css"],
+ // Resolve {N} system modules from tns-core-modules
+ modules: [
+ "node_modules/tns-core-modules",
+ "node_modules",
+ ],
+ alias: {
+ '~': appFullPath
+ },
+ // don't resolve symlinks to symlinked modules
+ symlinks: false
+ },
+ resolveLoader: {
+ // don't resolve symlinks to symlinked loaders
+ symlinks: false
+ },
+ node: {
+ // Disable node shims that conflict with NativeScript
+ "http": false,
+ "timers": false,
+ "setImmediate": false,
+ "fs": "empty",
+ "__dirname": false,
+ },
+ devtool: "none",
+ optimization: {
+ splitChunks: {
+ cacheGroups: {
+ vendor: {
+ name: "vendor",
+ chunks: "all",
+ test: (module, chunks) => {
+ const moduleName = module.nameForCondition ? module.nameForCondition() : '';
+ return /[\\/]node_modules[\\/]/.test(moduleName) ||
+ appComponents.some(comp => comp === moduleName);
+
+ },
+ enforce: true,
+ },
+ }
+ },
+ minimize: !!uglify,
+ minimizer: [
+ new UglifyJsPlugin({
+ uglifyOptions: {
+ parallel: true,
+ cache: true,
+ output: {
+ comments: false,
+ },
+ compress: {
+ // The Android SBG has problems parsing the output
+ // when these options are enabled
+ 'collapse_vars': platform !== "android",
+ sequences: platform !== "android",
+ }
+ }
+ })
+ ],
+ },
+ module: {
+ rules: [
+ {
+ test: new RegExp(entryPath),
+ use: [
+ // Require all Android app components
+ platform === "android" && {
+ loader: "nativescript-dev-webpack/android-app-components-loader",
+ options: { modules: appComponents }
+ },
+
+ {
+ loader: "nativescript-dev-webpack/bundle-config-loader",
+ options: {
+ loadCss: !snapshot, // load the application css if in debug mode
+ }
+ },
+ ].filter(loader => !!loader)
+ },
+
+ { test: /\.(html|xml)$/, use: "nativescript-dev-webpack/xml-namespace-loader"},
+
+ {
+ test: /\.css$/,
+ use: { loader: "css-loader", options: { minimize: false, url: false } }
+ },
+
+ {
+ test: /\.scss$/,
+ use: [
+ { loader: "css-loader", options: { minimize: false, url: false } },
+ "sass-loader"
+ ]
+ }
+ ]
+ },
+ plugins: [
+ // Define useful constants like TNS_WEBPACK
+ new webpack.DefinePlugin({
+ "global.TNS_WEBPACK": "true",
+ }),
+ // Remove all files from the out dir.
+ new CleanWebpackPlugin([ `${dist}/**/*` ]),
+ // Copy native app resources to out dir.
+ new CopyWebpackPlugin([
+ {
+ from: `${appResourcesFullPath}/${appResourcesPlatformDir}`,
+ to: `${dist}/App_Resources/${appResourcesPlatformDir}`,
+ context: projectRoot
+ },
+ ]),
+ // Copy assets to out dir. Add your own globs as needed.
+ new CopyWebpackPlugin([
+ { from: "fonts/**" },
+ { from: "**/*.jpg" },
+ { from: "**/*.png" },
+ ], { ignore: [`${relative(appPath, appResourcesFullPath)}/**`] }),
+ // Generate a bundle starter script and activate it in package.json
+ new nsWebpack.GenerateBundleStarterPlugin([
+ "./vendor",
+ "./bundle",
+ ]),
+ // For instructions on how to set up workers with webpack
+ // check out https://github.com/nativescript/worker-loader
+ new NativeScriptWorkerPlugin(),
+ new nsWebpack.PlatformFSPlugin({
+ platform,
+ platforms,
+ }),
+ // Does IPC communication with the {N} CLI to notify events when running in watch mode.
+ new nsWebpack.WatchStateLoggerPlugin(),
+ ],
+ };
+
+ if (report) {
+ // Generate report files for bundles content
+ config.plugins.push(new BundleAnalyzerPlugin({
+ analyzerMode: "static",
+ openAnalyzer: false,
+ generateStatsFile: true,
+ reportFilename: resolve(projectRoot, "report", `report.html`),
+ statsFilename: resolve(projectRoot, "report", `stats.json`),
+ }));
+ }
+
+ if (snapshot) {
+ config.plugins.push(new nsWebpack.NativeScriptSnapshotPlugin({
+ chunk: "vendor",
+ requireModules: [
+ "tns-core-modules/bundle-entry-points",
+ ],
+ projectRoot,
+ webpackConfig: config,
+ }));
+ }
+
+ return config;
+};
diff --git a/demo/TypeScriptApp/app/App_Resources/Android/AndroidManifest.xml b/demo/TypeScriptApp/app/App_Resources/Android/AndroidManifest.xml
index 9db83215..0bb603e9 100644
--- a/demo/TypeScriptApp/app/App_Resources/Android/AndroidManifest.xml
+++ b/demo/TypeScriptApp/app/App_Resources/Android/AndroidManifest.xml
@@ -19,14 +19,14 @@
diff --git a/demo/TypeScriptApp/app/activity.android.ts b/demo/TypeScriptApp/app/activity.android.ts
new file mode 100644
index 00000000..f04e39bd
--- /dev/null
+++ b/demo/TypeScriptApp/app/activity.android.ts
@@ -0,0 +1,42 @@
+import {setActivityCallbacks, AndroidActivityCallbacks} from "ui/frame";
+
+@JavaProxy("org.myApp.MainActivity")
+class Activity extends android.app.Activity {
+ private _callbacks: AndroidActivityCallbacks;
+
+ protected onCreate(savedInstanceState: any): void { // android.os.Bundle
+ if (!this._callbacks) {
+ setActivityCallbacks(this);
+ }
+
+ this._callbacks.onCreate(this, savedInstanceState, super.onCreate);
+ }
+
+ protected onSaveInstanceState(outState: any): void { // android.os.Bundle
+ this._callbacks.onSaveInstanceState(this, outState, super.onSaveInstanceState);
+ }
+
+ protected onStart(): void {
+ this._callbacks.onStart(this, super.onStart);
+ }
+
+ protected onStop(): void {
+ this._callbacks.onStop(this, super.onStop);
+ }
+
+ protected onDestroy(): void {
+ this._callbacks.onDestroy(this, super.onDestroy);
+ }
+
+ public onBackPressed(): void {
+ this._callbacks.onBackPressed(this, super.onBackPressed);
+ }
+
+ public onRequestPermissionsResult(requestCode: number, permissions: Array, grantResults: Array): void {
+ this._callbacks.onRequestPermissionsResult(this, requestCode, permissions, grantResults, undefined /*TODO: Enable if needed*/);
+ }
+
+ protected onActivityResult(requestCode: number, resultCode: number, data: any): void { // android.content.Intent
+ this._callbacks.onActivityResult(this, requestCode, resultCode, data, super.onActivityResult);
+ }
+}
diff --git a/demo/TypeScriptApp/app/app.android.css b/demo/TypeScriptApp/app/app.android.css
new file mode 100644
index 00000000..c55b85fe
--- /dev/null
+++ b/demo/TypeScriptApp/app/app.android.css
@@ -0,0 +1 @@
+@import url(/Users/vchimev/Work/git/nativescript-dev-webpack/demo/TypeScriptApp/node_modules/nativescript-theme-core/css/core.light.css);ActionBar{background-color:#7F9}.app-class{background-color:#7F9}
diff --git a/demo/TypeScriptApp/app/app.ios.css b/demo/TypeScriptApp/app/app.ios.css
new file mode 100644
index 00000000..2a1f4e39
--- /dev/null
+++ b/demo/TypeScriptApp/app/app.ios.css
@@ -0,0 +1 @@
+@import url(/Users/vchimev/Work/git/nativescript-dev-webpack/demo/TypeScriptApp/node_modules/nativescript-theme-core/css/core.light.css);ActionBar{background-color:#999}.app-class{background-color:#999}
diff --git a/demo/TypeScriptApp/app/application.android.ts b/demo/TypeScriptApp/app/application.android.ts
new file mode 100644
index 00000000..4c23696f
--- /dev/null
+++ b/demo/TypeScriptApp/app/application.android.ts
@@ -0,0 +1,10 @@
+@JavaProxy("org.myApp.Application")
+class Application extends android.app.Application {
+ onCreate(): void {
+ super.onCreate();
+ }
+
+ protected attachBaseContext(baseContext: any) { // android.content.Context
+ super.attachBaseContext(baseContext);
+ }
+}
diff --git a/demo/TypeScriptApp/app/application.d.ts b/demo/TypeScriptApp/app/application.d.ts
new file mode 100644
index 00000000..3cb28cfd
--- /dev/null
+++ b/demo/TypeScriptApp/app/application.d.ts
@@ -0,0 +1 @@
+declare const android: any;
diff --git a/demo/TypeScriptApp/package.json b/demo/TypeScriptApp/package.json
index 3cef17fa..c4ecf688 100644
--- a/demo/TypeScriptApp/package.json
+++ b/demo/TypeScriptApp/package.json
@@ -34,13 +34,6 @@
"typescript": "~2.7.2"
},
"scripts": {
- "ns-bundle": "ns-bundle",
- "start-android-bundle": "npm run ns-bundle --android --run-app",
- "start-ios-bundle": "npm run ns-bundle --ios --run-app",
- "build-android-bundle": "npm run ns-bundle --android --build-app",
- "build-ios-bundle": "npm run ns-bundle --ios --build-app",
- "publish-ios-bundle": "npm run ns-bundle --ios --publish-app",
- "generate-android-snapshot": "generate-android-snapshot --targetArchs arm,arm64,ia32 --install",
"e2e": "tsc -p e2e && mocha --opts ../config/mocha.opts --recursive e2e --appiumCapsLocation ../config/appium.capabilities.json",
"compile-tests": "tsc -p e2e --watch"
}
diff --git a/demo/TypeScriptApp/webpack.config.js b/demo/TypeScriptApp/webpack.config.js
new file mode 100644
index 00000000..3c2bd1e1
--- /dev/null
+++ b/demo/TypeScriptApp/webpack.config.js
@@ -0,0 +1,241 @@
+const { join, relative, resolve, sep } = require("path");
+
+const webpack = require("webpack");
+const nsWebpack = require("nativescript-dev-webpack");
+const nativescriptTarget = require("nativescript-dev-webpack/nativescript-target");
+const CleanWebpackPlugin = require("clean-webpack-plugin");
+const CopyWebpackPlugin = require("copy-webpack-plugin");
+const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");
+const { NativeScriptWorkerPlugin } = require("nativescript-worker-loader/NativeScriptWorkerPlugin");
+const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
+
+module.exports = env => {
+ // Add your custom Activities, Services and other Android app components here.
+ const appComponents = [
+ "tns-core-modules/ui/frame",
+ "tns-core-modules/ui/frame/activity",
+ resolve(__dirname, "app/activity.android.ts"),
+ ];
+
+ const platform = env && (env.android && "android" || env.ios && "ios");
+ if (!platform) {
+ throw new Error("You need to provide a target platform!");
+ }
+
+ const platforms = ["ios", "android"];
+ const projectRoot = __dirname;
+
+ // Default destination inside platforms//...
+ const dist = resolve(projectRoot, nsWebpack.getAppPath(platform, projectRoot));
+ const appResourcesPlatformDir = platform === "android" ? "Android" : "iOS";
+
+ const {
+ // The 'appPath' and 'appResourcesPath' values are fetched from
+ // the nsconfig.json configuration file
+ // when bundling with `tns run android|ios --bundle`.
+ appPath = "app",
+ appResourcesPath = "app/App_Resources",
+
+ // You can provide the following flags when running 'tns run android|ios'
+ snapshot, // --env.snapshot
+ uglify, // --env.uglify
+ report, // --env.report
+ } = env;
+
+ const appFullPath = resolve(projectRoot, appPath);
+ const appResourcesFullPath = resolve(projectRoot, appResourcesPath);
+
+ const entryModule = nsWebpack.getEntryModule(appFullPath);
+ const entryPath = `.${sep}${entryModule}.ts`;
+
+ const config = {
+ mode: uglify ? "production" : "development",
+ context: appFullPath,
+ watchOptions: {
+ ignored: [
+ appResourcesFullPath,
+ // Don't watch hidden files
+ "**/.*",
+ ]
+ },
+ target: nativescriptTarget,
+ entry: {
+ bundle: entryPath,
+ application: "./application.android",
+ },
+ output: {
+ pathinfo: false,
+ path: dist,
+ libraryTarget: "commonjs2",
+ filename: "[name].js",
+ globalObject: "global",
+ },
+ resolve: {
+ extensions: [".ts", ".js", ".scss", ".css"],
+ // Resolve {N} system modules from tns-core-modules
+ modules: [
+ resolve(__dirname, "node_modules/tns-core-modules"),
+ resolve(__dirname, "node_modules"),
+ "node_modules/tns-core-modules",
+ "node_modules",
+ ],
+ alias: {
+ '~': appFullPath
+ },
+ // don't resolve symlinks to symlinked modules
+ symlinks: false
+ },
+ resolveLoader: {
+ // don't resolve symlinks to symlinked loaders
+ symlinks: false
+ },
+ node: {
+ // Disable node shims that conflict with NativeScript
+ "http": false,
+ "timers": false,
+ "setImmediate": false,
+ "fs": "empty",
+ "__dirname": false,
+ },
+ devtool: "none",
+ optimization: {
+ splitChunks: {
+ cacheGroups: {
+ vendor: {
+ name: "vendor",
+ chunks: "all",
+ test: (module, chunks) => {
+ const moduleName = module.nameForCondition ? module.nameForCondition() : '';
+ return /[\\/]node_modules[\\/]/.test(moduleName) ||
+ appComponents.some(comp => comp === moduleName);
+
+ },
+ enforce: true,
+ },
+ }
+ },
+ minimize: !!uglify,
+ minimizer: [
+ new UglifyJsPlugin({
+ uglifyOptions: {
+ parallel: true,
+ cache: true,
+ output: {
+ comments: false,
+ },
+ compress: {
+ // The Android SBG has problems parsing the output
+ // when these options are enabled
+ 'collapse_vars': platform !== "android",
+ sequences: platform !== "android",
+ }
+ }
+ })
+ ],
+ },
+ module: {
+ rules: [
+ {
+ test: new RegExp(entryPath),
+ use: [
+ // Require all Android app components
+ platform === "android" && {
+ loader: "nativescript-dev-webpack/android-app-components-loader",
+ options: { modules: appComponents }
+ },
+
+ {
+ loader: "nativescript-dev-webpack/bundle-config-loader",
+ options: {
+ loadCss: !snapshot, // load the application css if in debug mode
+ }
+ },
+ ].filter(loader => !!loader)
+ },
+
+ { test: /\.(html|xml)$/, use: "nativescript-dev-webpack/xml-namespace-loader"},
+
+ {
+ test: /\.css$/,
+ use: { loader: "css-loader", options: { minimize: false, url: false } }
+ },
+
+ {
+ test: /\.scss$/,
+ use: [
+ { loader: "css-loader", options: { minimize: false, url: false } },
+ "sass-loader"
+ ]
+ },
+
+ {
+ test: /\.ts$/,
+ use: {
+ loader: "awesome-typescript-loader",
+ options: { configFileName: "tsconfig.esm.json" },
+ }
+ },
+ ]
+ },
+ plugins: [
+ // Define useful constants like TNS_WEBPACK
+ new webpack.DefinePlugin({
+ "global.TNS_WEBPACK": "true",
+ }),
+ // Remove all files from the out dir.
+ new CleanWebpackPlugin([ `${dist}/**/*` ]),
+ // Copy native app resources to out dir.
+ new CopyWebpackPlugin([
+ {
+ from: `${appResourcesFullPath}/${appResourcesPlatformDir}`,
+ to: `${dist}/App_Resources/${appResourcesPlatformDir}`,
+ context: projectRoot
+ },
+ ]),
+ // Copy assets to out dir. Add your own globs as needed.
+ new CopyWebpackPlugin([
+ { from: "fonts/**" },
+ { from: "**/*.jpg" },
+ { from: "**/*.png" },
+ ], { ignore: [`${relative(appPath, appResourcesFullPath)}/**`] }),
+ // Generate a bundle starter script and activate it in package.json
+ new nsWebpack.GenerateBundleStarterPlugin([
+ "./vendor",
+ "./bundle",
+ ]),
+ // For instructions on how to set up workers with webpack
+ // check out https://github.com/nativescript/worker-loader
+ new NativeScriptWorkerPlugin(),
+ new nsWebpack.PlatformFSPlugin({
+ platform,
+ platforms,
+ }),
+ // Does IPC communication with the {N} CLI to notify events when running in watch mode.
+ new nsWebpack.WatchStateLoggerPlugin(),
+ ],
+ };
+
+ if (report) {
+ // Generate report files for bundles content
+ config.plugins.push(new BundleAnalyzerPlugin({
+ analyzerMode: "static",
+ openAnalyzer: false,
+ generateStatsFile: true,
+ reportFilename: resolve(projectRoot, "report", `report.html`),
+ statsFilename: resolve(projectRoot, "report", `stats.json`),
+ }));
+ }
+
+ if (snapshot) {
+ config.plugins.push(new nsWebpack.NativeScriptSnapshotPlugin({
+ chunk: "vendor",
+ requireModules: [
+ "tns-core-modules/bundle-entry-points",
+ ],
+ projectRoot,
+ webpackConfig: config,
+ }));
+ }
+
+ return config;
+};
diff --git a/demo/config/appium.capabilities.json b/demo/config/appium.capabilities.json
index 16749592..4bdd8c65 100644
--- a/demo/config/appium.capabilities.json
+++ b/demo/config/appium.capabilities.json
@@ -5,7 +5,6 @@
"deviceName": "Emulator-Api19-Default",
"avd": "Emulator-Api19-Default",
"lt": 60000,
- "appActivity": "com.tns.NativeScriptActivity",
"newCommandTimeout": 720,
"noReset": true,
"fullReset": false,
@@ -17,7 +16,6 @@
"deviceName": "Emulator-Api21-Default",
"avd": "Emulator-Api21-Default",
"lt": 60000,
- "appActivity": "com.tns.NativeScriptActivity",
"newCommandTimeout": 720,
"noReset": true,
"fullReset": false,
@@ -29,7 +27,6 @@
"deviceName": "Emulator-Api23-Default",
"avd": "Emulator-Api23-Default",
"lt": 60000,
- "appActivity": "com.tns.NativeScriptActivity",
"newCommandTimeout": 720,
"noReset": true,
"fullReset": false,
@@ -41,7 +38,6 @@
"deviceName": "Emulator-Api24-Default",
"avd": "Emulator-Api24-Default",
"lt": 60000,
- "appActivity": "com.tns.NativeScriptActivity",
"newCommandTimeout": 720,
"noReset": true,
"fullReset": false,
@@ -53,7 +49,6 @@
"deviceName": "Emulator-Api25-Google",
"avd": "Emulator-Api25-Google",
"lt": 60000,
- "appActivity": "com.tns.NativeScriptActivity",
"newCommandTimeout": 720,
"noReset": true,
"fullReset": false,
@@ -65,7 +60,6 @@
"deviceName": "Emulator-Api26-Google",
"avd": "Emulator-Api26-Google",
"lt": 60000,
- "appActivity": "com.tns.NativeScriptActivity",
"newCommandTimeout": 720,
"noReset": true,
"fullReset": false,
@@ -77,7 +71,6 @@
"deviceName": "Emulator-Api27-Google",
"avd": "Emulator-Api27-Google",
"lt": 60000,
- "appActivity": "com.tns.NativeScriptActivity",
"newCommandTimeout": 720,
"noReset": true,
"fullReset": false,
diff --git a/projectHelpers.js b/projectHelpers.js
index 1e9464f5..bc66ac04 100644
--- a/projectHelpers.js
+++ b/projectHelpers.js
@@ -66,6 +66,16 @@ function safeGet(object, property, ...args) {
value;
}
+// Convert paths from C:\some\path to C:/some/path in order to be required
+function convertSlashesInPath(modulePath) {
+ if (isWindows) {
+ modulePath = modulePath.replace(/\\/g, "/");
+ }
+ return modulePath;
+}
+
+const isWindows = process.platform.startsWith("win32");
+
module.exports = {
getAppPathFromProjectData,
getAppResourcesPathFromProjectData,
@@ -76,4 +86,5 @@ module.exports = {
isAngular,
isTypeScript,
writePackageJson,
+ convertSlashesInPath
};
diff --git a/xml-namespace-loader.js b/xml-namespace-loader.js
index a0c0d664..f640b30d 100644
--- a/xml-namespace-loader.js
+++ b/xml-namespace-loader.js
@@ -1,6 +1,7 @@
const { parse, relative, join, basename, extname } = require("path");
+const { convertSlashesInPath } = require("./projectHelpers");
-module.exports = function(source) {
+module.exports = function (source) {
this.value = source;
const { XmlParser } = require("tns-core-modules/xml");
@@ -47,7 +48,7 @@ module.exports = function(source) {
namespaces.push({ name: namespace, path: resolvedPath });
namespaces.push({ name: moduleName, path: resolvedPath });
- const { dir, name } = parse(resolvedPath);
+ const { dir, name } = parse(resolvedPath);
const noExtFilename = join(dir, name);
const xml = tryResolve(`${noExtFilename}.xml`);
@@ -67,6 +68,7 @@ module.exports = function(source) {
parser.parse(source);
const moduleRegisters = namespaces
+ .map(convertPath)
.map(n =>
`global.registerModule("${n.name}", function() { return require("${n.path}"); });`
)
@@ -83,12 +85,16 @@ module.exports = function(source) {
this.callback(null, wrapped);
}
+function convertPath(obj) {
+ obj.path = convertSlashesInPath(obj.path);
+ return obj;
+}
+
function tryResolve(path) {
try {
return require.resolve(path);
- } catch(e) {
+ } catch (e) {
// The path couldn't be resolved
return;
}
}
-