This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2024-02-07
Channels
- # aleph (4)
- # announcements (9)
- # babashka (44)
- # beginners (6)
- # cider (8)
- # clj-kondo (5)
- # clojars (10)
- # clojure (10)
- # clojure-berlin (1)
- # clojure-dev (9)
- # clojure-europe (20)
- # clojure-gamedev (1)
- # clojure-miami (2)
- # clojure-nl (1)
- # clojure-norway (21)
- # clojure-uk (5)
- # clojurescript (12)
- # conjure (1)
- # cursive (19)
- # data-science (2)
- # datahike (10)
- # etaoin (5)
- # events (3)
- # fulcro (14)
- # gratitude (2)
- # honeysql (8)
- # humbleui (1)
- # hyperfiddle (60)
- # introduce-yourself (7)
- # jobs-discuss (27)
- # juxt (2)
- # kaocha (7)
- # lsp (23)
- # malli (9)
- # missionary (2)
- # off-topic (48)
- # pathom (24)
- # releases (1)
- # shadow-cljs (256)
- # sql (46)
- # xtdb (19)
Hello! I'm trying to use this npm package with clojurescript / shadow-cljs: https://vercel.com/font
The relevant js import seems to be: import { GeistSans } from 'geist/font/sans';
that afaik should translate to ["geist/font/sans" :refer [GeistSans]]
in my namespace's require in cljs
I've tried all the different combinations that the docs say (with $default
and whatsoever)
I get this error on my js console:
shadow-cljs - failed to load module$node_modules$geist$dist$sans
shadow.js.jsRequire @ js.js:89
js.js:90 TypeError: (0 , require.esmDefault(...).default) is not a function
at shadow$provide.module$node_modules$geist$dist$sans (sans.js:7:19)
at shadow.js.jsRequire (js.js:81:18)
at shadow.js.require (js.js:137:20)
at eval (example.reframe_playground.views.js:8:51)
at eval (<anonymous>)
at goog.globalEval (app.js:434:11)
at env.evalLoad (app.js:1405:12)
at app.js:1691:12
shadow.js.jsRequire @ js.js:90
Any ideas what I'm doing wrong?I'm guessing its a ESM/CJS interop issue, see https://clojurians.slack.com/archives/C6N245JGG/p1706896359632389
but I suspect that the code will end up relying on features shadow-cljs does not support, such as bundling fonts or css
I suspect that they expect you to be using the vercel platform which would take care of this
The font page seems to have instructions for non-nextjs projects (plain react with tailwind), thats why I thought it could work
take the zip, put it into a http reachable folder (e.g. "public/css") and add a css file to include the fonts. you can use this css file as a reference
using this font as a reference https://github.com/tonsky/FiraCode
the font itself has no code, only what I guess are "markers" for the next platform to do its thing
Ok I just tried
:target-defaults
{:browser
{:js-options {:entry-keys ["module" "browser" "main"]
:export-conditions ["import" "module" "browser" "require" "default"]}}}
behavior seems the sameI tried with
:target-defaults
{:browser
{:js-options {:ignore-exports true}}}
I get a build error now: The required JS dependency "geist/font/sans" is not available
(Just to be clear, I'm not really interested in adding this font to my playground project, I'm just trying to find out why this specific npm package does not work, in order to learn how to debug this kind of stuff)
Are you sure it has no js? https://github.com/vercel/geist-font/blob/main/packages/next/dist/font.js
this is the JS file you get for geist/font/sans
https://unpkg.com/[email protected]/dist/sans.js
shadow-cljs is following this all along, there is just code missing. everything else worked as its supposed to
like I said. I suspect that vercel is providing special support for this during compilation
Hello, I'm having problems with CSP (Content Security Policy) that the problem is coming from compiled .js code, reported as script-src
and rule eval
. The block of code is below.
oa=function(a,b,e){oa=Function.prototype.bind&&-1!=Function.prototype.bind.toString().indexOf("native code")?caa:daa;return oa.apply(null,arguments)};ra=function(a,b){var e=Array.prototype.slice.call(arguments,1);return function(){var g=e.slice();g.push.apply(g,arguments);return a.apply(this,g)}};ta=function(a){(0,eval <----- )(a)};
The eval
shold I consider as a shadow-cljs
source or closure
compile source? I can't permit using the rule unsafe-eval
in this case.run the build with npx shadow-cljs release <your-build-id> --pseudo-names
to identify where this eval is from
I'll do it
shadow-cljs or closure do not put eval in your code, so it is coming from other code you are using
it seems nothing changed
oa=function(a,b,e){oa=Function.prototype.bind&&-1!=Function.prototype.bind.toString().indexOf("native code")?caa:daa;return oa.apply(null,arguments)};ra=function(a,b){var e=Array.prototype.slice.call(arguments,1);return function(){var g=e.slice();g.push.apply(g,arguments);return a.apply(this,g)}};ta=function(a){(0,eval)(a)};
I have a compiler from Clojure Function:
from package.json:
{..."build:release-static": "npx shadow-cljs run dev.build/build-release-static --pseudo-names",...}
(defn build-release-static []
(clean-compiled-resources)
(export-image-assets-and-replace-paths)
(export-deeplinking-assets)
(shadow/release environment {:verbose true})
(compile-sass)
(export-assets)
(index-csp))
Should I put it into shadow/release
with :verbose?just run the regular release
command, you don't need all this extra stuff just for debugging this
$goog$globalEval$$ = function($script$jscomp$1$$) {
(0,eval)($script$jscomp$1$$);
};
if ($JSCompiler_StaticMethods_evaluateCode_$self$$.$sourceUrlInjection_$ || $JSCompiler_StaticMethods_evaluateCode_$self$$.$debugMode_$ && ($goog$userAgent$product$CHROME$$ || $goog$labs$userAgent$browser$matchFirefox_$$() && 0 <= $goog$string$internal$compareVersions$$($goog$labs$userAgent$browser$getVersion$$(), "36"))) {
for (var $i$jscomp$165$$ = 0; $i$jscomp$165$$ < $uris$jscomp$4$$.length; $i$jscomp$165$$++) {
$goog$globalEval$$($texts$$[$i$jscomp$165$$] + " //# sourceURL\x3d" + $uris$jscomp$4$$[$i$jscomp$165$$]);
}
} else {
$goog$globalEval$$($texts$$.join("\n"));
}
ok, now generate a build report via https://shadow-cljs.github.io/docs/UsersGuide.html#build-report
as in this example report you'll find a group for org.clojure/google-closure-library
https://code.thheller.com/demos/build-report/ui-report.html
trouble is that its kinda hard to identify what this code actually was before optimizations
hmm yeah that might be it then. the loader dynamically loads modules and evals them potentially
so, what's the ways?
I thougth it is internal from shadow, rigth?
I only use this in config:
...:modules {:base {:output-to "resources/public/js/compiled/base.js"
:init-fn core-client.core/init}
:checkout {:output-to "resources/public/js/compiled/checkout.js"
:entries [checkout.core]
:depends-on #{:base}}
:site {:output-to "resources/public/js/compiled/site.js"
:entries [site.core]
:depends-on #{:base}} ....
module-loader
I only load the base.<hash>.js
and use the namespaces.
into html
if you are not loading the modules dynamically then you do not need :module-loader true
sorry, I use shadows.loader
shadows.loader
call eval?
so, what is the solution for that?
after this line https://github.com/thheller/shadow-cljs/blob/master/src/main/shadow/loader.js#L17
https://github.com/google/closure-library/blob/master/closure/goog/module/moduleloader.js#L354-L380
yes, I see
so, if you could help me to understand right: copy the loader.js
to source code (where?), and include this ml.setUseScriptTags(true);
in that line you told?
is there any change do I have to fix in compile process?
src/cljs
thus you can add the line above to it to test if this actually fixes the problem and ends up removing the eval
no further changes required, just do another release build and see it eval
is still in it
the intention is that the goog.module.ModuleLoader
appears to have two separate loading mechanisms, one using eval one using script tags
I'm debugging with you, I never had to deal with the CSP restriction and I suspect no one else has
if it works I can add an option for this so you don't have to do this manual patching
that's amazing man, thank you very very much
I'm doing it
so the compiled code should remove the $goog$globalEval$$?
I included the source "loader.js" and included that line
we are testing whether this removes the eval or not, I thought that it might. if the above doesn't work then I guess it does not.
so, I have to deploy to see if is it work?
dunno if a full new deployment is necessary. if eval is still there it'll likely fail for the same reason
I'm still seeing the
$goog$globalEval$$ = function($script$jscomp$1$$) {
(0,eval)($script$jscomp$1$$);
};
I actually don't know if CSP actually already fails when it sees eval, or only when you actually try to eval?
I'm running in CSP report-only mode, but if it catches it as eval , browser will not permit runs the eval
you can try adding console.log("actually set to use script tags")
in the loader.js file, just to verify this hack actually worked
yes, the system have an event that calls shadlow.loader
, that is the time it's been reported
console.log("actually set to use script tags")
-> where?
yes, prior to this change it would have definitely used eval, the question is if it still does
should I see this message where? In compile process?
sorry, long process to run the system locally
worked -> actually set to use script tags
so, at this point , will it runs ok?
maybe it's depends the setUseScriptTags
well, it seems that the new loader.js
runs
I have to deploy to qa environment that has all the csp rules for checking
I'm still using "shadow-cljs": "2.15.3", is that a problem?
I don't think so, because it's 3 years old file
Hello @U05224H0W , It does not work
it's complaining about the eval stuffs
{
"csp-report": {
"document-uri": "https://*******/****",
"effective-directive": "script-src",
"original-policy": "...",
"blocked-uri": "eval",
"line-number": 1903,
"column-number": 322,
"source-file": "https://*******/js/compiled/base.ABCF3918963DA671CD471DB45FB2D01D.js",
"status-code": 200
}
}
hmm then I guess your only option is switching to :target :esm
and then restructuring a bit to not use :module-loader true
and shadow.loader
ok, I'll do it, do I have to use both or first try removing module-loader?
well, removing module-loader but keeping the lazy loaded functionality requires going :esm
so the main change is for :taget :esm?
test removing :module-load true
and :target :esm
?
the compiling failed with :target :esm
that fails in your code, not something I can debug for you. dev.build
is not part of shadow-cljs
humm, I'm using version 2.15.3
. Is there a problem with that version?
no. I repeat this is failing in code that is not part of shadow-cljs, it has never existed in shadow-cljs. It is your code that is failing. I cannot say why it is failing.
run npx shadow-cljs release app
, if that fails I can help you. otherwise you are on your own
yep, something here
it said that the manifest.edn
was not created
hummm, I use that files to read the main js with hash to inject into index.html
it seems that the :esm does not create the modules with hash in .js file names
well, it's a feature that is working 4 years
so, is the :esm the solution or a guess? Should I remove the shadow/loader too?
and use dynamic-import?
the simplest solution to me is allowing unsafe-eval, but you seem to have reasons thats not possible
yes, I'm implementing the CSP rules for security reasons
you mean include all the modules into script-src
?
well, I'm using 'self' as the rule
but the eval is not allowed
what is the propose of scriptTag? Do something like inject a <script> ..... Module .... </script>
?
yes, regular old JS doesn't have a standard way of fetching additiontal JS dynamically. so the goog.module.ModuleLoader
will either fetch the code via XHR and then eval it
with ESM you can just do a dynamic require to load the code, supported by the browser natively
but you cannot use dynamic import to load a :browser
module dynamically, since the rules for ESM are different and as such the output won't work
yes, that's I'm thinking
Hello @U05224H0W,how are you?
I could solve the problem with eval loading, replacing the shadow.load
I uses inject script tag into header
so, one thing, how do you convert the keyword to js path? In load function
shadow.load
this function receives the keyword defined into shadow-cljs.edn
modules
like here
:modules {:base {:output-to "resources/public/js/compiled/base.js"
:init-fn client.core/init}
ok, but where is this mapping injected?
what do you intend to do with it? I'm asking because this is all strictly for shadow.loader
, if you are not using that you are not supposed to use that data
for using the script tag aproach I have to know the filename of .js files. I have to use the hashes in the filenames because of caches. So, to this new module loader I wrote, how can I get the files if it will be dynamic because of hashes?
I'm thinking use the module-loader.edn to read all the references
I have a macro defined with an non-passing assert clause which throws an error (correctly) when I compile in dev with shadow.cljs.devtools.api/watch
but doesn't show any error when building for release with shadow.cljs.devtools.api/release
. Would this be the expected behavior?
if by assert you mean :pre
when yes, those are removed by default for release builds
I don't see the :pre
keyword but the macro has the form
(defmacro thing
([args]
(assert ...)
...))
that assert should still fire, given that its in the macro, not the emitted CLJS code
If I wanted to balance correctness checks and performance, would it possible elide CLJS asserts but maintain CLJ (macro) asserts?
"assert" by my definition are "this must not happen, if it does the world is allowed to explode"
I'm technically not against changing how *assert*
is bound, but the CLJS compiler will bind it like that too
since asserts work so differently and are so easy to toggle, sadly many people have many different interpretations