Fork me on GitHub
#shadow-cljs
<
2018-01-11
>
tony.kay00:01:56

are compiler-options ignored for compile?

thheller00:01:41

:optimizations only applies for release

tony.kay00:01:14

I see. So release means compile and optimize, or is it just a separate step?

thheller00:01:22

all shadow-cljs builds are basically 2-in-1 if you are used to other build tools

thheller00:01:04

compile is one time dev compile, watch is dev compile on repeat, release is a release compile + optimization

tony.kay00:01:39

got it…I’m going to have to apply my asciidoc skills to your documentation 😉

thheller00:01:11

your documentations skills definitely outshine mine

thheller00:01:43

whenever I start writing docs I start drifting to the code and just write some other code instead

tony.kay00:01:21

yeah, it’s tough…as you write them you discover bugs and missing things…and have to fix them right then

tony.kay00:01:31

I’m definitely liking the i18n ideas…I just discovered that trf is broken on extraction…compiler is moving the literal string to a var

tony.kay00:01:55

from a plug-ins perspective, wouldn’t it be better just to give a clean API for code to store/retrieve data during compile, and then a hook to run at end of compile?

tony.kay00:01:47

I love that macros give you the ability to extend the compiler…but it had never occurred to me that lifecycle would also be so useful.

tony.kay00:01:28

same thing with data_readers, now that I think of it

thheller00:01:33

compiler should also be able to help with css extractions and things like that

thheller00:01:18

could certainly create a proper API instead of directly messing with the cljs.env/*compiler* atom

tony.kay00:01:39

come to think of it…lifecycle is sufficient

tony.kay00:01:50

start and end, possibly events in th emiddle

thheller00:01:58

what do you mean by lifecycle? build events?

tony.kay00:01:01

you have access to the JVM and can create your own state

tony.kay00:01:14

yeah…:compile-started :compile-finished

tony.kay00:01:48

then an i18n package could just namespace their own atom, init it, and dump at the end

thheller00:01:26

can't really use an outside atom

thheller00:01:36

it really needs to be in the analyzer data

tony.kay00:01:51

why not? The JVM is a shared resource

thheller00:01:55

otherwise it won't be restored properly due do caching

thheller00:01:26

shadow-cljs caches compilation pretty aggressively

thheller00:01:48

that breaks whenever you touch things the compiler is not aware of

tony.kay00:01:50

oh…so you couldn’t just clear it

thheller00:01:10

sure you can clear it but I haven't done a lein clean in years

tony.kay00:01:20

nice…that’s good to hear 🙂

tony.kay00:01:52

so yeah, that kind of tooling would need a way to ensure that all files get processed

thheller00:01:37

thats my I'm dumping the strings into the analyzer data per ns

thheller00:01:43

instead of one global collection

thheller00:01:51

can't reliable cache the global thing

thheller00:01:45

come to think of it hot reloading may actually mess up the string collection and collect repeatedly

tony.kay00:01:45

so on startup the analyzer goes through all files, or is that timestamp shortcut too?

tony.kay00:01:14

I mean, with caching, how would it ever work to re-run a compile to gather strings?

tony.kay00:01:25

(other than to clean first)

thheller00:01:44

only the result of the compilation is cached

thheller00:01:20

its a two step process, first all entries are followed and collection

thheller00:01:27

for that only the ns is parsed nothing else

thheller00:01:44

then things are sorted in order

thheller00:01:56

and compile

thheller00:01:14

when a given namespace is to be compiled it is first checked if cache is available for that ns

thheller00:01:31

if yes it is restored into the proper places

thheller00:01:37

if not it is compiled as usual

tony.kay00:01:41

but then you’d skip the macro eval

thheller00:01:54

yes but the data is in the analyzer cache

thheller00:01:04

which is also restored

thheller00:01:11

cache is .js file + analyzer data

tony.kay00:01:12

oh…that cache is cached?

thheller00:01:54

basically just [:cljs.analyzer/namespaces the-ns] is written to a file so anything thats in there just works

tony.kay00:01:56

so, if there was an API with docs about the caching, then it’d be usable as a general store for general plug-ins

tony.kay00:01:56

ok, you write it and I’ll document it 🙂

tony.kay00:01:12

I’ve got some things I need to percolate on anyway…so writing some docs for your project would maybe keep me from jumping on something too quickly.

thheller00:01:20

probably should check with David first. I'm just abusing the analyzer data here, not sure if that is officially ok 😉

tony.kay00:01:51

oh..right, that’s in code you don’t control

thheller00:01:56

but given the namespaced keys and general clojure philosopy on open data structures that should be ok

tony.kay00:01:21

JAM in some keys baby!

thheller00:01:34

the compiler also isn't really concerned with any of it so it really should be ok

thheller00:01:20

I'll write the cljs.i18n things tomorrow

thheller00:01:48

its a good example use case. will ping David to get his opinion with that

tony.kay00:01:55

I’ll start a book for you tonight if you’d like. Pull together your wiki stuff and start augmenting. asciidoc ok with you?

thheller00:01:52

never used it but your docs look great so I'm in 😉

tony.kay00:01:02

cool. It’s very similar to markdown

tony.kay00:01:08

just more powerful and pretty

hlolli00:01:26

I added :use-document-host false then what I got was one of the stranger error logs I've seen 🙂 https://pastebin.com/MwwCmCsH short research led me to inline scripts in html causing this, it's maybe a longshot here https://developer.chrome.com/extensions/tut_migration_to_manifest_v2#inline_scripts (I'm also perfectly fine not haveing hot-reload, so no stress about this)

thheller00:01:57

weird, why devtools attempting to load ALL the files

thheller00:01:11

oh right ..

thheller00:01:18

when you generate the single output file the required things aren't set

thheller00:01:35

basically that needs to be added somewhere in the file

thheller00:01:51

the karma stuff doesn't do that since its not concerned with hot reload

thheller00:01:02

but yeah the security permissions are weird

thheller00:01:10

maybe you need to allow in the manifest?

thheller00:01:25

it tries to load from localhost which you are probably not allowed to connect to?

hlolli00:01:56

I haven't received not-permitted error yet, but I think they include message that x feature need to be permitted. But not ruleing that one out still.

thheller00:01:11

main.js:89433 DEVTOOLS: load JS goog/debug/error.js
main.js:89487 Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self' blob: filesystem: chrome-extension-resource:". Either the 'unsafe-inline' keyword, a hash ('sha256-M37Ss2WONZF7RdLxeAaEIHlfH/yox80jtDrUm4wIlr8='), or a nonce ('nonce-...') is required to enable inline execution.

thheller00:01:34

it is trying to load the goog/debug/error.js since it doesn't know that its already loaded

thheller00:01:50

but thats what hot reload would be attempting to do

thheller00:01:54

so that would fail too

hlolli00:01:09

ok now it works!

hlolli00:01:47

haha, facepalm, I was moveing node_modules folder around and shadow-cljs wasnt installed as dev-dependency. I installed it and now it's connected without warnings.

hlolli00:01:04

Or the fact I reloaded the plugin, could be either or.

thheller00:01:34

weird, that shouldn't affect the plugin but who knows

hlolli00:01:07

DEVTOOLS: connected!
main.js:89433 DEVTOOLS: disconnected!

hlolli00:01:26

[2018-01-11 01:47:54 - WARNING] stale websocket client, please reload client :vast

thheller00:01:39

it may also be complaining due to this trick

thheller00:01:32

that basically tries to execute inline script which is blocked

hlolli00:01:42

ok, just one step backward, this is the right way to start the hot-reload in the cmd shadow-cljs cljs-repl :vast ?

thheller00:01:43

so might have to use js/eval instead

hlolli00:01:56

where :vast is my id

thheller00:01:58

shadow-cljs watch vast

thheller00:01:19

cljs-repl vast only if you want the actual repl

thheller00:01:30

(while watch is running)

hlolli00:01:59

ok, I got all the errors back now again

thheller00:01:21

yeah it is most likely the script-eval thing

thheller00:01:28

it seems to be ok with loading the code via xhr

thheller00:01:34

its just blocking the eval

hlolli00:01:52

yes, and the way to permit it is with sha256 hash, I guess that hash changes a lot in development

thheller00:01:45

yeah, maybe eval works

thheller00:01:27

you can copy this file into your project

thheller00:01:19

and let the script-eval just use (js/goog.global.eval code) instead of creating a script element

thheller00:01:23

maybe that just fixes it

hlolli00:01:35

ok, I give it a try!

thheller00:01:12

maybe js/eval direct instead of going through goog.global try and see what works 😉

tony.kay01:01:32

@thheller I’m looking at dev-http. I don’t see a way to plug into the middleware…am I missing anything?

thheller01:01:06

you can only specify a custom handler (via :http-handler)

hlolli01:01:24

in short this fixes it, but I haven't yet seen the hot reload in action, could be that I need to look closer at where shadow.cljs.devtools.client.browser is being injected since I'm not useing the same name. Only quirk was that I had to add this into my manifest "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'"

tony.kay01:01:53

ah…that’s probably sufficient

tony.kay01:01:16

I see. I didn’t look above the middleware

thheller01:01:49

@tony.kay you are are providing a server anyways don't you? might be best to just use that instead of the dev http server shadow-cljs provides

tony.kay01:01:44

working on the book…it’s a thing that is sometimes useful

tony.kay01:01:52

so scanning through what is supported

thheller01:01:23

@hlolli I only suggested copying the file into your project to replace the one in shadow-cljs

thheller01:01:34

specifically to only test if js/eval would work

thheller01:01:51

can't test this easily myself since I have no basic setup for a chrome extension

thheller01:01:10

if you have something available publicly I can take a look

hlolli01:01:00

ok, I'll zip it and send this to you. Alternatively I could replace this one file, but I'd need to know how to compile shadow-cljs

thheller01:01:23

no you just the file into your classpath

thheller01:01:05

src/shadow/cljs/devtools/client/browser.cljs if you :source-paths is ["src"]

thheller01:01:15

that will then override the default

thheller01:01:25

no need to compile shadow-cljs itself or anything

thheller01:01:38

the classpath ordering will ensure that your version is loaded over the version in the jar

hlolli01:01:46

ah didn't know that works 🙂

thheller01:01:41

might need to restart the compile process

thheller01:01:59

but otherwise it just works

hlolli01:01:18

no error or warning in the console, I make changes, it compiles and nothing happens. You mentioned it shouldn't try to load all the files, the console looks like this:

thheller01:01:36

yeah that shouldn't happen

thheller01:01:16

basically it should NOT load anything before REPL init successful

thheller01:01:44

it only does because the goog.dependencies_ stuff is not properly set

thheller01:01:59

(because of manually generating the file)

hlolli01:01:20

hmm ok, so I could add it?

hlolli01:01:46

here

(defn flush-crx-to-file
  [{:keys [polyfill-js unoptimizable build-options build-sources] :as state}
   {:keys [output-to] :as config}]
  (let [prepend
        (str unoptimizable
             (output/closure-defines-and-base state)
             "var shadow$provide = {};\n"
             "goog.global[\"$CLJS\"] = goog.global;\n")
        out
        (->> build-sources
             (map #(data/get-source-by-id state %))
             (remove #(= "goog/base.js" (:resource-name %)))
             (map #(data/get-output! state %))
             (map :js)
             (str/join "\n"))]
    (spit output-to (str prepend out)))
  state)

thheller01:01:06

yeah add a map step that adds the two lines per file

thheller01:01:16

hmm you could try just adding :devtools {:async-require true} and just use the default :browser output

thheller01:01:22

ie. not a single file

thheller01:01:39

the async-require will load things via fetch instead of the usual closure debug loader

thheller01:01:45

fetch should just work

hlolli01:01:29

that would leave me again with the background-script thingy?

thheller01:01:12

I really need to sleep. I can take a look tomorrow

thheller01:01:26

way too tired. gn8.

hlolli01:01:36

haha yes good night, sleep well!

mhuebert12:01:48

is there a recommended “path of least awkwardness” for deploying maven artifacts from a clojure project which is otherwise fully ‘managed’ by shadow-cljs?

thheller12:01:08

sadly that would be using lein (or boot)

thheller12:01:17

I hope someone writes a generic deploy utility library that isn’t coupled to a build tool (ie. also works with tools.deps)

mhuebert12:01:26

hm. I guess I could have the project.clj read :source-paths and :dependencies from shadow-cljs.edn, https://stackoverflow.com/a/7741790/3421050

mhuebert12:01:51

avoid duplication of those entries

thheller12:01:44

yeah that works

hlolli13:01:26

boom! https://gist.github.com/hlolli/265b9183566a4c5829d7ee355e3d0998 @thheller ❤️

BUJAKA!
main.js:89714 DEVTOOLS: connected!
main.js:89714 DEVTOOLS: REPL init successful
main.js:89714 DEVTOOLS: load JS vast/core.cljs
core.cljs:31 BUJAKA!
main.js:89714 DEVTOOLS: load JS vast/core.cljs
core.cljs:31 BUJAKA!

martinklepsch22:01:02

> I hope someone writes a generic deploy utility library that isn’t coupled to a build tool While I agree that this would be a nice thing, deploying is a somewhat complex task and in the end you’ll end up with something like lein or boot. Now you have three things 🙂

thheller22:01:08

yeah probably

thheller22:01:25

but if boot had a declarative configuration for that I could just call clj -m boot.deploy 😉

martinklepsch22:01:13

declarative as in reading from a file?

thheller22:01:05

yeah, :boot.deploy/config {...} in deps.edn

thheller22:01:12

or separate file

martinklepsch22:01:31

and are you attached to running clj instead of boot? 😉

thheller22:01:00

shadow-cljs clj-run boot.deploy with [boot/deploy ...] in my deps

thheller22:01:16

generic clojure. not coupled to a build tool

thheller22:01:33

lein run -m boot.deploy … everything that is able to launch a JVM should work

thheller22:01:50

I like boot but I don’t like that its all code and not really very declarative

martinklepsch23:01:21

It’s an interesting idea to not have a binary like lein boot and just invoke namespaces

martinklepsch23:01:51

All Clojure build tools were conceived at a time when there was no tool to construct a classpath for you

martinklepsch23:01:39

> I like boot but I don’t like that its all code and not really very declarative It doesn’t have declarative interfaces because those generally end up falling short — that said bolting declarative interfaces on top of boot is something that is very trivial and should probably be embraced more

martinklepsch23:01:33

It would be interesting to see what boot would look like if there was no boot binary

thheller23:01:45

its definitely worth having a dedicated binary still

thheller23:01:03

can do way more optimizations for startup time and such

thheller23:01:26

but that doesn’t necessarily conflict with the thing working as a library as well

thheller23:01:04

my take on the subject I wrote recently

thheller23:01:21

its definitely more work though so it might not actually be easy to do

thheller23:01:46

too bad clojure makes it so hard to run isolated instances, too much static stuff

martinklepsch23:01:56

java -cp (clj -Spath) boot.App repl running boot without boot 😄

martinklepsch23:01:32

> too bad clojure makes it so hard to run isolated instances, too much static stuff not sure I understand what you mean @thheller

thheller23:01:16

well the reason boot pods exist basically

thheller23:01:36

can’t “fork” a clojure runtime