esbuild for Elixir/Phoenix

repository·main·Indexed 43 days ago

https://github.com/phoenixframework/esbuild

A set of Mix tasks for installing and invoking the esbuild JavaScript bundler within Elixir and Phoenix applications. It provides support for execution profiles, automatic binary installation, and integration with Phoenix asset pipelines, including watch mode and deployment minification.

Tokens
2.8K
Snippets
16
Records
17
Agent score
55%

What's inside esbuild

  1. Manage third-party JavaScript packages

    main

    You can handle JavaScript dependencies in two ways:

    1. Vendoring: Place the dependency inside your project (e.g., in assets/vendor/) and import it using a relative path:

      import topbar from "../vendor/topbar"
    2. NPM/Node Modules: Run npm install <package> --save inside your assets directory. esbuild will automatically resolve these imports:

      import topbar from "topbar"
    import topbar from "topbar"
  2. Use CSS with esbuild

    main

    esbuild provides basic CSS support. If you import a .css file at the top of your main JavaScript entry point, esbuild will bundle it and write the output to the same directory as your bundled JS file.

    import "../css/app.css"

    Note on CSS Frameworks: If you need to use a CSS framework (like Tailwind or SASS), esbuild's built-in support is insufficient. You should use:

  3. Install esbuild

    main

    To use esbuild in your Elixir project, add it as a dependency in your mix.exs. The configuration depends on whether you build assets in production or precompile them during development.

    Option 1: Build assets in production

    Add esbuild to all environments, but only start it in :dev to save resources in other environments:

    def deps do
      [
        {:esbuild, "~> 0.10", runtime: Mix.env() == :dev}
      ]
    end

    Option 2: Precompile assets during development

    If assets are precompiled during development, add it as a dev-only dependency:

    def deps do
      [
        {:esbuild, "~> 0.10", only: :dev}
      ]
    end

    Post-installation steps

    1. Specify the esbuild CLI version in config/config.exs:
      config :esbuild, version: "0.25.5"
    2. Run the installation task to download the executable:
      mix esbuild.install
  4. Add esbuild to a Phoenix application

    main

    Follow these four steps to integrate esbuild into a Phoenix project:

    1. Add dependency

    In mix.exs:

    def deps do
      [
        {:phoenix, github: "phoenixframework/phoenix", branch: "v1.5", override: true},
        {:esbuild, "~> 0.10", runtime: Mix.env() == :dev}
      ]
    end

    2. Configure esbuild

    In config/config.exs, define the default profile. Note the use of NODE_PATH to allow esbuild to find dependencies in your Elixir deps folder:

    config :esbuild,
      version: "0.25.5",
      default: [
        args: ~w(js/app.js --bundle --target=es2016 --outdir=../priv/static/assets),
        cd: Path.expand("../assets", __DIR__),
        env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)}
      ]

    Note: Ensure the assets directory in priv/static is listed in the :only option for Plug.Static in your lib/my_app_web/endpoint.ex.

    3. Enable Watch Mode for Development

    In config/dev.exs, add the esbuild watcher to your watchers configuration:

      esbuild: {Esbuild, :install_and_run, [:default, ~w(--sourcemap=inline --watch)]}

    4. Configure Deployment

    In mix.exs, add an assets.deploy alias to minify assets during deployment:

    "assets.deploy": ["esbuild default --minify", "phx.digest"]
    config :esbuild,
      version: "0.25.5",
      default: [
        args: ~w(js/app.js --bundle --target=es2016 --outdir=../priv/static/assets),
        cd: Path.expand("../assets", __DIR__),
        env: %{"NODE_PATH" => Path.expand("../deps", __DIR\)}
      ]
  5. Configure esbuild execution profiles

    main

    Execution profiles allow you to define default arguments, working directories (cd), and environment variables (env) for specific tasks. Profiles must be configured in config/config.exs because the esbuild task runs without starting your application (meaning it cannot access config/runtime.exs).

    When you call mix esbuild <profile_name>, the arguments provided in the CLI command are appended to the arguments defined in the profile.

    config :esbuild,
      version: "0.25.5",
      default: [
        args: ~w(js/app.js),
        cd: Path.expand("../assets", __DIR__)
      ]
  6. Use a system-installed esbuild executable

    main

    If you cannot download esbuild automatically (e.g., due to proxy restrictions) or prefer to manage it via npm, you can point the library to a specific executable location using the :path configuration key or the MIX_ESBUILD_PATH environment variable.

    To use a globally installed version via npm:

    1. Install esbuild: npm install -g esbuild
    2. Locate the binary (e.g., NPM_ROOT/esbuild/node_modules/@esbuild/TARGET/bin/esbuild on Unix).
    3. Set the path in your configuration or environment.
    config :esbuild, path: System.get_env("MIX_ESBUILD_PATH")
  7. Install the esbuild binary via Mix

    main

    Use the mix esbuild.install command to download and install the esbuild binary into your project's _build directory. This ensures the correct version of esbuild is available for your local environment.

    By default, it installs the latest version specified by the esbuild package, but you can pin a specific version in your application configuration.

    $ mix esbuild.install
  8. Configure esbuild profiles and global settings

    main

    You can configure esbuild using Elixir's config syntax. The library uses 'profiles' to define different execution contexts (e.g., for different entry points or environments). By default, a :default profile is available.

    Global Configurations

    • :version - The expected esbuild version (string).
    • :version_check - Boolean indicating whether to perform a version check on startup (defaults to true).
    • :path - The path to the esbuild executable. If not set, it is automatically managed in your _build directory.

    Profile Configuration

    A profile is an atom that maps to a configuration map containing:

    • args: A list of command-line arguments for esbuild.
    • cd: The current working directory for the command.
    • env: A map of environment variables to be passed to the process.
    config :esbuild,
            version: "0.25.0",
            default: [
              args: ~w(js/app.js --bundle --target=es2016 --outdir=../priv/static/assets),
              cd: Path.expand("../assets", __DIR__),
              env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)}
            ]
  9. Invoke esbuild via Mix tasks

    main

    You can run esbuild directly using the mix esbuild task. The syntax follows the pattern mix esbuild <profile> <args>.

    Example of a manual invocation with bundling, minification, and a specific target:

    mix esbuild default assets/js/app.js --bundle --minify --target=es2016 --outdir=priv/static/assets/

    The executable is stored in _build/esbuild-TARGET, where TARGET corresponds to your system architecture.

  10. Install and run esbuild automatically

    main

    Use Esbuild.install_and_run/2 to ensure the esbuild binary is present before executing a command. If the binary is missing, it will be downloaded and installed automatically before running the provided arguments with the specified profile.

    This method is safe to call concurrently; it handles concurrent installs to avoid race conditions.

    Esbuild.install_and_run(:default, ["--minify"])