esy Documentation

website·Indexed 33 days ago

https://esy.sh/

A rapid workflow for developing Reason and OCaml projects that supports native packages hosted on opam and npm. esy provides a project sandbox environment, manages the OCaml compiler via npm, and enables configurable workflows through low-level commands and package.json configuration.

Tokens
14.8K
Snippets
96
Records
125
Agent score
64%

What's inside esy

  1. Overview of esy package manager

    esy is a package manager that provides a package.json-like workflow with first-class support for native development. It is designed to provide isolated, fast, and hermetic builds, ensuring that builds are unaffected by global system software. It supports packages from opam and native packages published to npm, and it caches built packages across projects to speed up initialization.
  2. Understand Project Sandbox and Manifests

    A Project Sandbox is a directory containing a manifest file. Almost every esy command operates within the context of a project sandbox.

    The manifest is a JSON file containing the package name, version, dependency declarations, build/install commands, and metadata. While package.json is the standard, esy also supports esy.json. If both are present, esy.json takes precedence. Note that for packages published to the npm registry, esy relies on the registry API (populated by package.json) and cannot access esy.json.

  3. Understand the esy build pipeline

    The esy build process transforms a project manifest (e.g., package.json or esy.json) into built artifacts through a five-step pipeline:

    1. Solve Dependencies: Generates an esy.lock file from the manifest by constructing a package universe (via npm, opam, git, etc.) and processing it through a CUDF solver (esy-solve-cudf).
    2. Fetch Dependencies: Ensures all packages in esy.lock are downloaded, patched, and stored as .tgz files in the Global Installation Cache.
    3. Crawl Package Graph: Reads the lockfile and linked packages into a BuildManifest.t structure, mapping dependencies, peerDependencies, and optional dependencies.
    4. Produce Task Graph: Converts the BuildManifest.t into Plan.Task.t structures, which include the specific commands and environment variables required for building each package.
    5. Build Task Graph: Serializes Task.t into a JSON Build Plan and executes the build using the esy-build-package executable.
  4. Understand the Global Build Store architecture

    The Global Build Store caches built artifacts and metadata to avoid redundant builds.

    • Default Location: ~/.esy/3<prefix> (can be modified via the --store-path option of the esy executable). The <prefix> uses underscores to ensure the path to the ocamlrun executable is exactly 128 characters for shebang compatibility.
    • Cache Key: Composed of the package name, version, a hash of build/install commands/metadata from the manifest, and a hash of all dependencies' cache keys.
    • Directory Structure:
      • b/<key>: Build root for the package.
      • b/<key>.log: Build process logs.
      • b/<key>.info: Build process metadata (e.g., elapsed time).
      • s/<key>: Stage directory for installation (used for atomic moves).
      • i/<key>: Final installation directory hosting the built artifacts.
  5. Understand esy environment types

    esy manages three distinct environments for each project:

    1. Build Environment: Used specifically to build the project. It is isolated from user customizations (via $SHELL) and includes paths to regular dependencies.
    2. Command Environment: Used for running text editors, IDEs, and general testing of built artifacts. It includes paths to both regular and development dependencies.
    3. Test Environment (Exported Environment): Used when the current application needs to appear as if it is already installed. It includes paths to regular dependencies and the project's own installation directories.
  6. Use esy with supported editors

    Esy provides editor integrations that ensure the development environment is correctly constructed so that dependencies are visible to the editor while maintaining isolation between projects. This enables autocomplete to work based on esy.json or package.json and allows simultaneous editing of multiple projects with different dependency or compiler versions.

    Currently supported integrations include:

    • LSP: ocaml-language-server
    • Vim: vim-reason

    Caveats:

    • The Vim plugin currently only activates for .re files and does not support .ml extensions.
    • In VSCode, each project must be opened in a separate window to edit multiple projects simultaneously.
  7. Install OCaml compiler variants in esy

    To install specific compiler variants such as flambda or musl-static, specify the exact semver tag for that variant in your configuration. The OCaml compiler does not require additional patches to work with esy.
    {
      "ocaml": "4.10.1002-musl.static.flambda"
    }
  8. Generate opam files using Dune in Esy

    To generate an opam file using Dune within an Esy project, run the build command targeting the specific opam file. Note that because Dune does not support generating opam files exclusively in the build directory, this operation will not treat the source tree as immutable.
    esy dune build <project-name>.opam
  9. Compile OCaml code using an esy sandbox

    To compile OCaml code without installing the compiler globally, define the OCaml version in package.json. Running esy will fetch the dependencies and create an isolated sandbox. Use the esy prefix to run compiler commands like ocamlopt (native) or ocamlc (bytecode) within that sandbox.
    {
      "dependencies": {
        "ocaml": "4.10.x"
      }
    }
    # Install dependencies and create sandbox
    esy
    
    # Compile hello.ml to hello.exe using the native compiler
    esy ocamlopt -o hello.exe hello.ml
    
    # Execute the resulting binary
    ./hello.exe
  10. Manage the Dependency Solution (Lockfile)

    A Solution is the result of solving dependencies for a project sandbox. It is cached as the esy.lock directory in the project root. To ensure build environments are reproducible and independent of the current state of npm or opam registries, esy.lock should be committed to the project's version control system.
  11. Distribute binaries using npm-release

    Esy can bundle runtime dependencies with a binary executable for distribution. The esy npm-release command creates an npm package that bundles runtime binaries and includes a postinstall script to correctly install them and update the binaries to load dependencies from the install path.
    esy npm-release