neo.mjs 3.2.10 → 4.0.2

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.
package/README.md CHANGED
@@ -19,6 +19,8 @@ No need to take care of a workers setup, and the cross channel communication on
19
19
  <a href="https://youtu.be/aEA5333WiWY"><img height="316px" width="400px" src="https://raw.githubusercontent.com/neomjs/pages/master/resources/images/neo-movie.png"></a>
20
20
  </p>
21
21
 
22
+ <a href="https://tobiasuhlig.medium.com/predictive-offline-support-for-assets-you-have-not-used-yet-aeeccccd3754?source=friends_link&sk=e946e0f25f508e6a8cec4136400291a3">Version 4 release announcement</a>
23
+
22
24
  ## Content
23
25
  1. <a href="#slack-channel">Slack Channel for questions & feedback</a>
24
26
  2. <a href="#architectures">Scalable frontend architectures</a>
@@ -1,4 +1,30 @@
1
1
  [
2
+ {
3
+ "author" : "Tobias Uhlig",
4
+ "authorImage" : "author_TobiasUhlig.jpeg",
5
+ "date" : "Mar 28, 2022",
6
+ "id" : 51,
7
+ "image" : "predictive-offline-support-for-assets-you-have-not-used-yet.png",
8
+ "name" : "Predictive offline support for assets you have not used yet",
9
+ "provider" : "Medium",
10
+ "publisher" : "ITNEXT",
11
+ "selectedInto": [],
12
+ "type" : "Blog Post",
13
+ "url" : "https://itnext.io/predictive-offline-support-for-assets-you-have-not-used-yet-aeeccccd3754?source=friends_link&sk=e946e0f25f508e6a8cec4136400291a3"
14
+ },
15
+ {
16
+ "author" : "Tobias Uhlig",
17
+ "authorImage" : "author_TobiasUhlig.jpeg",
18
+ "date" : "Jan 31, 2022",
19
+ "id" : 50,
20
+ "image" : "clean-architectures-your-benefits-of-using-view-controllers.png",
21
+ "name" : "Clean architectures: Your benefits of using view controllers",
22
+ "provider" : "Medium",
23
+ "publisher" : "ITNEXT",
24
+ "selectedInto": [],
25
+ "type" : "Blog Post",
26
+ "url" : "https://itnext.io/clean-architectures-your-benefits-of-using-view-controllers-7ce6b00f0ad5?source=friends_link&sk=ebef34d36d5d307c7985ba4dedb261f9"
27
+ },
2
28
  {
3
29
  "author" : "Tobias Uhlig",
4
30
  "authorImage" : "author_TobiasUhlig.jpeg",
@@ -32,6 +32,7 @@ program
32
32
  .option('-i, --info', 'print environment debug info')
33
33
  .option('-a, --appName <value>')
34
34
  .option('-m, --mainThreadAddons <value>', `Comma separated list of:\n${addonChoices.join(', ')}\nDefaults to DragDrop, Stylesheet`)
35
+ .option('-s, --useServiceWorker <value>', '"yes", "no"')
35
36
  .option('-t, --themes <value>', ['all', ...themeFolders, 'none'].join(", "))
36
37
  .option('-u, --useSharedWorkers <value>', '"yes", "no"')
37
38
  .allowUnknownOption()
@@ -105,11 +106,22 @@ if (programOpts.info) {
105
106
  });
106
107
  }
107
108
 
109
+ if (!programOpts.useServiceWorker) {
110
+ questions.push({
111
+ type : 'list',
112
+ name : 'useServiceWorker',
113
+ message: 'Do you want to use a ServiceWorker for caching assets?',
114
+ choices: ['yes', 'no'],
115
+ default: 'no'
116
+ });
117
+ }
118
+
108
119
  inquirer.prompt(questions).then(answers => {
109
120
  let appName = programOpts.appName || answers.appName,
110
121
  mainThreadAddons = programOpts.mainThreadAddons || answers.mainThreadAddons,
111
122
  themes = programOpts.themes || answers.themes,
112
123
  useSharedWorkers = programOpts.useSharedWorkers || answers.useSharedWorkers,
124
+ useServiceWorker = programOpts.useServiceWorker || answers.useServiceWorker,
113
125
  lAppName = appName.toLowerCase(),
114
126
  appPath = 'apps/' + lAppName + '/',
115
127
  dir = 'apps/' + lAppName,
@@ -181,6 +193,10 @@ if (programOpts.info) {
181
193
  neoConfig.useSharedWorkers = true;
182
194
  }
183
195
 
196
+ if (useServiceWorker !== 'no') {
197
+ neoConfig.useServiceWorker = true;
198
+ }
199
+
184
200
  if (!insideNeo) {
185
201
  neoConfig.workerBasePath = '../../node_modules/neo.mjs/src/worker/';
186
202
  }
@@ -0,0 +1,55 @@
1
+ import Button from '../../../src/button/Base.mjs';
2
+ import MainContainerController from './MainContainerController.mjs';
3
+ import Toolbar from '../../../src/container/Toolbar.mjs';
4
+ import Viewport from '../../../src/container/Viewport.mjs';
5
+
6
+ /**
7
+ * @class Neo.examples.remotesApi.basic.MainContainer
8
+ * @extends Neo.container.Viewport
9
+ */
10
+ class MainContainer extends Viewport {
11
+ static getConfig() {return {
12
+ className : 'Neo.examples.remotesApi.basic.MainContainer',
13
+ autoMount : true,
14
+ controller: MainContainerController,
15
+ layout : {ntype: 'vbox', align: 'stretch'},
16
+
17
+ items: [{
18
+ module : Toolbar,
19
+ flex : 'none',
20
+ padding : 20,
21
+ reference: 'headerToolbar',
22
+
23
+ style: {
24
+ backgroundColor: '#f2f2f2',
25
+ padding : '10px 5px 10px 10px'
26
+ },
27
+
28
+ items: [{
29
+ module : Button,
30
+ handler: 'onGetAllUsersButtonClick',
31
+ height : 27,
32
+ iconCls: 'fa fa-users',
33
+ text : 'Get all users'
34
+ }, {
35
+ module : Button,
36
+ handler: 'onGetAllFriendsButtonClick',
37
+ height : 27,
38
+ iconCls: 'fab fa-github',
39
+ style : {marginLeft: '5px'},
40
+ text : 'Get all friends'
41
+ }, {
42
+ module : Button,
43
+ handler: 'onGetAllUsersPlusFriendsButtonClick',
44
+ height : 27,
45
+ iconCls: 'fa-regular fa-heart',
46
+ style : {marginLeft: '5px'},
47
+ text : 'Get users & friends'
48
+ }]
49
+ }]
50
+ }}
51
+ }
52
+
53
+ Neo.applyClassConfig(MainContainer);
54
+
55
+ export default MainContainer;
@@ -0,0 +1,45 @@
1
+ import ComponentController from '../../../src/controller/Component.mjs';
2
+
3
+ /**
4
+ * @class Neo.examples.remotesApi.basic.MainContainerController
5
+ * @extends Neo.controller.Component
6
+ */
7
+ class MainContainerController extends ComponentController {
8
+ static getConfig() {return {
9
+ /**
10
+ * @member {String} className='Neo.examples.remotesApi.basic.MainContainerController'
11
+ * @protected
12
+ */
13
+ className: 'Neo.examples.remotesApi.basic.MainContainerController'
14
+ }}
15
+
16
+ /**
17
+ * @param {Object} data
18
+ */
19
+ onGetAllFriendsButtonClick(data) {
20
+ MyApi.UserService.getAll().then(response => console.log(response))
21
+ }
22
+
23
+ /**
24
+ * @param {Object} data
25
+ */
26
+ onGetAllUsersButtonClick(data) {
27
+ MyApi.FriendService.getAll()
28
+ }
29
+
30
+ /**
31
+ * @param {Object} data
32
+ */
33
+ async onGetAllUsersPlusFriendsButtonClick(data) {
34
+ await Promise.all([
35
+ MyApi.UserService.getAll(),
36
+ MyApi.FriendService.getAll()
37
+ ]);
38
+
39
+ console.log('Both calls are done')
40
+ }
41
+ }
42
+
43
+ Neo.applyClassConfig(MainContainerController);
44
+
45
+ export default MainContainerController;
@@ -0,0 +1,6 @@
1
+ import MainContainer from './MainContainer.mjs';
2
+
3
+ export const onStart = () => Neo.app({
4
+ mainView: MainContainer,
5
+ name : 'Neo.examples.remotesApi.basic'
6
+ });
@@ -0,0 +1,11 @@
1
+ <!DOCTYPE HTML>
2
+ <html>
3
+ <head>
4
+ <meta name="viewport" content="width=device-width, initial-scale=1">
5
+ <meta charset="UTF-8">
6
+ <title>Remotes API Basic</title>
7
+ </head>
8
+ <body>
9
+ <script src="../../../src/MicroLoader.mjs" type="module"></script>
10
+ </body>
11
+ </html>
@@ -0,0 +1,7 @@
1
+ {
2
+ "appPath" : "examples/remotesApi/basic/app.mjs",
3
+ "basePath" : "../../../",
4
+ "environment" : "development",
5
+ "mainPath" : "./Main.mjs",
6
+ "remotesApiUrl": "remotes-api.json"
7
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "namespace": "MyApi",
3
+ "url" : "./",
4
+
5
+ "services": [{
6
+ "name" : "FriendService",
7
+ "methods": [{
8
+ "name": "getAll"
9
+ }]
10
+ }, {
11
+ "name" : "UserService",
12
+ "methods": [{
13
+ "name": "getAll"
14
+ }]
15
+ }]
16
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neo.mjs",
3
- "version": "3.2.10",
3
+ "version": "4.0.2",
4
4
  "description": "The webworkers driven UI framework",
5
5
  "type": "module",
6
6
  "repository": {
@@ -34,25 +34,25 @@
34
34
  },
35
35
  "homepage": "https://neomjs.github.io/pages/",
36
36
  "dependencies": {
37
- "@fortawesome/fontawesome-free": "^6.1.0",
37
+ "@fortawesome/fontawesome-free": "^6.1.1",
38
38
  "@material/mwc-button": "^0.25.3",
39
39
  "@material/mwc-textfield": "^0.25.3",
40
40
  "autoprefixer": "^10.4.4",
41
41
  "chalk": "^5.0.1",
42
42
  "clean-webpack-plugin": "^4.0.0",
43
43
  "commander": "^9.1.0",
44
- "cssnano": "^5.1.4",
44
+ "cssnano": "^5.1.7",
45
45
  "envinfo": "^7.8.1",
46
46
  "fs-extra": "^10.0.1",
47
47
  "highlightjs-line-numbers.js": "^2.8.0",
48
- "inquirer": "^8.2.1",
48
+ "inquirer": "^8.2.2",
49
49
  "neo-jsdoc": "^1.0.1",
50
50
  "neo-jsdoc-x": "^1.0.4",
51
51
  "postcss": "^8.4.12",
52
- "sass": "^1.49.9",
53
- "webpack": "^5.70.0",
52
+ "sass": "^1.50.0",
53
+ "webpack": "^5.72.0",
54
54
  "webpack-cli": "^4.9.2",
55
- "webpack-dev-server": "4.7.4",
55
+ "webpack-dev-server": "4.8.1",
56
56
  "webpack-hook-plugin": "^1.0.7",
57
57
  "webpack-node-externals": "^3.0.0"
58
58
  },
@@ -96,6 +96,16 @@ const DefaultConfig = {
96
96
  * @type String[]
97
97
  */
98
98
  mainThreadAddons: ['DragDrop', 'Stylesheet'],
99
+ /**
100
+ * Pass the URL of a JSON-file, which contains the services and methods from your backend,
101
+ * which you want to expose to the client.
102
+ * See: https://github.com/neomjs/neo/projects/32
103
+ * @default null
104
+ * @memberOf! module:Neo
105
+ * @name config.remotesApiUrl
106
+ * @type String|null
107
+ */
108
+ remotesApiUrl: null,
99
109
  /**
100
110
  * You can visually show the amount of delta updates per second using this config.
101
111
  * It expects a dom node with the id "neo-delta-updates" as the rendering target.
package/src/Fetch.mjs ADDED
@@ -0,0 +1,44 @@
1
+ import FetchConnection from './data/connection/Fetch.mjs';
2
+
3
+ /**
4
+ * @class Neo.Fetch
5
+ * @extends Neo.data.connection.Fetch
6
+ * @singleton
7
+ */
8
+ class Fetch extends FetchConnection {
9
+ static getConfig() {return {
10
+ /**
11
+ * @member {String} className='Neo.Fetch'
12
+ * @protected
13
+ */
14
+ className: 'Neo.Fetch',
15
+ /**
16
+ * @member {Object} remote
17
+ * @protected
18
+ */
19
+ remote: {
20
+ app: [
21
+ 'delete',
22
+ 'get',
23
+ 'head',
24
+ 'options',
25
+ 'patch',
26
+ 'post',
27
+ 'put'
28
+ ]
29
+ },
30
+ /**
31
+ * @member {Boolean} singleton=true
32
+ * @protected
33
+ */
34
+ singleton: true
35
+ }}
36
+ }
37
+
38
+ Neo.applyClassConfig(Fetch);
39
+
40
+ let instance = Neo.create(Fetch);
41
+
42
+ Neo.applyToGlobalNs(instance);
43
+
44
+ export default instance;
@@ -96,14 +96,12 @@ class MapboxGL extends Component {
96
96
  afterSetChartData(value, oldValue) {
97
97
  let me = this;
98
98
 
99
- if (value) {
100
- Neo.main.addon.MapboxGL.updateData({
101
- appName : me.appName,
102
- data : value,
103
- dataSourceId: me.dataSourceId,
104
- id : me.id
105
- });
106
- }
99
+ value && Neo.main.addon.MapboxGL.updateData({
100
+ appName : me.appName,
101
+ data : value,
102
+ dataSourceId: me.dataSourceId,
103
+ id : me.id
104
+ });
107
105
  }
108
106
 
109
107
  /**
@@ -113,13 +111,11 @@ class MapboxGL extends Component {
113
111
  * @protected
114
112
  */
115
113
  afterSetLayers(value, oldValue) {
116
- if (value) {
117
- Neo.main.addon.MapboxGL.addLayers({
118
- appName: this.appName,
119
- id : this.id,
120
- layers : value
121
- });
122
- }
114
+ value && Neo.main.addon.MapboxGL.addLayers({
115
+ appName: this.appName,
116
+ id : this.id,
117
+ layers : value
118
+ });
123
119
  }
124
120
 
125
121
  /**
@@ -131,14 +127,12 @@ class MapboxGL extends Component {
131
127
  afterSetMapboxStyle(value, oldValue) {
132
128
  let me = this;
133
129
 
134
- if (this.mounted) {
135
- Neo.main.addon.MapboxGL.setStyle({
136
- accessToken: me.accessToken,
137
- appName : me.appName,
138
- id : me.id,
139
- style : value
140
- });
141
- }
130
+ me.mounted && Neo.main.addon.MapboxGL.setStyle({
131
+ accessToken: me.accessToken,
132
+ appName : me.appName,
133
+ id : me.id,
134
+ style : value
135
+ });
142
136
  }
143
137
 
144
138
  /**
@@ -193,13 +187,11 @@ class MapboxGL extends Component {
193
187
  * @protected
194
188
  */
195
189
  afterSetSources(value, oldValue) {
196
- if (value) {
197
- Neo.main.addon.MapboxGL.addSources({
198
- appName: this.appName,
199
- id : this.id,
200
- sources: value
201
- });
202
- }
190
+ value && Neo.main.addon.MapboxGL.addSources({
191
+ appName: this.appName,
192
+ id : this.id,
193
+ sources: value
194
+ });
203
195
  }
204
196
 
205
197
  /**
@@ -211,13 +203,11 @@ class MapboxGL extends Component {
211
203
  afterSetZoom(value, oldValue) {
212
204
  let me = this;
213
205
 
214
- if (me.mounted) {
215
- Neo.main.addon.MapboxGL.zoom({
216
- appName: me.appName,
217
- id : me.id,
218
- zoom : value
219
- });
220
- }
206
+ me.mounted && Neo.main.addon.MapboxGL.zoom({
207
+ appName: me.appName,
208
+ id : me.id,
209
+ zoom : value
210
+ });
221
211
  }
222
212
 
223
213
  /**
@@ -269,7 +259,7 @@ class MapboxGL extends Component {
269
259
  */
270
260
  centerMap(value, animate=false) {
271
261
  Neo.main.addon.MapboxGL.center({
272
- animate: animate,
262
+ animate,
273
263
  appName: this.appName,
274
264
  id : this.id,
275
265
  lat : value.lat,
@@ -317,7 +307,7 @@ class MapboxGL extends Component {
317
307
  * @param {Number} value.lng
318
308
  */
319
309
  flyTo(value) {
320
- const me = this;
310
+ let me = this;
321
311
 
322
312
  value = me.beforeSetCenter(value, null); // long => lng if needed
323
313
 
@@ -0,0 +1,121 @@
1
+ import Base from '../../core/Base.mjs';
2
+
3
+ /**
4
+ * @class Neo.data.connection.Fetch
5
+ * @extends Neo.core.Base
6
+ */
7
+ class Fetch extends Base {
8
+ /**
9
+ * @member {Object} defaultHeaders=null
10
+ */
11
+ defaultHeaders = null
12
+
13
+ static getConfig() {return {
14
+ /**
15
+ * @member {String} className='Neo.data.connection.Fetch'
16
+ * @protected
17
+ */
18
+ className: 'Neo.data.connection.Fetch'
19
+ }}
20
+
21
+ /**
22
+ * @param {Object|String} url
23
+ * @param {Object} config
24
+ * @returns {Promise<any>}
25
+ */
26
+ delete(url, config) {
27
+ return this.request(url, config, 'delete');
28
+ }
29
+
30
+ /**
31
+ * @param {Object|String} url
32
+ * @param {Object} config
33
+ * @returns {Promise<any>}
34
+ */
35
+ get(url, config) {
36
+ return this.request(url, config, 'get');
37
+ }
38
+
39
+ /**
40
+ * @param {Object|String} url
41
+ * @param {Object} config
42
+ * @returns {Promise<any>}
43
+ */
44
+ head(url, config) {
45
+ return this.request(url, config, 'head');
46
+ }
47
+
48
+ /**
49
+ * @param {Object|String} url
50
+ * @param {Object} config
51
+ * @returns {Promise<any>}
52
+ */
53
+ options(url, config) {
54
+ return this.request(url, config, 'options');
55
+ }
56
+
57
+ /**
58
+ * @param {Object|String} url
59
+ * @param {Object} config
60
+ * @param {Object} data
61
+ * @returns {Promise<any>}
62
+ */
63
+ patch(url, config, data) {
64
+ return this.request(url, config, 'patch', data);
65
+ }
66
+
67
+ /**
68
+ * @param {Object|String} url
69
+ * @param {Object} config
70
+ * @param {Object} data
71
+ * @returns {Promise<any>}
72
+ */
73
+ post(url, config, data) {
74
+ return this.request(url, config, 'post', data);
75
+ }
76
+
77
+ /**
78
+ * @param {Object|String} url
79
+ * @param {Object} config
80
+ * @param {Object} data
81
+ * @returns {Promise<any>}
82
+ */
83
+ put(url, config, data) {
84
+ return this.request(url, config, 'put', data);
85
+ }
86
+
87
+ /**
88
+ * @param {Object|String} url
89
+ * @param {Object} config
90
+ * @param {String} method
91
+ * @param {Object} [data]
92
+ * @returns {Promise<any>}
93
+ */
94
+ request(url, config, method, data) {
95
+ if (!Neo.isString(url)) {
96
+ config = url;
97
+ url = config.url;
98
+ }
99
+
100
+ return fetch(url)
101
+ .then(resp => {
102
+ console.log(resp);
103
+
104
+ let response = {
105
+ ok : resp.ok,
106
+ redirected: resp.redirected,
107
+ request : config,
108
+ status : resp.status,
109
+ statusText: resp.statusText,
110
+ type : resp.type,
111
+ url : resp.url
112
+ };
113
+
114
+ return response
115
+ })
116
+ }
117
+ }
118
+
119
+ Neo.applyClassConfig(Fetch);
120
+
121
+ export default Fetch;
@@ -1,6 +1,5 @@
1
- import Base from '../../core/Base.mjs';
2
- import RemoteMethodAccess from '../../worker/mixin/RemoteMethodAccess.mjs';
3
- import WorkerManager from '../../worker/Manager.mjs';
1
+ import Base from '../../core/Base.mjs';
2
+ import WorkerManager from '../../worker/Manager.mjs';
4
3
 
5
4
  /**
6
5
  * Creates a ServiceWorker instance, in case Neo.config.useServiceWorker is set to true
@@ -15,15 +14,6 @@ class ServiceWorker extends Base {
15
14
  * @protected
16
15
  */
17
16
  className: 'Neo.main.addon.ServiceWorker',
18
- /**
19
- * @member {String[]|Neo.core.Base[]|null} mixins=[RemoteMethodAccess]
20
- */
21
- mixins: [RemoteMethodAccess],
22
- /**
23
- * @member {ServiceWorkerRegistration|null} registration=null
24
- * @protected
25
- */
26
- registration: null,
27
17
  /**
28
18
  * @member {Boolean} singleton=true
29
19
  * @protected
@@ -45,22 +35,30 @@ class ServiceWorker extends Base {
45
35
  path = (devMode ? config.basePath : config.workerBasePath) + (devMode ? folder : '') + fileName,
46
36
  serviceWorker = navigator.serviceWorker;
47
37
 
38
+ window.addEventListener('beforeunload', me.onBeforeUnload.bind(me));
39
+
48
40
  serviceWorker.register(path, opts)
49
41
  .then(registration => {
50
- me.registration = registration;
51
-
52
42
  serviceWorker.ready.then(() => {
53
43
  serviceWorker.onmessage = WorkerManager.onWorkerMessage.bind(WorkerManager);
54
44
 
55
45
  WorkerManager.sendMessage('service', {
56
- action : 'registerNeoConfig',
57
- channelPort: registration.active,
58
- data : config
46
+ action: 'registerNeoConfig',
47
+ data : config
59
48
  });
60
49
  });
61
50
  })
62
51
  }
63
52
  }
53
+
54
+ /**
55
+ *
56
+ */
57
+ onBeforeUnload() {
58
+ WorkerManager.sendMessage('service', {
59
+ action: 'unregisterPort'
60
+ });
61
+ }
64
62
  }
65
63
 
66
64
  Neo.applyClassConfig(ServiceWorker);
@@ -0,0 +1,78 @@
1
+ import Base from '../core/Base.mjs';
2
+
3
+ /**
4
+ * @class Neo.remotes.Api
5
+ * @extends Neo.core.Base
6
+ * @singleton
7
+ */
8
+ class Api extends Base {
9
+ static getConfig() {return {
10
+ /**
11
+ * @member {String} className='Neo.remotes.Api'
12
+ * @protected
13
+ */
14
+ className: 'Neo.remotes.Api',
15
+ /**
16
+ * @member {Boolean} singleton=true
17
+ * @protected
18
+ */
19
+ singleton: true
20
+ }}
21
+
22
+ /**
23
+ * @param {String} service
24
+ * @param {String} method
25
+ * @returns {function(*=, *=): Promise<any>}
26
+ */
27
+ generateRemote(service, method) {
28
+ return function(...args) {
29
+ return Neo.currentWorker.promiseMessage('data', {
30
+ action: 'rpc',
31
+ method,
32
+ params: [...args],
33
+ service
34
+ })
35
+ }
36
+ }
37
+
38
+ /**
39
+ *
40
+ */
41
+ load() {
42
+ let config = Neo.config,
43
+ path = config.remotesApiUrl;
44
+
45
+ // relative paths need a special treatment
46
+ if (!path.includes('http')) {
47
+ path = config.appPath.split('/');
48
+ path.pop();
49
+ path = `../../${path.join('/')}/${config.remotesApiUrl}`;
50
+ }
51
+
52
+ fetch(path)
53
+ .then(response => response.json())
54
+ .then(data => {this.register(data)})
55
+ }
56
+
57
+ /**
58
+ * @param {Object} data
59
+ */
60
+ register(data) {
61
+ let method, ns, service;
62
+
63
+ for (service of data.services) {
64
+ for (method of service.methods) {
65
+ ns = Neo.ns(`${data.namespace}.${service.name}`, true);
66
+ ns[method.name] = this.generateRemote(service.name, method.name);
67
+ }
68
+ }
69
+ }
70
+ }
71
+
72
+ Neo.applyClassConfig(Api);
73
+
74
+ let instance = Neo.create(Api);
75
+
76
+ Neo.applyToGlobalNs(instance);
77
+
78
+ export default instance;
@@ -185,27 +185,26 @@ class App extends Base {
185
185
  * @param {Object} data
186
186
  */
187
187
  onLoadApplication(data) {
188
- let me = this,
188
+ let me = this,
189
+ config = Neo.config,
189
190
  path;
190
191
 
191
192
  if (data) {
192
193
  me.data = data;
193
- Neo.config.resourcesPath = data.resourcesPath;
194
+ config.resourcesPath = data.resourcesPath;
194
195
  }
195
196
 
196
197
  path = me.data.path;
197
198
 
198
- if (Neo.config.environment !== 'development') {
199
+ if (config.environment !== 'development') {
199
200
  path = path.startsWith('/') ? path.substring(1) : path;
200
201
  }
201
202
 
202
203
  me.importApp(path).then(module => {
203
204
  module.onStart();
204
205
 
205
- if (Neo.config.hash) {
206
- // short delay to ensure Component Controllers are ready
207
- setTimeout(() => HashHistory.push(Neo.config.hash), 5);
208
- }
206
+ // short delay to ensure Component Controllers are ready
207
+ config.hash && setTimeout(() => HashHistory.push(config.hash), 5);
209
208
  });
210
209
  }
211
210
 
@@ -216,7 +215,7 @@ class App extends Base {
216
215
  super.onRegisterNeoConfig(msg);
217
216
 
218
217
  let config = Neo.config,
219
- url = `resources/theme-map${Neo.config.useCssVars ? '' : '-no-vars'}.json`;
218
+ url = `resources/theme-map${config.useCssVars ? '' : '-no-vars'}.json`;
220
219
 
221
220
  if (config.environment === 'development') {
222
221
  url = `../../${url}`;
@@ -234,6 +233,7 @@ class App extends Base {
234
233
  .then(response => response.json())
235
234
  .then(data => {this.createThemeMap(data)});
236
235
 
236
+ config.remotesApiUrl && import('../remotes/Api.mjs').then(module => module.default.load());
237
237
  !config.useVdomWorker && import('../vdom/Helper.mjs');
238
238
  }
239
239
 
@@ -1,6 +1,7 @@
1
1
  import Neo from '../Neo.mjs';
2
2
  import Base from './Base.mjs';
3
3
  import Compare from '../core/Compare.mjs';
4
+ import Fetch from '../Fetch.mjs';
4
5
  import StoreManager from '../manager/Store.mjs';
5
6
  import Util from '../core/Util.mjs';
6
7
  import Xhr from '../Xhr.mjs';
@@ -52,6 +53,26 @@ class Data extends Base {
52
53
  onLoad() {
53
54
  console.log('worker.Data onLoad');
54
55
  }
56
+
57
+ /**
58
+ * @param {Object} msg
59
+ */
60
+ async onRpc(msg) {
61
+ console.log('onRpc', msg);
62
+
63
+ let response = await Neo.Fetch.get(msg);
64
+
65
+ this.resolve(msg, response);
66
+ }
67
+
68
+ /**
69
+ * Just for testing
70
+ * @param {Number} ms
71
+ * @returns {Promise<unknown>}
72
+ */
73
+ timeout(ms) {
74
+ return new Promise(resolve => setTimeout(resolve, ms));
75
+ }
55
76
  }
56
77
 
57
78
  Neo.applyClassConfig(Data);
@@ -257,6 +257,19 @@ class ServiceBase extends Base {
257
257
  this.onConnect(event.source);
258
258
  }
259
259
 
260
+ /**
261
+ * @param {Object} msg
262
+ * @param {ExtendableMessageEvent} event
263
+ */
264
+ onUnregisterPort(msg, event) {
265
+ for (let [index, value] of this.channelPorts.entries()) {
266
+ if (value.clientId === event.source.id) {
267
+ this.channelPorts.splice(index, 1);
268
+ break;
269
+ }
270
+ }
271
+ }
272
+
260
273
  /**
261
274
  * @param {Object} data
262
275
  * @param {String} [data.cacheName=this.cacheName]
@@ -37,12 +37,12 @@ class RemoteMethodAccess extends Base {
37
37
  };
38
38
 
39
39
  if (me.isSharedWorker) {
40
- opts.appName = opts.appName || data?.appName;
41
- opts.port = opts.port || data?.port;
40
+ opts.appName = data?.appName;
41
+ opts.port = data?.port;
42
42
  }
43
43
 
44
44
  return me.promiseMessage(origin, opts, buffer);
45
- };
45
+ }
46
46
  }
47
47
 
48
48
  /**