This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-03-02
Channels
- # aleph (2)
- # announcements (3)
- # babashka (12)
- # beginners (55)
- # calva (11)
- # clj-http (12)
- # clj-together (2)
- # cljs-dev (41)
- # clojure (51)
- # clojure-denmark (2)
- # clojure-europe (32)
- # clojure-nl (17)
- # clojure-norway (2)
- # clojure-switzerland (1)
- # clojure-uk (3)
- # clojurescript (34)
- # cursive (20)
- # data-science (3)
- # datahike (23)
- # datomic (3)
- # events (1)
- # fulcro (1)
- # honeysql (4)
- # inf-clojure (2)
- # interop (38)
- # java (3)
- # kaocha (8)
- # lsp (51)
- # luminus (2)
- # malli (2)
- # nextjournal (5)
- # off-topic (21)
- # pedestal (2)
- # polylith (12)
- # re-frame (4)
- # reagent (8)
- # reitit (4)
- # releases (1)
- # ring (4)
- # shadow-cljs (179)
- # spacemacs (2)
- # specter (1)
- # xtdb (13)
I'm trying to port an existing cljsbuild to shadow-cljs, the reason I used cljsbuild in the first place was that I couldn't work out how to get shadow to use my externs and local javascript files, I'm trying to require my files and so far I'm not having any luck in getting shadow to detect them... Is there a specific file layout that I should be using?
Also is it possible for all of the functions in the javascript files to included verbatim, jsdoc's and all?
Basically I'd like to compile the clojurescript code with :advanced
optimisations, but include some js in the source that's not been modified at all... By include I mean inline.
===== EDIT =====
Ok, I've managed to get it to build, but not sure how to get the js code to inline in correctly?
(I'm also wondering is the appropriate thing to do is to just cat <path to js files> >> shadow-generated.js
or is there something better?
I'd like to do everything cljs land, but at the moment generating the correct structures is not going well...
@folcon what kind of code are you trying to append? does it not make more sense to keep as a separate file?
I'm building a google app script project. I have clojurescript that wraps the google externs and then some javascript for writing the functions that can be read by the google environment. Google's engine only accepts certain forms: https://developers.google.com/apps-script/guides/v8-runtime And if you want to use custom functions (which we do) then we also have to emit jsdoc's of the correct format, which we've not worked out how to do yet... So for the moment, we hand write that and append it on...
I've gotten this working with cljsbuild But I'd like to use shadow so I can start pulling in npm modules. It would be useful if I can just output a single file which we can then trigger an upload on. Though failing that I can do some bash magic to get the output
The environment doesn't understand cljs itself, so not sure what you mean there? They have a format called .gs
which is broadly v8 compatible which is what the target is
Lambda island did a short writeup if that's helpful as well: https://lambdaisland.com/blog/2016-10-01-clojurescript-and-google-apps-script
I'd just (js* "onOpen(e) { attendomat.core.create_menu(); }")
in my .cljs
ns instead of appending it 😛
/**
* Returns the domain for a given name
* @param {"Apple"} name The value or range of cells
* to lookup the domain for.
* @return The domain of the website
* @customfunction
*/
function WEBSITE_LOOKUP(name) {
Array.isArray(name) ?
name.map(row => row.map(cell => fetch_sitedata(cell, 'domain'))) :
fetch_sitedata(name, 'domain');
}
function test_WEBSITE_LOOKUP() {
Logger.log(String(WEBSITE_LOOKUP("Google")));
}
{:source-paths
["src/dev"
"src/main"
"src/js"
"src/test"]
:dependencies
[[applied-science/js-interop "0.3.1"]]
:builds
{:appscript {:output-to "Code.js"
:output-dir "target"
:compiler-options {:externs ["resources/gas.ext.js"]}
:exports-fn humble-app-script.core/generate-exports
:js-options {:js-provider :shadow}
:release {:compiler-options {;:optimizations :whitespace
:pretty-print true}}
:target :npm-module
:entries [example.core]}}}
but that what :target
is for. this is neither a browser nor node so none of the above fit.
Target ":appscript" for build :appscript was not found. The built-in targets are:
- :browser
- :browser-test
- :node-script
- :node-library
- :npm-module
- :karma
- :bootstrap
you can use an existing target but as I you have encountered that will always be a hack and require certain manual tweaks
I don't expect you to implement a custom target but thats what I would do if I had time and actual use for it 😛
Ok, well at the moment I'm trying to generate functions that fulfil this format:
function normalFunction() {}
async function asyncFunction() {}
function* generatorFunction() {}
var varFunction = function() {}
let letFunction = function() {}
const constFunction = function() {}
var namedVarFunction = function alternateNameVarFunction() {}
let namedLetFunction = function alternateNameLetFunction() {}
const namedConstFunction = function alternateNameConstFunction() {}
var varAsyncFunction = async function() {}
let letAsyncFunction = async function() {}
const constAsyncFunction = async function() {}
var namedVarAsyncFunction = async function alternateNameVarAsyncFunction() {}
let namedLetAsyncFunction = async function alternateNameLetAsyncFunction() {}
const namedConstAsyncFunction = async function alternateNameConstAsyncFunction() {}
var varGeneratorFunction = function*() {}
let letGeneratorFunction = function*() {}
const constGeneratorFunction = function*() {}
var namedVarGeneratorFunction = function* alternateNameVarGeneratorFunction() {}
let namedLetGeneratorFunction = function* alternateNameLetGeneratorFunction() {}
const namedConstGeneratorFunction = function* alternateNameConstGeneratorFunction() {}
var varLambda = () => {}
let letLambda = () => {}
const constLambda = () => {}
var varAsyncLambda = async () => {}
let letAsyncLambda = async () => {}
const constAsyncLambda = async () => {}
Or that are a custom function in the form I gave earlierall existing targets are here https://github.com/thheller/shadow-cljs/tree/master/src/main/shadow/build/targets
What's the best way to proceed, I'd just want to sort of get started, I've got a bunch of js code and a bit of cljs code and I'm slowly porting the js bits over which can be ported...
ends up as a goog.exportSymbol("onOpen", function(e) { ... })
which is not recognized
Ok, well is there a way to do that internally? I'm currently just using bash to cat and >>
(defn hook
{:shadow.build/stage :flush}
[build-state & args]
(spit
(io/file "regular" "out.js")
(slurp (io/file "file-to-append.js"))
:append true)
build-state)
I'm trying to use :target :node-library
and it doesn't like this:
'use strict';
var b, a = global;
error:
ReferenceError: global is not defined
(anonymous) @
(anonymous) @
(anonymous) @
I can then mock some of the environment and then do repl based development, but still compile out a release that goes to the google appscript
Or should I check out the build/targets
directory on github for how to navigate that 😃
Hmm, not sure why, but it's not generating the export. I've got an included js script file that I'm importing using your example:
(:require ["./entry_points" :as entry-points])
(defn generate-exports []
#js {:fetch_sitedata entry-points/fetch_sitedata})
I've got this in shadow-cljs.edn
:
:output-to "Code.js"
:exports-fn example/generate-exports
So when I look inside the target/main.js
there is no fetch_sitedata
function defined, I've been grepping for the name and it's not there...
Also not sure why it's ignoring my :output-to
instruction and is just generating the file main.js
inside target
dir...ie. :target :browser
does not have a :output-to
option and neither does it have a :exports-fn
option
There's two js files, entry_points.js
which has some wrapper code which I'm slowly going to be getting rid of, but probably should go through the pipeline and custom_functions.js
which I'm appending
I'll stick js in the appropriate file, but some functions in the entry_points.js
need to be called in my clojurescript and for some reason though they're in my :exports-fn example/generate-exports
in shadow-cljs.edn
, it's not appearing inside the final main.js
but :target :node-library
recognizes :exports-fn
. no other target does, so it will do nothing for those. and the only thing that will appear for :node-library
is module.exports = your.ns.generate_exports();
whereas the your.ns.generate_exports()
part may be renamed and shortened by :advanced
Ah, sorry, yep that makes sense. I'm mixing up target instructions. Basically my goal is to take some of the functions defined inside entry_points.js
and export them so they're available in the final output.
Should I just create something like this:
(ns example
(:require [clojure.string :as str]
[applied-science.js-interop :as j]
["./entry_points" :as entry-points]))
(def ^:export fetch_sitedata entry-points/fetch_sitedata)
;; OR
(defn ^:export fetch_sitedata [] (entry-points/fetch_sitedata))
it would make this really much much easier to talk about if you create a repo with some code
Yep, just saw this:
n("example.fetch_sitedata", vf.fetch_sitedata);
}).call(this);
The definition of fetch_sitedata
is missing... vf is probably some import, but one that doesn't seem to contain any of the original fetch_sitedata
definitionHmm ok let me put together an example case after dinner and poke you in this thread? Would that work?
How does this look? I tried to make a minimal example https://github.com/Folcon/example-appscript
what are you using to edit code? you should really run a formatter. the shadow-cljs.edn is a complete mess :P
Right, so I should use a Makefile
or another hook, to copy it to the correct location and append the other file?
{:source-paths
["src/dev"
"src/main"
"src/js"
"src/test"]
:dependencies
[[applied-science/js-interop "0.3.1"]]
:builds
{:appscript
{:target :browser
:output-dir "target"
:modules {:main {:entries [app-script.core]}}
:devtools {:enabled false}
:build-hooks [(app-script.hooks/build-hook)]
:compiler-options {:externs ["resources/gas.ext.js"]}}}
as I keep trying to tell you ... you are importing it into the build. IT WILL BE PROCESSED!
that means that the function it has will be DELETED since it is not referenced anywhere
is identical as far as the generated code is concerned. the entire entry_points.js
indirection does absolutely nothing
can you explain what exactly you are trying to achieve via that entry_points
stuff? like what does the final generated JS need to look like
So the entry_points.js
contains effectively working code that is broadly legacy.
When I was porting it to cljs I realised that because app-script has it's own weird formats and rules I'd have to feed it javascript to be able to work around some behaviours.
So I split it up into custom_functions.js
and the original entry_points.js
.
The idea was that anything we couldn't just port over that was externally facing could live inside custom_functions.js
. Any legacy stuff that was still in the process of being ported over that was internal behaviour could live in entry_points.js
which could be called and wrapped by clojurescript code.
So we have functions like mult_vals
which need to be called by functions in the clojurescript code or by functions in custom_functions.js
. But are not by themselves public.
I'd prefer to run as much as possible through the closure compiler to minimise / remove stuff we don't need. But in the worst case we can just use simple optimisations for now.
ok so then prepend or append BOTH entry_points.js
and custom_functions.js
to the output
but it will require adding export
in the .js
and re-exporting it so app-script can find it WILL NOT WORK!
this is just a limitation in the way the closure compiler treats exported things and there is no way to change that
so you can only :export
them and refer to them by the full name via the JS that is not going through the closure compiler
then create a index.html
that loads them via <script src="/entry_points.js">
and <script src="/js/main.js">
then in the shadow-cljs.edn
add :dev-http {3000 "public"}
and set :output-dir "public/js"
there are :prepend
and :append
options in :modules
but they only take strings. so doesn't make sense if its too long
I'm having a weird issue where I can't seem to run all the tests in my project with a node-test target. Using shadow 2.17.5, and with a basic target like this:
:test {:target :node-test
:output-to "target/test.js"
:ns-regexp "-test$"}
I can get it to work if I pass in the NS directly with like node target/test.js --test=foo.foo-test
. It successfully finds 4 -test$
NS's, but no others... I tried using ".*"
as the regex also to no avail. I can also confirm that the namespaces are correctly built and are loaded (by chucking a console.log
into the built namespace in .shadow-cljs/builds/tests/dev/out/cljs-runtime/foo.foo_test.js
). Any ideas?tests are written the same way as the working namespaces – using cljs.test
, deftest, and the async
macro
the default is to run all. so something must be off? --test
does not affect compilation in any way.
ah! I think I solved it! One of the tests in the last NS found used (async done blah)
but didn't call (done)
and so stopped the rest of the tests running. But weird that the test completed at all
its node so it'll exit when there are no more pending callbacks or whatever. it just assumes the program ended properly.
Hi there! I'm having a dependencies issue that I can't reproduce in pure JS, so I think it is shadow-cljs related.
I want to use a library that uses multiple versions of the same dependency, it looks like this folder tree:
node_modules
-- dep A
---- node_modules
------ dep B v2
-- dep B v1
=> It is always the dep B v1 that is used, even in the dep A code. The dep A code uses common JS API (`require`).
I can't find in the guide how I can make this work as expected.
(The library I try to use is @uiw/react-textarea-code-editor
)
The last one: 2.17.5 (I double checked with shadow-cljs info
)
hmm, I don't know. It is installed by npm
that version should support the nested packages. unless you disabled that in the build config
I don't think so
{:asset-path "/js"
:modules {:main {:init-fn app.core/main}}
:output-dir "public/js"
:target :browser}
I can create a minimal projet if you wantHere it is: https://github.com/schadocalex/shadow-cljs-deps-issue Actually it uses the wrong version of a sub sub dependency, not directly a sub dependency
it works for the first sub dependency
related issue with more details : https://github.com/thheller/shadow-cljs/issues/995
My boss would like my JS output to make life as easy as possible for JS programmers to both interact with and possibly even to 'take over' in case I leave the project. I use Reagent to create a React based app and use Shadow-cljs for compilation. How can I get my code and/or my config to be as JS friendly as possible (when compiled for development)?
You can't, you can only set up your project to be used as a black box library
Ohh, I see. Thanks for clarifying this up for me.