Fork me on GitHub

Using the new :bundle with figwheel latest (following the CLJS official guide) I have added firebase as a dependency in my package.json

  "devDependencies": {
    "webpack": "^4.43.0",
    "webpack-cli": "^3.3.11"
  "dependencies": {
    "firebase": "^7.14.4",
Then I can require the above like this and everything works.
However, the above will import the entire firebase JS package. I can save some kb by specifying exactly what I need. In JS, it would be this:
import * as firebase from 'firebase/app';

import 'firebase/auth';
What would the equivalent require be like in CLJS? Do we need to specify any additional configuration for the CLJS compiler?


If advanced compilation works, then dead code elimination will be automatic.


Not sure if that’s correct. The closure compiler doesn’t know anything about the internal structure of firebase, and won’t necessarily be able to do DCE inside that.


That said, it might not even help to express with a limited import either, as problem stays the same


Indeed. My understanding is that what you do in webpack is outside the scope of the GCC.


Normally this is not a problem because all the modules we import through webpack, once set to “production”, will be minified to the same level as everyone else in the JS ecosystem.


The challenge here comes with the fact that commonJS, unless the authors of the library did prep work, will include everything by default without webpack having the ability to eliminate the unused stuffs. There are workarounds in JS land though.


> That said, it might not even help to express with a limited import either, as problem stays the same I believe with the limited import (ES6 modules), you’re able to eliminate all the unused stuffs. But this might only be true for libraries like Firebase which have done the work to make this possible.


@tkjone No, advanced compilation works with webpack.


Interesting. Are we talking about the same thing? e.g. I have a package like React that is handled by webpack. We’re saying that React will be run through GCC’s advanced compilation step?


At least that is my understanding


But it depends on the library of course, not all will work.


That's why you write externs for the ones that don't


I will have to dig into this a little more, but my understanding is that something like React may already be compiled (to a certain degree) by GCC. This means it would be as small as it can be, yes? I’m not sure why I would try to run any package from the NPM ecosystem + webpack through GCC because it’s my understanding that those packages, in their production builds, are already as small as they can be.


But maybe your point is that is that whether you would run them through GCC is irrelevant and rather that the webpack packages are run through unless you tell the compiler otherwise?


the latter yes


It would be easy to test though. Just do a compilation with and without it.


See if advanced works as it should


Gotcha! For sure. What you mentioned is what I do during my builds (externs), but I never distinguished the externs and webpack code running through gcc. That’s my bad.

👍 4

@tkjone ah I was mistaken. It seems that in order to have to have it included within your code's compilation, you need to specify it as a foreign lib to tell the CC about it. I know you can refer to parts of JS libraries like so ["@react-navigation/native" :refer [NavigationContainer]], but I don't know if that affects the output size.


So by default packages setup through webpack are not run through GCC, yes?

💯 4
Oliver George00:05:31

Is there a way to write this in CLJS for use with the new :bundle target.


export default {
  title: 'Foo',
  component: FooComponent,
  decorators: [ ... ],
  parameters: { ... }


@olivergeorge should be possible if you write an ES6 file, but not sure if there are issues


@tkjone we only support CommonJS style import - so there's no way to express that - and no plans at least in the near future - would need a lot of thought

Oliver George12:05:10

@dnolen hmm. I have {:language-out :es6} set now. Adding (js* "export default " SimpleComponent) but a :simple compile throws ERROR - [JSC_MIXED_MODULE_TYPE] A file cannot be both a goog.provide'd file and an ES6 module.


expected far as I can tell


trying stuff with (js*...) in this case not likely to get you anywhere

Oliver George12:05:29

Yeah, was reaching. Not familiar with how this could/should work.

Oliver George12:05:45

I'm happy for wait and work with the ^:export approach for now.


I just don't know what you're trying to do


if you just want a prod build that exports some stuff then that's easy, write that stuff in your index.js

Oliver George12:05:54

Yep, figured that might be how it works.

Oliver George12:05:08

I was experimenting with getting reagent views to display in Storybook. The webpack guide works.

Oliver George12:05:05

My approach required referencing a global export which is fine but left me wondering if I was missing a more common approach to importing the component.

import React from 'react';

import '../out/index.js';

export default {
  title: 'SimpleComponent',
  component: SimpleComponent,

export const SimpleComponent = () => <hello_bundler.core.SimpleComponent />;

Oliver George12:05:24

I could provide an alternative index.js which imports my component does the "export default ..." to make a cleaner interface

Oliver George12:05:33

That hides the quirk.


@dnolen gotcha. Curious though: In the One example they use seems to be commonjs

var firebase = require('firebase/app');
but maybe I am misunderstanding their docs.


I don't know anything about firebase so I can't really offer more insight

👍 4

In a scenario like the above (aside from using shadow-cljs), to achieve the smaller packages in production, would the recommended approach be to go back to the previous way of using webpack and ClojureScript?


@tkjone try doing (:require [“firebase/auth” :as firebase.auth])


the important thing isn’t the es6 import stuff, it’s the way they’re referencing the package by path


No such namespace: firebase/auth, could not locate firebase_SLASH_auth.cljs, firebase_SLASH_auth.cljc, or JavaScript source providing "firebase/auth" (Please check that namespaces with dashes use underscores in the ClojureScript file name) in file src/pillar/app.cljs


> the important thing isn’t the es6 import stuff, it’s the way they’re referencing the package by path Totally. This was my thought as well.


and you’re using the :bundle build?


Everything else is working with the commonjs style, it’s just that “style” of require.


@dnolen does that seem like something that should be supported? are we doing something wrong?


I likely know answer to this but.. for cljs macros you can’t pre-compile javascript only code, right? (for react native, I was hoping to inline static style props, e.g. `{:style (sh {:flex 1})`, but doesn’t look like that’s possible since the `StyleSheet` is a js object)


@alidcastano not sure what you mean. can you explain what the desired CLJS or JS output is?


@lilactown using Helix, imagine this declaration

(def styles (.create rn/StyleSheet #js {:container #js {:flex 1})
(defnc Foo [] ($ rn/View {:styles (.-container styles))
i’d like to do this
(defnc Foo [] ($ rn/View {:styles (sh {:flex 1}))
where sh is a macro creating the static styles, so that I can inline them without re-creating them on every component render but in order to that I need some way to call (.create rn/StyleSheet) which I imagine isn’t possible. I know I can expand to the appropriate js code but that code wouldn’t be called until component is rendered (?), defeating the purpose. not sure if there’s some workaround that’d make this possible


okay, so what you want is to “lift” the style creation outside of the form you’ve written the macro in


yeah it’s not easy to do that in CLJS, I wouldn’t recommend it

🆗 4

it’s possible to lift the style creation outside the form with macros, but it seems like just memoizing the call should do what you want:

(def sh (memoize #(.create rn/StyleSheet (clj->js %)))

👍 4

depending on how many different styles you expect, you may or may not want to limit the maximum size of your cache using something like


@alidcastano I recommend offloading the code into a helper fn. so you emit (def styles (your-macro-ns/make-stylesheet #js {:container #js {:flex 1})) and have the make-stylesheet fn for whatever it needs to call rn/StyleSheet


with this suggestion the styles wouldn’t be inlined, right? it’d just make it easier to create the static styles in cljs outside the component


(defn make-stylesheet [s] (.create rn/StyleSheet s)) or so


Hi, I'm 100% sure that this question have been asked before, but after reading documentation, and few answers from google, I'm starting thinking that I don't understand something I have very simple clojurescript project with shadow-cljs.edn config

{:source-paths ["src"]
 :dependencies []
 :builds {:app {:target :browser
                :output-dir "public/js"
                :asset-path "/js"
                :modules {:main {
                                 :entries [app.core]}}}}}
after shadow-cljs watch app and shadow-cljs cljs-repl app I'm getting No application has connected to the REPL server. Make sure your JS environment has loaded your compiled ClojureScript code. I've opened in the browser


@rafal.wysocki the server running on 9630 is for the internal shadow-cljs UI and websockets. it does not load any of your code. if you want a webserver for your code use :dev-http


if you just want a browser repl use shadow-cljs browser-repl but that also won't load any of your code unless you (require 'app.core) it and use it that way


@thheller thanks, it's working now, I think it should be more explicitly mentioned in the docs


this is rather long read and I didn't notice it


it is mentioned here if you want something shorter 😛

Martin Rodriguez18:05:45

Hey! Is it possible to use SCSS with shadow-cljs live reloading?


@marodriguez if you start a scss watcher, shadow-cljs will hot reload changes to your CSS files

Martin Rodriguez19:05:58

@lilactown thanks, in that case I would need to start a scss watcher and a shadow watcher right? I was thinking of a plugin/config to add the scss watcher into the shadow one.

Martin Rodriguez19:05:04

Any suggestions?


yeah, you would start both watchers


there might be a JVM scss watch that you could start in your shadow-cljs process, I’m not sure


probably easier to run them separately tbh


there are many options to run multiple things for you. shadow-cljs does not need to do that.

Martin Rodriguez19:05:18

Will check it out thanks. I come from React/Angular/Vue and all of them have like scss out of the box. Maybe there was like a recommended way of doing it.


yeah that makes sense


I’m trying to build a clj+cljs library (using deps.edn and cljx) and I’m looking for guides on how to set up and organize everything, and/or other libraries that I can look at for inspiration. Does anybody have any recommendations? (Sorry in advance if this is the wrong place to ask!)


cljx is deprecated, cljc offers the functionality and is built into clojure itself

David Pham04:05:09

You can read the guide on Clojure Cli on the official website or shadow cljs readme