Fork me on GitHub
#shadow-cljs
<
2017-09-12
>
Jon10:09:10

(defmacro <>
  ([el content] (<> &form &env el content nil))
  ([el content style] `(~el {:inner-text ~content, :style ~style})))

Jon10:09:51

does shadow-cljs support multiple arity defmacro?

Jon10:09:07

cljs.user=> (ns foo.core$macros)
nil
foo.core$macros=>
foo.core$macros=> (defmacro <>
             #_=>   ([el content] (<> &form &env el content nil))
             #_=>   ([el content style] `(~el {:inner-text ~content, :style ~style})))
true
foo.core$macros=> (foo.core/<> 'a "a" nil)
nil
foo.core$macros=> (foo.core/<> 'a "a")
nil
foo.core$macros=> '(foo.core/<> 'a "a")
(foo.core/<> (quote a) "a")
foo.core$macros=> '(foo.core/<> 'a "a" nil)
(foo.core/<> (quote a) "a" nil)
foo.core$macros=> (macroexpand-1'(foo.core/<> 'a "a" nil))
WARNING: Use of undeclared Var foo.core$macros/macroexpand-1' at line 1
TypeError: Cannot read property 'call' of undefined
foo.core$macros=> (macroexpand-1 '(foo.core/<> 'a "a" nil))
((quote a) {:inner-text "a", :style nil})
foo.core$macros=> (macroexpand-1 '(foo.core/<> 'a "a"))
((quote a) {:inner-text "a", :style nil})

Jon10:09:32

it looks good in Lumo, but throw compilation errors in shadow-cljs

thheller12:09:18

@jiyinyiyong shadow-cljs is not self-hosted therefore macros need to be written in Clojure

thheller12:09:28

core.specs.alpha does not have anything to do with it

thheller12:09:46

you simply cannot do defmacro in CLJS (only CLJ)

thheller12:09:45

use shadow-cljs clj-repl and do the macro stuff there

thheller12:09:18

core.specs.alpha is for Clojure therefore it does not have :require-macros

thheller12:09:09

by the looks of it you are trying to use CLJS code from CLJ, that won’t work without some reader conditionals

Jon13:09:23

cljc files

thheller13:09:32

yes, in .cljc files

thheller13:09:34

.cljc files can be loaded by CLJS and CLJ but when loading CLJ you can’t use CLJS code so you have to use reader conditionals

Jon13:09:27

I feel confused, none of my files uses .clj as extension name

Jon13:09:01

it's mostly .cljc, with a main.cljs file

thheller13:09:21

so .cljc files are basically .clj and .cljs in one file

thheller13:09:25

if you :require-macros something that will be loaded by CLJ

thheller13:09:40

if that it turn does :require something that will also be loaded by CLJ

thheller13:09:35

so if the file that was required then tries to :require-macros it fails because CLJ is the one loading it and not CLJS

thheller13:09:08

two separate worlds

Jon13:09:23

...which means in every .cljc file, I can't use :require-macros too?

thheller13:09:00

I think you misunderstand

thheller13:09:08

the answer is it depends

thheller13:09:48

it matters who is loading the .cljc file. the CLJS compiler where :require-macros is fine OR Clojure where it is not fine

Jon13:09:48

my file is compiling with shadow-cljs and running in a browser, I can't see where is the .clj part

thheller13:09:13

if you :require-macros something that is loaded by clojure. everything macro related is clojure.

Jon13:09:08

Sounds like something I didn't even noticed before. The same code was ok, but I saw compilation errors today.

Jon13:09:41

not playing with cljs for weeks... also I haven't updated my dependencies yet

thheller13:09:53

doesn’t have anything to do with dependencies

thheller13:09:20

macros can be a bit confusing by themselves, they are extra confusing in CLJS

Jon13:09:53

I mean, the behaviors of the compiler just changed with the same copy of code. no new commits, not deps updates

thheller13:09:01

I doubt that

thheller13:09:21

maybe you added a :require somewhere?

Jon13:09:35

I don't think so

thheller13:09:37

if you have demo repo somewhere I can take a look

Jon13:09:13

still this repo, you may check the code on Aug

thheller13:09:35

which command produces the error?

Jon13:09:55

yarn watch,

Jon13:09:02

it starts shadow-cljs watch

Jon13:09:23

then I edit code, say in space.cljc, change value from 1 to 2

thheller13:09:02

shadow-cljs attempts to load the file as a macro, not sure why it would

Jon13:09:56

I don't trust my code anymore since I introduced Macros...

thheller13:09:56

I would stay away from .cljc files personally, they just make things a lot more complicated

thheller13:09:53

the macro reloading code in shadow-cljs is probably buggy with .cljc files

Jon13:09:59

maybe I should compile all my code to .cljs since I never really use Clojure(JVM)

thheller13:09:29

keep the macros in .clj files and everything else in .cljs

thheller13:09:39

only use .cljc when absolutely necessary

thheller13:09:13

thats what I do

Jon13:09:38

how to require .clj from .cljs by the way?

thheller13:09:01

you can’t … other than :require-macros. thats the point

Jon13:09:01

I remembered you write a Gist before, or just a script? Do you still have it?

thheller14:09:43

bascially whenever you need a macro you create a .cljs files and a .clj file of the same name

thheller14:09:54

the .cljs file then :require-macros the .clj files itself

thheller14:09:10

everything else just uses :require never :require-macros

thheller14:09:16

IMHO it is not a good idea to have a respo.macros namespace, puts too much emphasis on the macro part.

Jon14:09:31

I agree. But I don't have enough experience to decide which solution is best for my case. I still have to deal with the edge cases,

thheller14:09:58

well that you are writing your own editor that has to deal with all the edge cases certainly adds a bit of complexity on top 😉

thheller14:09:13

otherwise it is not that complicated

Jon14:09:10

kind of...

Jon14:09:26

I have a polyfill/ folder for bare ClojureScript code anyway.

Jon14:09:09

my current headache is, in the file I write Macros, I need to require code from my ClojureScript code written in .cljs.

thheller14:09:34

yeah, don’t do that. well keep it to an absolute minimum.

Jon14:09:34

previously it's in .cljs, so it's okay. now it's .cljs.

thheller14:09:54

btw do you know other JS build tools than rollup and webpack?

thheller14:09:24

I know there are others but can never remember their names

Jon14:09:52

tried, by barely use them. Webpack is the best.

thheller14:09:18

webpack is horrible if you want to write plugins for it

Jon14:09:30

I used requirejs and browserify before. but switched to Webpack.

thheller14:09:38

also does way too much suff I don’t need

thheller14:09:04

can requirejs bundle code together?

Jon14:09:24

but we need most of the features in Webpack, when we where trying to create single page apps.

thheller14:09:08

I need something for shadow-cljs as a fallback when closure does not work

Jon14:09:12

yeah, requirejs has a command line called r.js, which bundles code. But it's using AMD format, which not as useful as CommonJS, so it's barely used now.

thheller14:09:14

webpack is driving me crazy

thheller14:09:37

building my own is not an option

thheller14:09:52

maybe browserify works, checking it now

Jon14:09:16

heard that browserify is cleaner than Webpack.

Jon14:09:19

why is Webpack so crazy to you?

thheller14:09:46

because I’m trying to do something it is not intended to do

thheller14:09:29

well it sort of can do it if I combine DllPlugin and DllReferencePlugin but that whole setup is just crazy

Jon14:09:27

I never looked into Plugins.. 😨

thheller14:09:03

well if I ignore code splitting everything is easy

Jon14:09:09

do you think asking the maintainers can help?

thheller14:09:49

maybe, don’t know who to talk to or even how to describe what it is I’m trying to do

Jon14:09:00

it's his fault that Webpack gets so complicated. but people need those features anyway

thheller14:09:53

yeah he’s probably busy with other stuff

thheller14:09:29

I can just wait till Closure supports everything … which will happen eventually (hopefully)

Jon14:09:23

I remembered he is working in Webpack full-time

thheller14:09:29

yeah lots of stuff happening with webpack, getting more complicated with every change

Jon14:09:12

ClojureScript is so complicated.

thheller14:09:22

hehe not to me 🙂

Jon14:09:44

do you know about BuckleScript?

thheller14:09:57

know yes, used it no

Jon14:09:12

the author is a Chinese, so he is active in Chinese tech communities too

Jon14:09:47

BuckleScript has runtime libraries like ClojureScript, but not Macros.

Jon14:09:30

I just feel that he is so happy the performance of compiler beat all other compilers of altjs languages.

Jon14:09:32

and it doesn't run into traps like ClojureScript does, in using with Webpack

thheller14:09:48

well it doesn’t have the Closure Compiler

thheller14:09:34

I personally care very little about the speed of the compiler when my compiled output is a lot smaller and optimized

thheller14:09:44

hmm browserify might work for what I want. seems easier than webpack at least 🙂

Jon14:09:08

I think people don't always care about the bundle size that much, for example some of my apps in my previous work, they are used internally. So the size the not important. My manager just want the websites get online really quickly.

thheller14:09:44

well if you don’t care about the size then using webpack with shadow-cljs should just work fine?

Jon14:09:45

while some of the sites do care about that. They just choose Vue.js and not even React.

Jon14:09:59

yeah, if I can split ClojureScript libraries into another bundle, then it's acceptable in some scenarios.

Jon14:09:09

anyway, the current problem of using ClojureScript in China is just too few people are using it. we would think about size after people start using it.

thheller14:09:59

too few people are using it globally 😉

thheller14:09:12

looks like browserify may actually work 🙂

thheller14:09:45

attempted to write the webpack plugin at least 4 times in the last month and always gave up

thheller14:09:57

should have looked at alternatives earlier 🙂

Jon14:09:33

but I didn't hear you complain about it on Twitter 😅

thheller14:09:37

no point in complaining if the problem is that I don’t understand it 😉

Jon14:09:03

I imagined there might be some chance that Webpack maintainers will help ClojureScript, although it's rare.

thheller14:09:08

well by the looks of it all I need is browserify -r react -r react-dom and then something combined with -x=react

Jon14:09:23

being a user of both tools, I just hope to see ClojureScript works in Webpack, just like TypeScript and BuckleScript. 🙂

thheller14:09:36

probably won’t happen

thheller14:09:09

well works in webpack already but just not via a loader

Jon14:09:40

you are right

thheller14:09:36

the loader part is problematic because clojurescript uses namespaces to organize code

thheller14:09:48

the others just use files

thheller14:09:04

which looks similar but isn’t

Jon14:09:33

not even through compilation?

thheller14:09:42

I expect a whole lot more people using the Closure Compiler soon which should make things easier to use in CLJS as well

thheller14:09:27

GCC just needs a bit more tuning

Jon14:09:33

A lot of people are using React and Vue, which do not like Closure Compiler.

thheller14:09:39

don’t the typescript people already use it?

Jon14:09:58

not heard about TypeScript.

thheller14:09:16

Tsickle converts TypeScript code into a form acceptable to the Closure Compiler.

thheller14:09:28

that means that its also directly useable by CLJS

thheller14:09:58

yeah, well only because people talk about it more doesn’t mean that it is “better” 😉

Jon14:09:38

more popular~

Jon14:09:34

people in JavaScript world rely on documents heavily. I don't think Closure Compiler team is good at documents

thheller15:09:46

yeah agreed. its mostly used by Google internally so I bet they have internal docs just nothing public

thheller15:09:38

browserify uglifyify envify … they went a little overboard with the ify

Jon15:09:20

like loaders

Jon15:09:38

and coffeeify

thheller15:09:33

well it does what I need so thats a good thing 🙂

Jon15:09:35

does this file has to be empty?

thheller15:09:47

no you can put any kind of CLJS code in there

Jon15:09:23

but.... code in lib.clj can not access those variables

thheller15:09:47

at compile time no, at runtime yes

Jon15:09:04

any tricks to rescue?

thheller15:09:19

what do you want to do?

Jon15:09:45

my macros are wrapping create-element into div and span functions

Jon15:09:05

so I want to access create-element from macro definitions

thheller15:09:28

uhm but you don’t actually want to CALL the function right?

Jon15:09:09

not, during the time macros are defined,

thheller15:09:24

then its fine

Jon15:09:38

(defmacro meta' [props & children] `(create-element :meta ~props ~@children))

(defn gen-dom-macro [el]
  `(defmacro ~el [~'props ~'& ~'children]
    `(create-element ~(keyword '~el) ~~'props ~@~'children)))

Jon15:09:50

luckily not called

thheller15:09:20

so whats the issue?

Jon15:09:44

(ns respo.alias (:require [respo.core :as core]) (:require-macros [respo.alias]))

(def create-element core/create-element)

(def create-comp core/create-comp)

Jon15:09:18

now I put my code back in a file called alias.clj, but in alias.clj, I don't get the variables defined in alias.cljs.

Jon15:09:32

the snippet above is alias.cljs

thheller15:09:21

and alias.clj?

Jon15:09:33

oh, there might be a trick

thheller15:09:40

why do you need the alias at all?

thheller15:09:10

in the macro just emit respo.core/create-element instead of create-element

Jon15:09:53

all working now. thanks

thheller15:09:51

requires some trickery but it seems browserify has solved the issue I was trying to solve for the last month using webpack

thheller15:09:13

yay for simple tools 🙂

Jon15:09:30

interesting

Jon15:09:53

is it bundling?

thheller15:09:16

I needed a way of packages JS together but still being able to require the packages by name

thheller15:09:43

ie. want to bundle react and react-dom together (or separate) and then still use require to access them

thheller15:09:58

together was simple in webpack as well

thheller15:09:05

separate was nearly impossible

thheller15:09:25

well it was hard not impossible

thheller15:09:41

browserify -r react-dom -x react > react.dom.js and done

Jon15:09:57

:thinking_face:

thheller15:09:33

it will make more sense soon 😉

Jon15:09:14

looking forword

Jon15:09:35

but it sounds like Webpack users won't get the benefits

thheller15:09:45

webpack users never needed it

Jon15:09:11

well? :thinking_face:

thheller15:09:39

well if you use webpack you already have something that can provide require("react")

Jon15:09:00

it's by CommonJS, in Webpack

thheller15:09:40

but I wanted a more lightweight way of being able to use require("react") without using webpack

Jon15:09:00

so browserify is the alternative...

thheller15:09:15

well the primary goal is to use the Closure Compiler

thheller15:09:30

but in cases where it doesn’t work (yet) the fallback will be browserify

Jon15:09:54

anyway it sounds good now 😅

thheller15:09:14

so you can still (:require ["react"]) but without webpack

thheller15:09:02

just wish browserify was able to generate some kind of manifest 🙂

Jon15:09:08

like :npm-deps?

thheller15:09:42

I hate :npm-deps .. it is so misleading on what it actually does

thheller15:09:51

I call it :js-provider for now

thheller15:09:20

so if you set :js-provider :closure the (:require ["react"]) will attempt to import the npm react package via the closure compiler

Jon15:09:23

in the old days, we have gulp-rev for browserify https://stackoverflow.com/a/33507199/883571

thheller15:09:57

if you set :js-provider :require it will just emit a require("react") call, which just works for node.js or when using webpack

thheller15:09:13

but then also for the browser by using the browserify fallback

thheller15:09:53

basically :js-provider covers how native JS is “provided” by the system

thheller15:09:23

so no need for cljsjs anymore

Jon15:09:32

sounds like what Webpack does

thheller15:09:40

yes but inverted

thheller15:09:18

now its shadow-cljs, then that code is processed by webpack

thheller15:09:37

then its just shadow-cljs, no additional step

Jon15:09:45

are you adding browserify as a dependency in shadow-cljs?

Jon15:09:08

that's 😄

thheller15:09:46

but yes the goal is to only have shadow-cljs running and it managing everything

thheller15:09:09

first plan was using webpack in the background but that was way harder than I wanted it to be

Jon15:09:25

yeah, it's cool. and it makes things a lot easier to learn

thheller15:09:48

cool cool, thanks for suggesting browserify. I got further in the last hour than in the last 4 months trying to understand webpack 😛

Jon15:09:46

glad it helps

thheller15:09:27

oh perfect it even has --list which does what I need 😉

thheller15:09:47

gotta go … but this is exciting … I should finally be able to finish this beast of a branch 🙂

Jon15:09:24

looking forward to updates

Jon15:09:22

also late in Shanghai, going to clean all my tabs before sleep