- 1. Introduction
- 2. Installation
- 3. Usage
- 4. REPL
- 5. Configuration
- 6. Build Configuration
- 7. Targeting the Browser
- 8. Targeting JavaScript Modules
- 9. Targeting React Native
- 10. Targeting node.js
- 11. Embedding in the JS Ecosystem The :npm-module Target
- 12. Testing
- 13. JavaScript Integration
- 14. Generating Production Code All Targets
- 15. Editor Integration
- 16. Troubleshooting
- 17. Publishing Libraries
- 18. What to do when things don’t work?
- 19. Hacking
1. Introduction
shadow-cljs
provides everything you need to compile your ClojureScript projects with a focus on simplicity and ease of use. The provided build targets abstract away most of the manual configuration so that you only have to configure the essentials for your build. Each target provides optimal defaults for each environment and get an optimized experience during development and in release builds.
1.1. High-Level Overview
shadow-cljs
is composed of 2 parts:
The shadow-cljs Clojure library which handles all the actual work.
The shadow-cljs
npm
package which provides a convenient interface for running most of the build functionality directly from command line.
If desired you can easily integrate the shadow-cljs
Clojure library into any other Clojure/JVM build tool (eg. leiningen or the Clojure CLI tools).
It is recommended to use the npm
package as that provides a more optimized development experience tailored towards CLJS development.
1.2. Basic Workflow
When working with shadow-cljs
you will be defining one or more builds in the shadow-cljs.edn
configuration file. Each build will have a :target
property which represents a configuration preset optimized for the target environment (eg. the Browser, a node.js
application or a Chrome Extension).
Each build can either produce development or release output depending on the command used to trigger the compilation. The standard build commands are: compile
, watch
and release
.
1.2.1. Development Mode
You can either compile
a development build once or run a watch
process which will monitor your source files and re-compile them automatically (and live-reload the code if desired).
All development builds are optimized for the developer experience with fast feedback cycles and other features like a REPL to directly interact with your running code.
A development build should never be shipped publicly since they can become quite large and may only work on the machine they were compiled on depending on the :target
.
1.2.2. Release Mode
Creating a release
build will strip out all the development related code and finally run the code through the Closure Compiler. This is an optimizing Compiler for JavaScript which will significantly reduce the overall size of the code.
1.3. Important Concepts
There are several important concepts that you should familiarize yourself with when using shadow-cljs
. They are integral to understanding how everything fits together and how the tool works with your code.
1.3.1. The Classpath
shadow-cljs
uses the Java Virtual Machine (JVM) and its "classpath" when working with files. This is a virtual filesystem composed of many classpath entries. Each entry is either
A local filesystem directory, managed by
:source-paths
entry in the configuration.Or a
.jar
file, representing Clojure(Script) or JVM libraries. These are compressed archives containing many files (basically just a.zip
file). These are added by your:dependencies
.
In the Clojure(Script) everything is namespaced and each name is expected to resolve to a file. If you have a (ns demo.app)
namespace the compiler expects to find a demo/app.cljs
(or .cljc
) on the classpath. The classpath will be searched in order until it is found. Suppose you configured the :source-paths ["src/main" "src/test"]
the compiler will first look for a src/main/demo/app.cljs
and then src/test/demo/app.cljs
. When the file is not found on any source path the JVM will begin looking into the .jar
files on the classpath. When it finds a demo/app.cljs
at the root of any of the libraries that file it will be used.
Important | When a filename exists multiple times on the classpath then only the first one is used. Everything on the JVM and Clojure(Script) is namespaced to avoid such conflicts. Very similar to npm where each package must have a unique name. |
It is therefore recommended to be very disciplined about the names you choose and about properly namespacing everything. It may seem repetitive to always use (ns your-company.components.foo)
over (ns components.foo)
but it will save you from lot of headaches later on.
This is unlike npm
where the package name itself is never used inside the package itself and only relative paths are used.
1.3.2. Server Mode
shadow-cljs
can be started in "server" mode which is required for long-running tasks such as watch
. A watch
will implicitly start the server instance if it is not already running. The server will provide the Websocket endpoint that builds will connect to as well as all the other endpoints for nREPL, Socket REPL and the development HTTP servers.
When using the shadow-cljs
CLI all commands will re-use a running server instance JVM instead of starting a new JVM. This is substantially faster since start-up time can be quite slow.
Once the server is running however you only have to restart it whenever your :dependencies
change and everything else can be done via the REPL.
1.3.3. REPL
The REPL is at the heart of all Clojure(Script) development and every CLI command can also be used directly from the REPL as well. It is absolutely worth getting comfortable with the REPL even if the command line may seem more familiar.
1.4. About this Book
1.4.1. Work in Progress
This is a work in progress. If you find an error, please submit a PR to fix it, or an issue with details of the problem.
1.4.2. Contributing
This source for this book is hosted on Github.
1.4.3. Conventions Used
There are many examples in this book. Most things used in these should be obvious from their context, but to prevent misunderstanding it is important to know the author’s intentions.
When command-line examples are given we may include BASH comments (starting with #
), and will usually include the standard user UNIX prompt of $
to indicate separation of the command from its output.
# A comment. This command lists files:
$ ls -l
shadow-cljs.edn
project.clj
...
Many of the examples are of the configuration file for the compiler. This file contains an EDN map. Where we have already discussed required options we will often elide them for clarity. In this case we’ll usually include an ellipsis to indicate "content that is required but isn’t in our current focus":
Example 1. Specify dependencies{:dependencies [[lib "1.0"]]}
Example 2. Add source paths{...
:source-paths ["src"]
...}
This allows us to concisely include enough context to understand the nesting of the configuration of interest:
Example 3. Nested option{...
:builds {:build-id {...
:output-dir "resources/public/js"}}}
Code examples may be similarly shortened.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论