jsgui3-server 0.0.121 → 0.0.123
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/.vscode/settings.json +6 -0
- package/README.md +10 -10
- package/controls/Active_HTML_Document.js +116 -116
- package/controls/README.md +7 -7
- package/controls/page/admin.js +74 -74
- package/controls/panel/admin.js +11 -11
- package/examples/_css/basic.css +913 -913
- package/examples/_css/database-control.css +51 -51
- package/examples/_css/jsgui.css +66 -66
- package/examples/_css/multi-layout.css +23 -23
- package/examples/_css/style.css +1669 -1669
- package/examples/_css/top-and-bottom-bars.css +54 -54
- package/examples/box/1) square box/client.js +188 -188
- package/examples/box/1) square box/server.js +112 -112
- package/examples/box/2) twenty square boxes/css flex wrap/client.js +112 -248
- package/examples/box/2) twenty square boxes/css flex wrap/server.js +39 -112
- package/examples/box/3) twenty selectable square boxes/css flex wrap/client.js +129 -0
- package/examples/{controls/15) window, text field → box/3) twenty selectable square boxes/css flex wrap}/server.js +38 -38
- package/examples/boxes/square_boxes.js +45 -48
- package/examples/boxes/square_boxes_client.js +132 -136
- package/examples/client-side-popup-menu-button.html +93 -93
- package/examples/color_palette.js +51 -51
- package/examples/color_palette_client.js +95 -95
- package/examples/controls/1) window/client.js +186 -186
- package/examples/controls/1) window/server.js +117 -117
- package/examples/controls/10) window, mirrored text inputs/client.js +118 -320
- package/examples/controls/10) window, mirrored text inputs/server.js +37 -117
- package/examples/controls/11) window, mirrored text fields/client.js +493 -251
- package/examples/controls/11) window, mirrored text fields/server.js +117 -117
- package/examples/controls/11b) window, shared Data_Object model mirrored text fields/client.js +613 -331
- package/examples/controls/11b) window, shared Data_Object model mirrored text fields/server.js +117 -117
- package/examples/controls/11c) window, shared Data_Value model mirrored text fields/client.js +617 -617
- package/examples/controls/11c) window, shared Data_Value model mirrored text fields/server.js +117 -117
- package/examples/controls/11d) window, shared model mirrored integer text fields/client.js +611 -280
- package/examples/controls/11d) window, shared model mirrored integer text fields/server.js +134 -22
- package/examples/controls/12) window, Select_Options control/client.js +66 -452
- package/examples/controls/12) window, Select_Options control/server.js +19 -117
- package/examples/controls/13) window, Dropdown_Menu control/client.js +66 -0
- package/examples/controls/13) window, Dropdown_Menu control/server.js +20 -0
- package/examples/controls/2) two windows/client.js +193 -193
- package/examples/controls/2) two windows/server.js +113 -113
- package/examples/controls/3) five windows/client.js +217 -217
- package/examples/controls/3) five windows/server.js +116 -115
- package/examples/controls/4) window, tabbed panel/client.js +54 -225
- package/examples/controls/4) window, tabbed panel/server.js +17 -117
- package/examples/controls/5) window, grid/client.js +204 -484
- package/examples/controls/5) window, grid/server.js +117 -119
- package/examples/controls/6) window, color_palette/client.js +68 -204
- package/examples/controls/6) window, color_palette/server.js +117 -117
- package/examples/controls/7) window, month_view/client.js +40 -231
- package/examples/controls/7) window, month_view/server.js +117 -117
- package/examples/controls/8) window, checkbox/client.js +33 -209
- package/examples/controls/8) window, checkbox/server.js +117 -117
- package/examples/controls/9) window, date picker/client.js +76 -303
- package/examples/controls/9) window, date picker/server.js +117 -117
- package/examples/controls/9b) window, shared data.model mirrored date pickers/README.md +51 -0
- package/examples/controls/9b) window, shared data.model mirrored date pickers/client.js +83 -398
- package/examples/controls/9b) window, shared data.model mirrored date pickers/server.js +117 -117
- package/examples/controls/__old/_html-server-color-palette.js +114 -114
- package/examples/controls/__old/html-server-combo-box.js +104 -104
- package/examples/controls/__old/html-server-list.js +98 -98
- package/examples/controls/__old/html-server-popup-menu-button.js +114 -114
- package/examples/controls/__old/html-server-start-stop-toggle-button.js +146 -146
- package/examples/controls/__old/scs-arrow-button.js +36 -36
- package/examples/controls/__old/scs-date-picker.js +157 -157
- package/examples/controls/__old/scs-file-browser.js +82 -82
- package/examples/controls/__old/scs-item.js +159 -159
- package/examples/controls/__old/scs-month-arrow-selector.js +126 -126
- package/examples/controls/__old/scs-month-view.js +94 -94
- package/examples/controls/__old/scs-start-stop-toggle-button.js +40 -40
- package/examples/controls/__old/scs-tree.js +49 -49
- package/examples/controls/__old/scs-year-arrow-selector.js +127 -127
- package/examples/demos/date-picker.js +119 -119
- package/examples/demos/explain-encapsulation.js +9 -9
- package/examples/demos/resizing.js +35 -35
- package/examples/demos/server_time.js +6 -6
- package/examples/grids/grid_1.js +45 -45
- package/examples/grids/grid_1_client.js +329 -329
- package/examples/html-rendering.js +20 -20
- package/examples/html-server.js +105 -105
- package/examples/introducing jsgui3/server.js +110 -110
- package/examples/mx_display/mx_display_1.js +45 -45
- package/examples/mx_display/mx_display_1_client.js +444 -444
- package/fs2.js +1836 -1836
- package/http/responders/HTTP_Responder.js +15 -15
- package/http/responders/static/Static_Route_HTTP_Responder.js +105 -105
- package/module.js +34 -34
- package/old/_single-control-server.js +418 -418
- package/old/single-control-server.js +368 -368
- package/old/single-page-app.js +131 -131
- package/package.json +42 -42
- package/page-context.js +92 -92
- package/publishers/helpers/assigners/Assigner.js +10 -10
- package/publishers/helpers/assigners/static-compressed-response-buffers/Single_Control_Webpage_Server_Static_Compressed_Response_Buffers_Assigner.js +150 -150
- package/publishers/helpers/assigners/static-headers/Single_Control_Webpage_Server_Static_Headers_Assigner.js +109 -109
- package/publishers/helpers/assigners/static-routes/Single_Control_Webpage_Server_Static_Routes_Assigner.js +91 -91
- package/publishers/helpers/assigners/static-uncompressed-response-buffers/Single_Control_Webpage_Server_Static_Uncompressed_Response_Buffers_Assigner.js +104 -104
- package/publishers/helpers/preparers/static/bundle/Ready_To_Serve_Preparer.js +18 -18
- package/publishers/helpers/preparers/static/bundle/Static_Routes_Responses_Webpage_Bundle_Preparer.js +44 -44
- package/publishers/http-function-publisher.js +212 -212
- package/publishers/http-html-page-publisher.js +5 -5
- package/publishers/http-html-publisher.js +24 -24
- package/publishers/http-js-publisher.js +135 -135
- package/publishers/http-observable-publisher.js +124 -124
- package/publishers/http-publisher.js +53 -53
- package/publishers/http-resource-publisher.js +325 -325
- package/publishers/http-webpage-publisher.js +659 -658
- package/publishers/http-webpageorsite-publisher.js +343 -343
- package/publishers/http-website-publisher.js +640 -640
- package/publishers/notes.md +9 -9
- package/resources/README.md +16 -16
- package/resources/_old_website-javascript-resource.js +994 -994
- package/resources/_old_website-resource.js +507 -507
- package/resources/compile/server-resource-compilation.js +43 -43
- package/resources/data-resource.js +118 -118
- package/resources/fs-resource.js +146 -146
- package/resources/jsbuilder/Abstract_Single_Declaration.js +105 -105
- package/resources/jsbuilder/Abstract_Single_Declaration_Sequence.js +42 -42
- package/resources/jsbuilder/JS_AST/JS_AST_Abstract_Node.js +61 -61
- package/resources/jsbuilder/JS_AST/JS_AST_Abstract_Node_Group.js +41 -41
- package/resources/jsbuilder/JS_AST/JS_AST_Group_Shared.js +61 -61
- package/resources/jsbuilder/JS_AST/JS_AST_Node.js +93 -93
- package/resources/jsbuilder/JS_AST/JS_AST_Node_0-Core.js +253 -253
- package/resources/jsbuilder/JS_AST/JS_AST_Node_1-Babel.js +337 -337
- package/resources/jsbuilder/JS_AST/JS_AST_Node_10-Changing.js +39 -39
- package/resources/jsbuilder/JS_AST/JS_AST_Node_2.1.1-Child.js +96 -96
- package/resources/jsbuilder/JS_AST/JS_AST_Node_2.1.2-Parent.js +37 -37
- package/resources/jsbuilder/JS_AST/JS_AST_Node_2.1.3-Ancestor.js +61 -61
- package/resources/jsbuilder/JS_AST/JS_AST_Node_2.2-Inner.js +43 -43
- package/resources/jsbuilder/JS_AST/JS_AST_Node_2.3-All.js +72 -72
- package/resources/jsbuilder/JS_AST/JS_AST_Node_2.4-Sibling.js +92 -92
- package/resources/jsbuilder/JS_AST/JS_AST_Node_2.5-Available_In_Scope.js +29 -29
- package/resources/jsbuilder/JS_AST/JS_AST_Node_2.9-Signature.js +116 -116
- package/resources/jsbuilder/JS_AST/JS_AST_Node_3-Basics.js +159 -159
- package/resources/jsbuilder/JS_AST/JS_AST_Node_3.0.0-Basics_First.js +178 -178
- package/resources/jsbuilder/JS_AST/JS_AST_Node_3.0.1-Basics_Second.js +87 -87
- package/resources/jsbuilder/JS_AST/JS_AST_Node_3.0.99-Basics_Last.js +91 -91
- package/resources/jsbuilder/JS_AST/JS_AST_Node_3.1-Basics_Each.js +136 -136
- package/resources/jsbuilder/JS_AST/JS_AST_Node_3.1.5-Basics_Count.js +73 -73
- package/resources/jsbuilder/JS_AST/JS_AST_Node_3.2-Basics_Filter.js +39 -39
- package/resources/jsbuilder/JS_AST/JS_AST_Node_3.3-Basics_Collect.js +85 -85
- package/resources/jsbuilder/JS_AST/JS_AST_Node_3.4-Basics_Select.js +42 -42
- package/resources/jsbuilder/JS_AST/JS_AST_Node_3.5-Basics_Find.js +40 -40
- package/resources/jsbuilder/JS_AST/JS_AST_Node_3.6-Basics_Callmap.js +54 -54
- package/resources/jsbuilder/JS_AST/JS_AST_Node_4.0-Index_Indexes.js +45 -45
- package/resources/jsbuilder/JS_AST/JS_AST_Node_4.1-Index.js +343 -343
- package/resources/jsbuilder/JS_AST/JS_AST_Node_5.0-Category.js +38 -38
- package/resources/jsbuilder/JS_AST/JS_AST_Node_5.1-Category_Identifier.js +30 -30
- package/resources/jsbuilder/JS_AST/JS_AST_Node_5.2-Category_Literal.js +28 -28
- package/resources/jsbuilder/JS_AST/JS_AST_Node_5.3-Category_Expression.js +26 -26
- package/resources/jsbuilder/JS_AST/JS_AST_Node_5.4-Category_Pattern.js +8 -8
- package/resources/jsbuilder/JS_AST/JS_AST_Node_5.5-Category_Declaration.js +43 -43
- package/resources/jsbuilder/JS_AST/JS_AST_Node_5.6-Category_Statement.js +21 -21
- package/resources/jsbuilder/JS_AST/JS_AST_Node_6.0-Type.js +89 -89
- package/resources/jsbuilder/JS_AST/JS_AST_Node_6.1-Type_Class_Declaration.js +8 -8
- package/resources/jsbuilder/JS_AST/JS_AST_Node_6.2-Type_Variable_Declaration.js +27 -27
- package/resources/jsbuilder/JS_AST/JS_AST_Node_6.3-Type_Variable_Declarator.js +28 -28
- package/resources/jsbuilder/JS_AST/JS_AST_Node_7-Query.js +736 -736
- package/resources/jsbuilder/JS_AST/JS_AST_Node_8-Features.js +64 -64
- package/resources/jsbuilder/JS_AST/JS_AST_Node_9-Planning.js +31 -31
- package/resources/jsbuilder/JS_AST/JS_AST_Node_Arrangement.js +15 -15
- package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Node_Declared_Object.js +305 -305
- package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Node_Feature.js +77 -77
- package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Node_Feature_Declaration.js +248 -248
- package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Node_Feature_Declarator.js +138 -138
- package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Root_Node_Feature/JS_AST_Root_Node_Feature.js +10 -10
- package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Root_Node_Feature/JS_AST_Root_Node_Feature_Exported.js +100 -100
- package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Root_Node_Feature/JS_AST_Root_Node_Feature_Exports.js +60 -60
- package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Root_Node_Feature/JS_AST_Root_Node_Interpreted.js +179 -179
- package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Root_Node_Feature/_JSGUI_Root_Node_Interpreted.js +43 -43
- package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Root_Node_Feature/special_case_objectassign_to_object.js +12 -12
- package/resources/jsbuilder/JS_AST/JS_AST_Node_Group.js +35 -35
- package/resources/jsbuilder/JS_AST/JS_AST_Operation.js +11 -11
- package/resources/jsbuilder/JS_AST/JS_AST_Operation_On_Relationship.js +31 -31
- package/resources/jsbuilder/JS_AST/JS_AST_Ordered_Relationship_Node_To_Group.js +37 -37
- package/resources/jsbuilder/JS_AST/JS_AST_Ordinal.js +39 -39
- package/resources/jsbuilder/JS_AST/JS_AST_Ordinal_Relationship.js +25 -25
- package/resources/jsbuilder/JS_AST/JS_AST_Relationship_Node_To_Group.js +200 -200
- package/resources/jsbuilder/JS_AST/JS_AST_Relationship_Node_Within_Group_To_Node.js +43 -43
- package/resources/jsbuilder/JS_AST/_JS_AST_Node_3.8-Query_Features.js +76 -76
- package/resources/jsbuilder/JS_AST/query/enable_array_as_queryable.js +227 -227
- package/resources/jsbuilder/JS_AST/query/find_object_keys.js +404 -404
- package/resources/jsbuilder/JS_AST/query/node_queries.js +8 -8
- package/resources/jsbuilder/JS_AST/query/root_query_identidy.js +11 -11
- package/resources/jsbuilder/JS_AST_Node_Extended/JSGUI_Singular_Declaration.js +85 -85
- package/resources/jsbuilder/JS_AST_Node_Extended/JS_AST_Node_Declaration.js +123 -123
- package/resources/jsbuilder/JS_AST_Node_Extended/JS_AST_Node_Extended.js +87 -87
- package/resources/jsbuilder/JS_AST_Node_Extended/JS_AST_Node_Extended_0-Core.js +10 -10
- package/resources/jsbuilder/JS_Builder.js +10 -10
- package/resources/jsbuilder/JS_File/Feature/JS_File_Declared_Object.js +31 -31
- package/resources/jsbuilder/JS_File/Feature/JS_File_Exported_Object_Info.js +25 -25
- package/resources/jsbuilder/JS_File/Feature/JS_File_Exports.js +78 -78
- package/resources/jsbuilder/JS_File/Feature/JS_File_Feature.js +17 -17
- package/resources/jsbuilder/JS_File/Feature/JS_File_Imported_Object_Info.js +25 -25
- package/resources/jsbuilder/JS_File/Feature/JS_File_Imports.js +8 -8
- package/resources/jsbuilder/JS_File/JS_File.js +12 -12
- package/resources/jsbuilder/JS_File/JS_File_0-Core.js +202 -202
- package/resources/jsbuilder/JS_File/JS_File_1-Early_Parse.js +175 -175
- package/resources/jsbuilder/JS_File/JS_File_2-Babel.js +81 -81
- package/resources/jsbuilder/JS_File/JS_File_3-JS_AST_Node.js +86 -86
- package/resources/jsbuilder/JS_File/JS_File_4-Query.js +413 -413
- package/resources/jsbuilder/JS_File/JS_File_4.1-Query_Features.js +414 -414
- package/resources/jsbuilder/JS_File/JS_File_5-Planning.js +59 -59
- package/resources/jsbuilder/JS_File/JS_File_6-Changing.js +24 -24
- package/resources/jsbuilder/JS_File/JS_File_Export_Reference.js +12 -12
- package/resources/jsbuilder/JS_File/JS_File_Import_Reference.js +23 -23
- package/resources/jsbuilder/JS_File/JS_File_Import_References.js +31 -31
- package/resources/jsbuilder/JS_File/JS_File_Processor.js +16 -16
- package/resources/jsbuilder/JS_File/JS_Files.js +15 -15
- package/resources/jsbuilder/Module.js +14 -14
- package/resources/jsbuilder/Platform.js +13 -13
- package/resources/jsbuilder/Platforms.js +69 -69
- package/resources/jsbuilder/Project.js +109 -109
- package/resources/jsbuilder/Reference.js +1 -1
- package/resources/jsbuilder/Reference_Sequence.js +16 -16
- package/resources/jsbuilder/Scope.js +29 -29
- package/resources/jsbuilder/Variable_Name_Provider.js +42 -42
- package/resources/jsbuilder/_JS_File.js +225 -225
- package/resources/jsbuilder/ast_query.js +20 -20
- package/resources/jsbuilder/babel/babel_consts.js +162 -162
- package/resources/jsbuilder/babel/babel_node_tools.js +541 -541
- package/resources/jsbuilder/babel/deep_iterate/deep_iterate_babel.js +923 -904
- package/resources/jsbuilder/build.js +16 -16
- package/resources/jsbuilder/platform_notes.md +66 -66
- package/resources/jsbuilder/test/test_ast_node.js +381 -381
- package/resources/jsbuilder/test/test_js_file.js +303 -303
- package/resources/jsbuilder/test/test_project.js +157 -157
- package/resources/local-server-info-resource.js +96 -96
- package/resources/notes.txt +10 -10
- package/resources/old/website-image-resource.js +1185 -1185
- package/resources/process-js.js +498 -498
- package/resources/processors/bundlers/bundle.js +29 -29
- package/resources/processors/bundlers/bundler.js +23 -23
- package/resources/processors/bundlers/css-bundler.js +234 -234
- package/resources/processors/bundlers/js/JS_Bundler.js +51 -51
- package/resources/processors/bundlers/js/esbuild/Advanced_JS_Bundler_Using_ESBuild.js +388 -391
- package/resources/processors/bundlers/js/esbuild/Bundler_Using_ESBuild.js +8 -8
- package/resources/processors/bundlers/js/esbuild/Core_JS_Non_Minifying_Bundler_Using_ESBuild.js +188 -188
- package/resources/processors/bundlers/js/esbuild/Core_JS_Single_File_Minifying_Bundler_Using_ESBuild.js +191 -192
- package/resources/processors/bundlers/js/esbuild/_Old_CSS_Extractor.js +239 -239
- package/resources/processors/bundlers/js-bundler.js +263 -263
- package/resources/processors/bundlers/test_ast.js +73 -73
- package/resources/processors/bundlers/webpage-bundler.js +404 -404
- package/resources/processors/bundlers/website-bundler.js +22 -22
- package/resources/processors/extractors/Extractor.js +9 -11
- package/resources/processors/extractors/js/css_and_js/AST_Node/CSS_And_JS_From_JS_String_Using_AST_Node_Extractor.js +239 -254
- package/resources/processors/extractors/js/css_and_js/CSS_And_JS_From_JS_String_Extractor.js +3 -3
- package/resources/processors/extractors/string/Pos_Span_String_Extractor.js +93 -93
- package/resources/server-installed-tools.js +28 -28
- package/resources/server-resource-pool.js +41 -41
- package/resources/website-audio-resource.js +735 -735
- package/resources/website-css-resource.js +411 -411
- package/resources/website-image-resource.js +412 -412
- package/resources/website-javascript-resource-processor.js +908 -908
- package/resources/website-javascript-resource.js +874 -874
- package/resources/website-resource-processor.js +10 -10
- package/resources/website-resource.js +164 -164
- package/resources/website-static-html-resource.js +199 -199
- package/resources/website-template-html-resource.js +231 -231
- package/roadmap.md +75 -75
- package/server.js +609 -573
- package/static-page-context.js +13 -13
- package/website/webpage.js +81 -81
- package/website/website-group.js +15 -15
- package/website/website.js +260 -260
- package/examples/controls/11d) window, shared model mirrored integer text fields/both.js +0 -17
- package/examples/controls/13) window, shared model mirrored lat_long/client.js +0 -933
- package/examples/controls/13) window, shared model mirrored lat_long/server.js +0 -50
- package/examples/controls/14) window, control compositional model/client.js +0 -328
- package/examples/controls/14) window, control compositional model/server.js +0 -118
- package/examples/controls/14a) window, control spec has compositional model/client.js +0 -440
- package/examples/controls/14a) window, control spec has compositional model/server.js +0 -118
- package/examples/controls/15) window, text field/client.js +0 -256
- package/examples/controls/16) Window([Text_Input])/client.js +0 -266
- package/examples/controls/16) Window([Text_Input])/server.js +0 -109
- package/examples/controls/16a) Window([Text_Input]) Integer data.model.data_type/client.js +0 -494
- package/examples/controls/16a) Window([Text_Input]) Integer data.model.data_type/isomorphic.js +0 -24
- package/examples/controls/16a) Window([Text_Input]) Integer data.model.data_type/server.js +0 -73
- package/examples/controls/2b) two window, context menus/client.js +0 -193
- package/examples/controls/2b) two window, context menus/server.js +0 -114
- package/examples/controls/4a) window, tabbed panel with various controls inside/client.js +0 -233
- package/examples/controls/4a) window, tabbed panel with various controls inside/server.js +0 -118
|
@@ -1,995 +1,995 @@
|
|
|
1
|
-
// Sep 2023:
|
|
2
|
-
// This Resource itself is huge in scope, but maybe would be better to make the Resource more in terms of representing the Resource itself
|
|
3
|
-
// and having things like Resource_Processor? Resource_Analyser? Resource_Miner? Resource_Extracter? Resource_Transformer?
|
|
4
|
-
// Resource_Bundler? Resource_Builder?
|
|
5
|
-
|
|
6
|
-
// Resource_Verb_Carryouter Resource_Processor seems like the general name. Could do analysis, building, extraction etc.
|
|
7
|
-
// Raising events / announcements when it finds things.
|
|
8
|
-
|
|
9
|
-
// Does seem like refactoring the Resource so it is much simpler will be worth it, but also going into detail on the
|
|
10
|
-
// different ways the resources can be processed, doing it in a polymorphic way, observables, promises, making more classes for it if needed.
|
|
11
|
-
|
|
12
|
-
// Maybe do want the classes with processing functions built-in?
|
|
13
|
-
// Changing the syntax to more explictly use various files and classes which will be interchangable and separately upgradable
|
|
14
|
-
// and testable will help.
|
|
15
|
-
|
|
16
|
-
// Need to refactor, this code no longer works as first intended, and was slow when it did its full thing.
|
|
17
|
-
// Can do things much more optimially, maybe with esbuild and hashing and caching.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
// Nov 2020:
|
|
28
|
-
// Need to overhaul this, bugs are on the client, need to be careful and clear about what will be sent to the client.
|
|
29
|
-
// Need to get more into the tools for building JS for the client. Can I do the outline / much of the outline of it myself?
|
|
30
|
-
// Build up a huge JS AST of the whole thing.
|
|
31
|
-
// Build up a system that understands what code does (to an extent) and how it fits together.
|
|
32
|
-
|
|
33
|
-
// Could do my own application-level compression.
|
|
34
|
-
|
|
35
|
-
// JS-Build.
|
|
36
|
-
// Could identify the resources / files used in the site?
|
|
37
|
-
|
|
38
|
-
// Load all the files in, made into a function that will return what the module exports.
|
|
39
|
-
// Or not...
|
|
40
|
-
// Make the module into just the code, store it as a variable, then be able to build
|
|
41
|
-
|
|
42
|
-
// Would make quite a difference - with a lot of localised references made possible.
|
|
43
|
-
//
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
// JS_File
|
|
47
|
-
// Be able to get transformed versions of it
|
|
48
|
-
// JS_File_
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
// Much of this could be better expressed as a Compiler_Resource.
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
// Plan: Do more of this through lower level compilation features.
|
|
55
|
-
// Accessing a compilation resource makes sense structurally.
|
|
56
|
-
|
|
57
|
-
// May want a server to create and test compilation resources / compilers.
|
|
58
|
-
|
|
59
|
-
// Compilers, Bundlers, HTTP Request Handlers - Somewhat lower level, ie tools to get things done.
|
|
60
|
-
// Then also: resources which make use of upgraded and new lower level components.
|
|
61
|
-
|
|
62
|
-
// Server_Resource could help?
|
|
63
|
-
|
|
64
|
-
// Late 2023 - Should keep most of this for the moment, see about using parts when / where needed, also add in other (maybe simpler)
|
|
65
|
-
// ways to do things that are needed to publish JS.
|
|
66
|
-
|
|
67
|
-
// This resource seems like it's responsible for building JS.
|
|
68
|
-
// Seems like a piece of 'server' functionality that will be kind of hidden, need to make sure it's not a leaky abstraction.
|
|
69
|
-
// Also worth considering 'shorthands' where specific pieces of functionality are not needed to be specified, but usually we
|
|
70
|
-
// need to tell it that it needs to compile the JS (and other things).
|
|
71
|
-
|
|
72
|
-
// Maybe this JS resource would be responsible for extracting the CSS from JS and providing it to the CSS resource.
|
|
73
|
-
// Would be best to work through getting a few examples, and implementations of simple apps with nice (maybe new) APIs that need
|
|
74
|
-
// to be supported by jsgui3.
|
|
75
|
-
|
|
76
|
-
// For the moment, don't make anything really complex when it's not needed, but make it so on the lower levels (incl mid)
|
|
77
|
-
// it accesses functionality that is structured in a somewhat complex way, but uses it to do things which by default make the whole
|
|
78
|
-
// process simple.
|
|
79
|
-
|
|
80
|
-
// This runs automatically I think.
|
|
81
|
-
// Probably need to get it automatically building the client js on server start if needed.
|
|
82
|
-
// Likely best to save it locally, as well as to make a hash of all the files that went into the build, save that, only
|
|
83
|
-
// rebuild when it has changed.
|
|
84
|
-
|
|
85
|
-
// Could even provide a list of the intial control jsgui IDs, some empty items in an array? or the index of the node in the doc
|
|
86
|
-
// and then the control id that will be applied.
|
|
87
|
-
// This could make cleaner HTML be served by default, with IDs added later on the client-side using possibly a small amount of
|
|
88
|
-
// supplementary info.
|
|
89
|
-
// Or the ids could be assigned using xpaths.
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
const path = require('path'),
|
|
102
|
-
fs = require('fs'),
|
|
103
|
-
url = require('url'),
|
|
104
|
-
jsgui = require('jsgui3-html'),
|
|
105
|
-
os = require('os'),
|
|
106
|
-
http = require('http'),
|
|
107
|
-
libUrl = require('url'),
|
|
108
|
-
Resource = jsgui.Resource,
|
|
109
|
-
fs2 = require('../fs2'),
|
|
110
|
-
//brotli = require('iltorb').compress,
|
|
111
|
-
//UglifyJS = require('uglify-js'),
|
|
112
|
-
zlib = require('zlib');
|
|
113
|
-
|
|
114
|
-
//fs.createReadStream(filename).pipe(brotli()).pipe(res);
|
|
115
|
-
|
|
116
|
-
const fnl = require('fnl');
|
|
117
|
-
const prom_or_cb = fnl.prom_or_cb;
|
|
118
|
-
const fnlfs = require('fnlfs');
|
|
119
|
-
|
|
120
|
-
const each = jsgui.each,
|
|
121
|
-
arrayify = jsgui.arrayify,
|
|
122
|
-
tof = jsgui.tof;
|
|
123
|
-
const filter_map_by_regex = jsgui.filter_map_by_regex;
|
|
124
|
-
const Class = jsgui.Class,
|
|
125
|
-
Data_Object = jsgui.Data_Object,
|
|
126
|
-
Enhanced_Data_Object = jsgui.Enhanced_Data_Object;
|
|
127
|
-
const fp = jsgui.fp,
|
|
128
|
-
is_defined = jsgui.is_defined;
|
|
129
|
-
const Collection = jsgui.Collection;
|
|
130
|
-
const call_multi = jsgui.call_multi,
|
|
131
|
-
get_truth_map_from_arr = jsgui.get_truth_map_from_arr;
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
//var zlib = require('zlib');
|
|
135
|
-
const util = require('util');
|
|
136
|
-
|
|
137
|
-
const browserify = require('browserify');
|
|
138
|
-
const babel = require('@babel/core');
|
|
139
|
-
|
|
140
|
-
// Extends AutoStart_Resource?
|
|
141
|
-
const stream_to_array = require('stream-to-array');
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
const process_js = require('./process-js');
|
|
145
|
-
const {analyse_js_doc_formatting, extract_client_js} = process_js;
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
var serve_js_file_from_disk_updated_refs = function (filePath, response, callback) {
|
|
149
|
-
fs2.load_file_as_string(filePath, function (err, data) {
|
|
150
|
-
if (err) {
|
|
151
|
-
throw err;
|
|
152
|
-
} else {
|
|
153
|
-
//console.log('');
|
|
154
|
-
//console.log('serve_js_file_from_disk_updated_refs filePath ' + filePath);
|
|
155
|
-
//console.log('data ' + data);
|
|
156
|
-
//var servableJs = updateReferencesForServing(data);
|
|
157
|
-
response.writeHead(200, {
|
|
158
|
-
'Content-Type': 'text/javascript'
|
|
159
|
-
});
|
|
160
|
-
//response.end(servableJs);
|
|
161
|
-
response.end(data);
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
var check_served_directories_for_requested_file = function (arr_served_paths, split_path_within_js, callback) {
|
|
167
|
-
|
|
168
|
-
var fns = [
|
|
169
|
-
|
|
170
|
-
]
|
|
171
|
-
var checkPath = function (path, callback) {
|
|
172
|
-
// check to see if an existing file matches up with the path that is requested.
|
|
173
|
-
// so, from that path, we use the split_path_within_js for the rest of the file path.
|
|
174
|
-
// then we check if such a (JS) file exists.
|
|
175
|
-
}
|
|
176
|
-
// fns.push([fs2.load_file_as_string, [source_path_item], function(err, res_loaded) {
|
|
177
|
-
|
|
178
|
-
// Not so sure I can use the exists function like this...
|
|
179
|
-
var reconstitutedPathWithinJs = split_path_within_js.join('/');
|
|
180
|
-
var firstFoundPath;
|
|
181
|
-
each(arr_served_paths, function (i, fsPath) {
|
|
182
|
-
fns.push([function (callback) {
|
|
183
|
-
var checkingPath = fsPath + '/' + reconstitutedPathWithinJs;
|
|
184
|
-
fs.exists(checkingPath, function (exists) {
|
|
185
|
-
//console.log('cb fsPath ' + checkingPath + ' exists ' + exists)
|
|
186
|
-
if (exists & !firstFoundPath) {
|
|
187
|
-
firstFoundPath = checkingPath;
|
|
188
|
-
}
|
|
189
|
-
callback(null, exists);
|
|
190
|
-
})
|
|
191
|
-
},
|
|
192
|
-
[]
|
|
193
|
-
]);
|
|
194
|
-
});
|
|
195
|
-
call_multi(fns, function (err, res_multi) {
|
|
196
|
-
if (err) {
|
|
197
|
-
console.log('err ' + err);
|
|
198
|
-
throw 'stop';
|
|
199
|
-
} else {
|
|
200
|
-
//console.log('res_multi ' + stringify(res_multi));
|
|
201
|
-
//throw 'stop';
|
|
202
|
-
|
|
203
|
-
if (firstFoundPath) {
|
|
204
|
-
callback(null, firstFoundPath);
|
|
205
|
-
} else {
|
|
206
|
-
callback(null, null);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// A way of serving a file so that it includes custom code.
|
|
213
|
-
// Or have a standard client template that is easy to serve.
|
|
214
|
-
|
|
215
|
-
// Maybe do more with custom controls, such as custom page controls.
|
|
216
|
-
// Those page controls would know which control types are within them.
|
|
217
|
-
// That info could then be used to write JS code that sets up the references on the client.
|
|
218
|
-
|
|
219
|
-
// Possibly this should have its own routing tree to connect paths with js files?
|
|
220
|
-
// Need to set up custom paths.
|
|
221
|
-
|
|
222
|
-
class Site_JavaScript extends Resource {
|
|
223
|
-
//'fields': {
|
|
224
|
-
// 'custom_paths': 'data_object'
|
|
225
|
-
//},
|
|
226
|
-
constructor(spec) {
|
|
227
|
-
super(spec);
|
|
228
|
-
//this.meta.set('custom_paths', new Data_Object({}));
|
|
229
|
-
//this.custom_paths = new Data_Object({});
|
|
230
|
-
// Those are custom file paths.
|
|
231
|
-
// could have a collection of directories, indexed by name, that get served.
|
|
232
|
-
// Index the collection by string value?
|
|
233
|
-
//this.meta.set('served_directories', new Collection({'index_by': 'name'}));
|
|
234
|
-
|
|
235
|
-
// But this could be held (only) in the router.
|
|
236
|
-
this.served_directories = new Collection({
|
|
237
|
-
'index_by': 'name'
|
|
238
|
-
});
|
|
239
|
-
}
|
|
240
|
-
'start'(callback) {
|
|
241
|
-
//console.log('Site_JavaScript start');
|
|
242
|
-
const build_on_start = this.build_on_start;
|
|
243
|
-
if (build_on_start) {
|
|
244
|
-
this.build_client(function (err, res_build) {
|
|
245
|
-
if (err) {
|
|
246
|
-
callback(err)
|
|
247
|
-
} else {
|
|
248
|
-
callback(null, true);
|
|
249
|
-
}
|
|
250
|
-
})
|
|
251
|
-
} else {
|
|
252
|
-
callback(null, true);
|
|
253
|
-
}
|
|
254
|
-
// Let's have it build the client-side code.
|
|
255
|
-
// Need the options to ignore various files, as well as to include the source maps in the output.
|
|
256
|
-
}
|
|
257
|
-
// build client, and serve it from one particular place
|
|
258
|
-
// do so with a promise.
|
|
259
|
-
// serve_package
|
|
260
|
-
// Need to bundle / build together a package from the disk path, then serve it under a URL route.
|
|
261
|
-
|
|
262
|
-
// want to give it the file to build.
|
|
263
|
-
// There will be a variety of jsgui packages.
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
// Will be better as a promise.
|
|
267
|
-
|
|
268
|
-
'build_client'(callback) {
|
|
269
|
-
|
|
270
|
-
// Configurable building mechanisms....
|
|
271
|
-
// Want to provide jsgui events / logs on the build process.
|
|
272
|
-
|
|
273
|
-
// jsgui.notify could be used for some kinds of internal event logging.
|
|
274
|
-
// a specific type of event system.
|
|
275
|
-
|
|
276
|
-
// jsgui.raise('notification', )
|
|
277
|
-
|
|
278
|
-
// .note may be faster.
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
// jsgui.notify('start', 'build_client');
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
// Need the reference relative to the application directory.
|
|
287
|
-
//var path = __dirname + '/js/app.js';
|
|
288
|
-
|
|
289
|
-
// Can we stream it to a buffer in memory instead?
|
|
290
|
-
|
|
291
|
-
// Using a compilation resource may be better long-term.
|
|
292
|
-
// Creating and using a relevant abstraction.
|
|
293
|
-
|
|
294
|
-
// The server should have already loaded (a few) compilers.
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
var appDir = path.dirname(require.main.filename);
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
//console.log('appDir', appDir);
|
|
303
|
-
var app_path = appDir + '/js/app.js';
|
|
304
|
-
var app_bundle_path = appDir + '/js/app-bundle.js';
|
|
305
|
-
var wstream = fs.createWriteStream(app_bundle_path);
|
|
306
|
-
var b = browserify();
|
|
307
|
-
//b.require(app_path, {
|
|
308
|
-
// entry: true,
|
|
309
|
-
// debug: true
|
|
310
|
-
//});
|
|
311
|
-
b.add(app_path);
|
|
312
|
-
//console.log('app_path', app_path);
|
|
313
|
-
//console.log('pre browserify bundle');
|
|
314
|
-
//b.bundle().pipe(process.stdout);
|
|
315
|
-
|
|
316
|
-
b.bundle().pipe(wstream);
|
|
317
|
-
|
|
318
|
-
wstream.end = function (data) {
|
|
319
|
-
//console.log('file bundle write complete');
|
|
320
|
-
callback(null, app_bundle_path);
|
|
321
|
-
// no more writes after end
|
|
322
|
-
// emit "close" (optional)
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
// Will could serve all jsgui code?
|
|
326
|
-
// May be better not to allow server-side code to be read on the client.
|
|
327
|
-
// Could have specific directories within jsgui that get served to the client.
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
// May be best thinking of bundling up one or more objects / files ready for the server to serve.
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
'serve_directory'(path) {
|
|
334
|
-
// Serves that directory, as any files given in that directory can be served from /js
|
|
335
|
-
|
|
336
|
-
// Perhaps just using the router would be better.
|
|
337
|
-
|
|
338
|
-
var served_directories = this.served_directories;
|
|
339
|
-
//console.log('served_directories ' + stringify(served_directories));
|
|
340
|
-
//served_directories.push(path);
|
|
341
|
-
served_directories.push({
|
|
342
|
-
'name': path
|
|
343
|
-
});
|
|
344
|
-
//console.log('served_directories ' + stringify(served_directories));
|
|
345
|
-
//console.log('path ' + path);
|
|
346
|
-
//throw 'stop';
|
|
347
|
-
}
|
|
348
|
-
'serve_package'(url, js_package, options = {}, callback) {
|
|
349
|
-
//console.log('serve_package', url, js_package);
|
|
350
|
-
//console.log('js_package', js_package);
|
|
351
|
-
//console.log('typeof js_package', typeof js_package);
|
|
352
|
-
//let tjp = typeof js_package;
|
|
353
|
-
return this.serve_package_from_path(url, require.resolve(js_package), options, callback);
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
// Possibly some functionality would be better within the js bundler.
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
'package'(js_file_path, options = {}, callback) {
|
|
361
|
-
|
|
362
|
-
let a = arguments;
|
|
363
|
-
if (typeof a[2] === 'function') {
|
|
364
|
-
callback = a[2];
|
|
365
|
-
options = {
|
|
366
|
-
//'babel': 'mini',
|
|
367
|
-
'include_sourcemaps': true
|
|
368
|
-
};
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
return prom_or_cb((resolve, reject) => {
|
|
372
|
-
(async () => {
|
|
373
|
-
// options
|
|
374
|
-
// may want a replacement within the client-side code.
|
|
375
|
-
// Can we call browserify on the code string?
|
|
376
|
-
// Creating a modified copy of the file would do.
|
|
377
|
-
// Load the file, modify it, save it under a different name
|
|
378
|
-
|
|
379
|
-
let s = new require('stream').Readable(),
|
|
380
|
-
path = require('path').parse(js_file_path);
|
|
381
|
-
|
|
382
|
-
let fileContents = await fnlfs.load(js_file_path);
|
|
383
|
-
//console.log('1) fileContents.length', fileContents.length);
|
|
384
|
-
// are there any replacements to do?
|
|
385
|
-
// options.replacements
|
|
386
|
-
|
|
387
|
-
if (options.js_mode === 'debug') {
|
|
388
|
-
options.include_sourcemaps = true;
|
|
389
|
-
}
|
|
390
|
-
if (options.js_mode === 'compress' || options.js_mode === 'mini') {
|
|
391
|
-
options.include_sourcemaps = false;
|
|
392
|
-
options.babel = 'mini';
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
//console.log('options.babel', options.babel);
|
|
396
|
-
|
|
397
|
-
if (options.replace) {
|
|
398
|
-
let s_file_contents = fileContents.toString();
|
|
399
|
-
//console.log('s_file_contents', s_file_contents);
|
|
400
|
-
each(options.replace, (text, key) => {
|
|
401
|
-
//console.log('key', key);
|
|
402
|
-
//console.log('text', text);
|
|
403
|
-
let running_fn = '(' + text + ')();'
|
|
404
|
-
//console.log('running_fn', running_fn);
|
|
405
|
-
s_file_contents = s_file_contents.split(key).join(running_fn);
|
|
406
|
-
})
|
|
407
|
-
fileContents = Buffer.from(s_file_contents);
|
|
408
|
-
//console.log('2) fileContents.length', fileContents.length);
|
|
409
|
-
}
|
|
410
|
-
// Then we can replace some of the file contents with specific content given when we tall it to serve that file.
|
|
411
|
-
// We have a space for client-side activation.
|
|
412
|
-
s.push(fileContents);
|
|
413
|
-
s.push(null);
|
|
414
|
-
|
|
415
|
-
//let include_sourcemaps = true;
|
|
416
|
-
|
|
417
|
-
let b = browserify(s, {
|
|
418
|
-
basedir: path.dir,
|
|
419
|
-
//builtins: false,
|
|
420
|
-
builtins: ['buffer', 'process'],
|
|
421
|
-
'debug': options.include_sourcemaps
|
|
422
|
-
});
|
|
423
|
-
|
|
424
|
-
let parts = await stream_to_array(b.bundle());
|
|
425
|
-
|
|
426
|
-
const buffers = parts
|
|
427
|
-
.map(part => util.isBuffer(part) ? part : Buffer.from(part));
|
|
428
|
-
let buf_js = Buffer.concat(buffers);
|
|
429
|
-
let str_js = buf_js.toString();
|
|
430
|
-
|
|
431
|
-
let babel_option = options.babel
|
|
432
|
-
//console.log('babel_option', babel_option);
|
|
433
|
-
if (babel_option === 'es5') {
|
|
434
|
-
|
|
435
|
-
let o_transform = {
|
|
436
|
-
"presets": [
|
|
437
|
-
"es2015",
|
|
438
|
-
"es2017"
|
|
439
|
-
],
|
|
440
|
-
"plugins": [
|
|
441
|
-
"transform-runtime"
|
|
442
|
-
] //,
|
|
443
|
-
//'sourceMaps': 'inline'
|
|
444
|
-
};
|
|
445
|
-
|
|
446
|
-
if (options.include_sourcemaps) o_transform.sourceMaps = 'inline';
|
|
447
|
-
let res_transform = babel.transform(str_js, o_transform);
|
|
448
|
-
//console.log('res_transform', res_transform);
|
|
449
|
-
//console.log('Object.keys(res_transform)', Object.keys(res_transform));
|
|
450
|
-
let jst_es5 = res_transform.code;
|
|
451
|
-
//let {jst_es5, map, ast} = babel.transform(str_js);
|
|
452
|
-
//console.log('jst_es5.length', jst_es5.length);
|
|
453
|
-
buf_js = Buffer.from(jst_es5);
|
|
454
|
-
} else if (babel_option === 'mini') {
|
|
455
|
-
/*
|
|
456
|
-
let o_transform = {
|
|
457
|
-
presets: ["minify"]//,
|
|
458
|
-
//'sourceMaps': 'inline'
|
|
459
|
-
};
|
|
460
|
-
*/
|
|
461
|
-
let o_transform = {
|
|
462
|
-
"presets": [
|
|
463
|
-
["minify", {
|
|
464
|
-
//"mangle": {
|
|
465
|
-
//"exclude": ["MyCustomError"]
|
|
466
|
-
//},
|
|
467
|
-
//"unsafe": {
|
|
468
|
-
// "typeConstructors": false
|
|
469
|
-
//},
|
|
470
|
-
//"keepFnName": true
|
|
471
|
-
}]
|
|
472
|
-
],
|
|
473
|
-
//plugins: ["minify-dead-code-elimination"]
|
|
474
|
-
};
|
|
475
|
-
if (options.include_sourcemaps) o_transform.sourceMaps = 'inline';
|
|
476
|
-
|
|
477
|
-
let res_transform = babel.transform(str_js, o_transform);
|
|
478
|
-
buf_js = Buffer.from(res_transform.code);
|
|
479
|
-
} else {
|
|
480
|
-
buf_js = Buffer.from(str_js);
|
|
481
|
-
}
|
|
482
|
-
resolve(buf_js);
|
|
483
|
-
})();
|
|
484
|
-
}, callback);
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
// This is a lot about creating some 'package' that includes built JS and CSS
|
|
488
|
-
|
|
489
|
-
// It is not so clear what 'serve' means here though.
|
|
490
|
-
// Perhaps using this functionality could take a few more function calls that are more explicit,
|
|
491
|
-
// but also be set up so that it happens by default when appropriate, or some other function
|
|
492
|
-
// that uses some of the same newly refactored / referenced functions will do the job.
|
|
493
|
-
|
|
494
|
-
// Being more explicit about making sure the server has access to:
|
|
495
|
-
// 1) The client side JS
|
|
496
|
-
// 2) The means to build the client side JS
|
|
497
|
-
// 3) Analysis of the client-side JS source file / files
|
|
498
|
-
// If they contain CSS, that extracted CSS, as a CSS file.
|
|
499
|
-
// Probably best to make a callback saying that it's got it?
|
|
500
|
-
// An 'announcement'? New 'announcement' mechanism, so that when the CSS has been found the CSS publisher hears the announcement.
|
|
501
|
-
// Means the JS resource or publisher does not need a direct reference to the CSS resource or publisher.
|
|
502
|
-
|
|
503
|
-
// Also, make use of the distinction between a Resource and a Publisher.
|
|
504
|
-
// A Resource is something like a file on the disk.
|
|
505
|
-
// The Resources get provided to the Publishers.
|
|
506
|
-
// Then do the Publishers create Resources? Publications? Published_Resources?
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
// 3) The built client-side JS (with or without sourcemaps)
|
|
517
|
-
// 4) The compression setting (brotli/gzip) to compress that client-side JS
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
'serve_package_from_path'(url, js_file_path, options = {}, callback) {
|
|
523
|
-
//console.log('serve_package_from_path', url, js_file_path);
|
|
524
|
-
// js_mode option may need to be used.
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
// Make it an observable?
|
|
528
|
-
// Raise an event when we have the browserified fill js file (uncompressed?).
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
let a = arguments;
|
|
532
|
-
if (typeof a[2] === 'function') {
|
|
533
|
-
callback = a[2];
|
|
534
|
-
options = {
|
|
535
|
-
//'babel': 'mini',
|
|
536
|
-
'include_sourcemaps': false
|
|
537
|
-
};
|
|
538
|
-
}
|
|
539
|
-
let serve_raw = options.serve_raw || options.raw;
|
|
540
|
-
let accepts_brotli = false;
|
|
541
|
-
|
|
542
|
-
// Need to come up with compressed versions.
|
|
543
|
-
// An object that provides different versions.
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
return prom_or_cb((resolve, reject) => {
|
|
547
|
-
(async () => {
|
|
548
|
-
// options
|
|
549
|
-
// may want a replacement within the client-side code.
|
|
550
|
-
// Can we call browserify on the code string?
|
|
551
|
-
// Creating a modified copy of the file would do.
|
|
552
|
-
// Load the file, modify it, save it under a different name
|
|
553
|
-
const Stream = require('stream');
|
|
554
|
-
|
|
555
|
-
let s = new Stream.Readable(),
|
|
556
|
-
path = require('path').parse(js_file_path);
|
|
557
|
-
|
|
558
|
-
let fileContents = await fnlfs.load(js_file_path);
|
|
559
|
-
//console.log('1) fileContents.length', fileContents.length);
|
|
560
|
-
// are there any replacements to do?
|
|
561
|
-
// options.replacements
|
|
562
|
-
if (options.js_mode === 'debug') {
|
|
563
|
-
options.include_sourcemaps = true;
|
|
564
|
-
}
|
|
565
|
-
if (options.js_mode === 'compress' || options.js_mode === 'mini') {
|
|
566
|
-
options.include_sourcemaps = false;
|
|
567
|
-
options.babel = 'mini';
|
|
568
|
-
}
|
|
569
|
-
//console.log('options.babel', options.babel);
|
|
570
|
-
|
|
571
|
-
// Likely to remove this....
|
|
572
|
-
if (options.replace) {
|
|
573
|
-
let s_file_contents = fileContents.toString();
|
|
574
|
-
//console.log('s_file_contents', s_file_contents);
|
|
575
|
-
each(options.replace, (text, key) => {
|
|
576
|
-
//console.log('key', key);
|
|
577
|
-
//console.log('text', text);
|
|
578
|
-
const running_fn = '(' + text + ')();'
|
|
579
|
-
//console.log('running_fn', running_fn);
|
|
580
|
-
s_file_contents = s_file_contents.split(key).join(running_fn);
|
|
581
|
-
})
|
|
582
|
-
fileContents = Buffer.from(s_file_contents);
|
|
583
|
-
//console.log('2) fileContents.length', fileContents.length);
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
// Then we can replace some of the file contents with specific content given when we tall it to serve that file.
|
|
587
|
-
// We have a space for client-side activation.
|
|
588
|
-
// want a raw option with no browserify.
|
|
589
|
-
//console.log('serve_raw', serve_raw);
|
|
590
|
-
if (serve_raw) {
|
|
591
|
-
const escaped_url = url.replace(/\./g, '☺');
|
|
592
|
-
//this.custom_paths.set(escaped_url, fileContents);
|
|
593
|
-
|
|
594
|
-
throw 'NYI';
|
|
595
|
-
} else {
|
|
596
|
-
const formatting_info = analyse_js_doc_formatting(fileContents.toString());
|
|
597
|
-
//console.log('formatting_info', formatting_info);
|
|
598
|
-
|
|
599
|
-
const {arr_lines, line_break, indentation_analysis} = formatting_info;
|
|
600
|
-
const {parsed_lines, str_indentation} = indentation_analysis;
|
|
601
|
-
const client_root_js = extract_client_js(formatting_info);
|
|
602
|
-
|
|
603
|
-
//fnlfs.save('d:\\saved.js', client_root_js);
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
s.push(client_root_js);
|
|
607
|
-
s.push(null);
|
|
608
|
-
const lines_file_content = [];
|
|
609
|
-
|
|
610
|
-
// Don't always include sourcemap?
|
|
611
|
-
// Separate out the sourcemap?
|
|
612
|
-
|
|
613
|
-
const b = browserify(s, {
|
|
614
|
-
basedir: path.dir,
|
|
615
|
-
//builtins: false,
|
|
616
|
-
builtins: ['buffer'],
|
|
617
|
-
'debug': options.include_sourcemaps
|
|
618
|
-
});
|
|
619
|
-
// Prefer the idea of sending a stream to browserify.
|
|
620
|
-
const parts = await stream_to_array(b.bundle());
|
|
621
|
-
/*
|
|
622
|
-
var b = browserify([js_file_path], {
|
|
623
|
-
'debug': true
|
|
624
|
-
});
|
|
625
|
-
*/
|
|
626
|
-
//let parts = await stream_to_array(b.bundle());
|
|
627
|
-
const buffers = parts
|
|
628
|
-
.map(part => util.isBuffer(part) ? part : Buffer.from(part));
|
|
629
|
-
let buf_js = Buffer.concat(buffers);
|
|
630
|
-
const str_js = buf_js.toString();
|
|
631
|
-
const str_js_code = str_js;
|
|
632
|
-
let str_sourcemap;
|
|
633
|
-
|
|
634
|
-
let pos_prior_sourcemap = str_js.indexOf('//# sourceMappingURL');
|
|
635
|
-
if (pos_prior_sourcemap > -1) {
|
|
636
|
-
str_js_code = str_js.substr(0, pos_prior_sourcemap);
|
|
637
|
-
str_sourcemap = str_js.substr(pos_prior_sourcemap);
|
|
638
|
-
}
|
|
639
|
-
// filter_extract_css
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
/*
|
|
643
|
-
const js_remove_comments = (str_js_code) => {
|
|
644
|
-
// comments will be OK within a string.
|
|
645
|
-
|
|
646
|
-
// Be able to work out what type of code we are in at all points...?
|
|
647
|
-
// Non-tokenising scanner...?
|
|
648
|
-
|
|
649
|
-
// Knowing whether or not * / // / * is within a string is important - because if it's in a string its not a comment.
|
|
650
|
-
// seems like making the scanning parser is a bit of a large task. It would constantly need to know what symbol type / string encapsulator to use.
|
|
651
|
-
|
|
652
|
-
// Could split it into lines, spot whenever a line starts a comment...?
|
|
653
|
-
}
|
|
654
|
-
*/
|
|
655
|
-
|
|
656
|
-
const filter_js_extract_control_css = (str_js_code) => {
|
|
657
|
-
// res = [css, js_no_css]
|
|
658
|
-
// Split the js lines.
|
|
659
|
-
|
|
660
|
-
const s_js = str_js_code.split('\n');
|
|
661
|
-
let within_class_css = false;
|
|
662
|
-
const control_css_lines = [];
|
|
663
|
-
const js_non_css_lines = [];
|
|
664
|
-
// and the non-css lines.
|
|
665
|
-
// And need to look for its stop.
|
|
666
|
-
// And leave the first and last line out of the css.
|
|
667
|
-
each(s_js, js_line => {
|
|
668
|
-
let placed_js_line = false;
|
|
669
|
-
const pos_class_css_begin = js_line.indexOf('.css = `');
|
|
670
|
-
// if its 0
|
|
671
|
-
|
|
672
|
-
if (pos_class_css_begin > -1) {
|
|
673
|
-
//console.log('js_line', js_line);
|
|
674
|
-
within_class_css = true;
|
|
675
|
-
}
|
|
676
|
-
// Put empty lines (back) into the js array?
|
|
677
|
-
|
|
678
|
-
if (within_class_css) {
|
|
679
|
-
//console.log('js_line', js_line);
|
|
680
|
-
|
|
681
|
-
const pos_control_css_end = js_line.indexOf('`;');
|
|
682
|
-
//console.log('pos_control_css_end', pos_control_css_end);
|
|
683
|
-
if (pos_control_css_end > -1) {
|
|
684
|
-
within_class_css = false;
|
|
685
|
-
} else {
|
|
686
|
-
if (pos_class_css_begin > -1) {
|
|
687
|
-
|
|
688
|
-
} else {
|
|
689
|
-
control_css_lines.push(js_line);
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
}
|
|
693
|
-
} else {
|
|
694
|
-
js_non_css_lines.push(js_line);
|
|
695
|
-
placed_js_line = true;
|
|
696
|
-
}
|
|
697
|
-
|
|
698
|
-
if (!placed_js_line) {
|
|
699
|
-
js_non_css_lines.push('');
|
|
700
|
-
}
|
|
701
|
-
//let is_control_css_start = js_line.indexOf()
|
|
702
|
-
|
|
703
|
-
if (control_css_lines.length > 200) throw 'stop';
|
|
704
|
-
|
|
705
|
-
})
|
|
706
|
-
return [control_css_lines.join('\n'), js_non_css_lines.join('\n')];
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
let [str_css, str_js_no_css] = filter_js_extract_control_css(str_js_code);
|
|
710
|
-
|
|
711
|
-
// Add the sourcemaps back? Its working.
|
|
712
|
-
|
|
713
|
-
if (str_sourcemap) {
|
|
714
|
-
str_js_no_css = str_js_no_css + str_sourcemap;
|
|
715
|
-
}
|
|
716
|
-
this.raise('extracted-controls-css', str_css);
|
|
717
|
-
let babel_option = options.babel;
|
|
718
|
-
|
|
719
|
-
//console.log('babel_option', babel_option);
|
|
720
|
-
//throw 'stop';
|
|
721
|
-
//babel_option = 'es5';
|
|
722
|
-
//console.log('babel_option', babel_option);
|
|
723
|
-
if (babel_option === 'es5') {
|
|
724
|
-
// es5 option
|
|
725
|
-
// not sure if it babels async await though.
|
|
726
|
-
/*
|
|
727
|
-
{
|
|
728
|
-
"presets": [
|
|
729
|
-
"es2015",
|
|
730
|
-
"es2017"
|
|
731
|
-
],
|
|
732
|
-
"plugins": [
|
|
733
|
-
"transform-runtime"
|
|
734
|
-
]
|
|
735
|
-
}
|
|
736
|
-
*/
|
|
737
|
-
/*
|
|
738
|
-
let res_transform = babel.transform(str_js, {
|
|
739
|
-
//'plugins': ['transform-class']
|
|
740
|
-
'plugins': ['transform-es2015-object-super', 'transform-es2015-classes', 'remove-comments'],
|
|
741
|
-
'sourceMaps': 'inline'
|
|
742
|
-
//'plugins': ['transform-es2015-classes']
|
|
743
|
-
// transform-es2015-object-super
|
|
744
|
-
});
|
|
745
|
-
*/
|
|
746
|
-
let o_tranform = {
|
|
747
|
-
"presets": [
|
|
748
|
-
"es2015",
|
|
749
|
-
"es2017"
|
|
750
|
-
],
|
|
751
|
-
"plugins": [
|
|
752
|
-
"transform-runtime"
|
|
753
|
-
] //,
|
|
754
|
-
//'sourceMaps': 'inline'
|
|
755
|
-
};
|
|
756
|
-
if (options.include_sourcemaps) o_tranform.sourceMaps = 'inline';
|
|
757
|
-
|
|
758
|
-
let res_transform = babel.transform(str_js_no_css, o_tranform);
|
|
759
|
-
let jst_es5 = res_transform.code;
|
|
760
|
-
//let {jst_es5, map, ast} = babel.transform(str_js);
|
|
761
|
-
//console.log('jst_es5.length', jst_es5.length);
|
|
762
|
-
buf_js = Buffer.from(jst_es5);
|
|
763
|
-
} else if (babel_option === 'mini') {
|
|
764
|
-
/*
|
|
765
|
-
let o_transform = {
|
|
766
|
-
presets: ["minify"]//,
|
|
767
|
-
//'sourceMaps': 'inline'
|
|
768
|
-
};
|
|
769
|
-
*/
|
|
770
|
-
let o_transform = {
|
|
771
|
-
"presets": [
|
|
772
|
-
["minify", {
|
|
773
|
-
//"mangle": {
|
|
774
|
-
//"exclude": ["MyCustomError"]
|
|
775
|
-
//},
|
|
776
|
-
//"unsafe": {
|
|
777
|
-
// "typeConstructors": false
|
|
778
|
-
//},
|
|
779
|
-
//"keepFnName": true
|
|
780
|
-
}]
|
|
781
|
-
],
|
|
782
|
-
"comments": false
|
|
783
|
-
//plugins: ["minify-dead-code-elimination"]
|
|
784
|
-
};
|
|
785
|
-
|
|
786
|
-
if (options.include_sourcemaps) o_transform.sourceMaps = 'inline';
|
|
787
|
-
let res_transform = babel.transform(str_js_no_css, o_transform);
|
|
788
|
-
//let jst_es5 = res_transform.code;
|
|
789
|
-
//let {jst_es5, map, ast} = babel.transform(str_js);
|
|
790
|
-
//console.log('jst_es5.length', jst_es5.length);
|
|
791
|
-
buf_js = Buffer.from(res_transform.code);
|
|
792
|
-
} else {
|
|
793
|
-
buf_js = Buffer.from(str_js_no_css);
|
|
794
|
-
console.log('no babel use');
|
|
795
|
-
}
|
|
796
|
-
var escaped_url = url.replace(/\./g, '☺');
|
|
797
|
-
|
|
798
|
-
//console.log('pre compress buf_js.length', buf_js.length);
|
|
799
|
-
zlib.gzip(buf_js, {level: 9}, (err, buffer) => {
|
|
800
|
-
console.log('deflated buf_js buffer.length', buffer.length);
|
|
801
|
-
|
|
802
|
-
if (err) {
|
|
803
|
-
reject(err);
|
|
804
|
-
} else {
|
|
805
|
-
//
|
|
806
|
-
//buffer.encoding = 'deflate';
|
|
807
|
-
console.log('');
|
|
808
|
-
console.log('escaped_url', escaped_url);
|
|
809
|
-
console.log('url', url);
|
|
810
|
-
console.log('');
|
|
811
|
-
|
|
812
|
-
const rp = this.pool;
|
|
813
|
-
console.log('rp', rp);
|
|
814
|
-
console.log('rp.resource_names', rp.resource_names);
|
|
815
|
-
|
|
816
|
-
const router = rp.get_resource('Site Router');
|
|
817
|
-
console.log('router', router);
|
|
818
|
-
|
|
819
|
-
router.set_route(url, this, (req, res) => {
|
|
820
|
-
console.log('router', [!!req, !!res]);
|
|
821
|
-
});
|
|
822
|
-
|
|
823
|
-
/*
|
|
824
|
-
'set_route'(str_route, context, fn_handler) {
|
|
825
|
-
*/
|
|
826
|
-
|
|
827
|
-
// Setting up routing here?
|
|
828
|
-
// Or returning it to the server?
|
|
829
|
-
|
|
830
|
-
// hack_setup_routing - as in it hacks into another part of the system (which is available)
|
|
831
|
-
// to set up the routing. A more top-down approach would be for the Server module to set the
|
|
832
|
-
// routing up itself.
|
|
833
|
-
// May be nice if components / resources could set up their own routing, with access to the
|
|
834
|
-
// Resource_Pool.
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
/*
|
|
839
|
-
|
|
840
|
-
// Would need to check operation of custom paths.
|
|
841
|
-
// Maybe its use was removed...?
|
|
842
|
-
this.custom_paths.set(escaped_url, {
|
|
843
|
-
raw: buf_js,
|
|
844
|
-
gzip: buffer
|
|
845
|
-
});
|
|
846
|
-
|
|
847
|
-
*/
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
resolve(true);
|
|
852
|
-
}
|
|
853
|
-
});
|
|
854
|
-
}
|
|
855
|
-
})();
|
|
856
|
-
}, callback);
|
|
857
|
-
}
|
|
858
|
-
|
|
859
|
-
/*
|
|
860
|
-
'set_custom_path'(url, file_path) {
|
|
861
|
-
var escaped_url = url.replace(/\./g, '☺');
|
|
862
|
-
this.custom_paths.set(escaped_url, file_path);
|
|
863
|
-
}
|
|
864
|
-
*/
|
|
865
|
-
//
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
// Not so sure that it should process the request.
|
|
869
|
-
// A more general purpose request handler...?
|
|
870
|
-
// Have more request handling code within one js file, a cenralised portion of the app.
|
|
871
|
-
// And then within those request handlers call on useful abstractions.
|
|
872
|
-
|
|
873
|
-
// Setting up one or more Compilers seems like it would solve some of what this is doing.
|
|
874
|
-
// Even a Compilation_Process object that provides data for monitoring.
|
|
875
|
-
// Published with a Resource_Publisher possibly.
|
|
876
|
-
|
|
877
|
-
// Website_HTTP_Publisher maybe
|
|
878
|
-
|
|
879
|
-
// or just HTTP_Publisher, a Publisher rather than a Resource.
|
|
880
|
-
// HTTP_Publisher, which is focused on publishing HTTP, may be the best option here.
|
|
881
|
-
// Seems best to fix what we have already first though. Could then work on HTTP_Publisher.
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
// Website_HTTP_Publisher_Resource possibly?
|
|
886
|
-
|
|
887
|
-
//
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
// Site_JavaScript seems more about bundling / compiling rather than serving.
|
|
892
|
-
// Resources could present their data ahead of time / be asked for them and provide it, and the server
|
|
893
|
-
// keeps track of info more centrally.
|
|
894
|
-
//
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
'process'(req, res) {
|
|
900
|
-
console.log('Site_JavaScript processing req.url', req.url);
|
|
901
|
-
var remoteAddress = req.connection.remoteAddress;
|
|
902
|
-
var custom_paths = this.custom_paths;
|
|
903
|
-
var rurl = req.url.replace(/\./g, '☺');
|
|
904
|
-
var custom_response_entry = custom_paths[rurl];
|
|
905
|
-
var pool = this.pool;
|
|
906
|
-
if (custom_response_entry) {
|
|
907
|
-
const ae = req.headers['accept-encoding'];
|
|
908
|
-
let data_to_serve;
|
|
909
|
-
let o_head = {
|
|
910
|
-
'Content-Type': 'text/javascript'
|
|
911
|
-
}
|
|
912
|
-
if (ae.includes('gzip')) {
|
|
913
|
-
o_head['Content-Encoding'] = 'gzip';
|
|
914
|
-
data_to_serve = custom_response_entry._.gzip;
|
|
915
|
-
} else {
|
|
916
|
-
data_to_serve = custom_response_entry._.raw;
|
|
917
|
-
}
|
|
918
|
-
res.writeHead(200, o_head);
|
|
919
|
-
res.end(data_to_serve);
|
|
920
|
-
} else {
|
|
921
|
-
//var served_directories = this.served_directories;
|
|
922
|
-
//console.log('served_directories', served_directories);
|
|
923
|
-
var url_parts = url.parse(req.url, true);
|
|
924
|
-
//console.log('url_parts ' + stringify(url_parts));
|
|
925
|
-
var splitPath = url_parts.path.substr(1).split('/');
|
|
926
|
-
|
|
927
|
-
var wildcard_value = req.params.wildcard_value;
|
|
928
|
-
//console.log('*** wildcard_value', wildcard_value);
|
|
929
|
-
|
|
930
|
-
if (wildcard_value == 'web/require.js') {
|
|
931
|
-
|
|
932
|
-
} else {
|
|
933
|
-
var disk_path = path.dirname(require.main.filename) + '/' + 'js/' + wildcard_value;
|
|
934
|
-
var compress = false;
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
//console.log('disk_path', disk_path);
|
|
938
|
-
|
|
939
|
-
if (compress) {
|
|
940
|
-
throw 'NYI with Babel';
|
|
941
|
-
|
|
942
|
-
} else {
|
|
943
|
-
// try to load it from the project's js path.
|
|
944
|
-
//console.log('disk_path', disk_path);
|
|
945
|
-
var project_js_path = 'js/' + wildcard_value;
|
|
946
|
-
//console.log('project_js_path', project_js_path);
|
|
947
|
-
|
|
948
|
-
fs2.load_file_as_string(disk_path, function (err, str_js) {
|
|
949
|
-
if (err) {
|
|
950
|
-
console.log('error loading from project_js_path: ', project_js_path);
|
|
951
|
-
console.log(err);
|
|
952
|
-
} else {
|
|
953
|
-
// Have loaded the js from the project path, we can serve it.
|
|
954
|
-
console.log('have loaded js');
|
|
955
|
-
// serve the js.
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
//res.writeHead(200, {'Content-Type': 'text/javascript'});
|
|
959
|
-
// Could possibly stream it from disk instead, that would likely be more efficient.
|
|
960
|
-
console.log('str_js.length', str_js.length);
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
// use gzip in many cases.
|
|
964
|
-
// want to support that.
|
|
965
|
-
|
|
966
|
-
// a streaming middleware fn could work...?
|
|
967
|
-
|
|
968
|
-
zlib.deflate(str_js, function (err, buffer) {
|
|
969
|
-
console.log('deflated buffer.length', buffer.length);
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
if (err) throw err;
|
|
973
|
-
res.writeHead(200, {
|
|
974
|
-
'Content-Encoding': 'deflate',
|
|
975
|
-
'Content-Type': 'text/javascript'
|
|
976
|
-
});
|
|
977
|
-
res.end(buffer);
|
|
978
|
-
//res.writeHead(200, {'Content-Type': 'text/javascript'});
|
|
979
|
-
//response.end(servableJs);
|
|
980
|
-
//res.end(minified.code);
|
|
981
|
-
});
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
//response.end(servableJs);
|
|
985
|
-
//res.end(str_js);
|
|
986
|
-
//throw 'stop';
|
|
987
|
-
}
|
|
988
|
-
})
|
|
989
|
-
}
|
|
990
|
-
}
|
|
991
|
-
}
|
|
992
|
-
}
|
|
993
|
-
}
|
|
994
|
-
|
|
1
|
+
// Sep 2023:
|
|
2
|
+
// This Resource itself is huge in scope, but maybe would be better to make the Resource more in terms of representing the Resource itself
|
|
3
|
+
// and having things like Resource_Processor? Resource_Analyser? Resource_Miner? Resource_Extracter? Resource_Transformer?
|
|
4
|
+
// Resource_Bundler? Resource_Builder?
|
|
5
|
+
|
|
6
|
+
// Resource_Verb_Carryouter Resource_Processor seems like the general name. Could do analysis, building, extraction etc.
|
|
7
|
+
// Raising events / announcements when it finds things.
|
|
8
|
+
|
|
9
|
+
// Does seem like refactoring the Resource so it is much simpler will be worth it, but also going into detail on the
|
|
10
|
+
// different ways the resources can be processed, doing it in a polymorphic way, observables, promises, making more classes for it if needed.
|
|
11
|
+
|
|
12
|
+
// Maybe do want the classes with processing functions built-in?
|
|
13
|
+
// Changing the syntax to more explictly use various files and classes which will be interchangable and separately upgradable
|
|
14
|
+
// and testable will help.
|
|
15
|
+
|
|
16
|
+
// Need to refactor, this code no longer works as first intended, and was slow when it did its full thing.
|
|
17
|
+
// Can do things much more optimially, maybe with esbuild and hashing and caching.
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
// Nov 2020:
|
|
28
|
+
// Need to overhaul this, bugs are on the client, need to be careful and clear about what will be sent to the client.
|
|
29
|
+
// Need to get more into the tools for building JS for the client. Can I do the outline / much of the outline of it myself?
|
|
30
|
+
// Build up a huge JS AST of the whole thing.
|
|
31
|
+
// Build up a system that understands what code does (to an extent) and how it fits together.
|
|
32
|
+
|
|
33
|
+
// Could do my own application-level compression.
|
|
34
|
+
|
|
35
|
+
// JS-Build.
|
|
36
|
+
// Could identify the resources / files used in the site?
|
|
37
|
+
|
|
38
|
+
// Load all the files in, made into a function that will return what the module exports.
|
|
39
|
+
// Or not...
|
|
40
|
+
// Make the module into just the code, store it as a variable, then be able to build
|
|
41
|
+
|
|
42
|
+
// Would make quite a difference - with a lot of localised references made possible.
|
|
43
|
+
//
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
// JS_File
|
|
47
|
+
// Be able to get transformed versions of it
|
|
48
|
+
// JS_File_
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
// Much of this could be better expressed as a Compiler_Resource.
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
// Plan: Do more of this through lower level compilation features.
|
|
55
|
+
// Accessing a compilation resource makes sense structurally.
|
|
56
|
+
|
|
57
|
+
// May want a server to create and test compilation resources / compilers.
|
|
58
|
+
|
|
59
|
+
// Compilers, Bundlers, HTTP Request Handlers - Somewhat lower level, ie tools to get things done.
|
|
60
|
+
// Then also: resources which make use of upgraded and new lower level components.
|
|
61
|
+
|
|
62
|
+
// Server_Resource could help?
|
|
63
|
+
|
|
64
|
+
// Late 2023 - Should keep most of this for the moment, see about using parts when / where needed, also add in other (maybe simpler)
|
|
65
|
+
// ways to do things that are needed to publish JS.
|
|
66
|
+
|
|
67
|
+
// This resource seems like it's responsible for building JS.
|
|
68
|
+
// Seems like a piece of 'server' functionality that will be kind of hidden, need to make sure it's not a leaky abstraction.
|
|
69
|
+
// Also worth considering 'shorthands' where specific pieces of functionality are not needed to be specified, but usually we
|
|
70
|
+
// need to tell it that it needs to compile the JS (and other things).
|
|
71
|
+
|
|
72
|
+
// Maybe this JS resource would be responsible for extracting the CSS from JS and providing it to the CSS resource.
|
|
73
|
+
// Would be best to work through getting a few examples, and implementations of simple apps with nice (maybe new) APIs that need
|
|
74
|
+
// to be supported by jsgui3.
|
|
75
|
+
|
|
76
|
+
// For the moment, don't make anything really complex when it's not needed, but make it so on the lower levels (incl mid)
|
|
77
|
+
// it accesses functionality that is structured in a somewhat complex way, but uses it to do things which by default make the whole
|
|
78
|
+
// process simple.
|
|
79
|
+
|
|
80
|
+
// This runs automatically I think.
|
|
81
|
+
// Probably need to get it automatically building the client js on server start if needed.
|
|
82
|
+
// Likely best to save it locally, as well as to make a hash of all the files that went into the build, save that, only
|
|
83
|
+
// rebuild when it has changed.
|
|
84
|
+
|
|
85
|
+
// Could even provide a list of the intial control jsgui IDs, some empty items in an array? or the index of the node in the doc
|
|
86
|
+
// and then the control id that will be applied.
|
|
87
|
+
// This could make cleaner HTML be served by default, with IDs added later on the client-side using possibly a small amount of
|
|
88
|
+
// supplementary info.
|
|
89
|
+
// Or the ids could be assigned using xpaths.
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
const path = require('path'),
|
|
102
|
+
fs = require('fs'),
|
|
103
|
+
url = require('url'),
|
|
104
|
+
jsgui = require('jsgui3-html'),
|
|
105
|
+
os = require('os'),
|
|
106
|
+
http = require('http'),
|
|
107
|
+
libUrl = require('url'),
|
|
108
|
+
Resource = jsgui.Resource,
|
|
109
|
+
fs2 = require('../fs2'),
|
|
110
|
+
//brotli = require('iltorb').compress,
|
|
111
|
+
//UglifyJS = require('uglify-js'),
|
|
112
|
+
zlib = require('zlib');
|
|
113
|
+
|
|
114
|
+
//fs.createReadStream(filename).pipe(brotli()).pipe(res);
|
|
115
|
+
|
|
116
|
+
const fnl = require('fnl');
|
|
117
|
+
const prom_or_cb = fnl.prom_or_cb;
|
|
118
|
+
const fnlfs = require('fnlfs');
|
|
119
|
+
|
|
120
|
+
const each = jsgui.each,
|
|
121
|
+
arrayify = jsgui.arrayify,
|
|
122
|
+
tof = jsgui.tof;
|
|
123
|
+
const filter_map_by_regex = jsgui.filter_map_by_regex;
|
|
124
|
+
const Class = jsgui.Class,
|
|
125
|
+
Data_Object = jsgui.Data_Object,
|
|
126
|
+
Enhanced_Data_Object = jsgui.Enhanced_Data_Object;
|
|
127
|
+
const fp = jsgui.fp,
|
|
128
|
+
is_defined = jsgui.is_defined;
|
|
129
|
+
const Collection = jsgui.Collection;
|
|
130
|
+
const call_multi = jsgui.call_multi,
|
|
131
|
+
get_truth_map_from_arr = jsgui.get_truth_map_from_arr;
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
//var zlib = require('zlib');
|
|
135
|
+
const util = require('util');
|
|
136
|
+
|
|
137
|
+
const browserify = require('browserify');
|
|
138
|
+
const babel = require('@babel/core');
|
|
139
|
+
|
|
140
|
+
// Extends AutoStart_Resource?
|
|
141
|
+
const stream_to_array = require('stream-to-array');
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
const process_js = require('./process-js');
|
|
145
|
+
const {analyse_js_doc_formatting, extract_client_js} = process_js;
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
var serve_js_file_from_disk_updated_refs = function (filePath, response, callback) {
|
|
149
|
+
fs2.load_file_as_string(filePath, function (err, data) {
|
|
150
|
+
if (err) {
|
|
151
|
+
throw err;
|
|
152
|
+
} else {
|
|
153
|
+
//console.log('');
|
|
154
|
+
//console.log('serve_js_file_from_disk_updated_refs filePath ' + filePath);
|
|
155
|
+
//console.log('data ' + data);
|
|
156
|
+
//var servableJs = updateReferencesForServing(data);
|
|
157
|
+
response.writeHead(200, {
|
|
158
|
+
'Content-Type': 'text/javascript'
|
|
159
|
+
});
|
|
160
|
+
//response.end(servableJs);
|
|
161
|
+
response.end(data);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
var check_served_directories_for_requested_file = function (arr_served_paths, split_path_within_js, callback) {
|
|
167
|
+
|
|
168
|
+
var fns = [
|
|
169
|
+
|
|
170
|
+
]
|
|
171
|
+
var checkPath = function (path, callback) {
|
|
172
|
+
// check to see if an existing file matches up with the path that is requested.
|
|
173
|
+
// so, from that path, we use the split_path_within_js for the rest of the file path.
|
|
174
|
+
// then we check if such a (JS) file exists.
|
|
175
|
+
}
|
|
176
|
+
// fns.push([fs2.load_file_as_string, [source_path_item], function(err, res_loaded) {
|
|
177
|
+
|
|
178
|
+
// Not so sure I can use the exists function like this...
|
|
179
|
+
var reconstitutedPathWithinJs = split_path_within_js.join('/');
|
|
180
|
+
var firstFoundPath;
|
|
181
|
+
each(arr_served_paths, function (i, fsPath) {
|
|
182
|
+
fns.push([function (callback) {
|
|
183
|
+
var checkingPath = fsPath + '/' + reconstitutedPathWithinJs;
|
|
184
|
+
fs.exists(checkingPath, function (exists) {
|
|
185
|
+
//console.log('cb fsPath ' + checkingPath + ' exists ' + exists)
|
|
186
|
+
if (exists & !firstFoundPath) {
|
|
187
|
+
firstFoundPath = checkingPath;
|
|
188
|
+
}
|
|
189
|
+
callback(null, exists);
|
|
190
|
+
})
|
|
191
|
+
},
|
|
192
|
+
[]
|
|
193
|
+
]);
|
|
194
|
+
});
|
|
195
|
+
call_multi(fns, function (err, res_multi) {
|
|
196
|
+
if (err) {
|
|
197
|
+
console.log('err ' + err);
|
|
198
|
+
throw 'stop';
|
|
199
|
+
} else {
|
|
200
|
+
//console.log('res_multi ' + stringify(res_multi));
|
|
201
|
+
//throw 'stop';
|
|
202
|
+
|
|
203
|
+
if (firstFoundPath) {
|
|
204
|
+
callback(null, firstFoundPath);
|
|
205
|
+
} else {
|
|
206
|
+
callback(null, null);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// A way of serving a file so that it includes custom code.
|
|
213
|
+
// Or have a standard client template that is easy to serve.
|
|
214
|
+
|
|
215
|
+
// Maybe do more with custom controls, such as custom page controls.
|
|
216
|
+
// Those page controls would know which control types are within them.
|
|
217
|
+
// That info could then be used to write JS code that sets up the references on the client.
|
|
218
|
+
|
|
219
|
+
// Possibly this should have its own routing tree to connect paths with js files?
|
|
220
|
+
// Need to set up custom paths.
|
|
221
|
+
|
|
222
|
+
class Site_JavaScript extends Resource {
|
|
223
|
+
//'fields': {
|
|
224
|
+
// 'custom_paths': 'data_object'
|
|
225
|
+
//},
|
|
226
|
+
constructor(spec) {
|
|
227
|
+
super(spec);
|
|
228
|
+
//this.meta.set('custom_paths', new Data_Object({}));
|
|
229
|
+
//this.custom_paths = new Data_Object({});
|
|
230
|
+
// Those are custom file paths.
|
|
231
|
+
// could have a collection of directories, indexed by name, that get served.
|
|
232
|
+
// Index the collection by string value?
|
|
233
|
+
//this.meta.set('served_directories', new Collection({'index_by': 'name'}));
|
|
234
|
+
|
|
235
|
+
// But this could be held (only) in the router.
|
|
236
|
+
this.served_directories = new Collection({
|
|
237
|
+
'index_by': 'name'
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
'start'(callback) {
|
|
241
|
+
//console.log('Site_JavaScript start');
|
|
242
|
+
const build_on_start = this.build_on_start;
|
|
243
|
+
if (build_on_start) {
|
|
244
|
+
this.build_client(function (err, res_build) {
|
|
245
|
+
if (err) {
|
|
246
|
+
callback(err)
|
|
247
|
+
} else {
|
|
248
|
+
callback(null, true);
|
|
249
|
+
}
|
|
250
|
+
})
|
|
251
|
+
} else {
|
|
252
|
+
callback(null, true);
|
|
253
|
+
}
|
|
254
|
+
// Let's have it build the client-side code.
|
|
255
|
+
// Need the options to ignore various files, as well as to include the source maps in the output.
|
|
256
|
+
}
|
|
257
|
+
// build client, and serve it from one particular place
|
|
258
|
+
// do so with a promise.
|
|
259
|
+
// serve_package
|
|
260
|
+
// Need to bundle / build together a package from the disk path, then serve it under a URL route.
|
|
261
|
+
|
|
262
|
+
// want to give it the file to build.
|
|
263
|
+
// There will be a variety of jsgui packages.
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
// Will be better as a promise.
|
|
267
|
+
|
|
268
|
+
'build_client'(callback) {
|
|
269
|
+
|
|
270
|
+
// Configurable building mechanisms....
|
|
271
|
+
// Want to provide jsgui events / logs on the build process.
|
|
272
|
+
|
|
273
|
+
// jsgui.notify could be used for some kinds of internal event logging.
|
|
274
|
+
// a specific type of event system.
|
|
275
|
+
|
|
276
|
+
// jsgui.raise('notification', )
|
|
277
|
+
|
|
278
|
+
// .note may be faster.
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
// jsgui.notify('start', 'build_client');
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
// Need the reference relative to the application directory.
|
|
287
|
+
//var path = __dirname + '/js/app.js';
|
|
288
|
+
|
|
289
|
+
// Can we stream it to a buffer in memory instead?
|
|
290
|
+
|
|
291
|
+
// Using a compilation resource may be better long-term.
|
|
292
|
+
// Creating and using a relevant abstraction.
|
|
293
|
+
|
|
294
|
+
// The server should have already loaded (a few) compilers.
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
var appDir = path.dirname(require.main.filename);
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
//console.log('appDir', appDir);
|
|
303
|
+
var app_path = appDir + '/js/app.js';
|
|
304
|
+
var app_bundle_path = appDir + '/js/app-bundle.js';
|
|
305
|
+
var wstream = fs.createWriteStream(app_bundle_path);
|
|
306
|
+
var b = browserify();
|
|
307
|
+
//b.require(app_path, {
|
|
308
|
+
// entry: true,
|
|
309
|
+
// debug: true
|
|
310
|
+
//});
|
|
311
|
+
b.add(app_path);
|
|
312
|
+
//console.log('app_path', app_path);
|
|
313
|
+
//console.log('pre browserify bundle');
|
|
314
|
+
//b.bundle().pipe(process.stdout);
|
|
315
|
+
|
|
316
|
+
b.bundle().pipe(wstream);
|
|
317
|
+
|
|
318
|
+
wstream.end = function (data) {
|
|
319
|
+
//console.log('file bundle write complete');
|
|
320
|
+
callback(null, app_bundle_path);
|
|
321
|
+
// no more writes after end
|
|
322
|
+
// emit "close" (optional)
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
// Will could serve all jsgui code?
|
|
326
|
+
// May be better not to allow server-side code to be read on the client.
|
|
327
|
+
// Could have specific directories within jsgui that get served to the client.
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
// May be best thinking of bundling up one or more objects / files ready for the server to serve.
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
'serve_directory'(path) {
|
|
334
|
+
// Serves that directory, as any files given in that directory can be served from /js
|
|
335
|
+
|
|
336
|
+
// Perhaps just using the router would be better.
|
|
337
|
+
|
|
338
|
+
var served_directories = this.served_directories;
|
|
339
|
+
//console.log('served_directories ' + stringify(served_directories));
|
|
340
|
+
//served_directories.push(path);
|
|
341
|
+
served_directories.push({
|
|
342
|
+
'name': path
|
|
343
|
+
});
|
|
344
|
+
//console.log('served_directories ' + stringify(served_directories));
|
|
345
|
+
//console.log('path ' + path);
|
|
346
|
+
//throw 'stop';
|
|
347
|
+
}
|
|
348
|
+
'serve_package'(url, js_package, options = {}, callback) {
|
|
349
|
+
//console.log('serve_package', url, js_package);
|
|
350
|
+
//console.log('js_package', js_package);
|
|
351
|
+
//console.log('typeof js_package', typeof js_package);
|
|
352
|
+
//let tjp = typeof js_package;
|
|
353
|
+
return this.serve_package_from_path(url, require.resolve(js_package), options, callback);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// Possibly some functionality would be better within the js bundler.
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
'package'(js_file_path, options = {}, callback) {
|
|
361
|
+
|
|
362
|
+
let a = arguments;
|
|
363
|
+
if (typeof a[2] === 'function') {
|
|
364
|
+
callback = a[2];
|
|
365
|
+
options = {
|
|
366
|
+
//'babel': 'mini',
|
|
367
|
+
'include_sourcemaps': true
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
return prom_or_cb((resolve, reject) => {
|
|
372
|
+
(async () => {
|
|
373
|
+
// options
|
|
374
|
+
// may want a replacement within the client-side code.
|
|
375
|
+
// Can we call browserify on the code string?
|
|
376
|
+
// Creating a modified copy of the file would do.
|
|
377
|
+
// Load the file, modify it, save it under a different name
|
|
378
|
+
|
|
379
|
+
let s = new require('stream').Readable(),
|
|
380
|
+
path = require('path').parse(js_file_path);
|
|
381
|
+
|
|
382
|
+
let fileContents = await fnlfs.load(js_file_path);
|
|
383
|
+
//console.log('1) fileContents.length', fileContents.length);
|
|
384
|
+
// are there any replacements to do?
|
|
385
|
+
// options.replacements
|
|
386
|
+
|
|
387
|
+
if (options.js_mode === 'debug') {
|
|
388
|
+
options.include_sourcemaps = true;
|
|
389
|
+
}
|
|
390
|
+
if (options.js_mode === 'compress' || options.js_mode === 'mini') {
|
|
391
|
+
options.include_sourcemaps = false;
|
|
392
|
+
options.babel = 'mini';
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
//console.log('options.babel', options.babel);
|
|
396
|
+
|
|
397
|
+
if (options.replace) {
|
|
398
|
+
let s_file_contents = fileContents.toString();
|
|
399
|
+
//console.log('s_file_contents', s_file_contents);
|
|
400
|
+
each(options.replace, (text, key) => {
|
|
401
|
+
//console.log('key', key);
|
|
402
|
+
//console.log('text', text);
|
|
403
|
+
let running_fn = '(' + text + ')();'
|
|
404
|
+
//console.log('running_fn', running_fn);
|
|
405
|
+
s_file_contents = s_file_contents.split(key).join(running_fn);
|
|
406
|
+
})
|
|
407
|
+
fileContents = Buffer.from(s_file_contents);
|
|
408
|
+
//console.log('2) fileContents.length', fileContents.length);
|
|
409
|
+
}
|
|
410
|
+
// Then we can replace some of the file contents with specific content given when we tall it to serve that file.
|
|
411
|
+
// We have a space for client-side activation.
|
|
412
|
+
s.push(fileContents);
|
|
413
|
+
s.push(null);
|
|
414
|
+
|
|
415
|
+
//let include_sourcemaps = true;
|
|
416
|
+
|
|
417
|
+
let b = browserify(s, {
|
|
418
|
+
basedir: path.dir,
|
|
419
|
+
//builtins: false,
|
|
420
|
+
builtins: ['buffer', 'process'],
|
|
421
|
+
'debug': options.include_sourcemaps
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
let parts = await stream_to_array(b.bundle());
|
|
425
|
+
|
|
426
|
+
const buffers = parts
|
|
427
|
+
.map(part => util.isBuffer(part) ? part : Buffer.from(part));
|
|
428
|
+
let buf_js = Buffer.concat(buffers);
|
|
429
|
+
let str_js = buf_js.toString();
|
|
430
|
+
|
|
431
|
+
let babel_option = options.babel
|
|
432
|
+
//console.log('babel_option', babel_option);
|
|
433
|
+
if (babel_option === 'es5') {
|
|
434
|
+
|
|
435
|
+
let o_transform = {
|
|
436
|
+
"presets": [
|
|
437
|
+
"es2015",
|
|
438
|
+
"es2017"
|
|
439
|
+
],
|
|
440
|
+
"plugins": [
|
|
441
|
+
"transform-runtime"
|
|
442
|
+
] //,
|
|
443
|
+
//'sourceMaps': 'inline'
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
if (options.include_sourcemaps) o_transform.sourceMaps = 'inline';
|
|
447
|
+
let res_transform = babel.transform(str_js, o_transform);
|
|
448
|
+
//console.log('res_transform', res_transform);
|
|
449
|
+
//console.log('Object.keys(res_transform)', Object.keys(res_transform));
|
|
450
|
+
let jst_es5 = res_transform.code;
|
|
451
|
+
//let {jst_es5, map, ast} = babel.transform(str_js);
|
|
452
|
+
//console.log('jst_es5.length', jst_es5.length);
|
|
453
|
+
buf_js = Buffer.from(jst_es5);
|
|
454
|
+
} else if (babel_option === 'mini') {
|
|
455
|
+
/*
|
|
456
|
+
let o_transform = {
|
|
457
|
+
presets: ["minify"]//,
|
|
458
|
+
//'sourceMaps': 'inline'
|
|
459
|
+
};
|
|
460
|
+
*/
|
|
461
|
+
let o_transform = {
|
|
462
|
+
"presets": [
|
|
463
|
+
["minify", {
|
|
464
|
+
//"mangle": {
|
|
465
|
+
//"exclude": ["MyCustomError"]
|
|
466
|
+
//},
|
|
467
|
+
//"unsafe": {
|
|
468
|
+
// "typeConstructors": false
|
|
469
|
+
//},
|
|
470
|
+
//"keepFnName": true
|
|
471
|
+
}]
|
|
472
|
+
],
|
|
473
|
+
//plugins: ["minify-dead-code-elimination"]
|
|
474
|
+
};
|
|
475
|
+
if (options.include_sourcemaps) o_transform.sourceMaps = 'inline';
|
|
476
|
+
|
|
477
|
+
let res_transform = babel.transform(str_js, o_transform);
|
|
478
|
+
buf_js = Buffer.from(res_transform.code);
|
|
479
|
+
} else {
|
|
480
|
+
buf_js = Buffer.from(str_js);
|
|
481
|
+
}
|
|
482
|
+
resolve(buf_js);
|
|
483
|
+
})();
|
|
484
|
+
}, callback);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// This is a lot about creating some 'package' that includes built JS and CSS
|
|
488
|
+
|
|
489
|
+
// It is not so clear what 'serve' means here though.
|
|
490
|
+
// Perhaps using this functionality could take a few more function calls that are more explicit,
|
|
491
|
+
// but also be set up so that it happens by default when appropriate, or some other function
|
|
492
|
+
// that uses some of the same newly refactored / referenced functions will do the job.
|
|
493
|
+
|
|
494
|
+
// Being more explicit about making sure the server has access to:
|
|
495
|
+
// 1) The client side JS
|
|
496
|
+
// 2) The means to build the client side JS
|
|
497
|
+
// 3) Analysis of the client-side JS source file / files
|
|
498
|
+
// If they contain CSS, that extracted CSS, as a CSS file.
|
|
499
|
+
// Probably best to make a callback saying that it's got it?
|
|
500
|
+
// An 'announcement'? New 'announcement' mechanism, so that when the CSS has been found the CSS publisher hears the announcement.
|
|
501
|
+
// Means the JS resource or publisher does not need a direct reference to the CSS resource or publisher.
|
|
502
|
+
|
|
503
|
+
// Also, make use of the distinction between a Resource and a Publisher.
|
|
504
|
+
// A Resource is something like a file on the disk.
|
|
505
|
+
// The Resources get provided to the Publishers.
|
|
506
|
+
// Then do the Publishers create Resources? Publications? Published_Resources?
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
// 3) The built client-side JS (with or without sourcemaps)
|
|
517
|
+
// 4) The compression setting (brotli/gzip) to compress that client-side JS
|
|
518
|
+
|
|
519
|
+
|
|
520
|
+
|
|
521
|
+
|
|
522
|
+
'serve_package_from_path'(url, js_file_path, options = {}, callback) {
|
|
523
|
+
//console.log('serve_package_from_path', url, js_file_path);
|
|
524
|
+
// js_mode option may need to be used.
|
|
525
|
+
|
|
526
|
+
|
|
527
|
+
// Make it an observable?
|
|
528
|
+
// Raise an event when we have the browserified fill js file (uncompressed?).
|
|
529
|
+
|
|
530
|
+
|
|
531
|
+
let a = arguments;
|
|
532
|
+
if (typeof a[2] === 'function') {
|
|
533
|
+
callback = a[2];
|
|
534
|
+
options = {
|
|
535
|
+
//'babel': 'mini',
|
|
536
|
+
'include_sourcemaps': false
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
let serve_raw = options.serve_raw || options.raw;
|
|
540
|
+
let accepts_brotli = false;
|
|
541
|
+
|
|
542
|
+
// Need to come up with compressed versions.
|
|
543
|
+
// An object that provides different versions.
|
|
544
|
+
|
|
545
|
+
|
|
546
|
+
return prom_or_cb((resolve, reject) => {
|
|
547
|
+
(async () => {
|
|
548
|
+
// options
|
|
549
|
+
// may want a replacement within the client-side code.
|
|
550
|
+
// Can we call browserify on the code string?
|
|
551
|
+
// Creating a modified copy of the file would do.
|
|
552
|
+
// Load the file, modify it, save it under a different name
|
|
553
|
+
const Stream = require('stream');
|
|
554
|
+
|
|
555
|
+
let s = new Stream.Readable(),
|
|
556
|
+
path = require('path').parse(js_file_path);
|
|
557
|
+
|
|
558
|
+
let fileContents = await fnlfs.load(js_file_path);
|
|
559
|
+
//console.log('1) fileContents.length', fileContents.length);
|
|
560
|
+
// are there any replacements to do?
|
|
561
|
+
// options.replacements
|
|
562
|
+
if (options.js_mode === 'debug') {
|
|
563
|
+
options.include_sourcemaps = true;
|
|
564
|
+
}
|
|
565
|
+
if (options.js_mode === 'compress' || options.js_mode === 'mini') {
|
|
566
|
+
options.include_sourcemaps = false;
|
|
567
|
+
options.babel = 'mini';
|
|
568
|
+
}
|
|
569
|
+
//console.log('options.babel', options.babel);
|
|
570
|
+
|
|
571
|
+
// Likely to remove this....
|
|
572
|
+
if (options.replace) {
|
|
573
|
+
let s_file_contents = fileContents.toString();
|
|
574
|
+
//console.log('s_file_contents', s_file_contents);
|
|
575
|
+
each(options.replace, (text, key) => {
|
|
576
|
+
//console.log('key', key);
|
|
577
|
+
//console.log('text', text);
|
|
578
|
+
const running_fn = '(' + text + ')();'
|
|
579
|
+
//console.log('running_fn', running_fn);
|
|
580
|
+
s_file_contents = s_file_contents.split(key).join(running_fn);
|
|
581
|
+
})
|
|
582
|
+
fileContents = Buffer.from(s_file_contents);
|
|
583
|
+
//console.log('2) fileContents.length', fileContents.length);
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// Then we can replace some of the file contents with specific content given when we tall it to serve that file.
|
|
587
|
+
// We have a space for client-side activation.
|
|
588
|
+
// want a raw option with no browserify.
|
|
589
|
+
//console.log('serve_raw', serve_raw);
|
|
590
|
+
if (serve_raw) {
|
|
591
|
+
const escaped_url = url.replace(/\./g, '☺');
|
|
592
|
+
//this.custom_paths.set(escaped_url, fileContents);
|
|
593
|
+
|
|
594
|
+
throw 'NYI';
|
|
595
|
+
} else {
|
|
596
|
+
const formatting_info = analyse_js_doc_formatting(fileContents.toString());
|
|
597
|
+
//console.log('formatting_info', formatting_info);
|
|
598
|
+
|
|
599
|
+
const {arr_lines, line_break, indentation_analysis} = formatting_info;
|
|
600
|
+
const {parsed_lines, str_indentation} = indentation_analysis;
|
|
601
|
+
const client_root_js = extract_client_js(formatting_info);
|
|
602
|
+
|
|
603
|
+
//fnlfs.save('d:\\saved.js', client_root_js);
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
s.push(client_root_js);
|
|
607
|
+
s.push(null);
|
|
608
|
+
const lines_file_content = [];
|
|
609
|
+
|
|
610
|
+
// Don't always include sourcemap?
|
|
611
|
+
// Separate out the sourcemap?
|
|
612
|
+
|
|
613
|
+
const b = browserify(s, {
|
|
614
|
+
basedir: path.dir,
|
|
615
|
+
//builtins: false,
|
|
616
|
+
builtins: ['buffer'],
|
|
617
|
+
'debug': options.include_sourcemaps
|
|
618
|
+
});
|
|
619
|
+
// Prefer the idea of sending a stream to browserify.
|
|
620
|
+
const parts = await stream_to_array(b.bundle());
|
|
621
|
+
/*
|
|
622
|
+
var b = browserify([js_file_path], {
|
|
623
|
+
'debug': true
|
|
624
|
+
});
|
|
625
|
+
*/
|
|
626
|
+
//let parts = await stream_to_array(b.bundle());
|
|
627
|
+
const buffers = parts
|
|
628
|
+
.map(part => util.isBuffer(part) ? part : Buffer.from(part));
|
|
629
|
+
let buf_js = Buffer.concat(buffers);
|
|
630
|
+
const str_js = buf_js.toString();
|
|
631
|
+
const str_js_code = str_js;
|
|
632
|
+
let str_sourcemap;
|
|
633
|
+
|
|
634
|
+
let pos_prior_sourcemap = str_js.indexOf('//# sourceMappingURL');
|
|
635
|
+
if (pos_prior_sourcemap > -1) {
|
|
636
|
+
str_js_code = str_js.substr(0, pos_prior_sourcemap);
|
|
637
|
+
str_sourcemap = str_js.substr(pos_prior_sourcemap);
|
|
638
|
+
}
|
|
639
|
+
// filter_extract_css
|
|
640
|
+
|
|
641
|
+
|
|
642
|
+
/*
|
|
643
|
+
const js_remove_comments = (str_js_code) => {
|
|
644
|
+
// comments will be OK within a string.
|
|
645
|
+
|
|
646
|
+
// Be able to work out what type of code we are in at all points...?
|
|
647
|
+
// Non-tokenising scanner...?
|
|
648
|
+
|
|
649
|
+
// Knowing whether or not * / // / * is within a string is important - because if it's in a string its not a comment.
|
|
650
|
+
// seems like making the scanning parser is a bit of a large task. It would constantly need to know what symbol type / string encapsulator to use.
|
|
651
|
+
|
|
652
|
+
// Could split it into lines, spot whenever a line starts a comment...?
|
|
653
|
+
}
|
|
654
|
+
*/
|
|
655
|
+
|
|
656
|
+
const filter_js_extract_control_css = (str_js_code) => {
|
|
657
|
+
// res = [css, js_no_css]
|
|
658
|
+
// Split the js lines.
|
|
659
|
+
|
|
660
|
+
const s_js = str_js_code.split('\n');
|
|
661
|
+
let within_class_css = false;
|
|
662
|
+
const control_css_lines = [];
|
|
663
|
+
const js_non_css_lines = [];
|
|
664
|
+
// and the non-css lines.
|
|
665
|
+
// And need to look for its stop.
|
|
666
|
+
// And leave the first and last line out of the css.
|
|
667
|
+
each(s_js, js_line => {
|
|
668
|
+
let placed_js_line = false;
|
|
669
|
+
const pos_class_css_begin = js_line.indexOf('.css = `');
|
|
670
|
+
// if its 0
|
|
671
|
+
|
|
672
|
+
if (pos_class_css_begin > -1) {
|
|
673
|
+
//console.log('js_line', js_line);
|
|
674
|
+
within_class_css = true;
|
|
675
|
+
}
|
|
676
|
+
// Put empty lines (back) into the js array?
|
|
677
|
+
|
|
678
|
+
if (within_class_css) {
|
|
679
|
+
//console.log('js_line', js_line);
|
|
680
|
+
|
|
681
|
+
const pos_control_css_end = js_line.indexOf('`;');
|
|
682
|
+
//console.log('pos_control_css_end', pos_control_css_end);
|
|
683
|
+
if (pos_control_css_end > -1) {
|
|
684
|
+
within_class_css = false;
|
|
685
|
+
} else {
|
|
686
|
+
if (pos_class_css_begin > -1) {
|
|
687
|
+
|
|
688
|
+
} else {
|
|
689
|
+
control_css_lines.push(js_line);
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
}
|
|
693
|
+
} else {
|
|
694
|
+
js_non_css_lines.push(js_line);
|
|
695
|
+
placed_js_line = true;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
if (!placed_js_line) {
|
|
699
|
+
js_non_css_lines.push('');
|
|
700
|
+
}
|
|
701
|
+
//let is_control_css_start = js_line.indexOf()
|
|
702
|
+
|
|
703
|
+
if (control_css_lines.length > 200) throw 'stop';
|
|
704
|
+
|
|
705
|
+
})
|
|
706
|
+
return [control_css_lines.join('\n'), js_non_css_lines.join('\n')];
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
let [str_css, str_js_no_css] = filter_js_extract_control_css(str_js_code);
|
|
710
|
+
|
|
711
|
+
// Add the sourcemaps back? Its working.
|
|
712
|
+
|
|
713
|
+
if (str_sourcemap) {
|
|
714
|
+
str_js_no_css = str_js_no_css + str_sourcemap;
|
|
715
|
+
}
|
|
716
|
+
this.raise('extracted-controls-css', str_css);
|
|
717
|
+
let babel_option = options.babel;
|
|
718
|
+
|
|
719
|
+
//console.log('babel_option', babel_option);
|
|
720
|
+
//throw 'stop';
|
|
721
|
+
//babel_option = 'es5';
|
|
722
|
+
//console.log('babel_option', babel_option);
|
|
723
|
+
if (babel_option === 'es5') {
|
|
724
|
+
// es5 option
|
|
725
|
+
// not sure if it babels async await though.
|
|
726
|
+
/*
|
|
727
|
+
{
|
|
728
|
+
"presets": [
|
|
729
|
+
"es2015",
|
|
730
|
+
"es2017"
|
|
731
|
+
],
|
|
732
|
+
"plugins": [
|
|
733
|
+
"transform-runtime"
|
|
734
|
+
]
|
|
735
|
+
}
|
|
736
|
+
*/
|
|
737
|
+
/*
|
|
738
|
+
let res_transform = babel.transform(str_js, {
|
|
739
|
+
//'plugins': ['transform-class']
|
|
740
|
+
'plugins': ['transform-es2015-object-super', 'transform-es2015-classes', 'remove-comments'],
|
|
741
|
+
'sourceMaps': 'inline'
|
|
742
|
+
//'plugins': ['transform-es2015-classes']
|
|
743
|
+
// transform-es2015-object-super
|
|
744
|
+
});
|
|
745
|
+
*/
|
|
746
|
+
let o_tranform = {
|
|
747
|
+
"presets": [
|
|
748
|
+
"es2015",
|
|
749
|
+
"es2017"
|
|
750
|
+
],
|
|
751
|
+
"plugins": [
|
|
752
|
+
"transform-runtime"
|
|
753
|
+
] //,
|
|
754
|
+
//'sourceMaps': 'inline'
|
|
755
|
+
};
|
|
756
|
+
if (options.include_sourcemaps) o_tranform.sourceMaps = 'inline';
|
|
757
|
+
|
|
758
|
+
let res_transform = babel.transform(str_js_no_css, o_tranform);
|
|
759
|
+
let jst_es5 = res_transform.code;
|
|
760
|
+
//let {jst_es5, map, ast} = babel.transform(str_js);
|
|
761
|
+
//console.log('jst_es5.length', jst_es5.length);
|
|
762
|
+
buf_js = Buffer.from(jst_es5);
|
|
763
|
+
} else if (babel_option === 'mini') {
|
|
764
|
+
/*
|
|
765
|
+
let o_transform = {
|
|
766
|
+
presets: ["minify"]//,
|
|
767
|
+
//'sourceMaps': 'inline'
|
|
768
|
+
};
|
|
769
|
+
*/
|
|
770
|
+
let o_transform = {
|
|
771
|
+
"presets": [
|
|
772
|
+
["minify", {
|
|
773
|
+
//"mangle": {
|
|
774
|
+
//"exclude": ["MyCustomError"]
|
|
775
|
+
//},
|
|
776
|
+
//"unsafe": {
|
|
777
|
+
// "typeConstructors": false
|
|
778
|
+
//},
|
|
779
|
+
//"keepFnName": true
|
|
780
|
+
}]
|
|
781
|
+
],
|
|
782
|
+
"comments": false
|
|
783
|
+
//plugins: ["minify-dead-code-elimination"]
|
|
784
|
+
};
|
|
785
|
+
|
|
786
|
+
if (options.include_sourcemaps) o_transform.sourceMaps = 'inline';
|
|
787
|
+
let res_transform = babel.transform(str_js_no_css, o_transform);
|
|
788
|
+
//let jst_es5 = res_transform.code;
|
|
789
|
+
//let {jst_es5, map, ast} = babel.transform(str_js);
|
|
790
|
+
//console.log('jst_es5.length', jst_es5.length);
|
|
791
|
+
buf_js = Buffer.from(res_transform.code);
|
|
792
|
+
} else {
|
|
793
|
+
buf_js = Buffer.from(str_js_no_css);
|
|
794
|
+
console.log('no babel use');
|
|
795
|
+
}
|
|
796
|
+
var escaped_url = url.replace(/\./g, '☺');
|
|
797
|
+
|
|
798
|
+
//console.log('pre compress buf_js.length', buf_js.length);
|
|
799
|
+
zlib.gzip(buf_js, {level: 9}, (err, buffer) => {
|
|
800
|
+
console.log('deflated buf_js buffer.length', buffer.length);
|
|
801
|
+
|
|
802
|
+
if (err) {
|
|
803
|
+
reject(err);
|
|
804
|
+
} else {
|
|
805
|
+
//
|
|
806
|
+
//buffer.encoding = 'deflate';
|
|
807
|
+
console.log('');
|
|
808
|
+
console.log('escaped_url', escaped_url);
|
|
809
|
+
console.log('url', url);
|
|
810
|
+
console.log('');
|
|
811
|
+
|
|
812
|
+
const rp = this.pool;
|
|
813
|
+
console.log('rp', rp);
|
|
814
|
+
console.log('rp.resource_names', rp.resource_names);
|
|
815
|
+
|
|
816
|
+
const router = rp.get_resource('Site Router');
|
|
817
|
+
console.log('router', router);
|
|
818
|
+
|
|
819
|
+
router.set_route(url, this, (req, res) => {
|
|
820
|
+
console.log('router', [!!req, !!res]);
|
|
821
|
+
});
|
|
822
|
+
|
|
823
|
+
/*
|
|
824
|
+
'set_route'(str_route, context, fn_handler) {
|
|
825
|
+
*/
|
|
826
|
+
|
|
827
|
+
// Setting up routing here?
|
|
828
|
+
// Or returning it to the server?
|
|
829
|
+
|
|
830
|
+
// hack_setup_routing - as in it hacks into another part of the system (which is available)
|
|
831
|
+
// to set up the routing. A more top-down approach would be for the Server module to set the
|
|
832
|
+
// routing up itself.
|
|
833
|
+
// May be nice if components / resources could set up their own routing, with access to the
|
|
834
|
+
// Resource_Pool.
|
|
835
|
+
|
|
836
|
+
|
|
837
|
+
|
|
838
|
+
/*
|
|
839
|
+
|
|
840
|
+
// Would need to check operation of custom paths.
|
|
841
|
+
// Maybe its use was removed...?
|
|
842
|
+
this.custom_paths.set(escaped_url, {
|
|
843
|
+
raw: buf_js,
|
|
844
|
+
gzip: buffer
|
|
845
|
+
});
|
|
846
|
+
|
|
847
|
+
*/
|
|
848
|
+
|
|
849
|
+
|
|
850
|
+
|
|
851
|
+
resolve(true);
|
|
852
|
+
}
|
|
853
|
+
});
|
|
854
|
+
}
|
|
855
|
+
})();
|
|
856
|
+
}, callback);
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
/*
|
|
860
|
+
'set_custom_path'(url, file_path) {
|
|
861
|
+
var escaped_url = url.replace(/\./g, '☺');
|
|
862
|
+
this.custom_paths.set(escaped_url, file_path);
|
|
863
|
+
}
|
|
864
|
+
*/
|
|
865
|
+
//
|
|
866
|
+
|
|
867
|
+
|
|
868
|
+
// Not so sure that it should process the request.
|
|
869
|
+
// A more general purpose request handler...?
|
|
870
|
+
// Have more request handling code within one js file, a cenralised portion of the app.
|
|
871
|
+
// And then within those request handlers call on useful abstractions.
|
|
872
|
+
|
|
873
|
+
// Setting up one or more Compilers seems like it would solve some of what this is doing.
|
|
874
|
+
// Even a Compilation_Process object that provides data for monitoring.
|
|
875
|
+
// Published with a Resource_Publisher possibly.
|
|
876
|
+
|
|
877
|
+
// Website_HTTP_Publisher maybe
|
|
878
|
+
|
|
879
|
+
// or just HTTP_Publisher, a Publisher rather than a Resource.
|
|
880
|
+
// HTTP_Publisher, which is focused on publishing HTTP, may be the best option here.
|
|
881
|
+
// Seems best to fix what we have already first though. Could then work on HTTP_Publisher.
|
|
882
|
+
|
|
883
|
+
|
|
884
|
+
|
|
885
|
+
// Website_HTTP_Publisher_Resource possibly?
|
|
886
|
+
|
|
887
|
+
//
|
|
888
|
+
|
|
889
|
+
|
|
890
|
+
|
|
891
|
+
// Site_JavaScript seems more about bundling / compiling rather than serving.
|
|
892
|
+
// Resources could present their data ahead of time / be asked for them and provide it, and the server
|
|
893
|
+
// keeps track of info more centrally.
|
|
894
|
+
//
|
|
895
|
+
|
|
896
|
+
|
|
897
|
+
|
|
898
|
+
|
|
899
|
+
'process'(req, res) {
|
|
900
|
+
console.log('Site_JavaScript processing req.url', req.url);
|
|
901
|
+
var remoteAddress = req.connection.remoteAddress;
|
|
902
|
+
var custom_paths = this.custom_paths;
|
|
903
|
+
var rurl = req.url.replace(/\./g, '☺');
|
|
904
|
+
var custom_response_entry = custom_paths[rurl];
|
|
905
|
+
var pool = this.pool;
|
|
906
|
+
if (custom_response_entry) {
|
|
907
|
+
const ae = req.headers['accept-encoding'];
|
|
908
|
+
let data_to_serve;
|
|
909
|
+
let o_head = {
|
|
910
|
+
'Content-Type': 'text/javascript'
|
|
911
|
+
}
|
|
912
|
+
if (ae.includes('gzip')) {
|
|
913
|
+
o_head['Content-Encoding'] = 'gzip';
|
|
914
|
+
data_to_serve = custom_response_entry._.gzip;
|
|
915
|
+
} else {
|
|
916
|
+
data_to_serve = custom_response_entry._.raw;
|
|
917
|
+
}
|
|
918
|
+
res.writeHead(200, o_head);
|
|
919
|
+
res.end(data_to_serve);
|
|
920
|
+
} else {
|
|
921
|
+
//var served_directories = this.served_directories;
|
|
922
|
+
//console.log('served_directories', served_directories);
|
|
923
|
+
var url_parts = url.parse(req.url, true);
|
|
924
|
+
//console.log('url_parts ' + stringify(url_parts));
|
|
925
|
+
var splitPath = url_parts.path.substr(1).split('/');
|
|
926
|
+
|
|
927
|
+
var wildcard_value = req.params.wildcard_value;
|
|
928
|
+
//console.log('*** wildcard_value', wildcard_value);
|
|
929
|
+
|
|
930
|
+
if (wildcard_value == 'web/require.js') {
|
|
931
|
+
|
|
932
|
+
} else {
|
|
933
|
+
var disk_path = path.dirname(require.main.filename) + '/' + 'js/' + wildcard_value;
|
|
934
|
+
var compress = false;
|
|
935
|
+
|
|
936
|
+
|
|
937
|
+
//console.log('disk_path', disk_path);
|
|
938
|
+
|
|
939
|
+
if (compress) {
|
|
940
|
+
throw 'NYI with Babel';
|
|
941
|
+
|
|
942
|
+
} else {
|
|
943
|
+
// try to load it from the project's js path.
|
|
944
|
+
//console.log('disk_path', disk_path);
|
|
945
|
+
var project_js_path = 'js/' + wildcard_value;
|
|
946
|
+
//console.log('project_js_path', project_js_path);
|
|
947
|
+
|
|
948
|
+
fs2.load_file_as_string(disk_path, function (err, str_js) {
|
|
949
|
+
if (err) {
|
|
950
|
+
console.log('error loading from project_js_path: ', project_js_path);
|
|
951
|
+
console.log(err);
|
|
952
|
+
} else {
|
|
953
|
+
// Have loaded the js from the project path, we can serve it.
|
|
954
|
+
console.log('have loaded js');
|
|
955
|
+
// serve the js.
|
|
956
|
+
|
|
957
|
+
|
|
958
|
+
//res.writeHead(200, {'Content-Type': 'text/javascript'});
|
|
959
|
+
// Could possibly stream it from disk instead, that would likely be more efficient.
|
|
960
|
+
console.log('str_js.length', str_js.length);
|
|
961
|
+
|
|
962
|
+
|
|
963
|
+
// use gzip in many cases.
|
|
964
|
+
// want to support that.
|
|
965
|
+
|
|
966
|
+
// a streaming middleware fn could work...?
|
|
967
|
+
|
|
968
|
+
zlib.deflate(str_js, function (err, buffer) {
|
|
969
|
+
console.log('deflated buffer.length', buffer.length);
|
|
970
|
+
|
|
971
|
+
|
|
972
|
+
if (err) throw err;
|
|
973
|
+
res.writeHead(200, {
|
|
974
|
+
'Content-Encoding': 'deflate',
|
|
975
|
+
'Content-Type': 'text/javascript'
|
|
976
|
+
});
|
|
977
|
+
res.end(buffer);
|
|
978
|
+
//res.writeHead(200, {'Content-Type': 'text/javascript'});
|
|
979
|
+
//response.end(servableJs);
|
|
980
|
+
//res.end(minified.code);
|
|
981
|
+
});
|
|
982
|
+
|
|
983
|
+
|
|
984
|
+
//response.end(servableJs);
|
|
985
|
+
//res.end(str_js);
|
|
986
|
+
//throw 'stop';
|
|
987
|
+
}
|
|
988
|
+
})
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
|
|
995
995
|
module.exports = Site_JavaScript;
|