jsgui3-server 0.0.147 → 0.0.149
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/.github/workflows/control-scan-manifest-check.yml +31 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-071799b982906680f5fd699d.js +40 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-07352945ad5c92654fcb8b65.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-138a601fadb6191ea314c6fd.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-171f6c381c2cadf2e9fa7087.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-1d973388156b84a04373fac9.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-20e117bc8a10d2cd16234bbe.js +40 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-2b028a82b0e5efddba42425f.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-4518556cd5c7e059e82b22b8.js +40 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-5bac1aa0f213902f718ed74f.js +40 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-5f9996ac7822caf777d92f56.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-60a92c702e65fd9cf748e3ec.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-6164c1f8f738995c541895d2.js +44 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-6718a85eb9e5aa782dd47a05.js +45 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-69e280f14e37aee76a1d4675.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-7570d1b030d44b111ed59c4c.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-7798c9bbd55e510d5039f936.js +42 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-78cd511ea1ef18ecb03d1be5.js +40 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-7d482e0b95bcb5e3c543118b.js +43 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-80e9476d1127c55b40fdb36f.js +40 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-810ced55d5320a3088a05b13.js +40 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-8423565f1a40e329afc8c6cf.js +40 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-900bef783b8cee36506ec282.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-a1a37aff6416fdad74040ddf.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-ad48d5e8eda40f175b4df090.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-aec5a2d963015528c9099462.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-af9d34e0f1722fab9e28c269.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-b818e4015e2f1fe86280b5ab.js +41 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-bcb2541adc70b7aba61768c5.js +44 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-bfe89d2c78ed44f95ed7dd73.js +40 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-c06f04806a1e688e1187110c.js +40 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-c3f3adf904f585afc544b96a.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-d45acb873e1d8e32d5e60f2e.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-db06f132533706f4a0163b8c.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-f660f40d78b135fc8560a862.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-f9dee4ec18a96e09bee06bae.js +39 -0
- package/README.md +85 -3
- package/admin-ui/client.js +213 -0
- package/admin-ui/server.js +104 -0
- package/client/controls/auto-observable.js +207 -0
- package/dev-status.svg +139 -0
- package/docs/api-reference.md +301 -43
- package/docs/books/admin-ui/01-introduction.md +32 -0
- package/docs/books/admin-ui/02-architecture.md +92 -0
- package/docs/books/admin-ui/03-controls.md +194 -0
- package/docs/books/admin-ui/04-implementation-plan.md +62 -0
- package/docs/books/admin-ui/README.md +26 -0
- package/docs/books/jsgui3-bundling-research-book/00-table-of-contents.md +35 -0
- package/docs/books/jsgui3-bundling-research-book/01-pipeline-and-runtime-semantics.md +34 -0
- package/docs/books/jsgui3-bundling-research-book/02-javascript-bundling-core.md +36 -0
- package/docs/books/jsgui3-bundling-research-book/03-style-extraction-and-css-compilation.md +35 -0
- package/docs/books/jsgui3-bundling-research-book/04-static-publishing-and-delivery.md +39 -0
- package/docs/books/jsgui3-bundling-research-book/05-current-limits-and-size-bloat-vectors.md +25 -0
- package/docs/books/jsgui3-bundling-research-book/06-unused-module-elimination-strategy.md +77 -0
- package/docs/books/jsgui3-bundling-research-book/07-jsgui3-html-control-and-mixin-pruning.md +63 -0
- package/docs/books/jsgui3-bundling-research-book/08-test-and-verification-methodology.md +43 -0
- package/docs/books/jsgui3-bundling-research-book/09-roadmap-and-rollout.md +42 -0
- package/docs/books/jsgui3-bundling-research-book/10-further-research-strategies-and-upgrades.md +211 -0
- package/docs/books/jsgui3-bundling-research-book/README.md +35 -0
- package/docs/bundling-system-deep-dive.md +9 -4
- package/docs/comprehensive-documentation.md +49 -18
- package/docs/configuration-reference.md +152 -27
- package/docs/core/README.md +19 -0
- package/docs/core/jsgui3-server-core-book/00-table-of-contents.md +21 -0
- package/docs/core/jsgui3-server-core-book/01-startup-readiness-state-machine.md +41 -0
- package/docs/core/jsgui3-server-core-book/02-resource-abstraction-and-lifecycle.md +92 -0
- package/docs/core/jsgui3-server-core-book/03-resource-pool-and-event-topology.md +47 -0
- package/docs/core/jsgui3-server-core-book/04-sse-publisher-semantics.md +41 -0
- package/docs/core/jsgui3-server-core-book/05-serve-factory-resource-wiring.md +46 -0
- package/docs/core/jsgui3-server-core-book/06-e2e-testing-methodology.md +48 -0
- package/docs/core/jsgui3-server-core-book/07-defect-detection-and-hardening-loop.md +47 -0
- package/docs/publishers-guide.md +59 -4
- package/docs/resources-guide.md +184 -35
- package/docs/simple-server-api-design.md +72 -17
- package/docs/system-architecture.md +18 -14
- package/examples/controls/15) window, observable SSE/server.js +6 -1
- package/examples/controls/19) window, auto observable ui/client.js +125 -0
- package/examples/controls/19) window, auto observable ui/server.js +73 -0
- package/examples/controls/20) window, task manager app/README.md +133 -0
- package/examples/controls/20) window, task manager app/client.js +797 -0
- package/examples/controls/20) window, task manager app/server.js +178 -0
- package/examples/controls/6) window, color_palette/client.js +165 -68
- package/examples/controls/9) window, date picker/client.js +362 -76
- package/examples/controls/9b) window, shared data.model mirrored date pickers/client.js +104 -83
- package/examples/jsgui3-html/06) theming/client.js +22 -1
- package/examples/jsgui3-html/10) binding-debugger/client.js +137 -1
- package/http/responders/static/Static_Route_HTTP_Responder.js +52 -34
- package/lab/experiments/capture-color-controls.js +196 -0
- package/lab/results/screenshots/color-controls/full_page.png +0 -0
- package/lab/results/screenshots/color-controls/section_1_color_grid_12x12.png +0 -0
- package/lab/results/screenshots/color-controls/section_2_color_grid_4x2.png +0 -0
- package/lab/results/screenshots/color-controls/section_3_color_palette.png +0 -0
- package/lab/results/screenshots/color-controls/section_4_palette_comparison.png +0 -0
- package/lab/results/screenshots/color-controls/section_5_raw_swatches.png +0 -0
- package/lab/results/screenshots/color-controls/section_6_optimized_crayola.png +0 -0
- package/lab/results/screenshots/color-controls/section_7_pastel_palette.png +0 -0
- package/lab/results/screenshots/color-controls/section_8_extended_144.png +0 -0
- package/lab/screenshot-utils.js +248 -0
- package/module.js +11 -4
- package/package.json +14 -4
- package/publishers/Publishers.js +4 -3
- package/publishers/helpers/assigners/static-compressed-response-buffers/Single_Control_Webpage_Server_Static_Compressed_Response_Buffers_Assigner.js +5 -5
- package/publishers/http-observable-publisher.js +8 -0
- package/publishers/http-sse-publisher.js +341 -0
- package/publishers/http-webpage-publisher.js +13 -3
- package/publishers/http-webpageorsite-publisher.js +18 -0
- package/resources/process-resource.js +950 -0
- package/resources/processors/bundlers/js/esbuild/Advanced_JS_Bundler_Using_ESBuild.js +164 -46
- package/resources/processors/bundlers/js/esbuild/Core_JS_Non_Minifying_Bundler_Using_ESBuild.js +18 -7
- package/resources/processors/bundlers/js/esbuild/JSGUI3_HTML_Control_Optimizer.js +829 -0
- package/resources/remote-process-resource.js +355 -0
- package/resources/server-resource-pool.js +354 -41
- package/serve-factory.js +441 -259
- package/server.js +161 -16
- package/tests/README.md +66 -4
- package/tests/admin-ui-render.test.js +24 -0
- package/tests/assigners.test.js +56 -40
- package/tests/bundling-default-control-elimination.puppeteer.test.js +260 -0
- package/tests/configuration-validation.test.js +21 -18
- package/tests/content-analysis.test.js +7 -6
- package/tests/control-optimizer-cache-behavior.test.js +52 -0
- package/tests/control-scan-manifest-regression.test.js +144 -0
- package/tests/end-to-end.test.js +15 -14
- package/tests/error-handling.test.js +222 -179
- package/tests/fixtures/bundling-default-button-client.js +37 -0
- package/tests/fixtures/bundling-default-window-client.js +34 -0
- package/tests/fixtures/control_scan_manifest_expectations.json +48 -0
- package/tests/fixtures/resource-monitor-client.js +319 -0
- package/tests/helpers/puppeteer-e2e-harness.js +317 -0
- package/tests/http-sse-publisher.test.js +136 -0
- package/tests/performance.test.js +69 -65
- package/tests/process-resource.test.js +138 -0
- package/tests/publishers.test.js +7 -7
- package/tests/remote-process-resource.test.js +160 -0
- package/tests/sass-controls.e2e.test.js +7 -1
- package/tests/serve-resources.test.js +270 -0
- package/tests/serve.test.js +120 -50
- package/tests/server-resource-pool.test.js +106 -0
- package/tests/small-controls-bundle-size.test.js +252 -0
- package/tests/test-runner.js +13 -1
- package/tests/window-examples.puppeteer.test.js +204 -1
- package/tests/window-resource-integration.puppeteer.test.js +585 -0
- package/tests/temp_invalid.js +0 -7
- package/tests/temp_invalid_utf8.js +0 -1
- package/tests/temp_malformed.js +0 -10
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
const assert = require('assert');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { describe, it, before, after } = require('mocha');
|
|
4
|
+
|
|
5
|
+
const Server = require('../server');
|
|
6
|
+
const { get_free_port } = require('../port-utils');
|
|
7
|
+
const {
|
|
8
|
+
ensure_puppeteer_module,
|
|
9
|
+
launch_puppeteer_browser,
|
|
10
|
+
open_page,
|
|
11
|
+
stop_server_instance,
|
|
12
|
+
assert_clean_page_probe
|
|
13
|
+
} = require('./helpers/puppeteer-e2e-harness');
|
|
14
|
+
|
|
15
|
+
const button_fixture_client_path = path.join(__dirname, 'fixtures', 'bundling-default-button-client.js');
|
|
16
|
+
const window_fixture_client_path = path.join(__dirname, 'fixtures', 'bundling-default-window-client.js');
|
|
17
|
+
|
|
18
|
+
const window_markers = [
|
|
19
|
+
'Minimize window',
|
|
20
|
+
'window_manager',
|
|
21
|
+
'__type_name = "window"',
|
|
22
|
+
"__type_name = 'window'",
|
|
23
|
+
"__type_name='window'",
|
|
24
|
+
'add_class("window")',
|
|
25
|
+
"add_class('window')"
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
const find_window_markers = (bundle_text = '') => {
|
|
29
|
+
return window_markers.filter((marker) => bundle_text.includes(marker));
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const read_js_bundle_from_page = async (page) => {
|
|
33
|
+
return page.evaluate(async () => {
|
|
34
|
+
const response = await fetch('/js/js.js', { cache: 'no-store' });
|
|
35
|
+
const text = await response.text();
|
|
36
|
+
return {
|
|
37
|
+
status_code: response.status,
|
|
38
|
+
body_text: text
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const load_fixture_ctrl = (client_path, ctrl_name) => {
|
|
44
|
+
const resolved_client_path = require.resolve(client_path);
|
|
45
|
+
delete require.cache[resolved_client_path];
|
|
46
|
+
|
|
47
|
+
const fixture_module = require(resolved_client_path);
|
|
48
|
+
const ctrl_constructor = fixture_module.controls && fixture_module.controls[ctrl_name];
|
|
49
|
+
assert(ctrl_constructor, `Missing exported control jsgui.controls.${ctrl_name} in ${client_path}`);
|
|
50
|
+
return ctrl_constructor;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const start_fixture_server = async ({ client_path, ctrl_name, bundler }) => {
|
|
54
|
+
const ctrl_constructor = load_fixture_ctrl(client_path, ctrl_name);
|
|
55
|
+
|
|
56
|
+
const server_instance = new Server({
|
|
57
|
+
Ctrl: ctrl_constructor,
|
|
58
|
+
src_path_client_js: client_path,
|
|
59
|
+
name: `tests/bundling/${ctrl_name}`,
|
|
60
|
+
bundler
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
server_instance.allowed_addresses = ['127.0.0.1'];
|
|
64
|
+
|
|
65
|
+
await new Promise((resolve, reject) => {
|
|
66
|
+
const timeout_handle = setTimeout(() => reject(new Error('Publisher ready timeout')), 60000);
|
|
67
|
+
server_instance.on('ready', () => {
|
|
68
|
+
clearTimeout(timeout_handle);
|
|
69
|
+
resolve();
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const port = await get_free_port();
|
|
74
|
+
await new Promise((resolve, reject) => {
|
|
75
|
+
server_instance.start(port, (error) => {
|
|
76
|
+
if (error) reject(error);
|
|
77
|
+
else resolve();
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
server_instance,
|
|
83
|
+
port
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const close_page_with_probe = async (page, page_probe) => {
|
|
88
|
+
if (page_probe && typeof page_probe.detach === 'function') {
|
|
89
|
+
page_probe.detach();
|
|
90
|
+
}
|
|
91
|
+
if (page) {
|
|
92
|
+
await page.close();
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const stop_server_instance_with_timeout = async (server_instance, timeout_ms = 12000) => {
|
|
97
|
+
if (!server_instance) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
await Promise.race([
|
|
102
|
+
stop_server_instance(server_instance),
|
|
103
|
+
new Promise((resolve) => setTimeout(resolve, timeout_ms))
|
|
104
|
+
]);
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
describe('Bundling Default Control Elimination Puppeteer Tests', function () {
|
|
108
|
+
this.timeout(420000);
|
|
109
|
+
|
|
110
|
+
let puppeteer_module = null;
|
|
111
|
+
let browser_instance = null;
|
|
112
|
+
|
|
113
|
+
before(async function () {
|
|
114
|
+
this.timeout(60000);
|
|
115
|
+
|
|
116
|
+
puppeteer_module = ensure_puppeteer_module();
|
|
117
|
+
if (!puppeteer_module) {
|
|
118
|
+
this.skip();
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
try {
|
|
123
|
+
browser_instance = await launch_puppeteer_browser(puppeteer_module);
|
|
124
|
+
} catch {
|
|
125
|
+
this.skip();
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
after(async function () {
|
|
130
|
+
if (browser_instance) {
|
|
131
|
+
await browser_instance.close();
|
|
132
|
+
browser_instance = null;
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('removes unused Window code by default and restores it when elimination is disabled', async function () {
|
|
137
|
+
this.timeout(360000);
|
|
138
|
+
let default_server_instance = null;
|
|
139
|
+
let disabled_server_instance = null;
|
|
140
|
+
let default_page = null;
|
|
141
|
+
let disabled_page = null;
|
|
142
|
+
let default_page_probe = null;
|
|
143
|
+
let disabled_page_probe = null;
|
|
144
|
+
|
|
145
|
+
try {
|
|
146
|
+
const default_server = await start_fixture_server({
|
|
147
|
+
client_path: button_fixture_client_path,
|
|
148
|
+
ctrl_name: 'Bundling_Default_Button_App'
|
|
149
|
+
});
|
|
150
|
+
default_server_instance = default_server.server_instance;
|
|
151
|
+
|
|
152
|
+
const default_open_result = await open_page(
|
|
153
|
+
browser_instance,
|
|
154
|
+
`http://127.0.0.1:${default_server.port}/`,
|
|
155
|
+
{ wait_until: 'domcontentloaded' }
|
|
156
|
+
);
|
|
157
|
+
default_page = default_open_result.page;
|
|
158
|
+
default_page_probe = default_open_result.page_probe;
|
|
159
|
+
|
|
160
|
+
await default_page.waitForSelector('[data-test="bundle-test-button"]');
|
|
161
|
+
|
|
162
|
+
const default_bundle_response = await read_js_bundle_from_page(default_page);
|
|
163
|
+
assert.strictEqual(default_bundle_response.status_code, 200, 'Expected /js/js.js to load in default mode');
|
|
164
|
+
const default_markers = find_window_markers(default_bundle_response.body_text);
|
|
165
|
+
assert.strictEqual(
|
|
166
|
+
default_markers.length,
|
|
167
|
+
0,
|
|
168
|
+
`Unexpected Window markers in default bundle: ${default_markers.join(', ')}`
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
assert_clean_page_probe(default_page_probe);
|
|
172
|
+
|
|
173
|
+
await close_page_with_probe(default_page, default_page_probe);
|
|
174
|
+
default_page = null;
|
|
175
|
+
default_page_probe = null;
|
|
176
|
+
|
|
177
|
+
const disabled_server = await start_fixture_server({
|
|
178
|
+
client_path: button_fixture_client_path,
|
|
179
|
+
ctrl_name: 'Bundling_Default_Button_App',
|
|
180
|
+
bundler: {
|
|
181
|
+
elimination: {
|
|
182
|
+
enabled: false,
|
|
183
|
+
jsgui3_html_controls: {
|
|
184
|
+
enabled: false
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
disabled_server_instance = disabled_server.server_instance;
|
|
190
|
+
|
|
191
|
+
const disabled_open_result = await open_page(
|
|
192
|
+
browser_instance,
|
|
193
|
+
`http://127.0.0.1:${disabled_server.port}/`,
|
|
194
|
+
{ wait_until: 'domcontentloaded' }
|
|
195
|
+
);
|
|
196
|
+
disabled_page = disabled_open_result.page;
|
|
197
|
+
disabled_page_probe = disabled_open_result.page_probe;
|
|
198
|
+
|
|
199
|
+
await disabled_page.waitForSelector('[data-test="bundle-test-button"]');
|
|
200
|
+
|
|
201
|
+
const disabled_bundle_response = await read_js_bundle_from_page(disabled_page);
|
|
202
|
+
assert.strictEqual(disabled_bundle_response.status_code, 200, 'Expected /js/js.js to load in disabled mode');
|
|
203
|
+
const disabled_markers = find_window_markers(disabled_bundle_response.body_text);
|
|
204
|
+
assert(
|
|
205
|
+
disabled_markers.length > 0,
|
|
206
|
+
'Expected Window markers when elimination is explicitly disabled'
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
assert(
|
|
210
|
+
default_bundle_response.body_text.length < disabled_bundle_response.body_text.length,
|
|
211
|
+
'Expected default bundle to be smaller than elimination-disabled bundle'
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
assert_clean_page_probe(disabled_page_probe);
|
|
215
|
+
} finally {
|
|
216
|
+
await close_page_with_probe(default_page, default_page_probe);
|
|
217
|
+
await close_page_with_probe(disabled_page, disabled_page_probe);
|
|
218
|
+
await stop_server_instance_with_timeout(default_server_instance);
|
|
219
|
+
await stop_server_instance_with_timeout(disabled_server_instance);
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it('keeps Window code in the default bundle when Window control is used', async () => {
|
|
224
|
+
let server_instance = null;
|
|
225
|
+
let page = null;
|
|
226
|
+
let page_probe = null;
|
|
227
|
+
|
|
228
|
+
try {
|
|
229
|
+
const started_server = await start_fixture_server({
|
|
230
|
+
client_path: window_fixture_client_path,
|
|
231
|
+
ctrl_name: 'Bundling_Default_Window_App'
|
|
232
|
+
});
|
|
233
|
+
server_instance = started_server.server_instance;
|
|
234
|
+
|
|
235
|
+
const open_result = await open_page(
|
|
236
|
+
browser_instance,
|
|
237
|
+
`http://127.0.0.1:${started_server.port}/`,
|
|
238
|
+
{ wait_until: 'domcontentloaded' }
|
|
239
|
+
);
|
|
240
|
+
page = open_result.page;
|
|
241
|
+
page_probe = open_result.page_probe;
|
|
242
|
+
|
|
243
|
+
await page.waitForSelector('.bundle-test-window');
|
|
244
|
+
await page.waitForSelector('.bundle-test-window-content');
|
|
245
|
+
|
|
246
|
+
const window_buttons = await page.$$('.bundle-test-window .title.bar button.button');
|
|
247
|
+
assert(window_buttons.length >= 2, 'Expected window title bar controls to be rendered');
|
|
248
|
+
|
|
249
|
+
const bundle_response = await read_js_bundle_from_page(page);
|
|
250
|
+
assert.strictEqual(bundle_response.status_code, 200, 'Expected /js/js.js to load');
|
|
251
|
+
const markers = find_window_markers(bundle_response.body_text);
|
|
252
|
+
assert(markers.length > 0, 'Expected Window markers when Window control is used');
|
|
253
|
+
|
|
254
|
+
assert_clean_page_probe(page_probe);
|
|
255
|
+
} finally {
|
|
256
|
+
await close_page_with_probe(page, page_probe);
|
|
257
|
+
await stop_server_instance_with_timeout(server_instance);
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
});
|
|
@@ -309,23 +309,26 @@ describe('Configuration Validation Tests', function() {
|
|
|
309
309
|
assert.strictEqual(bundler.minify_config.enabled, false);
|
|
310
310
|
});
|
|
311
311
|
|
|
312
|
-
it('should default to enabled minification', function() {
|
|
313
|
-
const bundler = new Core_JS_Single_File_Minifying_Bundler_Using_ESBuild({
|
|
314
|
-
minify: {
|
|
315
|
-
level: 'aggressive'
|
|
316
|
-
}
|
|
317
|
-
});
|
|
318
|
-
|
|
319
|
-
assert.strictEqual(bundler.minify_config.
|
|
320
|
-
assert.
|
|
321
|
-
});
|
|
322
|
-
|
|
323
|
-
it('should handle missing minify configuration', function() {
|
|
324
|
-
const bundler = new Core_JS_Single_File_Minifying_Bundler_Using_ESBuild({});
|
|
325
|
-
|
|
326
|
-
assert.deepStrictEqual(bundler.minify_config, {
|
|
327
|
-
|
|
328
|
-
|
|
312
|
+
it('should default to enabled minification', function() {
|
|
313
|
+
const bundler = new Core_JS_Single_File_Minifying_Bundler_Using_ESBuild({
|
|
314
|
+
minify: {
|
|
315
|
+
level: 'aggressive'
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
assert.strictEqual(bundler.minify_config.level, 'aggressive');
|
|
320
|
+
assert.notStrictEqual(bundler.get_minify_options(), false);
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
it('should handle missing minify configuration', function() {
|
|
324
|
+
const bundler = new Core_JS_Single_File_Minifying_Bundler_Using_ESBuild({});
|
|
325
|
+
|
|
326
|
+
assert.deepStrictEqual(bundler.minify_config, {
|
|
327
|
+
enabled: true,
|
|
328
|
+
level: 'normal'
|
|
329
|
+
});
|
|
330
|
+
});
|
|
331
|
+
});
|
|
329
332
|
|
|
330
333
|
describe('Core_JS_Non_Minifying_Bundler_Using_ESBuild', function() {
|
|
331
334
|
it('should accept valid sourcemap configuration', function() {
|
|
@@ -527,4 +530,4 @@ describe('Configuration Validation Tests', function() {
|
|
|
527
530
|
assert.deepStrictEqual(minimalPublisher.bundler_config, {});
|
|
528
531
|
});
|
|
529
532
|
});
|
|
530
|
-
});
|
|
533
|
+
});
|
|
@@ -571,12 +571,13 @@ describe('Content Analysis Tests', function() {
|
|
|
571
571
|
})
|
|
572
572
|
};
|
|
573
573
|
|
|
574
|
-
const results = {};
|
|
575
|
-
|
|
576
|
-
for (const [name, bundler] of Object.entries(bundlers)) {
|
|
577
|
-
const startTime = Date.now();
|
|
578
|
-
const
|
|
579
|
-
const
|
|
574
|
+
const results = {};
|
|
575
|
+
|
|
576
|
+
for (const [name, bundler] of Object.entries(bundlers)) {
|
|
577
|
+
const startTime = Date.now();
|
|
578
|
+
const bundle_input = name === 'minifying' ? testJsContent : testJsFile;
|
|
579
|
+
const result = await bundler.bundle(bundle_input);
|
|
580
|
+
const endTime = Date.now();
|
|
580
581
|
|
|
581
582
|
const bundle = result[0];
|
|
582
583
|
const jsItem = bundle._arr.find(item => item.type === 'JavaScript');
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
const assert = require('assert');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { describe, it } = require('mocha');
|
|
4
|
+
|
|
5
|
+
const JSGUI3_HTML_Control_Optimizer = require('../resources/processors/bundlers/js/esbuild/JSGUI3_HTML_Control_Optimizer');
|
|
6
|
+
|
|
7
|
+
const entry_file_path = path.join(__dirname, 'fixtures', 'bundling-default-button-client.js');
|
|
8
|
+
|
|
9
|
+
describe('Control Optimizer Cache Behavior Tests', function () {
|
|
10
|
+
this.timeout(60000);
|
|
11
|
+
|
|
12
|
+
it('records cache hits on repeated optimize calls when cache is enabled', async function () {
|
|
13
|
+
const optimizer = new JSGUI3_HTML_Control_Optimizer({
|
|
14
|
+
package_name: 'jsgui3-html',
|
|
15
|
+
cacheEnabled: true,
|
|
16
|
+
sharedCache: false
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const first_result = await optimizer.optimize(entry_file_path);
|
|
20
|
+
const second_result = await optimizer.optimize(entry_file_path);
|
|
21
|
+
|
|
22
|
+
assert.strictEqual(first_result.enabled, true);
|
|
23
|
+
assert.strictEqual(second_result.enabled, true);
|
|
24
|
+
assert(first_result.manifest.selected_controls.includes('Button'));
|
|
25
|
+
|
|
26
|
+
const cache_stats = optimizer.cache_stats;
|
|
27
|
+
assert(cache_stats.entry_analysis_misses >= 1, 'Expected at least one entry analysis cache miss');
|
|
28
|
+
assert(cache_stats.entry_analysis_hits >= 1, 'Expected at least one entry analysis cache hit');
|
|
29
|
+
assert(cache_stats.controls_map_hits >= 1, 'Expected cached controls map reuse');
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('avoids cache hits when cache is disabled', async function () {
|
|
33
|
+
const optimizer = new JSGUI3_HTML_Control_Optimizer({
|
|
34
|
+
package_name: 'jsgui3-html',
|
|
35
|
+
cacheEnabled: false,
|
|
36
|
+
sharedCache: false
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const first_result = await optimizer.optimize(entry_file_path);
|
|
40
|
+
const second_result = await optimizer.optimize(entry_file_path);
|
|
41
|
+
|
|
42
|
+
assert.strictEqual(first_result.enabled, true);
|
|
43
|
+
assert.strictEqual(second_result.enabled, true);
|
|
44
|
+
|
|
45
|
+
const cache_stats = optimizer.cache_stats;
|
|
46
|
+
assert.strictEqual(cache_stats.entry_analysis_hits, 0, 'Expected no entry analysis cache hits');
|
|
47
|
+
assert.strictEqual(cache_stats.file_scan_hits, 0, 'Expected no file scan cache hits');
|
|
48
|
+
assert.strictEqual(cache_stats.controls_map_hits, 0, 'Expected no controls map cache hits');
|
|
49
|
+
assert(cache_stats.file_scan_misses >= 2, 'Expected repeated uncached file scans');
|
|
50
|
+
assert(cache_stats.controls_map_misses >= 2, 'Expected repeated uncached controls map reads');
|
|
51
|
+
});
|
|
52
|
+
});
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
const assert = require('assert');
|
|
2
|
+
const { describe, it, before, after } = require('mocha');
|
|
3
|
+
const fs = require('fs').promises;
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
const Advanced_JS_Bundler_Using_ESBuild = require('../resources/processors/bundlers/js/esbuild/Advanced_JS_Bundler_Using_ESBuild');
|
|
7
|
+
|
|
8
|
+
const fixture_file_path = path.join(__dirname, 'fixtures', 'control_scan_manifest_expectations.json');
|
|
9
|
+
const update_snapshots = process.env.UPDATE_CONTROL_SCAN_MANIFEST === '1';
|
|
10
|
+
|
|
11
|
+
const normalize_manifest = (manifest) => {
|
|
12
|
+
const safe_array = (value) => Array.isArray(value) ? Array.from(value).sort() : [];
|
|
13
|
+
const safe_paths = (value) => Array.isArray(value) ? value.map(file_path => path.basename(file_path)).sort() : [];
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
entry_file: manifest && manifest.entry_file_path ? path.basename(manifest.entry_file_path) : null,
|
|
17
|
+
uses_jsgui3_html: Boolean(manifest && manifest.uses_jsgui3_html),
|
|
18
|
+
dynamic_control_access_detected: Boolean(manifest && manifest.dynamic_control_access_detected),
|
|
19
|
+
reachable_files: safe_paths(manifest && manifest.reachable_files),
|
|
20
|
+
used_identifiers: safe_array(manifest && manifest.used_identifiers),
|
|
21
|
+
selected_controls: safe_array(manifest && manifest.selected_controls),
|
|
22
|
+
unmatched_identifiers: safe_array(manifest && manifest.unmatched_identifiers),
|
|
23
|
+
package_aliases: safe_array(manifest && manifest.package_aliases),
|
|
24
|
+
controls_aliases: safe_array(manifest && manifest.controls_aliases)
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const extract_scan_manifest = (bundle_result) => {
|
|
29
|
+
const bundle = bundle_result[0];
|
|
30
|
+
const analysis = bundle && bundle.bundle_analysis && bundle.bundle_analysis.jsgui3_html_control_scan;
|
|
31
|
+
assert(analysis, 'Expected bundle_analysis.jsgui3_html_control_scan metadata');
|
|
32
|
+
return analysis;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
describe('Control Scan Manifest Regression Tests', function () {
|
|
36
|
+
this.timeout(120000);
|
|
37
|
+
|
|
38
|
+
const temp_fixture_paths = [];
|
|
39
|
+
|
|
40
|
+
const write_temp_fixture = async (file_name, source_text) => {
|
|
41
|
+
const temp_path = path.join(__dirname, file_name);
|
|
42
|
+
await fs.writeFile(temp_path, source_text, 'utf8');
|
|
43
|
+
temp_fixture_paths.push(temp_path);
|
|
44
|
+
return temp_path;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
before(async function () {
|
|
48
|
+
// Ensure fixture directory exists when update mode writes snapshots.
|
|
49
|
+
await fs.mkdir(path.dirname(fixture_file_path), { recursive: true });
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
after(async function () {
|
|
53
|
+
await Promise.all(temp_fixture_paths.map(async (temp_path) => {
|
|
54
|
+
try {
|
|
55
|
+
await fs.unlink(temp_path);
|
|
56
|
+
} catch (err) {
|
|
57
|
+
// Ignore missing temp files.
|
|
58
|
+
}
|
|
59
|
+
}));
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('should match strict manifest snapshot for static and dynamic alias usage', async function () {
|
|
63
|
+
const static_alias_fixture_path = await write_temp_fixture('temp_control_scan_static_alias_client.js', `
|
|
64
|
+
const ui = require('jsgui3-html');
|
|
65
|
+
const ui_controls = ui.controls;
|
|
66
|
+
const { Button: Button_Control } = ui_controls;
|
|
67
|
+
|
|
68
|
+
class Tiny_Static_Alias_App extends ui_controls.Active_HTML_Document {
|
|
69
|
+
constructor(spec = {}) {
|
|
70
|
+
super(spec);
|
|
71
|
+
if (!spec.el) {
|
|
72
|
+
const button = new Button_Control({ context: this.context });
|
|
73
|
+
button.add('ok');
|
|
74
|
+
this.body.add(button);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
module.exports = { Tiny_Static_Alias_App };
|
|
80
|
+
`);
|
|
81
|
+
|
|
82
|
+
const dynamic_alias_fixture_path = await write_temp_fixture('temp_control_scan_dynamic_alias_client.js', `
|
|
83
|
+
const ui = require('jsgui3-html');
|
|
84
|
+
const ui_controls = ui.controls;
|
|
85
|
+
|
|
86
|
+
class Tiny_Dynamic_Alias_App extends ui_controls.Active_HTML_Document {
|
|
87
|
+
constructor(spec = {}) {
|
|
88
|
+
super(spec);
|
|
89
|
+
if (!spec.el) {
|
|
90
|
+
const control_name = 'Button';
|
|
91
|
+
const Dynamic_Control = ui_controls[control_name];
|
|
92
|
+
const button = new Dynamic_Control({ context: this.context });
|
|
93
|
+
button.add('ok');
|
|
94
|
+
this.body.add(button);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
module.exports = { Tiny_Dynamic_Alias_App };
|
|
100
|
+
`);
|
|
101
|
+
|
|
102
|
+
const bundler = new Advanced_JS_Bundler_Using_ESBuild({
|
|
103
|
+
debug: false,
|
|
104
|
+
bundler: {
|
|
105
|
+
minify: {
|
|
106
|
+
enabled: true,
|
|
107
|
+
level: 'normal'
|
|
108
|
+
},
|
|
109
|
+
elimination: {
|
|
110
|
+
enabled: true,
|
|
111
|
+
jsgui3_html_controls: {
|
|
112
|
+
enabled: true
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
const static_manifest = extract_scan_manifest(await bundler.bundle(static_alias_fixture_path));
|
|
119
|
+
const dynamic_manifest = extract_scan_manifest(await bundler.bundle(dynamic_alias_fixture_path));
|
|
120
|
+
|
|
121
|
+
const snapshot = {
|
|
122
|
+
static_alias: normalize_manifest(static_manifest),
|
|
123
|
+
dynamic_alias: normalize_manifest(dynamic_manifest)
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
if (update_snapshots) {
|
|
127
|
+
await fs.writeFile(fixture_file_path, `${JSON.stringify(snapshot, null, 2)}\n`, 'utf8');
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
let expected_snapshot;
|
|
132
|
+
try {
|
|
133
|
+
const expected_text = await fs.readFile(fixture_file_path, 'utf8');
|
|
134
|
+
expected_snapshot = JSON.parse(expected_text);
|
|
135
|
+
} catch (err) {
|
|
136
|
+
assert.fail(
|
|
137
|
+
`Missing manifest expectation fixture at ${fixture_file_path}. ` +
|
|
138
|
+
'Run with UPDATE_CONTROL_SCAN_MANIFEST=1 to generate it.'
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
assert.deepStrictEqual(snapshot, expected_snapshot);
|
|
143
|
+
});
|
|
144
|
+
});
|
package/tests/end-to-end.test.js
CHANGED
|
@@ -171,12 +171,13 @@ describe('End-to-End Integration Tests', function() {
|
|
|
171
171
|
...base_serve_options,
|
|
172
172
|
debug: false,
|
|
173
173
|
bundler: {
|
|
174
|
-
compression: {
|
|
175
|
-
enabled: true,
|
|
176
|
-
algorithms: ['gzip', 'br']
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
174
|
+
compression: {
|
|
175
|
+
enabled: true,
|
|
176
|
+
algorithms: ['gzip', 'br'],
|
|
177
|
+
threshold: 0
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
});
|
|
180
181
|
|
|
181
182
|
const css_identity_response = await makeRequest(`http://localhost:${serverPort}/css/css.css`, {
|
|
182
183
|
'Accept-Encoding': 'identity'
|
|
@@ -399,28 +400,28 @@ describe('End-to-End Integration Tests', function() {
|
|
|
399
400
|
});
|
|
400
401
|
|
|
401
402
|
it('should handle server port conflicts', async function() {
|
|
402
|
-
|
|
403
|
-
const
|
|
403
|
+
this.timeout(60000);
|
|
404
|
+
const server_1 = await Server.serve({
|
|
404
405
|
...base_serve_options,
|
|
405
406
|
debug: false,
|
|
406
407
|
host: '127.0.0.1'
|
|
407
408
|
});
|
|
408
409
|
|
|
409
|
-
|
|
410
|
+
let conflicting_server = null;
|
|
410
411
|
try {
|
|
411
|
-
await
|
|
412
|
+
conflicting_server = await Server.serve({
|
|
412
413
|
...base_serve_options,
|
|
413
|
-
port: serverPort,
|
|
414
|
+
port: serverPort,
|
|
414
415
|
debug: false,
|
|
415
416
|
host: '127.0.0.1'
|
|
416
417
|
});
|
|
417
418
|
assert.fail('Should have failed to start server on occupied port');
|
|
418
419
|
} catch (error) {
|
|
419
420
|
assert(error, 'Should throw error for port conflict');
|
|
421
|
+
} finally {
|
|
422
|
+
await stop_server(conflicting_server);
|
|
423
|
+
await stop_server(server_1);
|
|
420
424
|
}
|
|
421
|
-
|
|
422
|
-
// Clean up
|
|
423
|
-
await stop_server(server1);
|
|
424
425
|
});
|
|
425
426
|
});
|
|
426
427
|
});
|