this repo has no description

js_top_worker: replace static preloaded list with Symtable runtime check

Use Symtable.Global.of_ident / is_global_defined to detect packages
already linked into the worker binary at runtime, eliminating the
hand-maintained list that drifts out of sync with example/dune deps.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

+18 -73
+18 -73
lib/findlibish.ml
··· 17 17 in 18 18 List.map handle_lib libs |> List.flatten 19 19 20 - (* Packages compiled into the worker binary. When #require loads a package 21 - that is already linked into the worker, we must NOT call import_scripts on 22 - its .cma.js — doing so would re-register CMI files that are already in the 23 - virtual filesystem, causing a Sys_error "file already exists". 20 + (* Runtime check for packages compiled into the worker binary. 21 + When #require loads a package that is already linked into the worker, 22 + we must NOT call import_scripts on its .cma.js — doing so would 23 + re-register CMI files that are already in the virtual filesystem, 24 + causing a Sys_error "file already exists". 25 + 26 + Instead of maintaining a hand-written list, we use Symtable to check 27 + whether any of the package's toplevel modules are already in the 28 + bytecode global table (i.e. linked into the binary). *) 29 + 30 + let is_module_available module_name = 31 + let id = Ident.create_persistent module_name in 32 + match Symtable.Global.of_ident id with 33 + | None -> false 34 + | Some g -> Symtable.is_global_defined g 24 35 25 - This list must match the transitive closure of the worker's library deps 26 - (see example/dune). To regenerate: 27 - ocamlfind query -recursive -format '%p' \ 28 - js_top_worker-web logs.browser mime_printer tyxml \ 29 - js_top_worker-widget note | sort -u *) 30 - let preloaded = 31 - [ 32 - "angstrom"; 33 - "astring"; 34 - "bigstringaf"; 35 - "compiler-libs"; 36 - "compiler-libs.bytecomp"; 37 - "compiler-libs.common"; 38 - "compiler-libs.toplevel"; 39 - "csexp"; 40 - "findlib"; 41 - "findlib.internal"; 42 - "findlib.top"; 43 - "fpath"; 44 - "gen"; 45 - "js_of_ocaml"; 46 - "js_of_ocaml-compiler"; 47 - "js_of_ocaml-compiler.dynlink"; 48 - "js_of_ocaml-compiler.runtime"; 49 - "js_of_ocaml-lwt"; 50 - "js_of_ocaml-ppx"; 51 - "js_of_ocaml-toplevel"; 52 - "js_top_worker"; 53 - "js_top_worker-rpc.message"; 54 - "js_top_worker-web"; 55 - "js_top_worker-widget"; 56 - "logs"; 57 - "logs.browser"; 58 - "lwt"; 59 - "menhirLib"; 60 - "merlin-lib.analysis"; 61 - "merlin-lib.config"; 62 - "merlin-lib.dot_protocol"; 63 - "merlin-lib.extend"; 64 - "merlin-lib.index_format"; 65 - "merlin-lib.kernel"; 66 - "merlin-lib.ocaml_compression"; 67 - "merlin-lib.ocaml_merlin_specific"; 68 - "merlin-lib.ocaml_parsing"; 69 - "merlin-lib.ocaml_preprocess"; 70 - "merlin-lib.ocaml_typing"; 71 - "merlin-lib.ocaml_utils"; 72 - "merlin-lib.os_ipc"; 73 - "merlin-lib.query_commands"; 74 - "merlin-lib.query_protocol"; 75 - "merlin-lib.sherlodoc"; 76 - "merlin-lib.utils"; 77 - "mime_printer"; 78 - "note"; 79 - "ocaml-compiler-libs.common"; 80 - "ocaml-compiler-libs.shadow"; 81 - "re"; 82 - "sedlex"; 83 - "seq"; 84 - "str"; 85 - "stringext"; 86 - "tyxml"; 87 - "tyxml.functor"; 88 - "unix"; 89 - "uri"; 90 - "uutf"; 91 - "yojson"; 92 - ] 36 + let is_package_preloaded (dcs : Js_top_worker.Impl.dynamic_cmis) = 37 + List.exists is_module_available dcs.dcs_toplevel_modules 93 38 94 39 let rec read_libraries_from_pkg_defs ~library_name ~dir meta_uri pkg_expr = 95 40 try ··· 366 311 match fetch_dynamic_cmis sync_get (Uri.to_string uri) with 367 312 | Ok dcs -> 368 313 let should_load = 369 - (not (List.mem lib.name preloaded)) && not cmi_only 314 + (not (is_package_preloaded dcs)) && not cmi_only 370 315 in 371 316 Option.iter 372 317 (fun archive ->