neo.mjs 3.2.7 → 3.2.10

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
@@ -54,7 +54,7 @@ neo.mjs offers two different setups which follow the exact same API.
54
54
  You can switch between <a href="https://developer.mozilla.org/en-US/docs/Web/API/Worker">dedicated</a> and
55
55
  <a href="https://developer.mozilla.org/en-US/docs/Web/API/SharedWorker">shared</a> workers at any point.
56
56
 
57
- <img src="https://raw.githubusercontent.com/neomjs/pages/master/resources/images/workers-setup-canvas.png">
57
+ <img src="https://raw.githubusercontent.com/neomjs/pages/master/resources/images/workers-setup-v4.png">
58
58
 
59
59
  The dedicated workers setup uses 4 threads (CPUs).
60
60
  Most parts of the frameworks as well as your apps and components live within the app worker.
@@ -8,6 +8,12 @@ import ServiceBase from '../src/worker/ServiceBase.mjs';
8
8
  * @singleton
9
9
  */
10
10
  class ServiceWorker extends ServiceBase {
11
+ /**
12
+ * @member {String} workerId='service'
13
+ * @protected
14
+ */
15
+ workerId = 'service'
16
+
11
17
  static getConfig() {return {
12
18
  /**
13
19
  * @member {String} className='Neo.ServiceWorker'
@@ -18,12 +24,7 @@ class ServiceWorker extends ServiceBase {
18
24
  * @member {Boolean} singleton=true
19
25
  * @protected
20
26
  */
21
- singleton: true,
22
- /**
23
- * @member {String} workerId='service'
24
- * @protected
25
- */
26
- workerId: 'service'
27
+ singleton: true
27
28
  }}
28
29
  }
29
30
 
@@ -15,8 +15,10 @@ export default env => {
15
15
 
16
16
  if (filenameConfig.workers) {
17
17
  Object.entries(filenameConfig.workers).forEach(([key, value]) => {
18
+ // Inside a neo workspace, we want to use the SW inside the top level apps folder,
19
+ // to allow overriding its logic
18
20
  if (key === env.worker) {
19
- entry[key] = path.resolve(neoPath, value.input);
21
+ entry[key] = path.resolve(key === 'service' && !insideNeo ? cwd : neoPath, value.input);
20
22
  }
21
23
  });
22
24
  }
@@ -13,23 +13,5 @@
13
13
  "SharedDialog",
14
14
  "SharedDialog2",
15
15
  "Website"
16
- ],
17
- "workers": {
18
- "app": {
19
- "input": "./src/worker/App.mjs",
20
- "output": "appworker.js"
21
- },
22
- "canvas": {
23
- "input": "./src/worker/Canvas.mjs",
24
- "output": "canvasworker.js"
25
- },
26
- "data": {
27
- "input": "./src/worker/Data.mjs",
28
- "output": "dataworker.js"
29
- },
30
- "vdom": {
31
- "input": "./src/worker/VDom.mjs",
32
- "output": "vdomworker.js"
33
- }
34
- }
16
+ ]
35
17
  }
@@ -15,8 +15,10 @@ export default env => {
15
15
 
16
16
  if (filenameConfig.workers) {
17
17
  Object.entries(filenameConfig.workers).forEach(([key, value]) => {
18
+ // Inside a neo workspace, we want to use the SW inside the top level apps folder,
19
+ // to allow overriding its logic
18
20
  if (key === env.worker) {
19
- entry[key] = path.resolve(neoPath, value.input);
21
+ entry[key] = path.resolve(key === 'service' && !insideNeo ? cwd : neoPath, value.input);
20
22
  }
21
23
  });
22
24
  }
@@ -8,6 +8,12 @@ import ServiceBase from '../src/worker/ServiceBase.mjs';
8
8
  * @singleton
9
9
  */
10
10
  class ServiceWorker extends ServiceBase {
11
+ /**
12
+ * @member {String} workerId='service'
13
+ * @protected
14
+ */
15
+ workerId = 'service'
16
+
11
17
  static getConfig() {return {
12
18
  /**
13
19
  * @member {String} className='Neo.ServiceWorker'
@@ -18,12 +24,7 @@ class ServiceWorker extends ServiceBase {
18
24
  * @member {Boolean} singleton=true
19
25
  * @protected
20
26
  */
21
- singleton: true,
22
- /**
23
- * @member {String} workerId='service'
24
- * @protected
25
- */
26
- workerId: 'service'
27
+ singleton: true
27
28
  }}
28
29
  }
29
30
 
@@ -0,0 +1,6 @@
1
+ import MainContainer from './view/MainContainer.mjs';
2
+
3
+ export const onStart = () => Neo.app({
4
+ mainView: MainContainer,
5
+ name : 'MyApp'
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>Preloading Assets</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/preloadingAssets/app.mjs",
3
+ "basePath": "../../",
4
+ "environment": "development",
5
+ "mainPath": "./Main.mjs",
6
+ "useServiceWorker": true
7
+ }
@@ -0,0 +1,77 @@
1
+ import Component from '../../../src/component/Base.mjs';
2
+ import MainContainerController from './MainContainerController.mjs'
3
+ import TabContainer from '../../../src/tab/Container.mjs';
4
+ import Viewport from '../../../src/container/Viewport.mjs';
5
+
6
+ /**
7
+ * @class Neo.examples.preloadingAssets.view.MainContainer
8
+ * @extends Neo.container.Viewport
9
+ */
10
+ class MainContainer extends Viewport {
11
+ static getConfig() {return {
12
+ /**
13
+ * @member {String} className='Neo.examples.preloadingAssets.view.MainContainer'
14
+ * @protected
15
+ */
16
+ className: 'Neo.examples.preloadingAssets.view.MainContainer',
17
+ /**
18
+ * @member {Boolean} autoMount=true
19
+ */
20
+ autoMount: true,
21
+ /**
22
+ * @member {Neo.controller.Component} controller=MainContainerController
23
+ */
24
+ controller: MainContainerController,
25
+ /**
26
+ * @member {Object} layout={ntype:'fit'}
27
+ */
28
+ layout: {ntype: 'fit'},
29
+ /**
30
+ * @member {Object[]} items
31
+ */
32
+ items: [{
33
+ module: TabContainer,
34
+ height: 300,
35
+ width : 500,
36
+ style : {flex: 'none', margin: '20px'},
37
+
38
+ itemDefaults: {
39
+ module: Component,
40
+ style : {flex: 'none', padding: '20px'}
41
+ },
42
+
43
+ items: [{
44
+ tabButtonConfig: {
45
+ iconCls: 'fa fa-user-astronaut',
46
+ text : 'Bob'
47
+ },
48
+
49
+ vdom: {
50
+ tag: 'img',
51
+ src: 'https://raw.githubusercontent.com/neomjs/pages/master/resources/examples/ai_images/000150.jpg'
52
+ }
53
+ }, {
54
+ tabButtonConfig: {
55
+ iconCls: 'fa fa-user-ninja',
56
+ text : 'Alice'
57
+ },
58
+
59
+ vdom: {
60
+ tag: 'img',
61
+ src: 'https://raw.githubusercontent.com/neomjs/pages/master/resources/examples/ai_images/000074.jpg'
62
+ }
63
+ }],
64
+ /**
65
+ * @member {Object} listeners
66
+ */
67
+ listeners: {
68
+ activeIndexChange: 'onActiveIndexChange',
69
+ mounted : 'onMounted'
70
+ }
71
+ }]
72
+ }}
73
+ }
74
+
75
+ Neo.applyClassConfig(MainContainer);
76
+
77
+ export default MainContainer;
@@ -0,0 +1,41 @@
1
+ import Component from '../../../src/controller/Component.mjs';
2
+
3
+ /**
4
+ * @class Neo.examples.preloadingAssets.view.MainContainerController
5
+ * @extends Neo.controller.Component
6
+ */
7
+ class MainContainerController extends Component {
8
+ static getConfig() {return {
9
+ /**
10
+ * @member {String} className='Neo.examples.preloadingAssets.view.MainContainerController'
11
+ * @protected
12
+ */
13
+ className: 'Neo.examples.preloadingAssets.view.MainContainerController'
14
+ }}
15
+
16
+ /**
17
+ * @param {Object} data
18
+ */
19
+ onActiveIndexChange(data) {
20
+ console.log('onActiveIndexChange', data);
21
+ }
22
+
23
+ /**
24
+ * @param {String} id
25
+ */
26
+ onMounted(id) {
27
+ console.log('onMounted', id);
28
+
29
+ setTimeout(() => {
30
+ Neo.ServiceWorker.preloadAssets({
31
+ files: ['https://raw.githubusercontent.com/neomjs/pages/master/resources/examples/ai_images/000074.jpg']
32
+ }).then(data => {
33
+ console.log(data);
34
+ });
35
+ }, 3000)
36
+ }
37
+ }
38
+
39
+ Neo.applyClassConfig(MainContainerController);
40
+
41
+ export default MainContainerController;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neo.mjs",
3
- "version": "3.2.7",
3
+ "version": "3.2.10",
4
4
  "description": "The webworkers driven UI framework",
5
5
  "type": "module",
6
6
  "repository": {
@@ -34,21 +34,21 @@
34
34
  },
35
35
  "homepage": "https://neomjs.github.io/pages/",
36
36
  "dependencies": {
37
- "@fortawesome/fontawesome-free": "^6.0.0",
37
+ "@fortawesome/fontawesome-free": "^6.1.0",
38
38
  "@material/mwc-button": "^0.25.3",
39
39
  "@material/mwc-textfield": "^0.25.3",
40
- "autoprefixer": "^10.4.2",
41
- "chalk": "^5.0.0",
40
+ "autoprefixer": "^10.4.4",
41
+ "chalk": "^5.0.1",
42
42
  "clean-webpack-plugin": "^4.0.0",
43
- "commander": "^9.0.0",
44
- "cssnano": "^5.1.0",
43
+ "commander": "^9.1.0",
44
+ "cssnano": "^5.1.4",
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.1.5",
48
+ "inquirer": "^8.2.1",
49
49
  "neo-jsdoc": "^1.0.1",
50
50
  "neo-jsdoc-x": "^1.0.4",
51
- "postcss": "^8.4.7",
51
+ "postcss": "^8.4.12",
52
52
  "sass": "^1.49.9",
53
53
  "webpack": "^5.70.0",
54
54
  "webpack-cli": "^4.9.2",
@@ -1,2 +1,2 @@
1
1
  # Development in progress
2
- Currently, scheduled for the v2.4 release
2
+ Currently, scheduled for the v4.x release
@@ -92,10 +92,7 @@ class EditEventContainer extends FormContainer {
92
92
  */
93
93
  afterSetMounted(value, oldValue) {
94
94
  super.afterSetMounted(value, oldValue);
95
-
96
- if (value) {
97
- this.getField('title').focus();
98
- }
95
+ value && this.getField('title').focus();
99
96
  }
100
97
 
101
98
  /**
@@ -310,7 +310,7 @@ class MainContainer extends Container {
310
310
  style : {marginLeft: '10px'}
311
311
  });
312
312
  }, 10);
313
- } else if (value === false && oldValue) {
313
+ } else if (!value && oldValue) {
314
314
  // we only need this logic in case we dynamically change the config from true to false
315
315
  me.items[1] .removeLast();
316
316
  me.items[0].items[1].removeLast();
@@ -652,9 +652,7 @@ class MainContainer extends Container {
652
652
 
653
653
  map[me.activeView]();
654
654
 
655
- me.model.setData({
656
- currentDate: currentDate
657
- });
655
+ me.model.setData({currentDate});
658
656
  }
659
657
  }
660
658
 
@@ -29,9 +29,7 @@ class HBox extends Flexbox {
29
29
  */
30
30
  applyChildAttributes(item) {
31
31
  // Do not apply flex if fixed width
32
- if (!item.width) {
33
- super.applyChildAttributes(item);
34
- }
32
+ !item.width && super.applyChildAttributes(item);
35
33
  }
36
34
  }
37
35
 
@@ -29,9 +29,7 @@ class VBox extends Flexbox {
29
29
  */
30
30
  applyChildAttributes(item) {
31
31
  // Do not apply flex if fixed height
32
- if (!item.height) {
33
- super.applyChildAttributes(item);
34
- }
32
+ !item.height && super.applyChildAttributes(item);
35
33
  }
36
34
  }
37
35
 
@@ -36,15 +36,16 @@ class ServiceWorker extends Base {
36
36
  */
37
37
  construct(config) {
38
38
  if ('serviceWorker' in navigator) {
39
- let me = this,
40
- config = Neo.config,
41
- devMode = config.environment === 'development',
42
- fileName = devMode ? 'ServiceWorker.mjs' : 'serviceworker.js',
43
- folder = window.location.pathname.includes('/examples/') ? 'examples/' : 'apps/',
44
- opts = devMode ? {type: 'module'} : {},
39
+ let me = this,
40
+ config = Neo.config,
41
+ devMode = config.environment === 'development',
42
+ fileName = devMode ? 'ServiceWorker.mjs' : 'serviceworker.js',
43
+ folder = window.location.pathname.includes('/examples/') ? 'examples/' : 'apps/',
44
+ opts = devMode ? {type: 'module'} : {},
45
+ path = (devMode ? config.basePath : config.workerBasePath) + (devMode ? folder : '') + fileName,
45
46
  serviceWorker = navigator.serviceWorker;
46
47
 
47
- serviceWorker.register(config.basePath + folder + fileName, opts)
48
+ serviceWorker.register(path, opts)
48
49
  .then(registration => {
49
50
  me.registration = registration;
50
51
 
@@ -52,9 +53,9 @@ class ServiceWorker extends Base {
52
53
  serviceWorker.onmessage = WorkerManager.onWorkerMessage.bind(WorkerManager);
53
54
 
54
55
  WorkerManager.sendMessage('service', {
55
- action: 'registerNeoConfig',
56
- data : config,
57
- port : registration.active
56
+ action : 'registerNeoConfig',
57
+ channelPort: registration.active,
58
+ data : config
58
59
  });
59
60
  });
60
61
  })
@@ -53,7 +53,6 @@ class Stylesheet extends Base {
53
53
 
54
54
  if (Neo.config.themes.length > 0 && Neo.config.themes[0] !== '') {
55
55
  this.addGlobalCss();
56
- // this.insertTheme();
57
56
  }
58
57
  }
59
58
 
@@ -139,9 +139,9 @@ class Container extends BaseContainer {
139
139
  me.updateTabButtons();
140
140
 
141
141
  me.fire('activeIndexChange', {
142
- item : me.getActiveCard(),
143
- oldValue: oldValue,
144
- value : value
142
+ item: me.getActiveCard(),
143
+ oldValue,
144
+ value
145
145
  });
146
146
  }
147
147
  }
@@ -245,7 +245,7 @@ class Container extends BaseContainer {
245
245
  tabButtons.push(me.getTabButtonConfig(item.tabButtonConfig, index));
246
246
 
247
247
  if (!(item instanceof Neo.component.Base)) {
248
- item = {...me.itemDefaults, flex: 1, isTab:true, ...item};
248
+ item = {flex: 1, ...me.itemDefaults, isTab: true, ...item};
249
249
  }
250
250
 
251
251
  tabComponents.push(item);
@@ -390,9 +390,9 @@ class Manager extends Base {
390
390
  message, worker;
391
391
 
392
392
  if (!me.stopCommunication) {
393
- if (opts.port) {
394
- worker = opts.port;
395
- delete opts.port;
393
+ if (opts.channelPort) {
394
+ worker = opts.channelPort;
395
+ delete opts.channelPort;
396
396
  } else {
397
397
  worker = me.getWorker(dest);
398
398
  }
@@ -405,7 +405,7 @@ class Manager extends Base {
405
405
 
406
406
  message = new Message(opts);
407
407
 
408
- (me.sharedWorkersEnabled && NeoConfig.useSharedWorkers ? worker.port : worker).postMessage(message, transfer);
408
+ (worker.port ? worker.port : worker).postMessage(message, transfer);
409
409
  return message;
410
410
  }
411
411
  }
@@ -8,6 +8,19 @@ import RemoteMethodAccess from './mixin/RemoteMethodAccess.mjs';
8
8
  * @abstract
9
9
  */
10
10
  class ServiceBase extends Base {
11
+ /**
12
+ * @member {String} cacheName='neo-runtime'
13
+ */
14
+ cacheName = 'neo-runtime'
15
+ /**
16
+ * @member {String[]} cachePaths
17
+ */
18
+ cachePaths = [
19
+ 'raw.githubusercontent.com/',
20
+ '/dist/production/',
21
+ '/fontawesome',
22
+ '/resources/'
23
+ ]
11
24
  /**
12
25
  * @member {Object[]|null} channelPorts=null
13
26
  * @protected
@@ -28,6 +41,11 @@ class ServiceBase extends Base {
28
41
  * @protected
29
42
  */
30
43
  remotes = []
44
+ /**
45
+ * @member {String|null} workerId=null
46
+ * @protected
47
+ */
48
+ workerId = null
31
49
 
32
50
  static getConfig() {return {
33
51
  /**
@@ -35,19 +53,6 @@ class ServiceBase extends Base {
35
53
  * @protected
36
54
  */
37
55
  className: 'Neo.worker.ServiceBase',
38
- /**
39
- * @member {String} cacheName='neo-runtime'
40
- */
41
- cacheName: 'neo-runtime',
42
- /**
43
- * @member {String[]|null} cachePaths
44
- */
45
- cachePaths: [
46
- 'raw.githubusercontent.com/',
47
- '/dist/production/',
48
- '/fontawesome',
49
- '/resources/'
50
- ],
51
56
  /**
52
57
  * @member {String[]|Neo.core.Base[]|null} mixins=[RemoteMethodAccess]
53
58
  */
@@ -60,14 +65,11 @@ class ServiceBase extends Base {
60
65
  remote: {
61
66
  app: [
62
67
  'clearCache',
63
- 'clearCaches'
68
+ 'clearCaches',
69
+ 'preloadAssets',
70
+ 'removeAssets'
64
71
  ]
65
- },
66
- /**
67
- * @member {String|null} workerId=null
68
- * @protected
69
- */
70
- workerId: null
72
+ }
71
73
  }}
72
74
 
73
75
  /**
@@ -94,19 +96,20 @@ class ServiceBase extends Base {
94
96
 
95
97
  /**
96
98
  * @param {String} name=this.cacheName
99
+ * @returns {Object}
97
100
  */
98
- clearCache(name=this.cacheName) {
99
- caches.keys()
100
- .then(cacheNames => cacheNames.filter(cacheName => cacheName === name))
101
- .then(cachesToDelete => Promise.all(cachesToDelete.map(cacheToDelete => caches.delete(cacheToDelete))))
101
+ async clearCache(name=this.cacheName) {
102
+ await caches.delete(name);
103
+ return {success: true}
102
104
  }
103
105
 
104
106
  /**
105
- *
107
+ * @returns {Object}
106
108
  */
107
- clearCaches() {
108
- caches.keys()
109
- .then(cachesToDelete => Promise.all(cachesToDelete.map(cacheToDelete => caches.delete(cacheToDelete))))
109
+ async clearCaches() {
110
+ let keys = await caches.keys();
111
+ await Promise.all(keys.map(name => caches.delete(name)));
112
+ return {success: true}
110
113
  }
111
114
 
112
115
  /**
@@ -254,6 +257,41 @@ class ServiceBase extends Base {
254
257
  this.onConnect(event.source);
255
258
  }
256
259
 
260
+ /**
261
+ * @param {Object} data
262
+ * @param {String} [data.cacheName=this.cacheName]
263
+ * @param {String[]|String} data.files
264
+ * @param {Boolean} [data.foreReload=false]
265
+ */
266
+ async preloadAssets(data) {
267
+ let cacheName = data.cacheName || this.cacheName,
268
+ cache = await caches.open(cacheName),
269
+ files = data.files,
270
+ items = [],
271
+ asset, hasMatch, item;
272
+
273
+ if (!Array.isArray(files)) {
274
+ files = [files];
275
+ }
276
+
277
+ for (item of files) {
278
+ hasMatch = false;
279
+
280
+ if (!data.forceReload) {
281
+ asset = await cache.match(item);
282
+ hasMatch = !!asset;
283
+ }
284
+
285
+ !hasMatch && items.push(item);
286
+ }
287
+
288
+ if (items.length > 0) {
289
+ await cache.addAll(items);
290
+ }
291
+
292
+ return {success: true};
293
+ }
294
+
257
295
  /**
258
296
  * @param {String} dest app, data, main or vdom (excluding the current worker)
259
297
  * @param {Object} opts configs for Neo.worker.Message
@@ -273,6 +311,44 @@ class ServiceBase extends Base {
273
311
  });
274
312
  }
275
313
 
314
+ /**
315
+ * You can either pass an url, an array of urls or an object with additional options
316
+ * See: https://developer.mozilla.org/en-US/docs/Web/API/Cache/delete
317
+ * @param {String|String[]|Object} data
318
+ * @param {String|String[]} data.assets
319
+ * @param {String} data.cacheName=this.cacheName
320
+ * @param {Object} data.options
321
+ * @param {Boolean} data.options.ignoreMethod=false
322
+ * @param {Boolean} data.options.ignoreSearch=false
323
+ * @param {Boolean} data.options.ignoreVary=false
324
+ * @returns {Object}
325
+ */
326
+ async removeAssets(data) {
327
+ if (!Neo.isObject(data)) {
328
+ data = {
329
+ assets: data
330
+ };
331
+ }
332
+
333
+ let assets = data.assets,
334
+ cacheName = data.cacheName || this.cacheName,
335
+ options = data.options || {},
336
+ cache = await caches.open(cacheName),
337
+ promises = [];
338
+
339
+ if (!Array.isArray(assets)) {
340
+ assets = [assets];
341
+ }
342
+
343
+ assets.forEach(asset => {
344
+ promises.push(cache.delete(asset, options));
345
+ });
346
+
347
+ await Promise.all(promises);
348
+
349
+ return {success: true};
350
+ }
351
+
276
352
  /**
277
353
  * @param {String} dest app, data, main or vdom (excluding the current worker)
278
354
  * @param {Object} opts configs for Neo.worker.Message