Fork me on GitHub
#shadow-cljs
<
2022-09-18
>
dvingo17:09:05

hi - I'm working on malli cljs instrumentation. I am trying to get the updated namespaces during development/reload cycle is there a way to get the list of namespaces/files that triggered the fs watch? in the :compile-prepare hook

(:compiled (:shadow.build/build-info build-state)
is empty (obviously), is there an equivalent way to get the updated files in prepare stage? The goal is to reset! state used by a macro in order to communicate to the macro which namespaces need to be re-instrumented, which needs to be updated before compilation

Joe Dumont18:09:14

Hi, I have the following error when releasing an app:

shadow-cljs - connected to server
[:app] Compiling ...
Closure compilation failed with 1 errors
--- externs.shadow.js:8
Parse error. 'identifier' expected   
I went through suggested solutions here https://clojurians.slack.com/archives/C6N245JGG/p1612542030435100 and added the following variations of build-hooks as suggested in that thread, but didn't turn up a comparable solution. I'm wondering if there's another strategy to take to find whats causing this. I also went through and removed any unicode symbols and non-english characters in case that was the issue, but still have 1 error somewhere.
;; ;; This didn't find any empty ""
(defn find-it
  {:shadow.build/stage :optimize-prepare}
  [build-state]

  (prn (shadow.build.closure/extern-props-from-cljs build-state))

  build-state)
;; [:app] Compiling ...
;; #{"useLayoutEffect" "useRef" "useCallback" "useImperativeHandle" "$$Signature$$"
;;  "getElementById" "removeEventListener" "createRoot" "createElement" "flushSync"
;;  "Fragment" "PersistentVector" "useDebugValue" "$$Register$$" "DateTimeFormat"
;;  "useMemo" "hasNext" "forwardRef" "createContext" "PersistentArrayMap"
;;  "Suspense" "useReducer" "Component" "useEffect" "now" "useState" "useContext"
;;  "addEventListener" "Element" "core" "memo" "equiv"}

;; Closure compilation failed with 1 errors --- externs.shadow.js:8 Parse error.
;; 'identifier' expected
(defn find-it
  {:shadow.build/stage :optimize-prepare}
  [{:keys [output] :as build-state}]

  (doseq [{:keys [resource-id properties]} (vals output)
          prop properties
          :when (< (count prop) 2)]
    (prn [:prop resource-id prop]))

  build-state)
;; this one didn't log anything at all
;; beyond initial error
(defn find-it
  {:shadow.build/stage :optimize-prepare}
  [{:keys [output] :as build-state}]

  (->> (vals output)
       (filter #(contains? (:properties %) ""))
       (map :resource-id)
       (prn))

  build-state)
;; [:app] Compiling ...
;; ()
;; Closure compilation failed with 1 errors
;; --- externs.shadow.js:8
;; Parse error. 'identifier' expected
(defn find-it
  {:shadow.build/stage :optimize-prepare}
  [state]

  (doseq [src-id (:build-sources state)
          :let [{:keys [ns file] :as src}
                (get-in state [:sources src-id])
                {:shadow/keys [js-access-properties]}
                (get-in state [:compiler-env :cljs.analyzer/namespaces ns])]
          :when (contains? js-access-properties "")]
    (prn [:found ns js-access-properties]))

  state)
;; [:app] Compiling ...
;; Closure compilation failed with 1 errors
;; --- externs.shadow.js:8
;; Parse error. 'identifier' expected

thheller19:09:24

this doesn't necessarily have to be an empty string

thheller19:09:34

could be anything that is not a valid JS identifier

thheller19:09:05

can't think of anything quick to figure this out. let me think about it tomorrow

Joe Dumont19:09:48

Thank so much.

thheller19:09:04

I mean even these "_peek-at" looks suspicious

thheller19:09:18

because they are not valid identifiers

thheller19:09:26

can you check where that is from? with the find-it helper but looking for that not the empty string?

thheller19:09:12

"Children.toArray" is also incorrect

Joe Dumont19:09:15

Ah "_peek-at" was from the old thread, I don't have any of that in my output.

thheller19:09:19

so not sure where all of these are coming from

thheller19:09:01

the externs file is created in .shadow-cljs/builds/<the-id>/release/externs.shadow.js

Joe Dumont19:09:07

I only get

shadow-cljs - connected to server
[:app] Compiling ...
Closure compilation failed with 1 errors
--- externs.shadow.js:8
Parse error. 'identifier' expected

thheller19:09:11

look in line 8 šŸ˜‰

Joe Dumont19:09:57

Aha! I was searching for that... I think I was trying to throw a js error improperly ā•°ā”€$ cat .shadow-cljs/builds/app/release/externs.shadow.js

/** @const {ShadowJS} */ var Intl;
/** @const {ShadowJS} */ var Promise;
/** @const {ShadowJS} */ var React;
/** @const {ShadowJS} */ var clearInterval;
/** @const {ShadowJS} */ var clearTimeout;
/** @const {ShadowJS} */ var module;
/** @const {ShadowJS} */ var setInterval;
/** @const {ShadowJS} */ var throw;
/** @const {ShadowJS} */ var undefined;

thheller19:09:06

hmm where is that undefined coming from šŸ˜›

Joe Dumont19:09:29

I'll look for that as well. Removing a couple of (js/throw ...) now has it compiling without error though.

thheller19:09:26

just (throw ...) is fine. no need for the js/

šŸ‘ 1
Joe Dumont19:09:17

Aha. Even with it compiling without error now, I still see the undefined var. If I did want to locate where that's coming from, do you have a suggestion?

/** @const {ShadowJS} */ var Intl;
/** @const {ShadowJS} */ var Promise;
/** @const {ShadowJS} */ var React;
/** @const {ShadowJS} */ var clearInterval;
/** @const {ShadowJS} */ var clearTimeout;
/** @const {ShadowJS} */ var module;
/** @const {ShadowJS} */ var setInterval;
/** @const {ShadowJS} */ var undefined;

thheller19:09:57

well the find-it helper fn

thheller19:09:20

but not looking for properties

thheller19:09:13

extern-globals-from-cljs instead of the extern-properties-from-cljs

Joe Dumont19:09:38

Like so?

(defn find-it
  {:shadow.build/stage :optimize-prepare}
  [build-state]

  (prn (shadow.build.closure/extern-globals-from-cljs build-state))

  build-state)
[:app] Compiling ...
#{"window" "Symbol" "Promise" "Date" "document" "Intl" "clearTimeout" "React" "JSON" "clearInterval" "RegExp" "undefined" "Error" "setTimeout" "setInterval"}
[:app] Build completed. (72 files, 0 compiled, 0 warnings, 11.43s)

thheller19:09:53

(doseq [src-id (:build-sources state)
        :let [{:keys [ns file] :as src}
              (get-in state [:sources src-id])
              {:shadow/keys [js-access-properties]}
              (get-in state [:compiler-env :cljs.analyzer/namespaces ns])]
        :when (contains? js-access-properties "undefined")]
  (prn [:found ns js-access-properties]))

thheller19:09:02

the find-it hook

thheller19:09:14

just looking for undefined not the empty string

thheller19:09:06

sorry, like this. looking for globals not properties

(doseq [src-id (:build-sources state)
        :let [{:keys [ns file] :as src}
              (get-in state [:sources src-id])
              {:shadow/keys [js-access-global]}
              (get-in state [:compiler-env :cljs.analyzer/namespaces ns])]
        :when (contains? js-access-global "undefined")]
  (prn [:found ns js-access-global]))

thheller19:09:32

or rather the full hook

(defn find-it
  {:shadow.build/stage :optimize-prepare}
  [state]

  (doseq [src-id (:build-sources state)
          :let [{:keys [ns file] :as src}
                (get-in state [:sources src-id])
                {:shadow/keys [js-access-global]}
                (get-in state [:compiler-env :cljs.analyzer/namespaces ns])]
          :when (contains? js-access-global "undefined")]
    (prn [:found ns js-access-global]))
  
  state)

šŸ‘ 1
Joe Dumont19:09:54

[:app] Compiling ...
[:found helix.impl.props #{"RegExp" "undefined" "Error"}]
[:found helix.core #{"window" "Symbol" "undefined" "Error"}]
[:found helix.hooks #{"undefined" "Error"}]
[:app] Build completed. (72 files, 0 compiled, 0 warnings, 11.77s)

thheller19:09:23

hmm I guess it collects that for js/undefined

thheller19:09:32

probably shouldn't but seems like it doesn't hurt anything

Joe Dumont20:09:15

Thank you for all your time and help!