Hey folks, I'm working on a chrome-extension (built with shadow-cljs) which loads on every website the user visits. Some of our clients are reporting that it breaks Google docs completely (and disabling our extension fixes it), and I can't get any meaningful errors from them. I can't reproduce it either. Is there a possibility that closure / goog.global loaded on http://docs.google.com is somehow interfering the with the closure build we inject on the page as a part of the extension? π€
I had something similar when my namespace was called βcoreβ. It was then clashing with some βcoreβ package which was polyfilling window object.
uhm define "loads on every website"? usually when you inject code it runs in its own context. isolated to prevent exactly this problem?
but yes, it is totally possible that the code will conflict with something is injected into the same global context
chrome.scripting.executeScript is supposed to be safe against such conflicts? do you use that or some other method?
hmm or I'm confusing it with content scripts. been a while since I looked at any of this
Thanks @thheller for looking into this. We load content script on every tab / webpage the user visits. This content script inturn loads an extra script which creates a "sidebar". This is injected directly into the dom, so it's one with the host page (no chrome.runtime access but full DOM access). This is roughly what we do:
// The sidebar always runs in the execution context of the page, rather than in the extension's isolated world
const sidebarScript = document.createElement('script')
sidebarScript.setAttribute("type", "module")
sidebarScript.setAttribute("src", chrome.runtime.getURL('js/sidebar/main.js'))so its a :target :esm build?
It might be worthwhile to try and use chrome.scripting.executeScript to see if we can inject this in, but then I am not sure if we will have full dom access think_beret
:sidebar
{:target :esm
:output-dir "ext/js/sidebar"
:modules {:main {:init-fn chrome-ext.sidebar/init
:entries [chrome-ext.cli]}}
:closure-defines {chrome-ext.build-info/BUILD_ID "sidebar"
chrome-ext.build-info/PRIVILEGED false}
:release {:closure-defines {lambdaisland.glogi.console/colorize "false"}}
:dev {:closure-defines
{goog.DEBUG true}}}ESM should be fully isolated and not clash with anything else but there are some thing that might modify the global scope
for example using ^:export, which would create the chrome_ext.sidebar.whatever "global", which may clash with something else
it could also just be a different browser extension that just doesn't expect your sidebar to be there and then causes the actual breakage?
^:export is pretty unlikely to cause problems, but who knows whats going on in the global scope π
I'm assuming here we are talking about a release build. watch/compile I could easily see causing a whole bunch of issues π
basically one of the first lines in any closure build is var goog = goog || {};, it could just be that http://docs.google.com already has a non isolated goog defined. so everything ends up living on the same object. that will for sure cause issues
but I get Uncaught ReferenceError: goog is not defined if I tests on a google docs page. so that doesn't seem be the case
I can't find any ^:exports in the codebase. I've isolated it down to only our extension (all other uninstalled / disabled by the clients who have this issue). This was the error I was able to get from a client who had this issue, and this was the only log/error in console:
Error: VD`CustomError: Error in protected function: Deferred has already fired at D.onError () at tKe () at sL () at Both of these scripts don't have a global goog. Yup google docs has no global goog
@thheller Thanks for helping me investigate this, I'll try to pursue this further and see what I can find! For the time being we might just disable our extension on google docs page.
yeah :advanced typically renames it, so it could just be a different var name that happens to clash. but it would have to be put onto globalThis explicitely. don't know why anyone would do that π
Thanks a lot, really appreciate it πΈ π«‘
you could try a npx shadow-cljs release sidebar --pseudo-names build
that uses very long names, which reduces the chances of actually clashing with anything. just for debugging that might be useful
if the problem goes away that would at least confirm its a JS name clash, not something else
That's a great idea π€©! I'll try to debug it this way
but the build will be huge, so don't use that for anything other than debugging aid
Gotcha! Let me try it now π
Is there some way in shadow-cljs to pass some configuration info to the app so that it knows whether it is running :dev or :release mode?
I am reading https://shadow-cljs.github.io/docs/UsersGuide.html and experimenting with build-hooks. I can print the (prn "Build mode: " (:shadow.build/mode build-state)) ; => :dev in the build-hook, but I have no idea, how to store that to my app config (or whether it is event meant for that). Is goog.DEBUG the only viable way in the running frontend app to know if it is running in :dev or in :release ? I'd like to have some mechanism which I could store that info to my cljc file (and not in cljs).
I am not that experienced frontend developer, so the question might be a bit stupid. π
see https://shadow-cljs.github.io/docs/UsersGuide.html#closure-defines
build hooks are not meant for something like this
goog.DEBUG is also just an implicit closure define variable, but you can just setup your own wherever you want
macros can also get the :shadow.build/mode from their &env if you must, but the closure define way is preferred
Thanks! β€οΈ
Anyone have experience including plotly.js in a shadow project? I'm getting the following when adding any version (well, have tried 3 -- the current 3.0.1, and 2.35.2 and 2.14.0)....
Failed to inspect file
/home/cormacc/nmd/products/connect/portal/node_modules/maplibre-gl/dist/maplibre-gl.css
Errors encountered while trying to parse file
/home/cormacc/nmd/products/connect/portal/node_modules/maplibre-gl/dist/maplibre-gl.css
{:line 1, :column 1, :message "primary expression expected"}As a signpost to future travellers down this path... I had a facepalm moment after realising that using the the '-dist' variants of the plotly packages from npm eliminate this problem. So use 'plotly.js-dist' or 'plotly.js-dist-min' rather than plain 'plotly.js' in your package.json and require statements. On the plus side the ever-excellent shadow-cljs documentation helped me get js-processing with webpack working very easily, and good to know how it's done.
FWIW going with just the https://github.com/plotly/plotly.js?tab=readme-ov-file#load-via-script-tag from the docs is also valid, so just and (js/Plotly...)
then its not part of the build at all, so can't cause any trouble π
Yeah before my 'dist' revelation I'd set my dev build to use the CDN for convenience and a placeholder release build to use the split/webpack setup. Working within medical regulatory constraints so being able to package up all the deps at build time is a small win from the perspective of regulatory accountancy
shadow does not support processing css, so this won't work
you can offload the JS processing to webpack via https://shadow-cljs.github.io/docs/UsersGuide.html#js-provider-external
Great thanks - I'll take a look at that