Concepts
This serves as a glossary and an overview of concepts used in esy with links to detailed guide.
Project Sandbox
A directory with a manifest (usually package.json
).
Almost every esy
command operates in the context of a project sandbox.
Manifest
A JSON file usually called package.json
which contains information about esy
package:
- Package name and version.
- Dependency declarations.
- Commands needed to build and install package artifacts.
- Other metadata
Support for esy.json
Usually a manifest is represented as package.json
but to allow package.json
to be used exclusively with npm, esy allows manifests to be represented as
esy.json
files. In the case both package.json
and esy.json
are present in
the sandbox esy will prefer esy.json
over package.json
.
Note that in case of a published (on npm registry) package esy won't be able to access
esy.json
and will only read metadata using npm registry API which is populated frompackage.json
during publish time.Maintainers will need to make sure they have crafted a correct
package.json
with metadata during publish process.
Package
A unit of software distribution and the smallest unit which is esy operates on.
Release mode and Development mode
Any package can be built in two modes - release or development.
During release, a package is built as if it were being consumed by another dependency. Only its dependencies
are built (not devDependencies
)
During development mode, a package (most often only the root, is built along with it's devDependencies
with a special flag set (not important what exactly it is) to signify that a package is being built in development mode. When this flag is set, alternatives to regular configuration (like buildDev
instead of build
) are selected in the sandbox.
Root package
Package at the root of a sandbox.
Dependency
Any package that the root package needs to build the sandbox (either during development or releases mode)
Regular dependency
Dependencies that are required when a package is built in release mode. These are specified in the dependencies
field.
Packages like @reason-native/console
are a good example of regular dependencies as these dependencies are required to the build a given root package. They differ from development time dependencies (like @reason-native/rely
) as we'll see next.
Development time dependency
Dependencies that are required only during development mode are specified in the devDependencies
(similar to how yarn and npm work)
Good examples of dev-dependency is @opam/ocaml-lsp-server
or @reason-native/rely
as it is only required during development of the root package.
Build time dependency
Some dependencies are needed during the build. @opam/dune
and autotools packages are good examples.
Build time dependencies are meant to be specified as regular
dependencies as they are needed by the package dependending on it. Build time packages are better compared with runtime packages (instead of dependencies/devDependencies). Once the root package is built, build dependencies are not needed anymore by the root package. Runtime dependencies on the other hand are still needed in the sandbox for the root package to run correctly. @opam/uchar
is a good example of runtime package. A binary depending on it needs it installed in the sandbox when it is run.
Peer dependency
Deprecated. We now recommend resolutions
mechanism over peer dependencies.
Solution
A result of solving dependencies for a project sandbox.
Cached as esy.lock
directory in the root of a project.
It is advised to commit this file to a project's repository so that the build environment is reproducible and doesn't depend on the current state of package registries (either npm or opam).
Stores
Esy maintains three kinds of artifacts - sources, builds and installed artfiacts - in three different locations.
Sources
Source entries in the esy store are source code files and the recipes that build and install them bundled together. Change any of them, and esy creates a different entry for the source of a package.
If, for instance, build instructions of a package from opam are overridden (and the source files are not necessarily touched), esy places them in a different location.
Conceptually, a source entry in the esy store is both its source files and its recipe.
Build store
Build store is simply location where build artifacts are stored. They can be local to a project or global (so that they can be reused).
Build artifacts (object files, bytecode files etc) stored as separate entries dependending on the instructions that build and install them, environment variables present during its build and of course the sources (source code + recipe).
Change anyone of them, and esy creates a separate entry in the build store.
Global build store
Store where the build entries common to multiple projects are stored. This can be considered a a cache too.
By default the global install store can be found at ~/.esy/3/b
Local build store
Store where build entries that are relevant only to a give project are store.
By default the global install store can be found at <project root>/_esy/default/store/b/<build_id>
Install store
Install stores are where final, ready to be consumed, artifacts are stored. The paths (which uniquely identify them) depend on how they are built.
Like build artifacts, install stores can be both local and global.
By default the global install store can be found at ~/.esy/3__../i
and the local one can be found at <project root>/_esy/default/store/i/<build_id>
Package stage location
As packages are built and installed, they can fail for a lot of reasons. To prevent unusable entries in the install store, packages are first installed to a staging area and only once the steps complete successfully, are they moved to the final store.
Release
Before a binary executable can be distributed, esy
can bundle runtime depedendencies together with it and install them alongside. As a proof-of-concept, Esy provides npm-release
command that creates a npm package that bundle the runtime binaries with a postinstalls cript that correctly installs them and updates the binaries to load the depdendencies from this install path. Check out npm-release
to see what that looks like.
Additional notes
Compiler
Esy expects the ocaml compiler from NPM and not Opam - this is tied to how esy solves dependency constraints for opam packages. Esy begins solving the package dependency graph with OCaml compiler at the root and expects the formula version spec to be either in NPM or source form. Packages like @opam/ocaml
, @opam/ocaml-base-compiler
are not looked at while solving.