Fork me on GitHub
#shadow-cljs
<
2017-10-11
>
mhuebert08:10:34

@thheller ok, great to know re: :lein true

mhuebert09:10:33

are :js-options documented?

mhuebert10:10:55

wondering the best way to handle something like this:

[:browser] Build failure:
errors in file: /Users/MattPro/Documents/sites2017/keys/node_modules/keypress/index.js
{:js-requires ["events" "string_decoder"], :js-imports [], :js-invalid-requires [], :js-language "es3", :js-errors [{:line 374, :column 30, :message "Octal integer literals are not supported in strict mode."} {:line 375, :column 30, :message "Octal integer literals are not supported in strict mode."}], :js-warnings [{:line 36, :column 3, :message "illegal use of unknown JSDoc tag \"api\"; ignoring it"} {:line 76, :column 3, :message "illegal use of unknown JSDoc tag \"api\"; ignoring it"} {:line 104, :column 3, :message "illegal use of unknown JSDoc tag \"api\"; ignoring it"} {:line 117, :column 3, :message "illegal use of unknown JSDoc tag \"api\"; ignoring it"} {:line 130, :column 3, :message "illegal use of unknown JSDoc tag \"api\"; ignoring it"}], :tag :shadow.build.npm/errors}
ExceptionInfo: errors in file: /Users/MattPro/Documents/sites2017/keys/node_modules/keypress/index.js

mhuebert10:10:15

my current workaround is to include the keypress lib in a <script> tag and then a :js-option {"keypress": {:target :global :global "keypress"}}

thheller10:10:45

interesting error, I’ll check it out

thheller10:10:40

hmm that looks like a node package? are your building for the web or node?

mhuebert10:10:47

naming thing

thheller10:10:50

var EventEmitter = require('events').EventEmitter; events is a node built-in

mhuebert10:10:52

i thought this was a different library

mhuebert10:10:04

there is a popular library called “Keypress” and I just assumed

mhuebert10:10:42

:face_with_rolling_eyes:

thheller10:10:57

keypress.js maybe?

mhuebert10:10:17

that would be it

thheller10:10:00

will add a formatter for that error

mhuebert10:10:21

module without entry or suffix: keypress.js
{:package {:package-name "keypress.js", :package-dir #object[java.io.File 0x2e477178 "/Users/MattPro/Documents/sites2017/keys/node_modules/keypress.js"], :package-json {"name" "keypress.js", "version" "2.1.4", "main" "keypress.js", "description" "a robust keyboard input capturing Javascript utility focused on input for games. For details and documentation, please visit ", "devDependencies" {"jasmine" "1.3.0"}, "spm" {"main" "keypress.js", "ignore" ["compiler.jar"]}}, :version "2.1.4", :dependencies #{}}, :entry "keypress.js"}
ExceptionInfo: module without entry or suffix: keypress.js

mhuebert10:10:52

i’ll try the react way

thheller10:10:32

its one of those weird packages

thheller10:10:55

"main" : "keypress.js", yet there is no keypress.js file in the directory, only a keypress.coffee

mhuebert10:10:09

{:target  :npm
 :require "keypress.js/keypress-2.1.4.min.js"}

thheller10:10:21

exactly, I was about to suggest that

mhuebert10:10:25

it exports an object with {"keypress": <the-fn>}

thheller10:10:41

really something that should be done by the package but oh well

mhuebert10:10:02

# Anonymous Module Definition
if typeof define is "function" and define.amd
    define [], ->
        return keypress
else if exports?
    exports.keypress = keypress
else
    window.keypress = keypress

thheller10:10:51

(:require ["keypress.js" :refer (keypress)])

mhuebert10:10:01

yup just did that and it works

mhuebert10:10:20

so string requires also work with the other cljs build tools - meaning i can switch all my libraries to (:require [“react” as react])?

thheller10:10:06

yes they should

mhuebert14:10:54

maybe out of scope, but is there a way to specify a fallback for the dev server? (eg. for pushstate routes, so /whatever/non/file/route returns index.html)

richiardiandrea14:10:38

Reading about resolve in #cljs-dev I had the feeling that :type should default to :npm most of the time (convention over configuration they say?) - just an idea @thheller

thheller15:10:21

@richiardiandrea :type? you mean :target? :resolve is optional, the default is to look up :npm. you only specify :resolve if you want to override something.

thheller15:10:17

@mhuebert I could allow specifying a custom ring handler if required

mhuebert16:10:24

humm. hinting externs..

mhuebert16:10:00

(ns my.app (:require ["keypress.js" :refer [keypress]]))
(defonce Keypress (new (.-Listener keypress)))

mhuebert16:10:23

new $module$node_modules$keypress_js$keypress_2_1_4_min$$.$keypress$.$Listener$; the referred keypress as well as Listener are renamed by the compiler & so it breaks

mhuebert16:10:44

the only way I currently know how to get this working is pretty ugly:

(ns my.app (:require ["keypress.js" :as KP] 
                     [goog.object :as gobj]))
(defonce Keypress (new (gobj/getValueByKeys KP "keypress" "Listener")))

mhuebert16:10:13

not sure how one could add hints somewhere here, or write an externs file that references things brought in from node_modules

richiardiandrea16:10:59

@thheller cool that's exactly what I would expect 😉

thheller16:10:57

@mhuebert try running shadow-cljs check browser with the first version

mhuebert16:10:24

38 | (defonce Keypress (new (.-Listener keypress)))
-----------------------------------------^--------------------------------------
 Property keypress never defined on module$node_modules$keypress_js$keypress_2_1_4_min

thheller16:10:24

otherwise create an externs.js file somewhere

thheller16:10:27

/**
 * @externs
 */


/** @constructor */
var X = function() {};

X.prototype.Listener;
X.prototype.keypress;

thheller16:10:52

then in the build config :compiler-options {:externs ["path/to/that-file.js"]}

thheller16:10:09

Property keypress never defined on only this part is important

thheller16:10:16

the property is unknown

mhuebert16:10:23

i haven’t written externs by hand in awhile.. so X can be anything, doesn’t have to match module$node_modules$keypress...

thheller16:10:50

yes, since CLJS is untyped X can be anything

thheller16:10:58

but that “helps” us

thheller16:10:32

X.prototype.keypress basically tells the compiler that whenever it finds some.keypress property access and it doesn’t know the type of some to not rename it

thheller16:10:30

those are all the externs I use for the shadow-cljs script itself

thheller16:10:01

shadow-cljs check is meant as a quick way to find things that need externs

thheller16:10:35

btw not sure if you know that but shadow-cljs release browser --pseudo-names enables pseudo names to help debugging issues such as this

thheller16:10:44

no need to fiddle with the config 😉

thheller16:10:17

also shadow-cljs release browser --debug but source maps are currently not totally accurate once you use a JS dependency

thheller16:10:22

still working out how to fix that

mhuebert16:10:38

ah that’s a handy flag

thheller16:10:40

--debug is --source-maps + --pseudo-names

thheller16:10:53

I totally want to automate externs more … it should be possible to make it work automatically without additional config

thheller16:10:07

just needs some work (and time)

thheller16:10:15

anyways .. externs are not scary … don’t do this gobj/getValueByKeys 😉

thheller16:10:48

I can totally fix the :refered names though. those should never need externs.

mhuebert16:10:38

are there a lot of cases where externs files do more than list property names of the form you just showed?

thheller16:10:31

it depends on the goals. in my cases never.

thheller16:10:16

the Closure Library is fully typed, CLJS is not. so there are going to be cases where closure will be unable to infer the type of a thing

thheller16:10:44

you can typehint all externs but that only benefits you if everything is typed

thheller16:10:03

IMHO it is not necessary to typehint externs

mhuebert16:10:52

so in many cases, a sufficient externs file could be generated from a vector of property strings

thheller16:10:00

yes, in fact I should totally add that 😉

thheller16:10:47

the problem with externs is that they may actually hurt

thheller16:10:08

so if you have too many it might stop renaming things it could otherwise rename

thheller16:10:35

say if you have (defn render [] ...) in CLJS, the render name would usually be renamed

thheller16:10:48

but if you have render ANYWHERE in the externs it will not be renamed

thheller16:10:13

even if you never have any native JS that has a render property

thheller16:10:00

not yet sure what the best course of action is for externs

thheller16:10:19

worst case is you keep a few extra KB of js if you have too many

mhuebert16:10:37

yeah, and because these things are by definition repetitive, may not have a huge impact after gzip?

thheller16:10:04

the problem is that it also stops DCE, not just the rename

thheller16:10:28

so even if you never use render it will stay.

thheller16:10:06

still should not be a huge impact, could always let someone write specialized externs

thheller16:10:54

I will totally add support for an externs.txt, one string per line equals one property

thheller16:10:12

never thought of that before 🙂

thheller16:10:38

afk, shopping