Phoenix Web Framework

repository·main·Indexed 12 days ago

https://github.com/phoenixframework/phoenix

A high-performance, scalable web development framework for Elixir. It includes a JavaScript client (v1.9.0-dev) for managing Socket connections, Channels for real-time event brokering, and Presence for state synchronization. The framework features a dedicated project installer (phx.new) and a modern asset management pipeline using esbuild and Tailwind CSS.

Tokens
78.9K
Snippets
271
Records
335
Agent score
97%

What's inside Phoenix

  1. What is Phoenix?

    main

    Phoenix is a web development framework written in Elixir that implements the server-side Model View Controller (MVC) pattern. It is designed to provide high developer productivity alongside high application performance.

    Key features include:

    • MVC Pattern: Familiar structure for developers coming from frameworks like Ruby on Rails or Django.
    • Channels: Built-in support for implementing real-time features.
    • Pre-compiled Templates: Optimized for high-speed rendering.
  2. Understand the Phoenix project directory structure

    main

    A standard Phoenix application generated via mix phx.new follows a specific directory layout that separates business logic from web concerns:

    • lib/<app>: Contains the core business logic and domain (the "Model" in MVC). This is where your database interactions and domain rules live.
    • lib/<app>_web: Contains the web-related code (the "View" and "Controller" in MVC). This handles HTTP requests, routing, and rendering.
    • assets: Contains front-end source code (JavaScript, CSS) typically bundled by esbuild.
    • config: Holds project configuration. config/config.exs is the entry point, which imports environment-specific files like config/dev.exs or config/prod.exs. config/runtime.exs is used for dynamic configuration and secrets.
    • priv: Holds static resources like database scripts, translation files, and images. Generated assets from the assets directory are placed in priv/static/assets.
    • test: Contains application tests, often mirroring the lib structure.
    • _build: Contains compilation artifacts created by mix. This should not be checked into version control.
    • deps: Contains Mix dependencies. This should not be checked into version control.
    ├── _build
    ├── assets
    ├── config
    ├── deps
    ├── lib
    │   ├── hello
    │   ├── hello.ex
    │   └── hello_web
    │       └── hello_web.ex
    ├── priv
    └── test
  3. Identify core Phoenix ecosystem packages

    main

    A Phoenix application is composed of several specialized packages. Understanding the role of each is essential for navigating the framework:

    Core Framework Packages

    • Ecto: The database wrapper and query language integration.
    • Phoenix: The primary web framework.
    • Phoenix LiveView: Used for building real-time, server-rendered HTML experiences. It also provides Phoenix.Component and the HEEx template engine used for rendering HTML in both standard and real-time contexts.
    • Plug: Provides the connection abstraction and defines the standard request-response lifecycle for composable web modules.
  4. Identify supporting Phoenix ecosystem packages

    main

    Beyond the core framework, Phoenix developers frequently interact with these supporting libraries:

    Common Utilities

    • ExUnit: Elixir's built-in testing framework.
    • Gettext: Handles internationalization (i18n) and localization (l10n).
    • Swoosh: A library for composing, delivering, and testing emails (often used by mix phx.gen.auth).

    Low-level & Specialized Libraries

    • Phoenix HTML: Provides safe building blocks for HTML and forms.
    • Phoenix Ecto: Provides plugs and protocol implementations to integrate Phoenix with Ecto.
    • Phoenix PubSub: A distributed pub/sub system that includes presence support.

    Monitoring & Instrumentation

    • Phoenix LiveDashboard: Provides real-time performance monitoring and debugging tools.
    • Telemetry Metrics: A common interface for defining metrics based on Telemetry events.
  5. Understand Phoenix asset management

    main

    Phoenix manages assets like JavaScript, CSS, images, and fonts. Since v1.7, new applications use esbuild (via the Elixir esbuild wrapper) for JavaScript and tailwindcss (via the Elixir tailwind wrapper) for CSS. This setup avoids dependencies on Node.js or external build systems like Webpack for standard applications.

    • JavaScript: Typically located at assets/js/app.js. esbuild extracts it to priv/static/assets/js/app.js.
    • CSS: Handled by tailwind by default.
    • Static Assets: Images, fonts, and other unprocessed files go directly into priv/static.

    In development, esbuild runs via a watcher. In production, assets are prepared using mix assets.deploy.

  6. What is Plug and how does it work?

    main

    Plug is a specification for composable modules that act as transformations on a connection. Unlike middleware layers like Rack that separate request and response, Plug unifies the concept of a "connection" (%Plug.Conn{}) that is passed through a stack of transformations. In Phoenix, core components like Endpoints, Routers, and Controllers are all implemented as plugs. There are two primary types of plugs:

    1. Function plugs: Simple functions that accept a connection and options, and return a connection.
    2. Module plugs: Modules that implement init/1 (to initialize options) and call/2 (to perform the transformation).
    # Function plug example
    def introspect(conn, _opts) do
      # ... perform transformation
      conn
    end
    
    # Module plug example
    defmodule MyPlug do
      def init(opts), do: opts
      def call(conn, opts) do
        # ... perform transformation
        conn
      end
    end
  7. What is Phoenix LiveView?

    main

    Phoenix LiveView is a way to build interactive, real-time web applications by keeping state on the server and sending HTML diffs to the client over a persistent WebSocket connection.

    Unlike traditional Controller + View patterns that require full HTTP request/response cycles for every interaction, LiveView uses a declarative programming model. Instead of manually manipulating the DOM with JavaScript, you update the server-side state, and LiveView automatically re-renders the relevant parts of the HTML template and pushes those changes to the browser.

    Key benefits:

    • Minimal JavaScript: Most interactivity is handled in Elixir.
    • Real-time: Built on top of Phoenix Channels for bidirectional communication.
    • Efficient: Only HTML diffs are sent over the wire, reducing network traffic.
    • SEO Friendly: Pages are initially rendered as static HTML for fast first paint and search engine indexing.
  8. Handle multiple scopes with the same path

    main

    It is valid to define multiple scopes with the same path prefix (e.g., /) as long as they do not define overlapping routes. This is useful when different parts of your application belong to different namespaces but share the root path.

    Warning: If you define two routes that result in the exact same path and method, Phoenix will issue a warning: warning: this clause cannot match because a previous clause at line X always matches.

    scope "/", HelloWeb do
      pipe_through :browser
      resources "/users", UserController
    end
    
    scope "/", AnotherAppWeb do
      pipe_through :browser
      resources "/posts", PostController
    end
  9. Manage LiveView state with the Socket

    main

    In LiveView, the socket is the fundamental data structure that holds all state. It contains assigns, which are the key-value pairs available to your templates.

    Unlike controllers which use conn, LiveViews use socket. You modify the state using:

    • assign(socket, key, value): Sets a new value.
    • update(socket, key, func): Updates an existing value using a function.

    Any change to the socket triggers an automatic re-render of the template, sending only the necessary HTML diffs to the browser.

  10. Understand Phoenix Routing basics

    main

    Routers in Phoenix act as hubs that match HTTP requests to controller actions, wire up real-time channel handlers, and define pipeline transformations (plugs) scoped to specific routes.

    A typical router module uses use YourAppWeb, :router to make Phoenix router functions available. Routes are organized into scope blocks, which can use pipe_through to apply specific pipelines (sets of plugs) to the routes within that scope.

    defmodule HelloWeb.Router do
      use HelloWeb, :router
    
      pipeline :browser do
        plug :accepts, ["html"]
        # ... other plugs
      end
    
      scope "/", HelloWeb do
        pipe_through :browser
    
        get "/", PageController, :home
      end
    end
  11. How JSON views work in Phoenix

    main

    In Phoenix, JSON rendering follows a pattern similar to HTML rendering. A controller calls render/3, passing the connection, the view name (e.g., :index), and the data.

    Instead of an HTML view, you use a JSON view (e.g., UrlJSON). The JSON view's job is to convert complex Elixir data structures (like Ecto structs) into simple maps. Once the view returns a map, Phoenix uses the Jason library to encode it into a JSON string for the response.

    Example of a JSON view implementation:

    defmodule HelloWeb.UrlJSON do
      alias Hello.Urls.Url
    
      def index(%{urls: urls}) do
        %{data: for(url <- urls, do: data(url))}
      end
    
      def show(%{url: url}) do
        %{data: data(url)}
      end
    
      defp data(%Url{} = url) do
        %{
          id: url.id,
          link: url.link,
          title: url.title
        }
      end
    end
    defmodule HelloWeb.UrlJSON do
      alias Hello.Urls.Url
    
      def index(%{urls: urls}) do
        %{data: for(url <- urls, do: data(url))}
      end
    
      defp data(%Url{} = url) do
        %{
          id: url.id,
          link: url.link,
          title: url.title
        }
      end
    end