ClojureScript

Configurable reader features

Details

  • Type: Enhancement Enhancement
  • Status: Closed Closed
  • Priority: Major Major
  • Resolution: Declined
  • Affects Version/s: None
  • Fix Version/s: None
  • Component/s: None
  • Labels:
    None

Description

The reader features for .cljc files is currently hard coded to #{:cljs} and Clojure will use :clj. With the intent being that host-specific features can be chosen at read-time. Given that there are a variety of different JS host platforms it would be useful to allow setting build-specific reader features so that builds targeting node can use different code than using the browser.

We can not always rely on the Closure Compiler eliminating all the code for us and we currently have no other way to get conditional requires.

Kevin Lynagh described his use-case here: https://gist.github.com/lynaghk/0608a43f173558b6fcf30c3be53d77dd

I had a very similar use case in mind for conditional requires related to excluding some code from a node.js targeted build for doing SSR that otherwise should use the same code as the browser uses.

My suggestion would be to add :reader-features #{:kw1 kw1} to the compiler options which will be added to the default :cljs at read-time.

Activity

Hide
David Nolen added a comment -

This is serious language level feature request. Such ideas need to be discussed around Clojure first.

Show
David Nolen added a comment - This is serious language level feature request. Such ideas need to be discussed around Clojure first.
Hide
Thomas Heller added a comment -

I was under the impression that JIRA is the place to have these discussions so they don't get lost in Slack Archives.

The Clojure Reader and tools.reader already support everything we need so no changes to either are necessary.

Only the :features option would become configurable, nothing more. Clojure itself does not need this feature since it only runs on the JVM, has its :clj option and already ignores every other option. I do think it is useful to have this for CLJS given the wide variety of host platforms.

https://github.com/clojure/clojurescript/blob/245bdee2c35e19a9685b7a0849f26fce8bdaf7ca/src/main/clojure/cljs/analyzer.cljc#L3652 and very few other places would need to change.

Show
Thomas Heller added a comment - I was under the impression that JIRA is the place to have these discussions so they don't get lost in Slack Archives. The Clojure Reader and tools.reader already support everything we need so no changes to either are necessary. Only the :features option would become configurable, nothing more. Clojure itself does not need this feature since it only runs on the JVM, has its :clj option and already ignores every other option. I do think it is useful to have this for CLJS given the wide variety of host platforms. https://github.com/clojure/clojurescript/blob/245bdee2c35e19a9685b7a0849f26fce8bdaf7ca/src/main/clojure/cljs/analyzer.cljc#L3652 and very few other places would need to change.
Hide
Andrea Richiardi added a comment -

I have another use case in my app:

Two different namespaces use the AWS and the Azure JavaScript SDKs for performing tasks. At the moment I have to require both and use a goog-define for picking the desired one, hoping unused parts gets trimmed away - using :simple in node I am not even sure it is possible to trim..

The proposal seems cleaner.

Show
Andrea Richiardi added a comment - I have another use case in my app: Two different namespaces use the AWS and the Azure JavaScript SDKs for performing tasks. At the moment I have to require both and use a goog-define for picking the desired one, hoping unused parts gets trimmed away - using :simple in node I am not even sure it is possible to trim.. The proposal seems cleaner.
Hide
Matt Huebert added a comment -

I've run into the same issue trying to share code between server and browser builds. A couple examples –

1. the Firebase API is fairly consistent across browsers and node.js, but you need the `"firebase-admin"` package on the server, and just `"firebase"` for the browser.
2. I have a namespace where I define a series of API endpoints. A subset of the API metadata should be visible to the browser build, while the node.js build should also include references node.js-specific resolver code, via vars to namespaces which do not exist at all in the browser.

I'm currently using a combination of workarounds, like (1) modifying how JS modules are resolved at compile time, eg. redirecting "firebase" to "firebase-admin" for node.js builds using shadow-cljs :js-options, (2) creating extra namespaces that are included/excluded from different builds which "inject" platform-specific functionality into the reusable namespaces by resetting vars / atoms, (3) using macros to read the current :target from the cljs compiler env and conditionally eliding/including code based on that, (4) using `goog-define`'s which are set per-build to conditionally evaluate code based on platform.

I like this proposal because reader conditionals would be a direct, inline expression of my intent, whereas these workarounds tend to add indirection, extraneous code, and more complicated build configurations.

Show
Matt Huebert added a comment - I've run into the same issue trying to share code between server and browser builds. A couple examples – 1. the Firebase API is fairly consistent across browsers and node.js, but you need the `"firebase-admin"` package on the server, and just `"firebase"` for the browser. 2. I have a namespace where I define a series of API endpoints. A subset of the API metadata should be visible to the browser build, while the node.js build should also include references node.js-specific resolver code, via vars to namespaces which do not exist at all in the browser. I'm currently using a combination of workarounds, like (1) modifying how JS modules are resolved at compile time, eg. redirecting "firebase" to "firebase-admin" for node.js builds using shadow-cljs :js-options, (2) creating extra namespaces that are included/excluded from different builds which "inject" platform-specific functionality into the reusable namespaces by resetting vars / atoms, (3) using macros to read the current :target from the cljs compiler env and conditionally eliding/including code based on that, (4) using `goog-define`'s which are set per-build to conditionally evaluate code based on platform. I like this proposal because reader conditionals would be a direct, inline expression of my intent, whereas these workarounds tend to add indirection, extraneous code, and more complicated build configurations.

People

Vote (0)
Watch (3)

Dates

  • Created:
    Updated:
    Resolved: