tonsky / datascript

Immutable database and Datalog query engine for Clojure, ClojureScript and JS
Eclipse Public License 1.0
5.49k stars 309 forks source link

Nil values when building clojurescript for chrome extension #432

Closed macklinhrw closed 2 years ago

macklinhrw commented 2 years ago

Hello, I'm having some difficulty with using datascript in my chrome extension.

I'm building from clojurescript with shadow-cljs, using build settings :target :node-library and then importing the bundle in my chrome extension.

Besides some funkiness with the imports, everything has worked as expected, and I've been able to execute the bundled Clojure code from my chrome extension. I know that datascript has a javascript API, but I'm currently testing out this project setup to see if the added convenience of having a clojure REPL and developing the datascript queries/logic in clojurescript is worth it.

Here is my shadow-cljs.edn

;; shadow-cljs configuration
{:source-paths
 ["src/clojure/src/main"]

 :dependencies
 [[datascript "1.3.13"]]

 :builds
 {:lib
  {:target :node-library
   :output-to "src/clojure/bundle/clojure.cjs"
   :exports-var hello/exports}}}

The problem I'm having, is that my datascript query works perfectly fine when executed from a Clojure REPL, but when I run the code from the chrome extension the results of the query are, as far as I can tell, replaced with nil values.

My hello.cljs file

(ns hello
  (:require 
    [datascript.core :as d]))

(defn bookmark [] 
  (let [conn (d/create-conn)
        item {:db/id -1 :title "Title" :url "https://google.com"}]
    (d/transact! conn [item])
    (let [result (d/q '[:find ?e ?title :where [?e :title ?title]] (d/db conn))]
      (println (d/datoms (d/db conn) :eavt))
      (println result))))

(bookmark)
; => #{[1 Title]}

(def exports #js {
                  :bookmark bookmark
                  })

The result that gets printed when ran from the Clojure repl is #{[1 Title]}.

But when the function is called from my chrome extension, here is what gets printed:

; => (#datascript/Datom [1 :title Title 536870913 true] #datascript/Datom [1 :url https://google.com 536870913 true])
; => #{[1 nil]}

I think this isn't a datascript problem, and this is related somehow to the specifics of compiling and running my Clojure code in a chrome extension. However, since datascript has a javascript API* that has the expected behavior, I hope there might be some insights into my problem. Thank you!

*I set up this same project using the javascript API and it works as expected.

Here is my javascript code for reference: Popup.svelte

<script lang="ts">
  import '@src/index.css'
  import clj from "@src/popup/clojure"
  console.log(clj.bookmark())
</script>

clojure.ts

const test = await import('@clj/clojure.cjs')
const { default: clj } = test;
export default clj;

The build tool I'm using on the javascript side of things is vite. Github Repo (the code isn't great): https://github.com/macklinhrw/Bookmarks

tonsky commented 2 years ago

Try adding :externs ["datascript/externs.js"] to :compiler-options map in shadow-cljs.edn? #298 #216

macklinhrw commented 2 years ago

Try adding :externs ["datascript/externs.js"] to :compiler-options map in shadow-cljs.edn? #298 #216

This worked! Thanks, and of course, 1 line of code fixes my 6 hours of headache.

Here is the new config file for anybody interested:

;; shadow-cljs configuration
{:source-paths
 ["src/clojure/src/main"]

 :dependencies
 [[datascript "1.3.13"]]

 :builds
 {:lib
  {:target :node-library
   :output-to "src/clojure/bundle/clojure.cjs"
   :compiler-options {:externs ["datascript/externs.js"]}
   :exports-var hello/exports}}}
tonsky commented 2 years ago

Great! Added to README too