jsgui3-server 0.0.144 → 0.0.146

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 (71) hide show
  1. package/docs/jsgui3-html-improvement-ideas.md +162 -0
  2. package/docs/jsgui3-html-improvement-ideas.svg +151 -0
  3. package/docs/jsgui3-sass-patterns-book/01-vision-and-goals.md +31 -0
  4. package/docs/jsgui3-sass-patterns-book/02-stack-map.md +40 -0
  5. package/docs/jsgui3-sass-patterns-book/03-control-local-sass.md +60 -0
  6. package/docs/jsgui3-sass-patterns-book/04-extension-and-variants.md +76 -0
  7. package/docs/jsgui3-sass-patterns-book/05-theming-and-tokens.md +54 -0
  8. package/docs/jsgui3-sass-patterns-book/06-workspace-overrides.md +45 -0
  9. package/docs/jsgui3-sass-patterns-book/07-resource-and-bundling.md +46 -0
  10. package/docs/jsgui3-sass-patterns-book/08-examples.md +62 -0
  11. package/docs/jsgui3-sass-patterns-book/09-testing-and-adoption.md +27 -0
  12. package/docs/jsgui3-sass-patterns-book/README.md +23 -0
  13. package/docs/troubleshooting.md +44 -4
  14. package/examples/controls/14) window, canvas/client.js +1 -1
  15. package/examples/controls/14b) window, canvas (improved renderer)/client.js +1 -1
  16. package/examples/controls/14d) window, canvas globe/EarthGlobeRenderer.js +19 -14
  17. package/examples/controls/14d) window, canvas globe/client.js +1 -1
  18. package/examples/controls/14d) window, canvas globe/pipeline/TransformStage.js +5 -5
  19. package/examples/controls/14e) window, canvas multithreaded/client.js +1 -1
  20. package/examples/controls/14f) window, canvas polyglobe/client.js +1 -1
  21. package/examples/controls/16) window, form container/client.js +254 -0
  22. package/examples/controls/16) window, form container/server.js +20 -0
  23. package/examples/controls/17) window, mvvm binding/client.js +530 -0
  24. package/examples/controls/17) window, mvvm binding/server.js +20 -0
  25. package/examples/jsgui3-html/01) mvvm-counter/client.js +648 -0
  26. package/examples/jsgui3-html/01) mvvm-counter/server.js +21 -0
  27. package/examples/jsgui3-html/02) date-transform/client.js +764 -0
  28. package/examples/jsgui3-html/02) date-transform/server.js +21 -0
  29. package/examples/jsgui3-html/03) form-validation/client.js +1045 -0
  30. package/examples/jsgui3-html/03) form-validation/server.js +21 -0
  31. package/examples/jsgui3-html/04) data-grid/client.js +738 -0
  32. package/examples/jsgui3-html/04) data-grid/server.js +21 -0
  33. package/examples/jsgui3-html/05) master-detail/client.js +649 -0
  34. package/examples/jsgui3-html/05) master-detail/server.js +21 -0
  35. package/examples/jsgui3-html/06) theming/client.js +514 -0
  36. package/examples/jsgui3-html/06) theming/server.js +21 -0
  37. package/examples/jsgui3-html/07) mixins/client.js +465 -0
  38. package/examples/jsgui3-html/07) mixins/server.js +21 -0
  39. package/examples/jsgui3-html/08) router/client.js +372 -0
  40. package/examples/jsgui3-html/08) router/server.js +21 -0
  41. package/examples/jsgui3-html/09) resource-transform/client.js +692 -0
  42. package/examples/jsgui3-html/09) resource-transform/server.js +21 -0
  43. package/examples/jsgui3-html/10) binding-debugger/client.js +810 -0
  44. package/examples/jsgui3-html/10) binding-debugger/server.js +21 -0
  45. package/examples/jsgui3-html/README.md +48 -0
  46. package/http/responders/static/Static_Route_HTTP_Responder.js +25 -20
  47. package/package.json +3 -3
  48. package/publishers/http-webpageorsite-publisher.js +3 -1
  49. package/resources/processors/bundlers/js/esbuild/Core_JS_Non_Minifying_Bundler_Using_ESBuild.js +87 -100
  50. package/resources/processors/bundlers/js/esbuild/Core_JS_Single_File_Minifying_Bundler_Using_ESBuild.js +89 -60
  51. package/serve-factory.js +12 -5
  52. package/server.js +103 -85
  53. package/tests/README.md +52 -9
  54. package/tests/bundlers.test.js +53 -47
  55. package/tests/end-to-end.test.js +336 -365
  56. package/tests/examples-controls.e2e.test.js +15 -1
  57. package/tests/fixtures/end-to-end-client.js +54 -0
  58. package/tests/fixtures/jsgui3-html/binding_debugger_expectations.json +15 -0
  59. package/tests/fixtures/jsgui3-html/counter_expectations.json +31 -0
  60. package/tests/fixtures/jsgui3-html/data_grid_expectations.json +26 -0
  61. package/tests/fixtures/jsgui3-html/date_transform_expectations.json +26 -0
  62. package/tests/fixtures/jsgui3-html/form_validation_expectations.json +27 -0
  63. package/tests/fixtures/jsgui3-html/master_detail_expectations.json +15 -0
  64. package/tests/fixtures/jsgui3-html/mixins_expectations.json +10 -0
  65. package/tests/fixtures/jsgui3-html/resource_transform_expectations.json +11 -0
  66. package/tests/fixtures/jsgui3-html/router_expectations.json +10 -0
  67. package/tests/fixtures/jsgui3-html/theming_expectations.json +10 -0
  68. package/tests/jsgui3-html-examples.puppeteer.test.js +537 -0
  69. package/tests/sass-controls.e2e.test.js +123 -9
  70. package/tests/test-runner.js +1 -0
  71. package/tests/window-examples.puppeteer.test.js +217 -1
@@ -0,0 +1,62 @@
1
+ # Small examples
2
+
3
+ These examples are minimal and focus on how Sass can be placed near controls, extended, and overridden per server.
4
+
5
+ ## Example 1: control-local Sass
6
+
7
+ ```javascript
8
+ class Toast_Notice extends Control {
9
+ constructor(spec = {}) {
10
+ spec.__type_name = spec.__type_name || 'toast_notice';
11
+ super(spec);
12
+ this.add_class('toast-notice');
13
+ }
14
+ }
15
+
16
+ Toast_Notice.scss = `
17
+ .toast-notice {
18
+ background: var(--theme-surface, #1f1f1f);
19
+ color: var(--theme-on-surface, #ffffff);
20
+ padding: 8px 12px;
21
+ }
22
+ `;
23
+ ```
24
+
25
+ ## Example 2: extending a control with new Sass
26
+
27
+ ```javascript
28
+ class Window_Compact extends Window {
29
+ constructor(spec = {}) {
30
+ spec.__type_name = spec.__type_name || 'window_compact';
31
+ super(spec);
32
+ this.add_class('window-compact');
33
+ }
34
+ }
35
+
36
+ Window_Compact.scss = `
37
+ .window-compact .title-bar {
38
+ font-size: 0.85em;
39
+ }
40
+ `;
41
+ ```
42
+
43
+ ## Example 3: workspace override via server config
44
+
45
+ ```javascript
46
+ Server.serve({
47
+ Ctrl: Demo_UI,
48
+ style: {
49
+ load_paths: ['styles/themes'],
50
+ scss_sources: [
51
+ "@use 'obsidian_theme' as *;",
52
+ ":root { --theme-surface: $obsidian_surface; }"
53
+ ]
54
+ }
55
+ });
56
+ ```
57
+
58
+ ## Where to implement
59
+
60
+ - Control-local Sass: `jsgui3-html` control files or app-specific controls.
61
+ - Workspace overrides: `jsgui3-server` configuration for the host app.
62
+ - Theme tokens: a theme package consumed via `load_paths`.
@@ -0,0 +1,27 @@
1
+ # Testing and adoption plan
2
+
3
+ This chapter proposes how to validate Sass behavior and phase it into new workspaces.
4
+
5
+ ## Testing suggestions
6
+
7
+ - Add control-level Sass tests to confirm extraction order and compilation.
8
+ - Add theme override tests that validate token overrides in bundled CSS.
9
+ - Add sourcemap tests when a single compilation pass is used.
10
+
11
+ Relevant test locations:
12
+
13
+ - `tests/sass-controls.e2e.test.js`
14
+ - `tests/bundlers.test.js`
15
+
16
+ ## Incremental adoption plan
17
+
18
+ 1. Define token vocabulary in `jsgui3-html` control CSS.
19
+ 2. Introduce a theme package with token overrides.
20
+ 3. Add server-level `scss_sources` for the theme in examples.
21
+ 4. Expand theme package usage in additional workspaces.
22
+
23
+ ## Where to implement
24
+
25
+ - Test coverage: `jsgui3-server/tests`.
26
+ - Token vocabulary: `jsgui3-html` controls and docs.
27
+ - Theme package: new repo, consumed via `style.load_paths`.
@@ -0,0 +1,23 @@
1
+ # JSGUI3 Sass Patterns Book
2
+
3
+ This book is a set of proposals for how Sass and CSS can be used across the JSGUI3 stack. It focuses on co-locating styles with controls, supporting project-wide theming, and allowing workspace-level overrides without losing default styles.
4
+
5
+ The intent is to document patterns and where they could be implemented, not to prescribe a single build system. Each chapter includes a short "Where to implement" section that points at the relevant layer.
6
+
7
+ ## Table of contents
8
+
9
+ 1. Vision and goals - `01-vision-and-goals.md`
10
+ 2. Stack map - `02-stack-map.md`
11
+ 3. Control-local Sass patterns - `03-control-local-sass.md`
12
+ 4. Extending controls and variants - `04-extension-and-variants.md`
13
+ 5. Theme tokens and runtime theming - `05-theming-and-tokens.md`
14
+ 6. Workspace overrides and shared themes - `06-workspace-overrides.md`
15
+ 7. Resource pipeline and bundling - `07-resource-and-bundling.md`
16
+ 8. Small examples - `08-examples.md`
17
+ 9. Testing and adoption plan - `09-testing-and-adoption.md`
18
+
19
+ ## Scope notes
20
+
21
+ - These are implementation suggestions that build on existing JSGUI3 behavior.
22
+ - The Sass compiler is already in use in the server pipeline, so patterns lean on that capability.
23
+ - Examples are minimal and designed to be adapted into other workspaces.
@@ -743,8 +743,48 @@ controls.MinimalControl = MinimalControl;
743
743
  module.exports = jsgui;
744
744
  ```
745
745
 
746
- This minimal setup helps isolate whether the issue is with your specific code or the framework itself.
747
-
748
- ---
749
-
746
+ This minimal setup helps isolate whether the issue is with your specific code or the framework itself.
747
+
748
+ ---
749
+
750
+ ## Bundling and Test Failures
751
+
752
+ ### `waiting for wp_publisher ready` or Publisher Ready Timeout
753
+
754
+ **Symptoms:**
755
+ - Tests hang while starting servers
756
+ - Logs show `waiting for wp_publisher ready`
757
+ - Tests time out without a clear stack trace
758
+
759
+ **Likely cause:** the JS/CSS bundler failed before emitting `ready`.
760
+
761
+ **What to check:**
762
+ 1. Look earlier in the log for bundler errors (esbuild, Sass, file resolution).
763
+ 2. Confirm `sass` is installed if you are running Sass tests.
764
+ 3. Validate the client entry path passed to `src_path_client_js`.
765
+
766
+ ### esbuild platform mismatch (Windows vs WSL)
767
+
768
+ **Symptoms:**
769
+ - Error: `You installed esbuild for another platform than the one you're currently using`
770
+
771
+ **Cause:** `node_modules` was installed on a different OS and reused in this environment.
772
+
773
+ **Fix:**
774
+ 1. Remove the existing `node_modules` from the current workspace.
775
+ 2. Reinstall dependencies in the current environment:
776
+ ```bash
777
+ npm install
778
+ ```
779
+ 3. If you prefer to keep the lockfile untouched, use:
780
+ ```bash
781
+ npm ci
782
+ ```
783
+ 4. As a fast workaround, you can try:
784
+ ```bash
785
+ npm rebuild esbuild
786
+ ```
787
+
788
+ ---
789
+
750
790
  Remember: Most issues can be resolved by carefully checking the console output, verifying file paths, and ensuring proper control lifecycle management. Start with the basics and work systematically through the possible causes.
@@ -181,7 +181,7 @@ class Demo_UI extends Active_HTML_Document {
181
181
  pos: [5, 5]
182
182
  });
183
183
  window.size = [480, 400];
184
- const canvas = new controls.canvas({
184
+ const canvas = new controls.Canvas({
185
185
  context
186
186
  });
187
187
  canvas.dom.attributes.id = 'globeCanvas'
@@ -329,7 +329,7 @@ class Demo_UI extends Active_HTML_Document {
329
329
  pos: [5, 5]
330
330
  });
331
331
  window.size = [480, 400];
332
- const canvas = new controls.canvas({
332
+ const canvas = new controls.Canvas({
333
333
  context
334
334
  });
335
335
  canvas.dom.attributes.id = 'globeCanvas'
@@ -149,19 +149,24 @@ class EarthGlobeRenderer {
149
149
  enablePipeline() { this.pipelineEnabled = true; }
150
150
  disablePipeline() { this.pipelineEnabled = false; }
151
151
  setSunDirection(vec3) { this.sun = this._normVec(vec3); this.render(false); }
152
- setSunFromSpherical(lonDeg, latDeg) {
153
- // convenience API used by existing client code
154
- const λ = lonDeg * Math.PI/180;
155
- const φ = latDeg * Math.PI/180;
156
- const cφ = Math.cos(φ);
157
- this.setSunDirection([
158
- cφ * Math.sin(λ),
159
- Math.sin(φ),
160
- cφ * Math.cos(λ)
161
- ]);
162
- }
163
-
164
- _buildContinents() {
152
+ setSunFromSpherical(lonDeg, latDeg) {
153
+ // convenience API used by existing client code
154
+ const λ = lonDeg * Math.PI/180;
155
+ const φ = latDeg * Math.PI/180;
156
+ const cφ = Math.cos(φ);
157
+ this.setSunDirection([
158
+ cφ * Math.sin(λ),
159
+ Math.sin(φ),
160
+ cφ * Math.cos(λ)
161
+ ]);
162
+ }
163
+
164
+ _update_rot() {
165
+ this.R = mat3FromQuat(this.q);
166
+ this.Rt = mat3Transpose(this.R);
167
+ }
168
+
169
+ _buildContinents() {
165
170
  const arr = [];
166
171
  for (const name of Object.keys(CONTINENT_OUTLINES)) {
167
172
  const def = CONTINENT_OUTLINES[name];
@@ -356,4 +361,4 @@ class EarthGlobeRenderer {
356
361
  }
357
362
  }
358
363
 
359
- module.exports = EarthGlobeRenderer;
364
+ module.exports = EarthGlobeRenderer;
@@ -23,7 +23,7 @@ class Demo_UI extends Active_HTML_Document {
23
23
  pos: [5, 5]
24
24
  });
25
25
  window.size = [1300, 1300];
26
- const canvas = new controls.canvas({
26
+ const canvas = new controls.Canvas({
27
27
  context
28
28
  });
29
29
  canvas.dom.attributes.id = 'globeCanvas'
@@ -2,9 +2,9 @@ const BaseStage = require('./BaseStage');
2
2
 
3
3
  class TransformStage extends BaseStage {
4
4
  /** @param {RenderState} rs */
5
- execute(rs) {
6
- const r = this.r;
7
- r._updateRot();
5
+ execute(rs) {
6
+ const r = this.r;
7
+ r._update_rot();
8
8
 
9
9
  const rect = r.canvas.getBoundingClientRect();
10
10
  const width = rect.width || r.canvas.width / r.opts.dpr;
@@ -13,8 +13,8 @@ class TransformStage extends BaseStage {
13
13
  rs.height = height;
14
14
 
15
15
  const pad = r.opts.padding;
16
- const minSide = Math.min(width, height);
17
- rs.radius = Math.max(1, minSide / 2 - pad);
16
+ const min_side = Math.min(width, height);
17
+ rs.radius = Math.max(1, min_side / 2 - pad);
18
18
  rs.cx = width * 0.5;
19
19
  rs.cy = height * 0.5;
20
20
  }
@@ -877,7 +877,7 @@ class Demo_UI extends Active_HTML_Document {
877
877
  pos: [5, 5]
878
878
  });
879
879
  window.size = [1000, 1000];
880
- const canvas = new controls.canvas({
880
+ const canvas = new controls.Canvas({
881
881
  context
882
882
  });
883
883
  canvas.dom.attributes.id = 'globeCanvas'
@@ -515,7 +515,7 @@ class Demo_UI extends Active_HTML_Document {
515
515
  });
516
516
  windowCtrl.size = [1000, 1000];
517
517
 
518
- const canvas = new controls.canvas({ context });
518
+ const canvas = new controls.Canvas({ context });
519
519
  canvas.dom.attributes.id = 'globeCanvas';
520
520
  canvas.size = [900, 900];
521
521
 
@@ -0,0 +1,254 @@
1
+ const jsgui = require('jsgui3-client');
2
+ const { controls, Control } = jsgui;
3
+
4
+ const Active_HTML_Document = require('../../../controls/Active_HTML_Document');
5
+
6
+ const { Alert_Banner, Button, Form_Container, Window } = controls;
7
+
8
+ const validate_email = value => {
9
+ const trimmed = String(value || '').trim();
10
+ if (!trimmed) return 'Email is required.';
11
+ if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(trimmed)) return 'Enter a valid email.';
12
+ return true;
13
+ };
14
+
15
+ const validate_age = value => {
16
+ if (value === '' || value === undefined || value === null) return true;
17
+ const numeric = Number(value);
18
+ if (!Number.isFinite(numeric)) return 'Enter a number.';
19
+ if (numeric < 16 || numeric > 120) return 'Age must be between 16 and 120.';
20
+ return true;
21
+ };
22
+
23
+ const validate_bio = value => {
24
+ const trimmed = String(value || '').trim();
25
+ if (trimmed.length < 20) return 'Share at least 20 characters.';
26
+ return true;
27
+ };
28
+
29
+ class Demo_UI extends Active_HTML_Document {
30
+ constructor(spec = {}) {
31
+ spec.__type_name = spec.__type_name || 'demo_ui';
32
+ super(spec);
33
+ const { context } = this;
34
+
35
+ if (typeof this.body.add_class === 'function') {
36
+ this.body.add_class('demo-ui');
37
+ }
38
+
39
+ const compose_ui = () => {
40
+ const window_ctrl = new Window({
41
+ context,
42
+ title: 'jsgui3-html Form_Container',
43
+ pos: [10, 10]
44
+ });
45
+
46
+ window_ctrl.size = [640, 520];
47
+
48
+ const alert_banner = new Alert_Banner({
49
+ context,
50
+ status: 'info',
51
+ message: 'Fill out the form and submit to see validation.'
52
+ });
53
+ alert_banner.add_class('form-banner');
54
+
55
+ const fields = [
56
+ {
57
+ name: 'full_name',
58
+ label: 'Full name',
59
+ required: true,
60
+ placeholder: 'Ada Lovelace'
61
+ },
62
+ {
63
+ name: 'email',
64
+ label: 'Email',
65
+ type: 'email',
66
+ required: true,
67
+ placeholder: 'ada@example.com',
68
+ validator: validate_email
69
+ },
70
+ {
71
+ name: 'age',
72
+ label: 'Age',
73
+ type: 'number',
74
+ placeholder: '36',
75
+ validator: validate_age
76
+ },
77
+ {
78
+ name: 'newsletter',
79
+ label: 'Newsletter',
80
+ type: 'checkbox',
81
+ value: true
82
+ },
83
+ {
84
+ name: 'bio',
85
+ label: 'Short bio',
86
+ type: 'textarea',
87
+ required: true,
88
+ placeholder: 'What are you working on?',
89
+ validator: validate_bio
90
+ }
91
+ ];
92
+
93
+ const form_container = new Form_Container({
94
+ context,
95
+ fields,
96
+ show_status_badge: true
97
+ });
98
+
99
+ const actions_row = new Control({
100
+ context,
101
+ tag_name: 'div'
102
+ });
103
+ actions_row.add_class('form-actions');
104
+
105
+ const submit_button = new Button({
106
+ context,
107
+ text: 'Submit'
108
+ });
109
+ submit_button.dom.attributes.type = 'submit';
110
+ submit_button.add_class('button-primary');
111
+
112
+ const reset_button = new Button({
113
+ context,
114
+ text: 'Reset'
115
+ });
116
+ reset_button.dom.attributes.type = 'button';
117
+ reset_button.add_class('button-secondary');
118
+
119
+ actions_row.add(submit_button);
120
+ actions_row.add(reset_button);
121
+
122
+ form_container.add(actions_row);
123
+
124
+ window_ctrl.inner.add(alert_banner);
125
+ window_ctrl.inner.add(form_container);
126
+
127
+ this.body.add(window_ctrl);
128
+
129
+ this.alert_banner = alert_banner;
130
+ this.form_container = form_container;
131
+ this.reset_button = reset_button;
132
+ };
133
+
134
+ if (!spec.el) {
135
+ compose_ui();
136
+ }
137
+ }
138
+
139
+ activate() {
140
+ if (!this.__active) {
141
+ super.activate();
142
+
143
+ const { form_container, alert_banner, reset_button } = this;
144
+
145
+ if (form_container && alert_banner) {
146
+ form_container.on('submit', e_submit => {
147
+ const values = e_submit && e_submit.values ? e_submit.values : {};
148
+ const summary_name = values.full_name ? `Thanks, ${values.full_name}.` : 'Thanks!';
149
+ alert_banner.set_status('success');
150
+ alert_banner.set_message(`${summary_name} Form submission looks good.`);
151
+ });
152
+
153
+ form_container.on('invalid', () => {
154
+ alert_banner.set_status('error');
155
+ alert_banner.set_message('Please fix the highlighted fields and try again.');
156
+ });
157
+ }
158
+
159
+ if (reset_button && form_container && alert_banner) {
160
+ reset_button.on('click', () => {
161
+ form_container.set_values({
162
+ full_name: '',
163
+ email: '',
164
+ age: '',
165
+ newsletter: false,
166
+ bio: ''
167
+ });
168
+
169
+ if (form_container.field_controls) {
170
+ Object.keys(form_container.field_controls).forEach(field_name => {
171
+ form_container.update_field_status(
172
+ form_container.field_controls[field_name],
173
+ '',
174
+ ''
175
+ );
176
+ });
177
+ }
178
+
179
+ alert_banner.set_status('info');
180
+ alert_banner.set_message('Form reset.');
181
+ });
182
+ }
183
+ }
184
+ }
185
+ }
186
+
187
+ Demo_UI.css = `
188
+ * {
189
+ margin: 0;
190
+ padding: 0;
191
+ }
192
+
193
+ body {
194
+ overflow-x: hidden;
195
+ overflow-y: hidden;
196
+ background-color: #e0e0e0;
197
+ }
198
+
199
+ .demo-ui .window .inner {
200
+ padding: 16px;
201
+ }
202
+
203
+ .demo-ui .form-banner {
204
+ margin-bottom: 12px;
205
+ }
206
+
207
+ .demo-ui .form-actions {
208
+ display: flex;
209
+ justify-content: flex-end;
210
+ gap: 12px;
211
+ padding-top: 8px;
212
+ }
213
+
214
+ .demo-ui .button-primary {
215
+ border: none;
216
+ border-radius: 4px;
217
+ padding: 6px 14px;
218
+ background: #0d47a1;
219
+ color: #fff;
220
+ cursor: pointer;
221
+ }
222
+
223
+ .demo-ui .button-secondary {
224
+ border: 1px solid #c5c5c5;
225
+ border-radius: 4px;
226
+ padding: 6px 14px;
227
+ background: #fff;
228
+ color: #333;
229
+ cursor: pointer;
230
+ }
231
+
232
+ @media (max-width: 720px) {
233
+ .demo-ui .window .inner {
234
+ padding: 12px;
235
+ }
236
+
237
+ .demo-ui .form-container-field {
238
+ grid-template-columns: 1fr;
239
+ gap: 6px;
240
+ }
241
+
242
+ .demo-ui .form-container-message {
243
+ grid-column: 1;
244
+ }
245
+
246
+ .demo-ui .form-actions {
247
+ flex-direction: column;
248
+ align-items: stretch;
249
+ }
250
+ }
251
+ `;
252
+
253
+ controls.Demo_UI = Demo_UI;
254
+ module.exports = jsgui;
@@ -0,0 +1,20 @@
1
+ const jsgui = require('./client');
2
+
3
+ const { Demo_UI } = jsgui.controls;
4
+ const Server = require('../../../server');
5
+
6
+ if (require.main === module) {
7
+ const server = new Server({
8
+ Ctrl: Demo_UI,
9
+ src_path_client_js: require.resolve('./client.js')
10
+ });
11
+
12
+ server.one('ready', () => {
13
+ server.start(52000, err => {
14
+ if (err) {
15
+ throw err;
16
+ }
17
+ console.log('server started');
18
+ });
19
+ });
20
+ }