From 91fcad9c50595ff1ef87c625a6e9c52505384df0 Mon Sep 17 00:00:00 2001
From: imeepos <1037483576@qq.com>
Date: Fri, 3 May 2019 10:20:51 +0800
Subject: [PATCH] native app
---
.gitignore | 4 +-
.../template/admin/task-edit/index.tsx | 3 +-
.../template/admin/task-list/index.tsx | 7 +-
nsconfig.json | 4 +
package.json | 35 +-
.../nger-core/lib/decorators/component.ts | 2 +-
.../nger-platform-browser/lib/application.tsx | 24 +-
packages/nger-platform-h5/lib/cache.ts | 12 +-
packages/nger-platform-h5/lib/router.ts | 20 +-
.../nger-platform-ios/lib/app-host-view.ts | 34 ++
packages/nger-platform-ios/lib/bootstrap.ts | 49 ++-
packages/nger-platform-ios/lib/index.ts | 3 +-
packages/nger-platform-native/lib/index.ts | 3 +-
packages/nger-platform-swap/lib/cache.ts | 12 +-
packages/nger-platform-swap/lib/logger.ts | 8 +-
packages/nger-platform-tt/lib/cache.ts | 12 +-
packages/nger-platform-weapp/lib/cache.ts | 12 +-
src/template/admin/footer/index.tsx | 4 +-
tsconfig.json | 20 +-
tsconfig.tns.json | 7 +
webpack.config.js | 373 ++++++++++++------
21 files changed, 487 insertions(+), 161 deletions(-)
create mode 100644 nsconfig.json
create mode 100644 packages/nger-platform-ios/lib/app-host-view.ts
create mode 100644 tsconfig.tns.json
diff --git a/.gitignore b/.gitignore
index 066c306..54f239b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,4 +9,6 @@
/**/.rts2_cache_cjs
/**/.rts2_cache_es
/**/.rts2_cache_umd
-/**/node_modules
\ No newline at end of file
+/**/node_modules
+/app
+/hooks
\ No newline at end of file
diff --git a/addon/nger-todo/template/admin/task-edit/index.tsx b/addon/nger-todo/template/admin/task-edit/index.tsx
index 9ae575c..f91796d 100644
--- a/addon/nger-todo/template/admin/task-edit/index.tsx
+++ b/addon/nger-todo/template/admin/task-edit/index.tsx
@@ -1,7 +1,8 @@
import { Page } from 'nger-core';
+
@Page({
path: 'task/edit',
- type: 'admin',
+ type: ['admin'],
title: '编辑',
styleUrls: ['./index.scss']
})
diff --git a/addon/nger-todo/template/admin/task-list/index.tsx b/addon/nger-todo/template/admin/task-list/index.tsx
index d40d7d6..7b4af09 100644
--- a/addon/nger-todo/template/admin/task-list/index.tsx
+++ b/addon/nger-todo/template/admin/task-list/index.tsx
@@ -1,15 +1,12 @@
import { Page } from 'nger-core';
-import { Table } from 'nger-ui'
import { NgerTodoAdminHome } from './index.controller'
@Page({
path: 'task/list',
- type: 'admin',
+ type: ['admin'],
title: '任务',
styleUrls: ['./index.scss']
})
export class NgerTodoTaskListPage {
constructor(public controller: NgerTodoAdminHome) { }
- render() {
- return
- }
+ render() {}
}
diff --git a/nsconfig.json b/nsconfig.json
new file mode 100644
index 0000000..1098969
--- /dev/null
+++ b/nsconfig.json
@@ -0,0 +1,4 @@
+{
+ "appResourcesPath": "app/App_Resources",
+ "appPath": "app"
+}
\ No newline at end of file
diff --git a/package.json b/package.json
index 0d0316d..8868376 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,7 @@
"@babel/template": "^7.4.4",
"@babel/traverse": "^7.4.4",
"@babel/types": "^7.4.4",
+ "@progress-nativechat/nativescript-nativechat": "2.0.3",
"@stencil/core": "^0.18.1",
"@types/autoprefixer": "^9.4.0",
"@types/babel__core": "^7.1.1",
@@ -71,6 +72,7 @@
"imagemin-mozjpeg": "^8.0.0",
"imagemin-pngquant": "^7.0.0",
"imagemin-svgo": "^7.0.0",
+ "kinvey-nativescript-sdk": "3.12.4",
"koa-compress": "^3.0.0",
"koa-webpack": "^5.2.2",
"less": "^3.9.0",
@@ -79,11 +81,31 @@
"mocha": "^6.1.4",
"multihashing": "^0.3.3",
"multihashing-async": "^0.7.0",
+ "nativescript-accelerometer": "2.0.1",
+ "nativescript-background-http": "3.4.0",
+ "nativescript-camera": "4.4.0",
+ "nativescript-dev-typescript": "0.9.0",
+ "nativescript-dev-webpack": "0.21.0",
+ "nativescript-fresco": "5.2.0",
+ "nativescript-geolocation": "5.0.0",
+ "nativescript-imagepicker": "6.1.2",
+ "nativescript-intl": "3.0.0",
+ "nativescript-iqkeyboardmanager": "1.4.0",
+ "nativescript-social-share": "1.5.1",
+ "nativescript-theme-core": "1.0.4",
+ "nativescript-ui-autocomplete": "4.0.0",
+ "nativescript-ui-calendar": "4.0.0",
+ "nativescript-ui-chart": "4.0.0",
+ "nativescript-ui-dataform": "4.0.0",
+ "nativescript-ui-gauge": "4.0.0",
+ "nativescript-ui-listview": "6.1.0",
+ "nativescript-ui-sidedrawer": "6.0.0",
"node-sass": "^4.11.0",
"ora": "^3.4.0",
"postcss": "^7.0.14",
"postcss-mpvue-wxss": "^1.0.2",
"postcss-wxss": "^1.0.6",
+ "preact": "^8.4.2",
"readable-stream": "^3.3.0",
"resolve-from": "^5.0.0",
"rollup": "^1.10.1",
@@ -95,6 +117,7 @@
"stylelint-webpack-plugin": "^0.10.5",
"stylus": "^0.54.5",
"tns-core-modules": "^5.3.1",
+ "tns-platform-declarations": "5.3.1",
"ts-loader": "^5.4.4",
"ts-node": "^8.1.0",
"tsconfig-paths": "^3.8.0",
@@ -133,6 +156,15 @@
"typeorm": "^0.2.16",
"webpack-merge": "^4.2.1"
},
+ "nativescript": {
+ "id": "org.nativescript.blankts",
+ "tns-android": {
+ "version": "5.3.0"
+ },
+ "tns-ios": {
+ "version": "5.3.0"
+ }
+ },
"scripts": {
"test": "mocha -r ts-node/register -r tsconfig-paths/register ./**/__tests__/**/*.ts",
"ts": "ts-node -r tsconfig-paths/register",
@@ -143,8 +175,9 @@
"admin:build": "ts-node -r tsconfig-paths/register packages/nger-cli/lib/bin.ts build admin",
"admin:dev": "ts-node -r tsconfig-paths/register packages/nger-cli/lib/bin.ts build admin --watch",
"admin:stats": "webpack-bundle-analyzer template/admin/stats.json",
+ "preview:android": "tns preview",
"platform:native": "ts-node -r tsconfig-paths/register packages/nger-cli/lib/bin.ts build lib -n nger-platform-native",
"platform:ios": "ts-node -r tsconfig-paths/register packages/nger-cli/lib/bin.ts build lib -n nger-platform-ios",
"platform:android": "ts-node -r tsconfig-paths/register packages/nger-cli/lib/bin.ts build lib -n nger-platform-android"
}
-}
\ No newline at end of file
+}
diff --git a/packages/nger-core/lib/decorators/component.ts b/packages/nger-core/lib/decorators/component.ts
index d96efe6..0dd5e46 100644
--- a/packages/nger-core/lib/decorators/component.ts
+++ b/packages/nger-core/lib/decorators/component.ts
@@ -17,7 +17,7 @@ export interface ComponentOptions extends DirectiveOptions {
interpolation?: [string, string];
entryComponents?: Array | any[]>;
preserveWhitespaces?: boolean;
- type: ComponentType[];
+ type?: ComponentType[];
}
// P 是props
// S 是state
diff --git a/packages/nger-platform-browser/lib/application.tsx b/packages/nger-platform-browser/lib/application.tsx
index 16364a1..c3164c3 100644
--- a/packages/nger-platform-browser/lib/application.tsx
+++ b/packages/nger-platform-browser/lib/application.tsx
@@ -23,18 +23,20 @@ export class BrowserApplicationRef extends ApplicationRef {
const factory = ref.injector.get(ComponentFactory)
const parent = ref.injector.get(ElementRef, null, InjectFlags.SkipSelf) || new ElementRef(this.root);
//这里渲染preact
- const tpl = factory.def.render;
- const res = tpl(ref.instance)
- render(res, parent.nativeElement)
- // 更新试图,后面有可能会自己实现
- ref.$ngOnChange && ref.$ngOnChange.subscribe(() => {
+ if (ref.instance.render) {
+ const tpl = ref.instance.render();
const res = tpl(ref.instance)
- render(res, parent.nativeElement, parent.nativeElement.lastElementChild)
- });
- super.attachView(ref, injector);
- const nowTime = new Date().getTime();
- const totalTime = nowTime - (window as any).nger.startTime
- console.log(`总耗时:${totalTime}ms`);
+ render(res, parent.nativeElement)
+ // 更新试图,后面有可能会自己实现
+ ref.$ngOnChange && ref.$ngOnChange.subscribe(() => {
+ const res = tpl(ref.instance)
+ render(res, parent.nativeElement, parent.nativeElement.lastElementChild)
+ });
+ super.attachView(ref, injector);
+ const nowTime = new Date().getTime();
+ const totalTime = nowTime - (window as any).nger.startTime
+ console.log(`总耗时:${totalTime}ms`);
+ }
} catch (e) {
console.log({
ref, injector,
diff --git a/packages/nger-platform-h5/lib/cache.ts b/packages/nger-platform-h5/lib/cache.ts
index 12e8200..9db4950 100644
--- a/packages/nger-platform-h5/lib/cache.ts
+++ b/packages/nger-platform-h5/lib/cache.ts
@@ -1,7 +1,13 @@
import { Cache } from 'nger-core'
export class NgerH5Cache extends Cache {
- get(key: string): Promise { }
- put(key: string, value: T): Promise { }
- remove(key: string): Promise { }
+ get(key: string): Promise {
+ return new Promise(() => { })
+ }
+ put(key: string, value: T): Promise {
+ return new Promise(() => { })
+ }
+ remove(key: string): Promise {
+ return new Promise(() => { })
+ }
clear(): void { }
}
\ No newline at end of file
diff --git a/packages/nger-platform-h5/lib/router.ts b/packages/nger-platform-h5/lib/router.ts
index 5d60ee8..e21c3ad 100644
--- a/packages/nger-platform-h5/lib/router.ts
+++ b/packages/nger-platform-h5/lib/router.ts
@@ -1,13 +1,23 @@
import { Router } from 'nger-core'
export class NgerH5Router extends Router {
// 跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
- switchTab(url: string): Promise { }
+ switchTab(url: string): Promise {
+ return new Promise(() => { })
+ }
// 关闭所有页面,打开到应用内的某个页面
- reLaunch(url: string): Promise { }
+ reLaunch(url: string): Promise {
+ return new Promise(() => { })
+ }
// 关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面。
- redirectTo(url: string): Promise { }
+ redirectTo(url: string): Promise {
+ return new Promise(() => { })
+ }
// 保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面
- navigateTo(url: string): Promise { }
+ async navigateTo(url: string): Promise {
+ return new Promise(() => { })
+ }
// 关闭当前页面,返回上一页面或多级页面
- navigateBack(delta: number): Promise { }
+ navigateBack(delta: number): Promise {
+ return new Promise(() => { })
+ }
}
\ No newline at end of file
diff --git a/packages/nger-platform-ios/lib/app-host-view.ts b/packages/nger-platform-ios/lib/app-host-view.ts
new file mode 100644
index 0000000..8b7384b
--- /dev/null
+++ b/packages/nger-platform-ios/lib/app-host-view.ts
@@ -0,0 +1,34 @@
+import { ContentView } from "tns-core-modules/ui/content-view";
+import { GridLayout } from "tns-core-modules/ui/layouts/grid-layout";
+import { ProxyViewContainer } from "tns-core-modules/ui/proxy-view-container";
+import { View } from "tns-core-modules/ui/core/view";
+
+export class AppHostView extends ContentView {
+ private _ngAppRoot: View;
+ private _content: View;
+ get ngAppRoot(): View {
+ return this._ngAppRoot;
+ }
+ set ngAppRoot(value: View) {
+ this._ngAppRoot = value;
+ }
+ get content(): View {
+ return this._content;
+ }
+ set content(value: View) {
+ if (this._content) {
+ this._content.parentNode = undefined as any;
+ }
+ this._content = value;
+ if (value) {
+ this._content.parentNode = this;
+ }
+ this.ngAppRoot = value;
+ if (this._content instanceof ProxyViewContainer) {
+ const grid = new GridLayout();
+ grid.addChild(this._content);
+ this.ngAppRoot = grid;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/packages/nger-platform-ios/lib/bootstrap.ts b/packages/nger-platform-ios/lib/bootstrap.ts
index 29a1607..3e8c5fa 100644
--- a/packages/nger-platform-ios/lib/bootstrap.ts
+++ b/packages/nger-platform-ios/lib/bootstrap.ts
@@ -1,12 +1,55 @@
-import { NgModuleBootstrap, NgModuleRef } from 'nger-core'
+import { NgModuleBootstrap, NgModuleRef, ApplicationRef, NgModuleMetadataKey, NgModuleClassAst } from 'nger-core'
import {
- run as applicationRun
+ run as applicationRun,
+ on,
+ launchEvent,
+ LaunchEventData,
+ exitEvent,
+ ApplicationEventData,
} from "tns-core-modules/application";
-import { Injector } from 'nger-di'
+import { profile, uptime } from "tns-core-modules/profiling";
+import { View } from "tns-core-modules/ui/core/view/view";
+import { Injector, InjectionToken } from 'nger-di'
+import { AppHostView } from './app-host-view'
+import { setRootPage } from 'nger-platform-native'
+export const NATIVE_CONFIG = new InjectionToken(`NATIVE_CONFIG`)
export class NgerPlatformIosBootstrap extends NgModuleBootstrap {
injector: Injector;
async run(ref: NgModuleRef) {
this.injector = ref.injector;
+ on('launch', (args) => {
+ console.log(`launch`)
+ })
+ on('exitEvent', (args) => {
+ console.log(`exitEvent`)
+ });
+ const config = ref.injector.get(NATIVE_CONFIG)
+ // ref.componentFactoryResolver.resolveComponentFactory()
+ const ngModule = ref.context.getClass(NgModuleMetadataKey) as NgModuleClassAst;
+ const bootstrap = ngModule.ast.metadataDef.bootstrap;
+ const root = document.getElementById('app') as HTMLDivElement;
+ const application = ref.injector.get(ApplicationRef)
+ let rootContent: View;
+ let tempAppHostView: AppHostView;
+ tempAppHostView = new AppHostView();
+ setRootPage(tempAppHostView);
+ if (bootstrap) {
+ bootstrap.map(boot => {
+ const factory = ref.componentFactoryResolver.resolveComponentFactory(boot)
+ const component = factory.create(ref.injector);
+ })
+ }
+ const launchCallback = profile(
+ "nativescript-angular/platform-common.launchCallback",
+ (args: LaunchEventData) => {
+ console.log(`launchCallback`)
+ })
+ const exitCallback = profile(
+ "nativescript-angular/platform-common.exitCallback", (args: ApplicationEventData) => {
+ console.log(`exitCallback`)
+ })
+ on(launchEvent, launchCallback);
+ on(exitEvent, exitCallback);
applicationRun();
}
}
diff --git a/packages/nger-platform-ios/lib/index.ts b/packages/nger-platform-ios/lib/index.ts
index 9f10bfa..fc03b82 100644
--- a/packages/nger-platform-ios/lib/index.ts
+++ b/packages/nger-platform-ios/lib/index.ts
@@ -7,4 +7,5 @@ export default createPlatformFactory(ngerPlatformNative, 'native', [
useClass: NgerPlatformIosBootstrap,
deps: []
}
-])
\ No newline at end of file
+])
+export { NATIVE_CONFIG } from './bootstrap'
\ No newline at end of file
diff --git a/packages/nger-platform-native/lib/index.ts b/packages/nger-platform-native/lib/index.ts
index bcffe4f..975991e 100644
--- a/packages/nger-platform-native/lib/index.ts
+++ b/packages/nger-platform-native/lib/index.ts
@@ -2,4 +2,5 @@ import {platformCore,createPlatformFactory} from 'nger-core'
import platformProviders from './platform-providers'
export default createPlatformFactory(platformCore,'native',[
...platformProviders
-])
\ No newline at end of file
+])
+export * from './platform-providers'
\ No newline at end of file
diff --git a/packages/nger-platform-swap/lib/cache.ts b/packages/nger-platform-swap/lib/cache.ts
index 306dc0f..ee37cd9 100644
--- a/packages/nger-platform-swap/lib/cache.ts
+++ b/packages/nger-platform-swap/lib/cache.ts
@@ -1,7 +1,13 @@
import { Cache } from 'nger-core'
export class NgerSwapCache extends Cache {
- get(key: string): Promise { }
- put(key: string, value: T): Promise { }
- remove(key: string): Promise { }
+ get(key: string): Promise {
+ return new Promise(() => { })
+ }
+ put(key: string, value: T): Promise {
+ return new Promise(() => { })
+ }
+ remove(key: string): Promise {
+ return new Promise(() => { })
+ }
clear(): void { }
}
\ No newline at end of file
diff --git a/packages/nger-platform-swap/lib/logger.ts b/packages/nger-platform-swap/lib/logger.ts
index dc0416b..3c0c679 100644
--- a/packages/nger-platform-swap/lib/logger.ts
+++ b/packages/nger-platform-swap/lib/logger.ts
@@ -1 +1,7 @@
-export class NgerSwapLogger implements Logger { }
\ No newline at end of file
+import { Logger } from 'nger-core'
+export class NgerSwapLogger implements Logger {
+ debug(...args: any[]) { }
+ info(...args: any[]) { }
+ warn(...args: any[]) { }
+ error(...args: any[]) { }
+}
\ No newline at end of file
diff --git a/packages/nger-platform-tt/lib/cache.ts b/packages/nger-platform-tt/lib/cache.ts
index 0fb067b..0b38235 100644
--- a/packages/nger-platform-tt/lib/cache.ts
+++ b/packages/nger-platform-tt/lib/cache.ts
@@ -1,7 +1,13 @@
import { Cache } from 'nger-core'
export class NgerTtCache extends Cache {
- get(key: string): Promise { }
- put(key: string, value: T): Promise { }
- remove(key: string): Promise { }
+ async get(key: string): Promise {
+ return new Promise(() => { })
+ }
+ async put(key: string, value: T): Promise {
+ return new Promise(() => { })
+ }
+ async remove(key: string): Promise {
+ return new Promise(() => { })
+ }
clear(): void { }
}
\ No newline at end of file
diff --git a/packages/nger-platform-weapp/lib/cache.ts b/packages/nger-platform-weapp/lib/cache.ts
index 6328d11..141bd0d 100644
--- a/packages/nger-platform-weapp/lib/cache.ts
+++ b/packages/nger-platform-weapp/lib/cache.ts
@@ -1,7 +1,13 @@
import { Cache } from 'nger-core'
export class NgerWeappCache extends Cache {
- get(key: string): Promise { }
- put(key: string, value: T): Promise { }
- remove(key: string): Promise { }
+ async get(key: string): Promise {
+ return new Promise(() => { })
+ }
+ async put(key: string, value: T): Promise {
+ return new Promise(() => { })
+ }
+ async remove(key: string): Promise {
+ return new Promise(() => { })
+ }
clear(): void { }
}
\ No newline at end of file
diff --git a/src/template/admin/footer/index.tsx b/src/template/admin/footer/index.tsx
index 86bb323..a8d36a5 100644
--- a/src/template/admin/footer/index.tsx
+++ b/src/template/admin/footer/index.tsx
@@ -3,7 +3,5 @@ import { Component } from 'nger-core'
selector: 'nger-admin-footer'
})
export class NgerAdminFooter {
- render() {
- return
- }
+ render() { }
}
diff --git a/tsconfig.json b/tsconfig.json
index 164be54..3dd01ec 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -4,7 +4,8 @@
"module": "commonjs",
"lib": [
"dom",
- "esnext"
+ "esnext",
+ "es6"
],
"jsx": "react",
"jsxFactory": "h",
@@ -19,7 +20,7 @@
"allowUnusedLabels": true,
"noImplicitReturns": false,
"suppressImplicitAnyIndexErrors": false,
- "baseUrl": "./",
+ "baseUrl": ".",
"outDir": "./dist",
"rootDir": "./",
"strictPropertyInitialization": false,
@@ -154,6 +155,13 @@
],
"@babel/traverse": [
"node_modules/@types/babel__traverse"
+ ],
+ "*": [
+ "./node_modules/*",
+ "packages/*"
+ ],
+ "~/*": [
+ "app/*"
]
},
"typeRoots": [
@@ -179,9 +187,13 @@
"addon",
"src",
"typings/*.d.ts",
- "src/global.d.ts"
+ "src/global.d.ts",
+ "app"
],
"exclude": [
- "node_modules"
+ "node_modules",
+ "platforms",
+ "typings",
+ "**/*.aot.ts"
]
}
\ No newline at end of file
diff --git a/tsconfig.tns.json b/tsconfig.tns.json
new file mode 100644
index 0000000..95f2ece
--- /dev/null
+++ b/tsconfig.tns.json
@@ -0,0 +1,7 @@
+{
+ "extends": "./tsconfig",
+ "compilerOptions": {
+ "module": "es2015",
+ "moduleResolution": "node"
+ }
+}
diff --git a/webpack.config.js b/webpack.config.js
index b9d0fdc..7d6822b 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -1,135 +1,286 @@
-import { resolve } from 'path';
-import {
- DefinePlugin,
- EnvironmentPlugin,
- IgnorePlugin,
- optimize,
-} from 'webpack';
-import WXAppWebpackPlugin, { Targets } from 'wxapp-webpack-plugin';
-import StylelintPlugin from 'stylelint-webpack-plugin';
-import MinifyPlugin from 'babel-minify-webpack-plugin';
-import CopyPlugin from 'copy-webpack-plugin';
-import pkg from './package.json';
-
-const { NODE_ENV, LINT } = process.env;
-const isDev = NODE_ENV !== 'production';
-const shouldLint = !!LINT && LINT !== 'false';
-const srcDir = resolve('src');
-
-const copyPatterns = []
- .concat(pkg.copyWebpack || [])
- .map(
- (pattern) =>
- typeof pattern === 'string' ? { from: pattern, to: pattern } : pattern,
- );
-
-export default (env = {}) => {
- const min = env.min;
- const target = env.target || 'Wechat';
- const isWechat = env.target !== 'Alipay';
- const isAlipay = !isWechat;
-
- const relativeFileLoader = (ext = '[ext]') => {
- const namePrefix = isWechat ? '' : '[path]';
- return {
- loader: 'file-loader',
- options: {
- useRelativePath: isWechat,
- name: `${namePrefix}[name].${ext}`,
- context: srcDir,
- },
- };
+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");
+const hashSalt = Date.now().toString();
+
+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",
+ ];
+
+ 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
+ sourceMap, // --env.sourceMap
+ hmr, // --env.hmr,
+ unitTesting, // --env.unitTesting
+ } = env;
+ const externals = nsWebpack.getConvertedExternals(env.externals);
+
+ const appFullPath = resolve(projectRoot, appPath);
+ const appResourcesFullPath = resolve(projectRoot, appResourcesPath);
+
+ const entryModule = nsWebpack.getEntryModule(appFullPath);
+ const entryPath = `.${sep}${entryModule}.ts`;
+ const entries = { bundle: entryPath };
+ if (platform === "ios") {
+ entries["tns_modules/tns-core-modules/inspector_modules"] = "inspector_modules.js";
};
- return {
- entry: {
- app: './src/app.js',
+ const config = {
+ mode: uglify ? "production" : "development",
+ context: appFullPath,
+ externals,
+ watchOptions: {
+ ignored: [
+ appResourcesFullPath,
+ // Don't watch hidden files
+ "**/.*",
+ ]
},
+ target: nativescriptTarget,
+ entry: entries,
output: {
- filename: '[name].js',
- publicPath: '/',
- path: resolve('dist', isWechat ? 'wechat' : 'alipay'),
+ pathinfo: false,
+ path: dist,
+ libraryTarget: "commonjs2",
+ filename: "[name].js",
+ globalObject: "global",
+ hashSalt
+ },
+ 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
+ },
+ // resolve symlinks to symlinked modules
+ symlinks: true
+ },
+ 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: sourceMap ? "inline-source-map" : "none",
+ optimization: {
+ runtimeChunk: "single",
+ 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({
+ parallel: true,
+ cache: true,
+ uglifyOptions: {
+ output: {
+ comments: false,
+ },
+ compress: {
+ // The Android SBG has problems parsing the output
+ // when these options are enabled
+ 'collapse_vars': platform !== "android",
+ sequences: platform !== "android",
+ }
+ }
+ })
+ ],
},
- target: Targets[target],
module: {
rules: [
{
- test: /\.js$/,
- include: /src/,
- exclude: /node_modules/,
- use: ['babel-loader', shouldLint && 'eslint-loader'].filter(Boolean),
- },
- {
- test: /\.wxs$/,
- include: /src/,
- exclude: /node_modules/,
- use: [
- relativeFileLoader(),
- 'babel-loader',
- shouldLint && 'eslint-loader',
- ].filter(Boolean),
- },
- {
- test: /\.(scss|wxss|acss)$/,
- include: /src/,
+ test: nsWebpack.getEntryPathRegExp(appFullPath, entryPath),
use: [
- relativeFileLoader(isWechat ? 'wxss' : 'acss'),
+ // Require all Android app components
+ platform === "android" && {
+ loader: "nativescript-dev-webpack/android-app-components-loader",
+ options: { modules: appComponents }
+ },
+
{
- loader: 'sass-loader',
+ loader: "nativescript-dev-webpack/bundle-config-loader",
options: {
- includePaths: [resolve('src', 'styles'), srcDir],
- },
+ loadCss: !snapshot, // load the application css if in debug mode
+ unitTesting,
+ appFullPath,
+ projectRoot,
+ }
},
- ],
+ ].filter(loader => !!loader)
},
+
{
- test: /\.(json|png|jpg|gif)$/,
- include: /src/,
- use: relativeFileLoader(),
+ test: /-page\.ts$/,
+ use: "nativescript-dev-webpack/script-hot-loader"
},
+
+ {
+ test: /\.(css|scss)$/,
+ use: "nativescript-dev-webpack/style-hot-loader"
+ },
+
+ {
+ test: /\.(html|xml)$/,
+ use: "nativescript-dev-webpack/markup-hot-loader"
+ },
+
+ { test: /\.(html|xml)$/, use: "nativescript-dev-webpack/xml-namespace-loader" },
+
{
- test: /\.(wxml|axml)$/,
- include: /src/,
+ test: /\.css$/,
+ use: { loader: "css-loader", options: { minimize: false, url: false } }
+ },
+
+ {
+ test: /\.scss$/,
use: [
- relativeFileLoader(isWechat ? 'wxml' : 'axml'),
- {
- loader: 'wxml-loader',
- options: {
- root: srcDir,
- enforceRelativePath: true,
- },
+ { loader: "css-loader", options: { minimize: false, url: false } },
+ "sass-loader"
+ ]
+ },
+
+ {
+ test: /\.ts$/,
+ use: {
+ loader: "ts-loader",
+ options: {
+ configFile: "tsconfig.tns.json",
+ allowTsInNodeModules: true,
},
- ],
+ }
},
- ],
+ ]
},
plugins: [
- new EnvironmentPlugin({
- NODE_ENV: 'development',
+ // Define useful constants like TNS_WEBPACK
+ new webpack.DefinePlugin({
+ "global.TNS_WEBPACK": "true",
+ "process": undefined,
}),
- new DefinePlugin({
- __DEV__: isDev,
- __WECHAT__: isWechat,
- __ALIPAY__: isAlipay,
- wx: isWechat ? 'wx' : 'my',
- my: isWechat ? 'wx' : 'my',
+ // Remove all files from the out dir.
+ new CleanWebpackPlugin([`${dist}/**/*`]),
+ // Copy assets to out dir. Add your own globs as needed.
+ new CopyWebpackPlugin([
+ { from: { glob: "fonts/**" } },
+ { from: { glob: "**/*.jpg" } },
+ { from: { glob: "**/*.png" } },
+ ], { ignore: [`${relative(appPath, appResourcesFullPath)}/**`] }),
+ // Generate a bundle starter script and activate it in package.json
+ new nsWebpack.GenerateBundleStarterPlugin(
+ // Don't include `runtime.js` when creating a snapshot. The plugin
+ // configures the WebPack runtime to be generated inside the snapshot
+ // module and no `runtime.js` module exist.
+ (snapshot ? [] : ["./runtime"])
+ .concat([
+ "./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,
}),
- new WXAppWebpackPlugin({
- clear: !isDev,
- }),
- new optimize.ModuleConcatenationPlugin(),
- new IgnorePlugin(/vertx/),
- shouldLint && new StylelintPlugin(),
- min && new MinifyPlugin(),
- new CopyPlugin(copyPatterns, { context: srcDir }),
- ].filter(Boolean),
- devtool: isDev ? 'source-map' : false,
- resolve: {
- modules: [resolve(__dirname, 'src'), 'node_modules'],
- },
- watchOptions: {
- ignored: /dist|manifest/,
- aggregateTimeout: 300,
- },
+ // Does IPC communication with the {N} CLI to notify events when running in watch mode.
+ new nsWebpack.WatchStateLoggerPlugin(),
+ ],
};
-};
\ No newline at end of file
+
+ // Copy the native app resources to the out dir
+ // only if doing a full build (tns run/build) and not previewing (tns preview)
+ if (!externals || externals.length === 0) {
+ config.plugins.push(new CopyWebpackPlugin([
+ {
+ from: `${appResourcesFullPath}/${appResourcesPlatformDir}`,
+ to: `${dist}/App_Resources/${appResourcesPlatformDir}`,
+ context: projectRoot
+ },
+ ]));
+ }
+
+ 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,
+ }));
+ }
+
+ if (hmr) {
+ config.plugins.push(new webpack.HotModuleReplacementPlugin());
+ }
+
+
+ return config;
+};