Async Alpine

repository·main·Indexed 42 days ago

https://github.com/accudio/async-alpine

A performance-oriented wrapper for Alpine.js version 2.0.3 that enables asynchronous, on-demand loading of components. It supports code splitting and lazy loading through various strategies including eager, event, idle, media, and visible loading to reduce initial bundle sizes.

Tokens
1.9K
Snippets
10
Records
11
Agent score
52%

What's inside Async Alpine

  1. What is Async Alpine?

    main
    Async Alpine is a wrapper for the Alpine.js framework designed to enable code splitting and lazy-loading of components. It allows you to split your Alpine.js components into multiple files and load them asynchronously on-demand, which helps reduce initial bundle sizes and improves performance for large sites.
  2. Install Async Alpine via CDN

    main

    To use Async Alpine via a CDN, include the Async Alpine script and the Alpine.js script in your HTML. Ensure both use the defer attribute. Note that Async Alpine should be loaded alongside Alpine.js.

    <script defer src="https://cdn.jsdelivr.net/npm/async-alpine@2.x.x/dist/async-alpine.script.js"></script>
    <script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
  3. Configure Playwright for async-alpine

    main

    The playwright.config.js file defines the testing environment for async-alpine. It configures the test directory, parallelization, reporting, and the local web server used to host the application during tests.

    Key configuration settings include:

    • testDir: Set to ./tests.
    • fullyParallel: Enabled (true) to run tests in parallel.
    • reporter: Set to 'html' for HTML-based test reports.
    • use.baseURL: Configured to http://localhost:3000.
    • use.trace: Set to 'on-first-retry' to capture traces only when a test fails and is retried.
    • webServer: Automatically starts a local server using npx http-server . -p 3000 at the specified url before running tests.
    import { defineConfig, devices } from '@playwright/test';
    
    const port = 3000
    export default defineConfig({
      testDir: './tests',
      fullyParallel: true,
      reporter: 'html',
      use: {
        baseURL: `http://localhost:${port}`,
        trace: 'on-first-retry',
      },
      projects: [
        {
          name: 'chromium',
          use: { ...devices['Desktop Chrome'] },
        },
        {
          name: 'firefox',
          use: { ...devices['Desktop Firefox'] },
        },
        {
          name: 'webkit',
          use: { ...devices['Desktop Safari'] },
        },
      ],
      webServer: {
        command: `npx http-server . -p ${port}`,
        url: `http://localhost:${port}`
      },
    });
  4. Configure Playwright test projects

    main

    The Playwright configuration defines multiple browser projects to ensure cross-browser compatibility. The current setup includes:

    • chromium: Uses Desktop Chrome device emulation.
    • firefox: Uses Desktop Firefox device emulation.
    • webkit: Uses Desktop Safari device emulation.
      projects: [
        {
          name: 'chromium',
          use: { ...devices['Desktop Chrome'] },
        },
        {
          name: 'firefox',
          use: { ...devices['Desktop Firefox'] },
        },
        {
          name: 'webkit',
          use: { ...devices['Desktop Safari'] },
        },
      ],
  5. Await component requirements with awaitRequirements()

    main

    Use awaitRequirements(component) to pause the initialization of a component until its specified strategy requirements are met.

    Requirements are defined using a JS-like syntax within the component's strategy property. The function parses this expression and resolves the underlying asynchronous strategies. It supports logical operators for complex dependency management:

    • && (AND): All requirements must resolve successfully (uses Promise.all).
    • || (OR): At least one requirement must resolve successfully (uses Promise.any).
    • |: A legacy alias for &&.

    Individual requirements are defined as methodName(argument) and are resolved using the registered strategies available in the project.

    import { awaitRequirements } from 'async-alpine';
    
    // Example component structure
    const component = {
      strategy: 'someMethod(arg) && (otherMethod() || thirdMethod(val))'
    };
    
    await awaitRequirements(component);
  6. Use the media loading strategy

    main

    The media strategy delays component loading until a specific CSS media query condition is met. It uses window.matchMedia and triggers only once.

    • The argument must be a media query string (e.g., 'min-width: 768px').
    • If no argument is provided, it defaults to the eager behavior.
    • If the media query is already satisfied when the strategy is called, it resolves immediately.
    // Load when the screen is at least 768px wide
    media({ argument: 'min-width: 768px' })
  7. Use the visible loading strategy

    main

    The visible strategy delays component loading until the component's element enters the viewport using the IntersectionObserver API.

    • The argument allows you to specify a rootMargin string (e.g., '100px') to trigger the load before the element actually enters the viewport.
    • If no argument is provided, it defaults to '0px 0px 0px 0px'.
    // Load when the element is 200px away from entering the viewport
    visible({ component, argument: '200px' })
    
    // Load exactly when the element enters the viewport
    visible({ component })
  8. Use the event loading strategy

    main

    The event strategy delays component loading until a specific DOM event is dispatched on the window object.

    • If an argument is provided, the strategy listens for that specific custom event name.
    • If no argument is provided, it listens for the async-alpine:load event and checks if event.detail.id matches the component's ID.
    // Listen for a custom event
    event({ component, argument: 'my-custom-event' })
    
    // Listen for the default async-alpine:load event
    event({ component })