Browse Source

fix: CLI start time

Lazy load namespaces as start time goes up with more required namespaces
external to nbb-logseq or node. CLI now only loads ~6 namespaces instead
of 55 namespaces at start and then lazy loads a command ns as needed
Gabriel Horner 2 months ago
parent
commit
3ae3ff2cd4

+ 6 - 0
deps/cli/.carve/ignore

@@ -0,0 +1,6 @@
+;; Lazy loaded
+logseq.cli.commands.export-edn/export
+logseq.cli.commands.graph/show-graph
+logseq.cli.commands.graph/list-graphs
+logseq.cli.commands.query/query
+logseq.cli.commands.search/search

+ 25 - 13
deps/cli/src/logseq/cli.cljs

@@ -4,12 +4,10 @@
             ["path" :as node-path]
             [babashka.cli :as cli]
             [clojure.string :as string]
-            [logseq.cli.commands.export-edn :as cli-export-edn]
-            [logseq.cli.commands.graph :as cli-graph]
-            [logseq.cli.commands.query :as cli-query]
-            [logseq.cli.commands.search :as cli-search]
             [logseq.cli.common.graph :as cli-common-graph]
-            [nbb.error :as error]))
+            [logseq.cli.spec :as cli-spec]
+            [nbb.error :as error]
+            [promesa.core :as p]))
 
 (defn- format-commands [{:keys [table]}]
   (let [table (mapv (fn [{:keys [cmds desc spec]}]
@@ -51,18 +49,32 @@
                          (cli/format-opts {:spec (:spec cmd-map)})))))
     (println "Command" (pr-str command) "does not exist")))
 
+(defn- lazy-load-fn
+  "Lazy load fn to speed up start time. After nbb requires ~30 namespaces, start time gets close to 1s"
+  [fn-sym]
+  (fn [& args]
+    (p/let [_ (require (symbol (namespace fn-sym)))]
+      (apply (resolve fn-sym) args))))
+
 (def ^:private table
-  [{:cmds ["list"] :fn cli-graph/list-graphs :desc "List graphs"}
-   {:cmds ["show"] :fn cli-graph/show-graph :desc "Show DB graph(s) info"
+  [{:cmds ["list"] :desc "List graphs"
+    :fn (lazy-load-fn 'logseq.cli.commands.graph/list-graphs)}
+   {:cmds ["show"] :desc "Show DB graph(s) info"
+    :fn (lazy-load-fn 'logseq.cli.commands.graph/show-graph)
     :args->opts [:graphs] :coerce {:graphs []}}
-   {:cmds ["search"] :fn cli-search/search :desc "Search current DB graph"
+   {:cmds ["search"]
+    :fn (lazy-load-fn 'logseq.cli.commands.search/search)
+    :desc "Search current DB graph"
     :args->opts [:search-terms] :coerce {:search-terms []}
-    :spec cli-search/spec}
-   {:cmds ["query"] :fn cli-query/query :desc "Query DB graph(s)"
+    :spec cli-spec/search}
+   {:cmds ["query"] :desc "Query DB graph(s)"
+    :fn (lazy-load-fn 'logseq.cli.commands.query/query)
     :args->opts [:graph :queries] :coerce {:queries []} :no-keyword-opts true
-    :spec cli-query/spec}
-   {:cmds ["export-edn"] :fn cli-export-edn/export :desc "Export DB graph as EDN"
-    :args->opts [:graph] :spec cli-export-edn/spec}
+    :spec cli-spec/query}
+   {:cmds ["export-edn"] :desc "Export DB graph as EDN"
+    :fn (lazy-load-fn 'logseq.cli.commands.export-edn/export)
+    :args->opts [:graph]
+    :spec cli-spec/export-edn}
    {:cmds ["help"] :fn command-help :desc "Print a command's help"
     :args->opts [:command]}
    {:cmds []

+ 0 - 20
deps/cli/src/logseq/cli/commands/export_edn.cljs

@@ -6,26 +6,6 @@
             [logseq.db.sqlite.export :as sqlite-export]
             [logseq.cli.util :as cli-util]))
 
-(def spec
-  "Options spec"
-  {:include-timestamps? {:alias :T
-                         :desc "Include timestamps in export"}
-   :file {:alias :f
-          :desc "Saves edn to file"}
-   :catch-validation-errors? {:alias :c
-                              :desc "Catch validation errors for dev"}
-   :exclude-namespaces {:alias :e
-                        :coerce #{}
-                        :desc "Namespaces to exclude from properties and classes"}
-   :exclude-built-in-pages? {:alias :b
-                             :desc "Exclude built-in pages"}
-   :exclude-files? {:alias :F
-                    :desc "Exclude :file/path files"}
-   :export-type {:alias :t
-                 :coerce :keyword
-                 :desc "Export type"
-                 :default :graph}})
-
 (defn export [{{:keys [graph] :as options} :opts}]
   (if (fs/existsSync (cli-util/get-graph-dir graph))
    (let [conn (apply sqlite-cli/open-db! (cli-util/->open-db-args graph))

+ 0 - 8
deps/cli/src/logseq/cli/commands/query.cljs

@@ -10,14 +10,6 @@
             [logseq.db.frontend.rules :as rules]
             [promesa.core :as p]))
 
-(def spec
-  "Query spec"
-  {:graphs {:alias :g
-            :coerce []
-            :desc "Additional graphs to query"}
-   :api-query-token {:alias :a
-                     :desc "Query current graph with api server token"}})
-
 (defn- api-query
   [query token]
   (let [datalog-query? (string/starts-with? query "[")

+ 0 - 9
deps/cli/src/logseq/cli/commands/search.cljs

@@ -6,15 +6,6 @@
             [logseq.cli.text-util :as cli-text-util]
             [promesa.core :as p]))
 
-(def spec {:api-query-token {:alias :a
-                             :require true
-                             :desc "Api server token"}
-           :raw {:alias :r
-                 :desc "Print raw response"}
-           :limit {:alias :l
-                   :default 100
-                   :desc "Limit max number of results"}})
-
 (defn- highlight
   "Shows up as soft red on terminals that support ANSI 24-bit color like iTerm"
   [text]

+ 39 - 0
deps/cli/src/logseq/cli/spec.cljs

@@ -0,0 +1,39 @@
+(ns logseq.cli.spec
+  "Specs for commands. Normally these would live alongside their commands but are separate
+   because command namespaces are lazy loaded")
+
+(def export-edn
+  {:include-timestamps? {:alias :T
+                         :desc "Include timestamps in export"}
+   :file {:alias :f
+          :desc "Saves edn to file"}
+   :catch-validation-errors? {:alias :c
+                              :desc "Catch validation errors for dev"}
+   :exclude-namespaces {:alias :e
+                        :coerce #{}
+                        :desc "Namespaces to exclude from properties and classes"}
+   :exclude-built-in-pages? {:alias :b
+                             :desc "Exclude built-in pages"}
+   :exclude-files? {:alias :F
+                    :desc "Exclude :file/path files"}
+   :export-type {:alias :t
+                 :coerce :keyword
+                 :desc "Export type"
+                 :default :graph}})
+
+(def query
+  {:graphs {:alias :g
+            :coerce []
+            :desc "Additional graphs to query"}
+   :api-query-token {:alias :a
+                     :desc "Query current graph with api server token"}})
+
+(def search
+  {:api-query-token {:alias :a
+                     :require true
+                     :desc "Api server token"}
+   :raw {:alias :r
+         :desc "Print raw response"}
+   :limit {:alias :l
+           :default 100
+           :desc "Limit max number of results"}})