Clojurescript options :foreign-libs (and an idea seeking opinions)

807 views
Skip to first unread message

Dave Sann

unread,
Feb 8, 2012, 9:22:05 PM2/8/12
to clo...@googlegroups.com
I think that the use of :foreign-libs to include non closure js libs in cljs builds may be hazardous 

My reasoning as as follows:

if you use :foreign-libs, you create a namespace for the library - and must require this namespace in order for it to be included in the build.

But, if you plan to use advanced compilation and use :externs this namespace is never provided.

The result is that switching for simple to advance compilation requires a change in every file that required the dependency - to remove it.

Probably not a huge issue - but not ideal either.
-----------

Following on from this I have an Idea for browser targeted foreign js libs and I would like input/opinions

suppose a macro

(wrap-js js-file externs-file options
  (foo [] (.foo js/SomeClass)
)

to be used something like:

(ns my-wrapper)

(wrap-js "some.js" "some.externs.js" {:inline true}
 ...fn definitions...
)


this will then:
 1. ensure that the externs file is included in the build.
 2. generate a function that is called in the client when bootstrap.js is loaded to insert a <script> tag in the head of the page, loading or inlining the raw js

There would probably be need to ensure that the script is read before fns can be called.

Feasible?

Cheers

Dave

Dave Sann

unread,
Feb 9, 2012, 1:40:49 AM2/9/12
to clo...@googlegroups.com
Having read through some of the closure compiler code - I don't think that inserting the externs file into the build is possible - without changes to the compiler.

I do think that support for wrapping foreign libs into a usable unit would be a good idea.

D

David Nolen

unread,
Feb 9, 2012, 11:58:31 AM2/9/12
to clo...@googlegroups.com
I'm not following your line of reasoning - http://lukevanderhart.com/2011/09/30/using-javascript-and-clojurescript.html, shows that :foreign-libs and advanced compilation work fine together.

David


Dave

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Dave Sann

unread,
Feb 9, 2012, 6:24:37 PM2/9/12
to clo...@googlegroups.com
Maybe - but I don't think so.

I tested with jquery this morning - to try and re-confirm - details appended at the end of this post

I think that this falls into the: 
"If the library you want to use simply doesn't work with advanced compilation...." at the bottom of the link you added

My understanding is as follows - please correct me if I have this wrong.

:foreign-libs are included in the build and are optimised with it.
:externs does not apply to any :foreign-libs - only if you include the lib separately (which has no namespace)

so, in advanced mode, var/function names are mangled.

If you just want to include the code - and it runs in its own world - you may see some warnings, but this works fine 
but references to vars/functions in the library from clojurescript will not work.

Which, I think means pretty much any non-gclosure library in advanced mode.

Dave

-----

Test with jquery

with and without :externs, in :simple and :advanced.
jquery - intentionally not referenced externally in the page.

using
{
 :optimizations :advanced
 :externs ["resources/js/jquery-externs.js"]
 :foreign-libs [{:file "resources/js/jquery.1.7.1.min.js" :provides ["jquery"]}]
 }

the libs in:
resources/js/jquery-externs.js
resources/js/jquery.1.7.1.min.js

main.cljs calls:

(.log js/console (js/JQuery "body"))

respectively.
in simple: Ok

In advanced:
compiles with warnings
in the browser when referencing js/jQuery 
  1. Uncaught ReferenceError: jQuery is not defined
    1. (anonymous function)


David Nolen

unread,
Feb 9, 2012, 6:35:24 PM2/9/12
to clo...@googlegroups.com
Ah yes. What you want is something like "extern-lib" (not saying it will be called that) - some way for you to include JS that won't get submitted to advanced compilation yet which has externs to define.

Please open a ticket in JIRA for this.

David

Dave Sann

unread,
Feb 9, 2012, 7:11:27 PM2/9/12
to clo...@googlegroups.com
yes exactly, but I would like to be able to package js libs as jars - not specify them directly to the build in the cljsc opts.

I have done half of this, here: 

see the following examples:


To complete it, I need a way to specify that the externs file/files provided should used by the compiler.

possibly something along the lines of the require-externs added below

(ns jayq.inline-jquery
(:require [wrap-js.core :as wrap-js])
(:require-macros [wrap-js.macros.file-contents :as mfc]))

;; Just require this namespace if you want JQuery inlined and inserted into your webpage.
;; do this before you require jayq.core

;; specify externs for the compiler
(require-externs "js/jquery-externs.1.7.1.js")
; inline from local
(def jquery-src (mfc/from-local-file "js/jquery.1.7.1.min.js"))
(wrap-js/add-inline! jquery-src)


The nice thing here is that if you don't require this namespace jquery is omitted from your page and your bootstrap.
no compiler options required. 

Currently though - you must specify the externs to the compiler if using advanced mode.

I suspect that the above call may be hard to add - or undesirable.
A simple alternative to this would be to use a convention 
  - for example - that the compiler will always read, as an externs file, any js file found on the classpath in "js/externs"
 

D

Dave Sann

unread,
Feb 9, 2012, 7:23:13 PM2/9/12
to clo...@googlegroups.com
created:


with pointer to discussion here.

Reply all
Reply to author
Forward
0 new messages