@worktile/planet 10.0.0 → 12.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (256) hide show
  1. package/.all-contributorsrc +84 -0
  2. package/.circleci/config.yml +17 -0
  3. package/.coveralls.yml +1 -0
  4. package/.docgeni/public/assets/favicon.ico +0 -0
  5. package/.docgeni/public/index.html +13 -0
  6. package/.docgenirc.js +35 -0
  7. package/.dockerignore +1 -0
  8. package/.editorconfig +22 -0
  9. package/.github/FUNDING.yml +12 -0
  10. package/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
  11. package/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  12. package/.prettierignore +7 -0
  13. package/.prettierrc +28 -0
  14. package/.travis.yml +26 -0
  15. package/.wpmrc.js +11 -0
  16. package/CHANGELOG.md +391 -0
  17. package/CODE_OF_CONDUCT.md +76 -0
  18. package/Dockerfile +11 -0
  19. package/LICENSE +21 -0
  20. package/README.md +348 -0
  21. package/README.zh-CN.md +307 -0
  22. package/SECURITY.md +21 -0
  23. package/angular.json +373 -0
  24. package/commitlint.config.js +6 -0
  25. package/docs/api/defineApplication.md +46 -0
  26. package/docs/api/globalEventDispatcher.md +51 -0
  27. package/docs/api/index.md +5 -0
  28. package/docs/api/planet.md +117 -0
  29. package/docs/guides/getting-started.md +174 -0
  30. package/docs/guides/index.md +5 -0
  31. package/docs/guides/intro.md +216 -0
  32. package/examples/app1/browserslist +11 -0
  33. package/examples/app1/extra-webpack.config.js +33 -0
  34. package/examples/app1/karma.conf.js +31 -0
  35. package/examples/app1/postcss.config.js +1 -0
  36. package/examples/app1/src/app/app.module.ts +44 -0
  37. package/examples/app1/src/app/app.routing.ts +49 -0
  38. package/examples/app1/src/app/counter.service.ts +16 -0
  39. package/examples/app1/src/app/dashboard/dashboard.component.html +51 -0
  40. package/examples/app1/src/app/dashboard/dashboard.component.ts +70 -0
  41. package/examples/app1/src/app/detail/detail.component.html +8 -0
  42. package/examples/app1/src/app/detail/detail.component.ts +18 -0
  43. package/examples/app1/src/app/overlay.ts +26 -0
  44. package/examples/app1/src/app/projects/dialog/projects-dialog.component.html +10 -0
  45. package/examples/app1/src/app/projects/dialog/projects-dialog.component.ts +41 -0
  46. package/examples/app1/src/app/projects/projects.component.ts +33 -0
  47. package/examples/app1/src/app/root/root.component.css +3 -0
  48. package/examples/app1/src/app/root/root.component.html +16 -0
  49. package/examples/app1/src/app/root/root.component.ts +35 -0
  50. package/examples/app1/src/app/services/initialized-data.resolver.ts +15 -0
  51. package/examples/app1/src/app/shared.module.ts +57 -0
  52. package/examples/app1/src/app/user/detail/user-detail.component.html +5 -0
  53. package/examples/app1/src/app/user/detail/user-detail.component.ts +20 -0
  54. package/examples/app1/src/app/user/user-list.component.html +7 -0
  55. package/examples/app1/src/app/user/user-list.component.ts +20 -0
  56. package/examples/app1/src/app/user/user.module.ts +31 -0
  57. package/examples/app1/src/assets/.gitkeep +0 -0
  58. package/examples/app1/src/assets/github.png +0 -0
  59. package/examples/app1/src/assets/main.css +3 -0
  60. package/examples/app1/src/environments/environment.prod.ts +3 -0
  61. package/examples/app1/src/environments/environment.ts +16 -0
  62. package/examples/app1/src/favicon.ico +0 -0
  63. package/examples/app1/src/index.html +14 -0
  64. package/examples/app1/src/main.ts +35 -0
  65. package/examples/app1/src/polyfills.ts +84 -0
  66. package/examples/app1/src/styles.scss +35 -0
  67. package/examples/app1/src/test.ts +14 -0
  68. package/examples/app1/temp.js +221 -0
  69. package/examples/app1/tsconfig.app.json +10 -0
  70. package/examples/app1/tsconfig.spec.json +18 -0
  71. package/examples/app1/tslint.json +17 -0
  72. package/examples/app1/webpack.config.js +127 -0
  73. package/examples/app2/browserslist +11 -0
  74. package/examples/app2/extra-webpack.config.js +32 -0
  75. package/examples/app2/karma.conf.js +31 -0
  76. package/examples/app2/src/app/app.module.ts +90 -0
  77. package/examples/app2/src/app/dashboard/dashboard.component.html +21 -0
  78. package/examples/app2/src/app/dashboard/dashboard.component.ts +27 -0
  79. package/examples/app2/src/app/overlay.ts +26 -0
  80. package/examples/app2/src/app/projects/detail/detail.component.html +16 -0
  81. package/examples/app2/src/app/projects/detail/detail.component.ts +21 -0
  82. package/examples/app2/src/app/projects/project-list.component.html +29 -0
  83. package/examples/app2/src/app/projects/project-list.component.ts +58 -0
  84. package/examples/app2/src/app/projects/project.resolver.ts +15 -0
  85. package/examples/app2/src/app/projects/projects.service.ts +28 -0
  86. package/examples/app2/src/app/projects/tasks/tasks.component.html +10 -0
  87. package/examples/app2/src/app/projects/tasks/tasks.component.ts +16 -0
  88. package/examples/app2/src/app/projects/view/view.component.html +1 -0
  89. package/examples/app2/src/app/projects/view/view.component.ts +20 -0
  90. package/examples/app2/src/app/root/root.component.html +14 -0
  91. package/examples/app2/src/app/root/root.component.scss +12 -0
  92. package/examples/app2/src/app/root/root.component.ts +28 -0
  93. package/examples/app2/src/app/shared.module.ts +59 -0
  94. package/examples/app2/src/assets/.gitkeep +0 -0
  95. package/examples/app2/src/environments/environment.prod.ts +3 -0
  96. package/examples/app2/src/environments/environment.ts +16 -0
  97. package/examples/app2/src/favicon.ico +0 -0
  98. package/examples/app2/src/index.html +14 -0
  99. package/examples/app2/src/main.ts +36 -0
  100. package/examples/app2/src/polyfills.ts +84 -0
  101. package/examples/app2/src/styles.scss +28 -0
  102. package/examples/app2/src/test.ts +14 -0
  103. package/examples/app2/tsconfig.app.json +10 -0
  104. package/examples/app2/tsconfig.spec.json +18 -0
  105. package/examples/app2/tslint.json +7 -0
  106. package/examples/app2/webpack.config.js +92 -0
  107. package/examples/common/app-root-context.ts +10 -0
  108. package/examples/common/cache.ts +82 -0
  109. package/examples/common/index.ts +13 -0
  110. package/examples/common/module.ts +10 -0
  111. package/examples/common/overlay-container.service.ts +28 -0
  112. package/examples/common/section-card/section-card.component.html +5 -0
  113. package/examples/common/section-card/section-card.component.scss +15 -0
  114. package/examples/common/section-card/section-card.component.ts +11 -0
  115. package/examples/common/utils.ts +0 -0
  116. package/examples/portal/src/app/a-detail/a-detail.component.html +8 -0
  117. package/examples/portal/src/app/a-detail/a-detail.component.ts +18 -0
  118. package/examples/portal/src/app/about/about.component.html +27 -0
  119. package/examples/portal/src/app/about/about.component.scss +0 -0
  120. package/examples/portal/src/app/about/about.component.spec.ts +26 -0
  121. package/examples/portal/src/app/about/about.component.ts +26 -0
  122. package/examples/portal/src/app/app-routing.module.ts +57 -0
  123. package/examples/portal/src/app/app.component.html +73 -0
  124. package/examples/portal/src/app/app.component.scss +58 -0
  125. package/examples/portal/src/app/app.component.spec.ts +33 -0
  126. package/examples/portal/src/app/app.component.ts +111 -0
  127. package/examples/portal/src/app/app.module.ts +64 -0
  128. package/examples/portal/src/app/custom-settings.service.ts +44 -0
  129. package/examples/portal/src/app/overlay.ts +26 -0
  130. package/examples/portal/src/app/settings/settings.component.html +31 -0
  131. package/examples/portal/src/app/settings/settings.component.scss +3 -0
  132. package/examples/portal/src/app/settings/settings.component.ts +43 -0
  133. package/examples/portal/src/assets/.gitkeep +0 -0
  134. package/examples/portal/src/assets/apps.json +29 -0
  135. package/examples/portal/src/assets/icons/sprite.defs.svg +1 -0
  136. package/examples/portal/src/assets/images/logo.svg +16 -0
  137. package/examples/portal/src/assets/ngx-planet-micro-front-end.gif +0 -0
  138. package/examples/portal/src/browserslist +11 -0
  139. package/examples/portal/src/environments/environment.prod.ts +3 -0
  140. package/examples/portal/src/environments/environment.ts +16 -0
  141. package/examples/portal/src/extra-webpack.config.js +32 -0
  142. package/examples/portal/src/favicon.ico +0 -0
  143. package/examples/portal/src/index.html +14 -0
  144. package/examples/portal/src/karma.conf.js +31 -0
  145. package/examples/portal/src/main.ts +18 -0
  146. package/examples/portal/src/polyfills.ts +84 -0
  147. package/examples/portal/src/reboot.scss +14 -0
  148. package/examples/portal/src/styles.scss +14 -0
  149. package/examples/portal/src/test.ts +14 -0
  150. package/examples/portal/src/tsconfig.app.json +10 -0
  151. package/examples/portal/src/tsconfig.spec.json +9 -0
  152. package/examples/portal/src/tslint.json +7 -0
  153. package/extra-webpack.config.js +5 -0
  154. package/nginx.conf +17 -0
  155. package/package.json +120 -15
  156. package/packages/planet/karma.conf.js +37 -0
  157. package/packages/planet/ng-package.json +7 -0
  158. package/packages/planet/package.json +10 -0
  159. package/packages/planet/src/application/planet-application-loader.spec.ts +1102 -0
  160. package/packages/planet/src/application/planet-application-loader.ts +549 -0
  161. package/packages/planet/src/application/planet-application-ref.spec.ts +233 -0
  162. package/packages/planet/src/application/planet-application-ref.ts +131 -0
  163. package/packages/planet/src/application/planet-application.service.spec.ts +145 -0
  164. package/packages/planet/src/application/planet-application.service.ts +88 -0
  165. package/packages/planet/src/application/portal-application.spec.ts +53 -0
  166. package/packages/planet/src/application/portal-application.ts +28 -0
  167. package/packages/planet/src/assets-loader.spec.ts +689 -0
  168. package/packages/planet/src/assets-loader.ts +247 -0
  169. package/packages/planet/src/component/planet-component-loader.spec.ts +187 -0
  170. package/packages/planet/src/component/planet-component-loader.ts +173 -0
  171. package/{component/planet-component-ref.d.ts → packages/planet/src/component/planet-component-ref.ts} +3 -2
  172. package/{component/plant-component.config.d.ts → packages/planet/src/component/plant-component.config.ts} +4 -3
  173. package/packages/planet/src/debug.spec.ts +58 -0
  174. package/packages/planet/src/debug.ts +66 -0
  175. package/packages/planet/src/empty/empty.component.spec.ts +34 -0
  176. package/packages/planet/src/empty/empty.component.ts +7 -0
  177. package/packages/planet/src/global-event-dispatcher.spec.ts +81 -0
  178. package/packages/planet/src/global-event-dispatcher.ts +82 -0
  179. package/packages/planet/src/global-planet.spec.ts +39 -0
  180. package/packages/planet/src/global-planet.ts +73 -0
  181. package/packages/planet/src/helpers.spec.ts +242 -0
  182. package/packages/planet/src/helpers.ts +125 -0
  183. package/packages/planet/src/module.spec.ts +79 -0
  184. package/packages/planet/src/module.ts +25 -0
  185. package/packages/planet/src/planet.class.ts +59 -0
  186. package/packages/planet/src/planet.spec.ts +226 -0
  187. package/packages/planet/src/planet.ts +113 -0
  188. package/{public-api.d.ts → packages/planet/src/public-api.ts} +4 -0
  189. package/packages/planet/src/sandbox/constants.ts +6 -0
  190. package/packages/planet/src/sandbox/exec.ts +22 -0
  191. package/packages/planet/src/sandbox/index.ts +24 -0
  192. package/packages/planet/src/sandbox/proxy/patches/document.ts +13 -0
  193. package/packages/planet/src/sandbox/proxy/patches/eventListener.ts +49 -0
  194. package/packages/planet/src/sandbox/proxy/patches/index.ts +13 -0
  195. package/packages/planet/src/sandbox/proxy/patches/storage.ts +53 -0
  196. package/packages/planet/src/sandbox/proxy/patches/timer.ts +50 -0
  197. package/packages/planet/src/sandbox/proxy/proxies/common.ts +137 -0
  198. package/packages/planet/src/sandbox/proxy/proxies/document.ts +140 -0
  199. package/packages/planet/src/sandbox/proxy/proxies/window.ts +176 -0
  200. package/packages/planet/src/sandbox/proxy/proxy-sandbox.ts +59 -0
  201. package/packages/planet/src/sandbox/proxy/types.ts +20 -0
  202. package/packages/planet/src/sandbox/sandbox.ts +20 -0
  203. package/packages/planet/src/sandbox/snapshot/snapshot-sandbox.ts +12 -0
  204. package/packages/planet/src/sandbox/types.ts +1 -0
  205. package/packages/planet/src/test.ts +16 -0
  206. package/packages/planet/src/testing/app1.module.ts +34 -0
  207. package/packages/planet/src/testing/app2.module.ts +24 -0
  208. package/packages/planet/src/testing/applications.ts +58 -0
  209. package/packages/planet/src/testing/index.ts +2 -0
  210. package/packages/planet/src/testing/utils.ts +31 -0
  211. package/packages/planet/tsconfig.lib.json +27 -0
  212. package/packages/planet/tsconfig.lib.prod.json +9 -0
  213. package/packages/planet/tsconfig.spec.json +17 -0
  214. package/packages/planet/tslint.json +7 -0
  215. package/postcss.config.js +3 -0
  216. package/proxy.conf.js +15 -0
  217. package/tsconfig.json +23 -0
  218. package/tslint.json +80 -0
  219. package/application/planet-application-loader.d.ts +0 -68
  220. package/application/planet-application-ref.d.ts +0 -32
  221. package/application/planet-application.service.d.ts +0 -18
  222. package/application/portal-application.d.ts +0 -14
  223. package/assets-loader.d.ts +0 -23
  224. package/bundles/worktile-planet.umd.js +0 -1670
  225. package/bundles/worktile-planet.umd.js.map +0 -1
  226. package/bundles/worktile-planet.umd.min.js +0 -16
  227. package/bundles/worktile-planet.umd.min.js.map +0 -1
  228. package/component/planet-component-loader.d.ts +0 -27
  229. package/empty/empty.component.d.ts +0 -2
  230. package/esm2015/application/planet-application-loader.js +0 -417
  231. package/esm2015/application/planet-application-ref.js +0 -86
  232. package/esm2015/application/planet-application.service.js +0 -87
  233. package/esm2015/application/portal-application.js +0 -16
  234. package/esm2015/assets-loader.js +0 -165
  235. package/esm2015/component/planet-component-loader.js +0 -157
  236. package/esm2015/component/planet-component-ref.js +0 -3
  237. package/esm2015/component/plant-component.config.js +0 -7
  238. package/esm2015/empty/empty.component.js +0 -10
  239. package/esm2015/global-event-dispatcher.js +0 -71
  240. package/esm2015/global-planet.js +0 -51
  241. package/esm2015/helpers.js +0 -116
  242. package/esm2015/module.js +0 -27
  243. package/esm2015/planet.class.js +0 -9
  244. package/esm2015/planet.js +0 -86
  245. package/esm2015/public-api.js +0 -18
  246. package/esm2015/worktile-planet.js +0 -6
  247. package/fesm2015/worktile-planet.js +0 -1257
  248. package/fesm2015/worktile-planet.js.map +0 -1
  249. package/global-event-dispatcher.d.ts +0 -19
  250. package/global-planet.d.ts +0 -22
  251. package/helpers.d.ts +0 -37
  252. package/module.d.ts +0 -5
  253. package/planet.class.d.ts +0 -34
  254. package/planet.d.ts +0 -24
  255. package/worktile-planet.d.ts +0 -5
  256. package/worktile-planet.metadata.json +0 -1
@@ -0,0 +1,125 @@
1
+ import { PlanetApplication } from './planet.class';
2
+
3
+ const ELEMENT_NODE_TYPE = 1;
4
+
5
+ export function hashCode(str: string): number {
6
+ let hash = 0;
7
+ let chr: number;
8
+ if (str.length === 0) {
9
+ return hash;
10
+ }
11
+ for (let i = 0; i < str.length; i++) {
12
+ chr = str.charCodeAt(i);
13
+ hash = (hash << 5) - hash + chr;
14
+ hash |= 0; // Convert to 32bit integer
15
+ }
16
+ return hash;
17
+ }
18
+
19
+ export function getHTMLElement(selector: string | HTMLElement): HTMLElement | null {
20
+ if (selector instanceof HTMLElement) {
21
+ return selector;
22
+ } else {
23
+ return document.querySelector(selector);
24
+ }
25
+ }
26
+
27
+ export function getTagNameByTemplate(template: string): string {
28
+ const element = createElementByTemplate(template);
29
+ return element ? element.nodeName : '';
30
+ }
31
+
32
+ export function createElementByTemplate(template: string) {
33
+ if (!template) {
34
+ return null;
35
+ }
36
+ const element = document.createRange().createContextualFragment(template).firstChild;
37
+ if (element && element.nodeType === ELEMENT_NODE_TYPE) {
38
+ return element as HTMLElement;
39
+ } else {
40
+ throw new Error(`invalid template '${template}'`);
41
+ }
42
+ }
43
+
44
+ export function coerceArray<T>(value: T | T[]): T[] {
45
+ return Array.isArray(value) ? value : [value];
46
+ }
47
+
48
+ export function isEmpty(value: any): boolean {
49
+ if (!value || value.length === 0) {
50
+ return true;
51
+ } else {
52
+ return false;
53
+ }
54
+ }
55
+
56
+ export function isFunction(value: any): value is Function {
57
+ const type = typeof value;
58
+ return !!value && type === 'function';
59
+ }
60
+
61
+ export function isObject(val: any) {
62
+ return val && typeof val === 'object';
63
+ }
64
+ /**
65
+ * Get file name from path
66
+ * 1. "main.js" => "main.js"
67
+ * 2. "assets/scripts/main.js" => "main.js"
68
+ * @param path path
69
+ */
70
+ export function getResourceFileName(path: string) {
71
+ const lastSlashIndex = path.lastIndexOf('/');
72
+ if (lastSlashIndex >= 0) {
73
+ return path.slice(lastSlashIndex + 1);
74
+ } else {
75
+ return path;
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Build resource path by manifest
81
+ * if manifest is { "main.js": "main.h2sh23abee.js"}
82
+ * 1. "main.js" => "main.h2sh23abee.js"
83
+ * 2. "assets/scripts/main.js" =>"assets/scripts/main.h2sh23abee.js"
84
+ * @param resourceFilePath Resource File Path
85
+ * @param manifestResult manifest
86
+ */
87
+ export function buildResourceFilePath(resourceFilePath: string, manifestResult: { [key: string]: string }) {
88
+ const fileName = getResourceFileName(resourceFilePath);
89
+ if (manifestResult[fileName]) {
90
+ return resourceFilePath.replace(fileName, manifestResult[fileName]);
91
+ } else {
92
+ return resourceFilePath;
93
+ }
94
+ }
95
+
96
+ /**
97
+ * Get static resource full path
98
+ * @param app PlanetApplication
99
+ * @param manifestResult manifest
100
+ */
101
+ export function getScriptsAndStylesFullPaths(app: PlanetApplication, manifestResult?: { [key: string]: string }) {
102
+ let scripts = app.scripts || [];
103
+ let styles = app.styles || [];
104
+ // combine resource path by manifest
105
+ if (manifestResult) {
106
+ scripts = scripts.map(script => {
107
+ return buildResourceFilePath(script, manifestResult);
108
+ });
109
+ styles = styles.map(style => {
110
+ return buildResourceFilePath(style, manifestResult);
111
+ });
112
+ }
113
+ if (app.resourcePathPrefix) {
114
+ scripts = scripts.map(script => {
115
+ return `${app.resourcePathPrefix}${script}`;
116
+ });
117
+ styles = styles.map(style => {
118
+ return `${app.resourcePathPrefix}${style}`;
119
+ });
120
+ }
121
+ return {
122
+ scripts: scripts,
123
+ styles: styles
124
+ };
125
+ }
@@ -0,0 +1,79 @@
1
+ import { TestBed } from '@angular/core/testing';
2
+ import { NgxPlanetModule } from './module';
3
+ import { NgModule } from '@angular/core';
4
+ import { Planet } from './planet';
5
+ import { clearGlobalPlanet } from './global-planet';
6
+ import { PlanetApplicationService } from './application/planet-application.service';
7
+ import { RouterTestingModule } from '@angular/router/testing';
8
+
9
+ const app1 = {
10
+ name: 'app1',
11
+ hostParent: '.host-selector',
12
+ selector: 'app1-root',
13
+ routerPathPrefix: '/app1',
14
+ hostClass: 'app1-host',
15
+ preload: false,
16
+ resourcePathPrefix: '/static/app1/',
17
+ styles: ['styles/main.css'],
18
+ scripts: ['vendor.js', 'main.js'],
19
+ loadSerial: false,
20
+ manifest: '',
21
+ extra: {
22
+ appName: '应用1'
23
+ }
24
+ };
25
+
26
+ @NgModule({
27
+ imports: [NgxPlanetModule, RouterTestingModule.withRoutes([])]
28
+ })
29
+ class AppModule {}
30
+
31
+ @NgModule({
32
+ imports: [NgxPlanetModule.forRoot([app1]), RouterTestingModule.withRoutes([])]
33
+ })
34
+ class AppModuleWithApps {}
35
+
36
+ describe('NgxPlanetModule', () => {
37
+ afterEach(() => {
38
+ clearGlobalPlanet();
39
+ const applicationService = TestBed.inject(PlanetApplicationService);
40
+ applicationService['apps'] = [];
41
+ applicationService['appsMap'] = {};
42
+ });
43
+
44
+ describe('basic', () => {
45
+ beforeEach(() => {
46
+ TestBed.configureTestingModule({
47
+ imports: [AppModule]
48
+ });
49
+ });
50
+
51
+ it('should get NgxPlanetModule', () => {
52
+ expect(TestBed.inject(NgxPlanetModule)).toBeTruthy();
53
+ });
54
+
55
+ it('should get planet', () => {
56
+ const planet: Planet = TestBed.inject(Planet);
57
+ expect(planet).toBeTruthy();
58
+ expect(planet.getApps()).toEqual([]);
59
+ });
60
+ });
61
+
62
+ describe('forRoot', () => {
63
+ beforeEach(() => {
64
+ TestBed.configureTestingModule({
65
+ imports: [AppModuleWithApps]
66
+ });
67
+ });
68
+
69
+ it('should get NgxPlanetModule', () => {
70
+ expect(TestBed.inject(NgxPlanetModule)).toBeTruthy();
71
+ });
72
+
73
+ it('should register app1 when use forRoot', () => {
74
+ const planet: Planet = TestBed.inject(Planet);
75
+ expect(planet).toBeTruthy();
76
+ expect(planet.getApps()).toEqual([app1]);
77
+ });
78
+ });
79
+ });
@@ -0,0 +1,25 @@
1
+ import { NgModule, ModuleWithProviders } from '@angular/core';
2
+ import { PlanetApplication, PLANET_APPLICATIONS } from './planet.class';
3
+ import { HttpClientModule } from '@angular/common/http';
4
+ import { EmptyComponent } from './empty/empty.component';
5
+
6
+ @NgModule({
7
+ declarations: [EmptyComponent],
8
+ entryComponents: [EmptyComponent],
9
+ imports: [HttpClientModule],
10
+ providers: [],
11
+ exports: [HttpClientModule, EmptyComponent]
12
+ })
13
+ export class NgxPlanetModule {
14
+ static forRoot(apps: PlanetApplication[]): ModuleWithProviders<NgxPlanetModule> {
15
+ return {
16
+ ngModule: NgxPlanetModule,
17
+ providers: [
18
+ {
19
+ provide: PLANET_APPLICATIONS,
20
+ useValue: apps
21
+ }
22
+ ]
23
+ };
24
+ }
25
+ }
@@ -0,0 +1,59 @@
1
+ import { InjectionToken } from '@angular/core';
2
+ import { Debug } from './debug';
3
+
4
+ export interface PlanetOptions {
5
+ switchMode?: SwitchModes;
6
+ errorHandler: (error: Error) => void;
7
+ debugFactory?: Debug;
8
+ }
9
+
10
+ export interface PlanetApplication<TExtra = any> {
11
+ name: string;
12
+ // 应用加载的宿主元素或者选择器
13
+ hostParent: string | HTMLElement;
14
+
15
+ // 子应用的选择器
16
+ /**
17
+ * @deprecated please use new defineApplication to set selector
18
+ */
19
+ selector?: string;
20
+ // 子应用路由前缀路径
21
+ routerPathPrefix: string | RegExp;
22
+ // 宿主元素附加样式
23
+ hostClass?: string | string[];
24
+ // 是否需要预加载
25
+ preload?: boolean;
26
+ // 是否开启沙箱
27
+ sandbox?: boolean;
28
+ // 切换应用的模式
29
+ switchMode?: SwitchModes;
30
+ // 资源文件路径的前缀
31
+ resourcePathPrefix?: string;
32
+ // 样式前缀
33
+ stylePrefix?: string;
34
+ // 样式资源文件
35
+ styles?: string[];
36
+ // 脚本资源文件
37
+ scripts?: string[];
38
+ // 串行加载,默认并行加载脚本资源
39
+ loadSerial?: boolean;
40
+ // 皮肤样式的路径
41
+ themeStylesPath?: string;
42
+ // 应用程序打包后的脚本和样式文件替换
43
+ manifest?: string;
44
+ // 附加数据,主要应用于业务,比如图标,子应用的颜色,显示名等个性化配置
45
+ extra?: TExtra;
46
+ }
47
+
48
+ export enum SwitchModes {
49
+ default = 'default',
50
+ coexist = 'coexist'
51
+ }
52
+
53
+ export interface PlanetRouterEvent {
54
+ url: string;
55
+ }
56
+
57
+ const PLANET_APPLICATIONS = new InjectionToken<PlanetApplication>('PLANET_APPLICATIONS');
58
+
59
+ export { PLANET_APPLICATIONS };
@@ -0,0 +1,226 @@
1
+ import { TestBed, tick, fakeAsync, waitForAsync } from '@angular/core/testing';
2
+ import { Planet } from './planet';
3
+ import { NgxPlanetModule } from './module';
4
+ import { Router, Event } from '@angular/router';
5
+ import { SwitchModes, PlanetRouterEvent, PlanetOptions } from './planet.class';
6
+ import { PlanetApplicationService } from './application/planet-application.service';
7
+ import { PlanetApplicationLoader } from './application/planet-application-loader';
8
+ import { EmptyComponent } from './empty/empty.component';
9
+ import { NgZone } from '@angular/core';
10
+ import { getApplicationService, getApplicationLoader, clearGlobalPlanet } from './global-planet';
11
+ import { RouterTestingModule } from '@angular/router/testing';
12
+ import { debug } from 'debug';
13
+ import { getDebugFactory, setDebugFactory } from './debug';
14
+
15
+ const app1 = {
16
+ name: 'app1',
17
+ hostParent: '.host-selector',
18
+ selector: 'app1-root',
19
+ routerPathPrefix: '/app1',
20
+ hostClass: 'app1-host',
21
+ preload: false,
22
+ switchMode: SwitchModes.default,
23
+ resourcePathPrefix: '/static/app1/',
24
+ styles: ['styles/main.css'],
25
+ scripts: ['vendor.js', 'main.js'],
26
+ loadSerial: false,
27
+ manifest: '',
28
+ extra: {
29
+ appName: '应用1'
30
+ }
31
+ };
32
+
33
+ const app2 = {
34
+ name: 'app2',
35
+ hostParent: '.host-selector',
36
+ selector: 'app2-root',
37
+ routerPathPrefix: '/app2',
38
+ hostClass: 'app2-host',
39
+ preload: false,
40
+ switchMode: SwitchModes.coexist,
41
+ resourcePathPrefix: '/static/app2',
42
+ styles: ['styles/main.css'],
43
+ scripts: ['vendor.js', 'main.js'],
44
+ loadSerial: false,
45
+ extra: {
46
+ appName: '应用2'
47
+ }
48
+ };
49
+
50
+ describe('Planet', () => {
51
+ let planet: Planet;
52
+ let planetApplicationService: PlanetApplicationService;
53
+ let planetApplicationLoader: PlanetApplicationLoader;
54
+
55
+ beforeEach(() => {
56
+ TestBed.configureTestingModule({
57
+ imports: [
58
+ NgxPlanetModule,
59
+ RouterTestingModule.withRoutes([
60
+ {
61
+ path: '**',
62
+ component: EmptyComponent
63
+ }
64
+ ])
65
+ ]
66
+ });
67
+ planet = TestBed.inject(Planet);
68
+ planetApplicationService = getApplicationService();
69
+ planetApplicationLoader = getApplicationLoader();
70
+ });
71
+
72
+ afterEach(() => {
73
+ clearGlobalPlanet();
74
+ });
75
+
76
+ it('should create planet', () => {
77
+ expect(planet).toBeTruthy();
78
+ });
79
+
80
+ it('should register app1', () => {
81
+ const registerSpy = spyOn(planetApplicationService, 'register');
82
+ expect(registerSpy).not.toHaveBeenCalled();
83
+ planet.registerApp(app1);
84
+ expect(registerSpy).toHaveBeenCalled();
85
+ expect(registerSpy).toHaveBeenCalledWith(app1);
86
+ });
87
+
88
+ it('should register multiple apps', () => {
89
+ const registerSpy = spyOn(planetApplicationService, 'register');
90
+ expect(registerSpy).not.toHaveBeenCalled();
91
+ planet.registerApps([app1, app2]);
92
+ expect(registerSpy).toHaveBeenCalled();
93
+ expect(registerSpy).toHaveBeenCalledWith([app1, app2]);
94
+ });
95
+
96
+ it('should unregister app', () => {
97
+ const unregisterSpy = spyOn(planetApplicationService, 'unregister');
98
+ expect(unregisterSpy).not.toHaveBeenCalled();
99
+ planet.unregisterApp('app1');
100
+ expect(unregisterSpy).toHaveBeenCalled();
101
+ expect(unregisterSpy).toHaveBeenCalledWith('app1');
102
+ });
103
+
104
+ it('should get apps', () => {
105
+ const getAppsSpy = spyOn(planetApplicationService, 'getApps');
106
+ getAppsSpy.and.returnValue([app1, app2]);
107
+ expect(getAppsSpy).not.toHaveBeenCalled();
108
+ const apps = planet.getApps();
109
+ expect(getAppsSpy).toHaveBeenCalled();
110
+ expect(apps).toEqual([app1, app2]);
111
+ });
112
+
113
+ it('should set options success', () => {
114
+ const setOptionsSpy = spyOn(planetApplicationLoader, 'setOptions');
115
+ expect(setOptionsSpy).not.toHaveBeenCalled();
116
+ const options: PlanetOptions = {
117
+ switchMode: SwitchModes.coexist,
118
+ errorHandler: () => {},
119
+ debugFactory: debug
120
+ };
121
+ planet.setOptions(options);
122
+ expect(setOptionsSpy).toHaveBeenCalled();
123
+ expect(setOptionsSpy).toHaveBeenCalledWith(options);
124
+ expect(getDebugFactory()).toEqual(debug);
125
+ setDebugFactory(null);
126
+ });
127
+
128
+ it('should reroute when start or navigateByUrl', fakeAsync(() => {
129
+ const router: Router = TestBed.inject(Router);
130
+ const ngZone: NgZone = TestBed.inject(NgZone);
131
+ const rerouteSpy = spyOn(planetApplicationLoader, 'reroute');
132
+ expect(rerouteSpy).not.toHaveBeenCalled();
133
+ planet.start();
134
+ expect(rerouteSpy).toHaveBeenCalledTimes(1);
135
+
136
+ ngZone.run(() => {
137
+ router.navigateByUrl('/app1/dashboard');
138
+ });
139
+
140
+ tick();
141
+
142
+ expect(rerouteSpy).toHaveBeenCalledTimes(2);
143
+ expect(rerouteSpy).toHaveBeenCalledWith({
144
+ url: '/app1/dashboard'
145
+ });
146
+
147
+ ngZone.run(() => {
148
+ router.navigateByUrl('/app1/users');
149
+ });
150
+ tick();
151
+
152
+ expect(rerouteSpy).toHaveBeenCalledTimes(3);
153
+ expect(rerouteSpy).toHaveBeenCalledWith({
154
+ url: '/app1/users'
155
+ });
156
+ }));
157
+
158
+ it('should load app when redirect to app url "users"', fakeAsync(() => {
159
+ const router: Router = TestBed.inject(Router);
160
+ const ngZone: NgZone = TestBed.inject(NgZone);
161
+ const rerouteSpy = spyOn(planetApplicationLoader, 'reroute');
162
+ router.resetConfig([
163
+ {
164
+ path: '',
165
+ redirectTo: 'users',
166
+ pathMatch: 'full'
167
+ },
168
+ {
169
+ path: 'redirect-to-users',
170
+ redirectTo: 'users',
171
+ pathMatch: 'full'
172
+ },
173
+ {
174
+ path: 'users',
175
+ component: EmptyComponent
176
+ }
177
+ ]);
178
+ let planetRouterEvent!: PlanetRouterEvent;
179
+ rerouteSpy.and.callFake(function(event) {
180
+ planetRouterEvent = event;
181
+ });
182
+ expect(rerouteSpy).toHaveBeenCalledTimes(0);
183
+ planet.start();
184
+ expect(rerouteSpy).toHaveBeenCalledTimes(1);
185
+ ngZone.run(() => {
186
+ router.navigateByUrl('/redirect-to-users');
187
+ });
188
+ tick();
189
+ expect(rerouteSpy).toHaveBeenCalledTimes(2);
190
+ expect(planetRouterEvent.url).toEqual('/users');
191
+ }));
192
+
193
+ it('should reroute not be call when planet stop', fakeAsync(() => {
194
+ const router: Router = TestBed.inject(Router);
195
+ const ngZone: NgZone = TestBed.inject(NgZone);
196
+ const rerouteSpy = spyOn(planetApplicationLoader, 'reroute');
197
+ expect(rerouteSpy).not.toHaveBeenCalled();
198
+ planet.start();
199
+ expect(rerouteSpy).toHaveBeenCalledTimes(1);
200
+
201
+ ngZone.run(() => {
202
+ router.navigateByUrl('/app1/dashboard');
203
+ });
204
+
205
+ tick();
206
+
207
+ expect(rerouteSpy).toHaveBeenCalledTimes(2);
208
+ expect(rerouteSpy).toHaveBeenCalledWith({
209
+ url: '/app1/dashboard'
210
+ });
211
+
212
+ planet.stop();
213
+
214
+ ngZone.run(() => {
215
+ router.navigateByUrl('/app1/users');
216
+ });
217
+ tick();
218
+
219
+ // rerouteSpy should not be call
220
+ // url should not change
221
+ expect(rerouteSpy).toHaveBeenCalledTimes(2);
222
+ expect(rerouteSpy).toHaveBeenCalledWith({
223
+ url: '/app1/dashboard'
224
+ });
225
+ }));
226
+ });
@@ -0,0 +1,113 @@
1
+ import { Injectable, Inject, Optional, Injector } from '@angular/core';
2
+ import { NavigationEnd, RouterEvent, Router } from '@angular/router';
3
+ import { PlanetOptions, PlanetApplication, PLANET_APPLICATIONS } from './planet.class';
4
+ import { PlanetApplicationService } from './application/planet-application.service';
5
+ import {
6
+ PlanetApplicationLoader,
7
+ AppsLoadingStartEvent,
8
+ AppStatusChangeEvent
9
+ } from './application/planet-application-loader';
10
+ import { Observable, Subscription } from 'rxjs';
11
+ import { filter, startWith, distinctUntilChanged, map } from 'rxjs/operators';
12
+ import {
13
+ setPortalApplicationData,
14
+ setApplicationLoader,
15
+ setApplicationService,
16
+ getApplicationLoader,
17
+ getApplicationService
18
+ } from './global-planet';
19
+ import { setDebugFactory } from './debug';
20
+
21
+ @Injectable({
22
+ providedIn: 'root'
23
+ })
24
+ export class Planet {
25
+ private get planetApplicationLoader(): PlanetApplicationLoader {
26
+ return getApplicationLoader();
27
+ }
28
+
29
+ private get planetApplicationService() {
30
+ return getApplicationService();
31
+ }
32
+
33
+ public get loadingDone() {
34
+ return this.planetApplicationLoader.loadingDone;
35
+ }
36
+
37
+ public get appStatusChange(): Observable<AppStatusChangeEvent> {
38
+ return this.planetApplicationLoader.appStatusChange;
39
+ }
40
+
41
+ public get appsLoadingStart(): Observable<AppsLoadingStartEvent> {
42
+ return this.planetApplicationLoader.appsLoadingStart;
43
+ }
44
+
45
+ private subscription?: Subscription;
46
+
47
+ constructor(
48
+ private injector: Injector,
49
+ private router: Router,
50
+ @Inject(PLANET_APPLICATIONS) @Optional() planetApplications: PlanetApplication[]
51
+ ) {
52
+ if (!this.planetApplicationLoader) {
53
+ setApplicationLoader(this.injector.get(PlanetApplicationLoader));
54
+ }
55
+ if (!this.planetApplicationService) {
56
+ setApplicationService(this.injector.get(PlanetApplicationService));
57
+ }
58
+
59
+ if (planetApplications) {
60
+ this.registerApps(planetApplications);
61
+ }
62
+ }
63
+
64
+ setOptions(options: Partial<PlanetOptions>) {
65
+ this.planetApplicationLoader.setOptions(options);
66
+ if (options.debugFactory) {
67
+ setDebugFactory(options.debugFactory);
68
+ }
69
+ }
70
+
71
+ setPortalAppData<T>(data: T) {
72
+ setPortalApplicationData(data);
73
+ }
74
+
75
+ registerApp<TExtra>(app: PlanetApplication<TExtra>) {
76
+ this.planetApplicationService.register(app);
77
+ }
78
+
79
+ registerApps<TExtra>(apps: PlanetApplication<TExtra>[]) {
80
+ this.planetApplicationService.register(apps);
81
+ }
82
+
83
+ unregisterApp(name: string) {
84
+ this.planetApplicationService.unregister(name);
85
+ }
86
+
87
+ getApps() {
88
+ return this.planetApplicationService.getApps();
89
+ }
90
+
91
+ start() {
92
+ this.subscription = (this.router.events as Observable<RouterEvent>)
93
+ .pipe(
94
+ filter(event => {
95
+ return event instanceof NavigationEnd;
96
+ }),
97
+ map(event => {
98
+ return (event as NavigationEnd).urlAfterRedirects || event.url;
99
+ }),
100
+ startWith(location.pathname),
101
+ distinctUntilChanged()
102
+ )
103
+ .subscribe((url: string) => {
104
+ this.planetApplicationLoader.reroute({
105
+ url: url
106
+ });
107
+ });
108
+ }
109
+
110
+ stop() {
111
+ this.subscription?.unsubscribe();
112
+ }
113
+ }
@@ -1,3 +1,7 @@
1
+ /*
2
+ * Public API Surface of core
3
+ */
4
+
1
5
  export * from './planet';
2
6
  export * from './global-event-dispatcher';
3
7
  export * from './application/portal-application';
@@ -0,0 +1,6 @@
1
+ export const PLANET_SANDBOX_WINDOW_WHITELIST = window['___PLANET_SANDBOX_WINDOW_WHITELIST___'];
2
+ export const PLANET_SANDBOX_DOCUMENT_WHITELIST = window['___PLANET_SANDBOX_DOCUMENT_WHITELIST___'];
3
+ export const SANDBOX_INSTANCE = Symbol.for('PLANET_SANDBOX_INSTANCE');
4
+ export const RAW_NODE = Symbol.for('PLANET_RAW_NODE');
5
+ export const WINDOW_BIND_FN = Symbol.for('PLANET_WINDOW_BIND_FN');
6
+ export const DOCUMENT_BIND_FN = Symbol.for('PLANET_DOCUMENT_BIND_FN');
@@ -0,0 +1,22 @@
1
+ import { Global } from './types';
2
+
3
+ export function execScript(code: string, url: string, global: Global, strictGlobal: boolean) {
4
+ const sourceUrl = '//# sourceURL='.concat(url, '\n');
5
+ const window = (0, eval)('window');
6
+ window.tempGlobal = global;
7
+ code = strictGlobal
8
+ ? ';(function(window, self, globalThis){with(window){;'
9
+ .concat(code, '\n')
10
+ .concat(
11
+ sourceUrl,
12
+ '}}).bind(window.tempGlobal)(window.tempGlobal, window.tempGlobal, window.tempGlobal);'
13
+ )
14
+ : ';(function(window, self, globalThis){;'
15
+ .concat(code, '\n')
16
+ .concat(
17
+ sourceUrl,
18
+ '}).bind(window.tempGlobal)(window.tempGlobal, window.tempGlobal, window.tempGlobal);'
19
+ );
20
+ (0, eval)(code);
21
+ delete window.tempGlobal;
22
+ }
@@ -0,0 +1,24 @@
1
+ import { SandboxOptions } from './sandbox';
2
+ import { ProxySandbox } from './proxy/proxy-sandbox';
3
+ import { SnapshotSandbox } from './snapshot/snapshot-sandbox';
4
+ import { SANDBOX_INSTANCE } from './constants';
5
+
6
+ export { Sandbox } from './sandbox';
7
+
8
+ const defaultOptions: Partial<SandboxOptions> = {
9
+ strictGlobal: false
10
+ };
11
+
12
+ export function createSandbox(app: string, options?: SandboxOptions) {
13
+ options = Object.assign({}, defaultOptions, options || {});
14
+
15
+ if (window.Proxy) {
16
+ return new ProxySandbox(app, options);
17
+ } else {
18
+ return new SnapshotSandbox(app, options);
19
+ }
20
+ }
21
+
22
+ export function getSandboxInstance() {
23
+ return window[SANDBOX_INSTANCE];
24
+ }