Shadow-cljs error only on release version (using promises)

So. I have this code working normally on watch:

(ns bop.invoice-maker.core
  (:require
    ["cuid" :as cuid]
    ["puppeteer" :as puppeteer]
    ["rfdc" :as deep-copy]
    ["path" :as path]
    ["toml" :as toml]
    ["minimist" :as minimist]
    ["fs/promises" :rename {readFile  read-file}]
    [promesa.core :as p]
    [cljs.core.async :refer [go]]
    [cljs.core.async.interop :refer-macros [<p!]]
    [goog.string :as gstring]
    [goog.string.format]))

(set! *warn-on-infer* false)

(def state (atom {:browser nil :page nil}))
(def url "https://invoice.remessaonline.com.br/")
(def config-path (.resolve path "config.toml"))

(def log js/console.log)
(defn copy [x] ((deep-copy) x))

; (prn (gstring/format  "Pad with leading zeros %07d" 5432))
(defn left-pad-number [char how-many text]
  (gstring/format (str "%" char how-many "d") text))

(defn parse-config [path]
  (-> (read-file path)
       (.then #(.parse toml %))
       (.then #(js->clj (copy %) :keywordize-keys true))))

(defn set-browser [current]
    (swap! state assoc :browser current))

(defn set-page [current]
    (swap! state assoc :page current))

(defn create-file-name [] 
  (str "./screenshots/" (cuid) ".png"))

(defn select-tab [page]
  (.click page ".tab-link-tab-2"))

(defn open-page [page]
  (.goto page url #js {:waitUntil "networkidle2"}))

(defn wait-for [page selector]
  (.waitForSelector page (str "[data-w-tab=\"Tab 2\"].tab-pane-tab-2 " selector)))

(defn type-input [page input value]
  (prn (str "[data-w-tab=\"Tab 2\"].tab-pane-tab-2 " input))
  (.type page (str "[data-w-tab=\"Tab 2\"].tab-pane-tab-2 " input) value))

(defn set-timeout [time] 
  (js/Promise. #(js/setTimeout %1 time)))

(defn as-vector [x]
  (cond
    (vector? x) x
    (sequential? x) (vec x)
    :else (vector x)))

(defn close-browser-if-open []
  (if (not (nil? (get @state :browser)))
          (.close (get @state :browser))))

(defn get-payer-data [data keys]
  (get-in data (as-vector (concat [:payer] (as-vector keys)))))

(defn get-receiver-data [data keys]
  (get-in data (as-vector (concat [:receiver] (as-vector keys)))))

(defn handle-browser [browser]
  (close-browser-if-open)
  (set-browser browser)
  (.newPage browser))

(defn handle-page [page config parsed-args]
  (p/do
    (set-page page)
    (open-page page)
    (select-tab page)
    (p/delay 2000)
    (type-input page "#value-usd-2"
                (get-receiver-data config :name))))

(defn init [& argv]
  (println (minimist (clj->js (or argv []))))
  (println "Initializing...")
  (p/let [parsed-args (minimist (clj->js (or argv [])))
          config (parse-config config-path)
          browser (.launch puppeteer #js {:headless false})
          page (.newPage browser)]
      (handle-browser browser)
      (-> (handle-page page config parsed-args)
          (p/catch #(prn "Error!:" %))
          (p/finally #(prn "Done!")))))

Then I ran: npx shadow-cljs release script --debug

And then node dist/main.js

Gives me this output:

/Users/bruno/personal/invoice-maker/dist/main.js:7383
          return $promesa$protocols$_bind$$($promesa$protocols$_promise$$($browser$jscomp$1$$.$newPage$()), function($page$jscomp$5$$) {
                                                                                              ^

TypeError: $browser$jscomp$1$$.$newPage$ is not a function
    at /Users/bruno/personal/invoice-maker/dist/main.js:7383:95
    at /Users/bruno/personal/invoice-maker/dist/main.js:7217:150
    at processTicksAndRejections (node:internal/process/task_queues:96:5)

what is happening here?

This is an error due to missing externs. The .newPage gets renamed, when it shouldn’t be. Normally you should be getting an inference warning due to this?

The solution would be adding ^js hints as here:

(defn init [& argv]
  (println (minimist (clj->js (or argv []))))
  (println "Initializing...")
  (p/let [parsed-args (minimist (clj->js (or argv [])))
          config (parse-config config-path)
          ^js browser (.launch puppeteer #js {:headless false})
          page (.newPage browser)]
      (handle-browser browser)
      (-> (handle-page page config parsed-args)
          (p/catch #(prn "Error!:" %))
          (p/finally #(prn "Done!")))))

See more about externs here in the docs.

https://shadow-cljs.github.io/docs/UsersGuide.html#externs

1 Like