|
| 1 | +# How to Use Calva with figwheel-main, deps and webpack |
| 2 | + |
| 3 | + |
| 4 | +<!-- [Figwheel-main](https://figwheel.org/docs/) Figwheel is famous for introducing hot reloading to the clojurescript world. Figwheel-main is its latest incarnation - a step up from the original figwheel which is still available. --> |
| 5 | + |
| 6 | +The advantage of using webpack over previous techniques such as `cljsjs` is that you can access all NPM libraries without the complexities of cljsjs, foreign-libs etc. Webpack should also do a better job of compressing and bundling those libraries for production as it should only include code you use rather than a whole cljsjs package. |
| 7 | + |
| 8 | +--- |
| 9 | +## Setting up figwheel-main |
| 10 | +Figwheel has [excellent docs](https://figwheel.org/docs/). Read those first - you will suffer if you don't. They include instructions for both a leiningen and a deps build, but we will concentrate on deps here. |
| 11 | + |
| 12 | +@PEZ has written a [fresh-figwheel-main](https://github.com/PEZ/fresh-figwheel-main) repo which will get you started. This already combines Calva, figwheel-main in a deps build. When setting this up, pay attention to the README at [step 3](https://github.com/PEZ/fresh-figwheel-main/blob/master/README.md). |
| 13 | + |
| 14 | +An alternative starter is the [figwheel.main.template](https://github.com/bhauman/figwheel-main-template), choosing the clj-new option for a deps build. |
| 15 | +<!-- |
| 16 | +As we are going to add webpack to the mix, it's a good idea to build fresh-figwheel-main both with and without picking an alias to understand the difference. One route takes you to the Calva Jack-in repl, and the other drops you into the figwheel terminal repl. Currently we need the `fig` alias for the webpack build, but once this is built, we want the convenience of the Jack-in route for an in-line repl. --> |
| 17 | + |
| 18 | +Other basic docs that you should be familiar with are [the clojure Deps and CLI guide](https://clojure.org/guides/deps_and_cli), and the |
| 19 | +[Clojurescript quickstart](https://clojurescript.org/guides/quick-start#clojurescript-compiler). |
| 20 | + |
| 21 | +## Key configuration files |
| 22 | +* `deps.edn` - List dependencies, aliases and paths. :extra-deps and :extra-paths can be added into alias option maps for individual build configuration. |
| 23 | +* `figwheel-main.edn` - These parameters may also be configured using metadata in the build. You will probably want to adjust |
| 24 | + - `:watch-dirs` - a vector of folder paths you want figwheel to watch for changes |
| 25 | + - `:css-dirs` - if you also want figwheel to hot reload on CSS updates |
| 26 | + - `:target-dir` - this determines where the compiler will place runtime javascript outputs - see below. |
| 27 | + - `:autotesting` - set this to true to enable the figwheel test endpoint /figwheel-extra-main/auto-testing in your app. |
| 28 | +* `xxx.cljs.edn` - is the name of the configuration file used for build `xxx`. |
| 29 | +* `dev.cljs.edn` - This configures the 'dev' build. |
| 30 | + * Optionally, you can add figwheel-main.edn options as metadata attached to the main map here. Useful if these change between builds |
| 31 | + * `:main` should contain your main namespace. |
| 32 | +* `test.cljs.edn` |
| 33 | + * `:main` should point to your test driver. |
| 34 | + |
| 35 | +## Check things work without webpack |
| 36 | +Clone [fresh-figwheel-main](https://github.com/PEZ/fresh-figwheel-main/blob/master/deps.edn) first. Use Calva Jack in and check that teh app launches at localhost:9500. In a separate tab you should see the tests running at localhost:9500/figwheel-extra-main/auto-testing for a nice heads-up display with test notifications appearing in the editor. |
| 37 | + |
| 38 | + |
| 39 | +## Adding NPM modules |
| 40 | +Read the [Using NPM](https://figwheel.org/docs/npm.html) guide. This documents how to use `:bundle` target to generate a webpack bundle. If you are using webpack, you will also be adding some NPM packages to your app. See [ClojureScript with Webpack](https://clojurescript.org/guides/webpack) for a rundown on how this works without figwheel or Calva. |
| 41 | + |
| 42 | +For web apps, you will commonly want to include react libs as NPM module. NPM install them. Your `package.json` might look something like this: |
| 43 | +``` |
| 44 | +{ |
| 45 | + "dependencies": { |
| 46 | + "bootstrap": "4.5.0", |
| 47 | + "react": "16.13.0", |
| 48 | + "react-bootstrap": "1.2.2", |
| 49 | + "react-dom": "16.13.0" |
| 50 | + }, |
| 51 | + "devDependencies": { |
| 52 | + "webpack": "^4.43.0", |
| 53 | + "webpack-cli": "^3.3.11" |
| 54 | + } |
| 55 | +} |
| 56 | +``` |
| 57 | + |
| 58 | +## Configure a webpack build |
| 59 | +We'll change the fresh-figwheel-main `build` alias to a webpack build. |
| 60 | + |
| 61 | +Create a build configuration for it which has :target set to :bundle. This triggers creation of a webpack compatible bundle. |
| 62 | +The figwheel docs suggest that the :bundle-cmd is optional. I have not found it to be so. We'll leave out the :output-to and :final-output-to keys as figwheel will insert its defaults. |
| 63 | + |
| 64 | +``` |
| 65 | +^{:watch-dirs ["test" "src"] |
| 66 | + :css-dirs ["resources/public/css"] |
| 67 | + :auto-testing true |
| 68 | + } |
| 69 | +{:main fresh-figwheel-main.core |
| 70 | + :target :bundle |
| 71 | + :bundle-cmd {:none ["npx" "webpack" "--mode=development" :output-to "-o" :final-output-to]}} |
| 72 | +``` |
| 73 | + |
| 74 | +## Reconfigure deps |
| 75 | +We can now exclude the cljsjs packages as these will be brought in from npm-modules in the webpack bundle. |
| 76 | +Notice also that the `:build` alias now targets the "build" build. |
| 77 | + |
| 78 | +{:deps {org.clojure/clojure {:mvn/version "1.10.0"} |
| 79 | + org.clojure/clojurescript {:mvn/version "1.10.773"} |
| 80 | + reagent {:mvn/version "1.0.0-alpha2" |
| 81 | + :exclusions [cljsjs/react |
| 82 | + cljsjs/react-dom |
| 83 | + cljsjs/react-dom-server]}} |
| 84 | + :paths ["src" "resources"] |
| 85 | + :aliases {:fig {:extra-deps |
| 86 | + {com.bhauman/rebel-readline-cljs {:mvn/version "0.1.4"} |
| 87 | + com.bhauman/figwheel-main {:mvn/version "0.2.11"}} |
| 88 | + :extra-paths ["target" "test"]} |
| 89 | + :build {:main-opts ["-m" "figwheel.main" "-b" "build" "-r"]} |
| 90 | + :min {:main-opts ["-m" "figwheel.main" "-O" "advanced" "-bo" "dev"]} |
| 91 | + :test {:main-opts ["-m" "figwheel.main" "-co" "test.cljs.edn" "-m" "fresh-figwheel-main.test-runner"]}}} |
| 92 | + |
| 93 | +## Calva Jack-in to start the build |
| 94 | +If you now Jack-in and select BOTH `fig` and `build` the `build` alias will run `figwheel.main`. |
| 95 | +Notice that it runs the compilation and then runs webpack, creating final artefacts at `target/public/cljs-out/build/main_bundle.js` and `target/public/cljs-out/build/main_bundle-auto-testing.js`. |
| 96 | + |
| 97 | +The Jack-in will not complete in the output.repl-file window as the figwheel REPL has taken over at this point. So don't expect the nice Calva REPL commands to work yet. |
| 98 | + |
| 99 | +``` |
| 100 | +> Executing task: clojure -Sdeps '{:deps {nrepl {:mvn/version "0.6.0"} cider/cider-nrepl {:mvn/version "0.23.0"} clj-kondo {:mvn/version "2020.04.05"} cider/piggieback {:mvn/version "0.4.2"}}}' -A:fig:build < |
| 101 | +
|
| 102 | +2020-08-21 18:06:40.161:INFO::main: Logging initialized @4776ms to org.eclipse.jetty.util.log.StdErrLog |
| 103 | +[Figwheel] Validating figwheel-main.edn |
| 104 | +[Figwheel] figwheel-main.edn is valid \(ツ)/ |
| 105 | +[Figwheel] Compiling build build to "target/public/cljs-out/build/main.js" |
| 106 | +[Figwheel] Successfully compiled build build to "target/public/cljs-out/build/main.js" in 3.891 seconds. |
| 107 | +[Figwheel] Bundling: npx webpack --mode=development target/public/cljs-out/build/main.js -o target/public/cljs-out/build/main_bundle.js |
| 108 | +[Figwheel] Outputting main file: target/public/cljs-out/build/main-auto-testing.js |
| 109 | +[Figwheel] Bundling: npx webpack --mode=development target/public/cljs-out/build/main-auto-testing.js -o target/public/cljs-out/build/main_bundle-auto-testing.js |
| 110 | +[Figwheel] Watching paths: ("test" "src") to compile build - build |
| 111 | +[Figwheel] Starting Server at http://localhost:9600 |
| 112 | +[Figwheel] Starting REPL |
| 113 | +Prompt will show when REPL connects to evaluation environment (i.e. a REPL hosting webpage) |
| 114 | +Figwheel Main Controls: |
| 115 | + (figwheel.main/stop-builds id ...) ;; stops Figwheel autobuilder for ids |
| 116 | + (figwheel.main/start-builds id ...) ;; starts autobuilder focused on ids |
| 117 | + (figwheel.main/reset) ;; stops, cleans, reloads config, and starts autobuilder |
| 118 | + (figwheel.main/build-once id ...) ;; builds source one time |
| 119 | + (figwheel.main/clean id ...) ;; deletes compiled cljs target files |
| 120 | + (figwheel.main/status) ;; displays current state of system |
| 121 | +Figwheel REPL Controls: |
| 122 | + (figwheel.repl/conns) ;; displays the current connections |
| 123 | + (figwheel.repl/focus session-name) ;; choose which session name to focus on |
| 124 | +In the cljs.user ns, controls can be called without ns ie. (conns) instead of (figwheel.repl/conns) |
| 125 | + Docs: (doc function-name-here) |
| 126 | + Exit: :cljs/quit |
| 127 | + Results: Stored in vars *1, *2, *3, *e holds last exception object |
| 128 | +[Rebel readline] Type :repl/help for online help info |
| 129 | +Opening URL http://localhost:9500 |
| 130 | +``` |
| 131 | +## Edit the HTML to reference the bundled js |
| 132 | + |
| 133 | +http://localhost:9500 is probably showing a blank white page and teh console will be saying that "react" is undefined. |
| 134 | +That's because the html is still pointing at the unbundled output which no longer includes react as we excluded it. |
| 135 | + |
| 136 | +Edit `target/public/index.html` to reference `<script src="cljs-out/build/main_bundle.js"></script>`, and all should now work |
| 137 | + |
| 138 | +## Testing |
| 139 | +Furthermore the autotest end-point should be working too. |
| 140 | + |
| 141 | +## Using the Calva REPL |
| 142 | +Building the webpack bundle broke the link with the CAlva REPL. Fortunately, the webpack bundle references the standard output main file. In development it's therefore only necessary to create the webpack bundle once. You can simply reconnect using a Calva Jack-in that does not call the figwheel main repl. |
| 143 | + |
| 144 | +Jack-in and ONLY select `fig` this time, NOT `build`. In deps, the `fig` alias does not contain a call to figwheel.main. |
| 145 | +Wait for the second Calva prompt. This time, select `build`. The Jack in will complete in the Calva context. |
| 146 | + |
| 147 | +Nice - we have the Calva inline REPL experience running on a webpack bundle :) |
| 148 | + |
| 149 | + |
0 commit comments