How can I compile code ClojureScript for use in PhantomJS? - phantomjs

I'm trying to script PhantomJS in ClojureScript. I'm targeting Node and using phantomjs-node [1]. I have a basic example working:
(def phantom (js/require "phantom"))
(defn -main [& args]
(-> phantom
(.create (fn [browser]
(-> browser
(.createPage (fn [page]
(-> page
(.open "http://google.com" (fn [status]
(if (= status "success")
(-> page (.render "example.png")))
(-> browser .exit)))))))))))
Now, if I use evaluate function [2] of PhantomJS webpage object, I the following error:
phantom stdout: ReferenceError: Can't find variable: <namespace here>
When compiling into JavaScript the code to be evaluated contains the CLJS namespace and hence doesn't properly eval within the context of PhantomJS' webpage object. Here is an example:
(defn -main [& args]
(-> phantom
(.create (fn [browser]
(-> browser
(.createPage (fn [page]
(-> page
(.open "http://google.com" (fn [status]
(println (str "opened google? " status))
(-> page
(.evaluate #(-> document .-title)
#(do
(println (str "Page title is " %))
(-> browser .exit))))))))))))))
How can I prevent the code to be evaluated within the webpage object of PhantomJS from being namespaced with the CLJS namespace? Or secondly do I have any other options?
[1] https://github.com/sgentle/phantomjs-node
[2] http://phantomjs.org/api/webpage/method/evaluate.html

You need to use js/document instead of document.
document is a reference to clojurescript variable, js/document is a document in js world.

Related

Using ReactNative External library in ClojureScript Project - Syntax

I am trying to use react-native-swipe-list-view inside clojurescript. But I am having some trouble in converting documented js code in cljs code.
Documentations:
import { SwipeRow } from 'react-native-swipe-list-view';
<SwipeRow>
<View>
</View>
</SwipeRow>
My Cljs Code:
(:require [react-native-swipe-list-view :as swipe_list])
(defn item[]
(
[swipe_list/SwipeRow
[:View]]
))
Online tool:
(def SwipeRow (.-SwipeRow (js/require "react-native-swipe-list-view")))
(defn item[]
(
[SwipeRow
[:View]]
))
None of the above worked. I am new to cljs. it will be a big help if someone can tell me how to convert the above lines of js into cljs. Thanks
Reagent Documents: Creating Reagent "Components" from React Components
Here I am going to create two reagent components, view and swipeRow. I am using different ways for both, to show two ways for importing library and creating components. You can use either.
;; Importing Reagent and React Native
(ns type_name_server_here
(:require [reagent.core :as reagent]
["react-native" :as rn]))
;; 1st Way: Importing SwipeRow
(def SwipeRowImport (.-SwipeRow (js/require "react-native-swipe-list-view")))
;; Converting it into Reagent Component
(def SwipeRow (reagent/adapt-react-class SwipeRowImport))
;; 2nd Way: Importing View from already imported react-native library and converting it into reagent component
(def view (reagent/adapt-react-class (.-View ^js rn)))
;; SwipeRow requires two children (Check out documentation)
(defn item[]
(
[SwipeRow
[view] [view]]
))
If you are using shadow-cljs, you can use this table as a reference, for converting ES6 Import statments to CLJS Require

How to use react navigation in cljs?

Here’s my code in which I’m trying to create multiple bottom tabs using react navigation
(defn sample-comp []
[:> View [:> Text "Sample Container!"]])
(defn root-comp []
[:> NavigationContainer
[:> SafeAreaView
(let [Tab (createBottomTabNavigator)]
[:> (.-Navigator Tab)
[:> (.-Screen Tab)
{:name "Home"
:component (r/reactify-component sample-comp)}]])]])
(defn init []
;; register error also occurs if there's a non-
;; related error in the code
(dispatch [:register-db])
(render-root "Humboi" (r/as-element [root-comp])))
but I’m getting the following error:
requireNativeComponent: “RNCSafeAreaProvider” was not found in UIManager.
How to fix this error?

How to properly import components from other files using reagent?

I want to use a reagent component I've created in another file/namespace, say this.is.the.namespace, and it contains a component defined like so:
(defn component-name []
; stuff
)
In my entry file, I do the following:
(ns entry.point.namespace.name
(:require [this.is.the.namespace]
))
And when I include [component-name] in a component in the entry file, the component doesn't show. Why might this be?
(ns this.is.the.namespace)
(defn component-name []
[:p "Hello There"])
(ns entry.point.namespace.name
(:require [reagent.core :as reagent]
[this.is.the.namespace :as my-components]))
(reagent/render [my-components/component-name] (js/getElementById "main-div"))
Change "main-div" to id of the div that you are rendering into.

How to use StackNavigator of React Navigation in clojurescript

I am new to clojurescript and reagent. I try to use react-navigation in my react-native app but I getting this error
Error rendering component (in env.main.reloader > exp_cljs.core.app_root > reagent2)
This is my code
(def react-navigation (js/require "react-navigation"))
(def StackNavigator (aget react-navigation "StackNavigator"))
(defn Home
[]
[text "Hello Navigator"])
(defn SimpleApp
[]
(StackNavigator
(clj->js {:Home {:screen (r/create-class {:reagent-render (Home)})}})))
(defn init []
(dispatch-sync [:initialize-db])
(.registerComponent rn/app-registry "main" #(r/reactify-component app-root)))
This is my app-root
(defn app-root []
(SimpleApp)); -- error
;(r/create-class {:reagent-render SimpleApp}); error
;(r/as-element (SimpleApp)); -- error
;(r/adapt-react-class SimpleApp)); -- error
(ns same.app
(:require [reagent.core :as r]
[same.ui :as ui]
[same.util :as u]
[same.screens.auth :refer [AuthScreen]]
; [same.screens.reg :refer [RegScreen]]
; [same.screens.resend :refer [ResendScreen]]
[same.screens.splash :refer [SplashScreen]]
; [same.screens.drawer :refer [Drawer]]
[same.screens.presentation :refer [Presentation]]))
(def routes #js {;:Drawer #js {:screen (r/reactify-component Drawer)}
:AuthScreen #js {:screen (r/reactify-component AuthScreen)}
;:RegScreen #js {:screen (r/reactify-component RegScreen)}
;:ResendScreen #js {:screen (r/reactify-component ResendScreen)}
:Presentation #js {:screen (r/reactify-component Presentation)}
:Splash #js {:screen (r/reactify-component SplashScreen)}})
(def Routing (ui/StackNavigator.
routes
#js {:initialRouteName "Splash"
:headerMode "none"
:mode "modal"}))
(def routing (r/adapt-react-class Routing))
(defn AppNavigator []
(fn []
[routing]))
and android.core:
(ns same.android.core
(:require [reagent.core :as r :refer [atom]]
[re-frame.core :refer [dispatch-sync]]
[same.ui :as ui]
[same.events]
[same.subs]
[same.app :refer [AppNavigator]]))
(aset js/console "disableYellowBox" true)
(defn app-root []
(fn []
[AppNavigator]))
(defn init []
(dispatch-sync [:initialize-db])
(.registerComponent ui/app-registry "Same" #(r/reactify-component app-root)))
The trick is to convert React Native components to Reagent components and back where needed. In the following example definitions of login-screen and main-screen are omitted, they're just regular Reagent components.
(def react-navigation (js/require "react-navigation"))
(def stack-navigator (.-createStackNavigator react-navigation))
(def switch-navigator (.-createSwitchNavigator react-navigation))
; ...
; ...
; ...
(defn application-nav-stack []
(stack-navigator (clj->js { "MainApp" (r/reactify-component main-screen) })))
(defn authentication-nav-stack []
(stack-navigator (clj->js { "Login" (r/reactify-component login-screen) })))
(defn app-navigation-switch []
(switch-navigator
(clj->js { :Auth (authentication-nav-stack) :MainApp (application-nav-stack) })
(clj->js { :initialRouteName :Auth } )))
(defn app-root []
[ (r/adapt-react-class (app-navigation-switch)) ] )
(defn init []
(dispatch-sync [:initialize-db])
(.registerComponent app-registry "MyApp" #(r/reactify-component app-root)))
Whenever you pass a Reagent component to ReactNavigation function you need to use reactify-component to convert it to the native JS form; whenever you need to use ReactNavigation component as a part of Reagent component, you need to use adapt-react-class to convert it back.

Multi-lines input on phantom.js console

Does phantom.js (>= 1.7.0) support multi-lines input on its console? Neither pressing Enter nor META-Enter works below,
phantomjs> function foo() {
Parse error