olivere/vite

repository·main·Indexed 42 days ago

https://github.com/olivere/vite

A Go library that facilitates integrating a Vite-based frontend with a Go-based backend. It provides tools like vite.NewHandler for automated asset serving and middleware integration, and vite.HTMLFragment for manual asset linking in HTML templates. The library supports Hot Module Replacement (HMR) in development mode and manifest-based asset resolution in production, including support for multi-page applications and multiple Vite apps within a single Go backend.

Tokens
12.2K
Snippets
47
Records
59
Agent score
50%

What's inside olivere/vite

  1. Overview of Go-Vite integration approaches

    main

    The library provides two primary ways to integrate a Vite frontend with a Go backend:

    1. Helper Function: Use this approach to generate specific HTML tags that link to your Vite assets (scripts, styles, etc.) within your Go templates.
    2. HTTP Handler: Use this approach to implement a complete http.Handler that serves your entire Vite application, handling asset routing and serving automatically.
  2. Use ViteTemplate to enable framework preambles

    main

    When running in development mode (IsDev: true), certain frontend frameworks require a preamble (a JavaScript snippet) to enable Hot Module Replacement (HMR) features like React Fast Refresh.

    Setting the ViteTemplate option tells the library to automatically inject the correct preamble into your HTML.

    Frameworks requiring a preamble:

    • React
    • ReactTs
    • ReactSwc
    • ReactSwcTs

    Frameworks that do NOT require a preamble:

    • Vue / VueTs
    • Vanilla / VanillaTs
    • Preact / PreactTs
    • Lit / LitTs
    • Svelte / SvelteTs
    • Solid / SolidTs
    • Qwik / QwikTs
    • None (to opt out)
  3. Run a multi-app Vite and Go project

    main

    This project uses make commands to orchestrate the multiple Vite development servers and the Go backend.

    Development Mode

    To start the Go backend and all Vite development servers (supporting HMR):

    make start-all
    • Main App: http://localhost:8080/
    • Admin App: http://localhost:8080/admin

    Production Mode

    To build all frontend assets and run the backend in production mode:

    make build-all
    APP_ENV=production ./backend
    # Development
    make start-all
    
    # Production
    make build-all
    APP_ENV=production ./backend
  4. Configure multiple Vite applications in Go

    main

    To serve multiple Vite applications from a single Go backend, you must generate unique HTML tags for each application using vite.HTMLFragment. Each application requires its own vite.Config instance specifying its unique development URL, entry point, template type, and filesystem context.

    Key configuration requirements for multiple apps:

    • Unique ViteURL: Assign a distinct port or path for each app's development server (e.g., http://localhost:5173 and http://localhost:5174/admin).
    • ViteTemplate: Specify the correct template type (e.g., vite.ReactTs or vite.Vue).
    • FS: Use fs.Sub to provide a sub-filesystem for each app's specific distribution directory.
    • AssetsURLPrefix: Use this to prevent path collisions in production by prefixing asset URLs.
    // Example for a Main App
    assetsApp, _ := fs.Sub(app.DistFS, "app")
    viteConfig := vite.Config{
    	IsDev:        app.InDevelopment,
    	ViteURL:      "http://localhost:5173",
    	ViteEntry:    "src/main.tsx",
    	ViteTemplate: vite.ReactTs,
    	FS:           assetsApp,
    }
    
    // Example for an Admin App with a custom prefix
    assetsAdmin, _ := fs.Sub(app.DistFS, "admin-app")
    viteConfigAdmin := vite.Config{
    	IsDev:           app.InDevelopment,
    	ViteURL:         "http://localhost:5174/admin",
    	ViteEntry:       "src/main.js",
    	ViteTemplate:    vite.Vue,
    	FS:              assetsAdmin,
    	AssetsURLPrefix: "/admin-app",
    }
    
    // Generate the tags
    fragment, _ := vite.HTMLFragment(viteConfig)
    return fragment.Tags
  5. Try the Multiple Vite Instances setup

    main

    For complex applications that need to manage different Vite instances simultaneously (for example, an admin panel using React + TypeScript and a main application using Vue), use the multiple-vite-apps example.

    $ npx degit olivere/vite/examples/multiple-vite-apps multiple-vite-apps
    $ cd my-multi-page-app
    # Follow setup instructions in the example README
  6. Try the Inertia.js Integration setup

    main

    This example demonstrates how to use Golang with net/http, Inertia.js, and this library to manage Vite assets. Note that this is a third-party integration.

    $ npx degit danclaytondev/go-inertia-vite my-inertia-app
    $ cd my-inertia-app
    # Follow setup instructions in the example README
  7. Run the application in Production mode

    main

    In production mode, the Go server serves assets directly from the compiled files embedded within the Go binary.

    1. Build the Vite assets first:

      npm run build
    2. Run the Go application without the -dev flag:

      go run main.go

    Note: The Go code relies on the dist directory being present and embedded into the binary during the build process.

    npm run build
    go run main.go
  8. Serve assets when using the Helper Function

    main

    When using the HTMLFragment helper function, you are responsible for serving static assets yourself.

    • Development Mode: The Vite dev server handles JS and CSS. Your Go server must serve other assets (images, SVGs, etc.) from the public folder or source directories.
    • Production Mode: You must serve the built assets from your dist directory.

    Example of manual asset serving in Go:

    if isDev {
        // Serve assets from the source directory in development
        serveStaticFolder(mux, "/src/assets/", os.DirFS("frontend/src/assets"))
        // Serve the public folder
        serveStaticFolder(mux, "/", os.DirFS("frontend/public"))
    }
    
    if !isDev {
        // Serve the build directory in production
        serveStaticFolder(mux, "/assets/", os.DirFS("frontend/dist/assets"))
        // Serve the public folder
        serveStaticFolder(mux, "/", os.DirFS("frontend/dist"))
    }
    
    func serveStaticFolder(mux *http.ServeMux, path string, fs fs.FS) {
        mux.Handle(path, http.StripPrefix(path, http.FileServer(http.FS(fs))))
    }
  9. Integrate Vite using the Helper Function approach

    main

    The helper function approach generates the necessary HTML tags (<script>, <link>) to connect your Go application to Vite assets. It automatically switches between the Vite dev server in development and built assets in production.

    To use this, call vite.HTMLFragment with a vite.Config object and pass the resulting fragment to your HTML template. You must access the .Tags property of the fragment within your template.

    // Initialize the helper function
    viteFragment, err := vite.HTMLFragment(vite.Config{
        FS:        os.DirFS("frontend/dist"), // Required: Vite build output directory
        IsDev:     *isDev,                     // Required: Development or Production mode
        ViteURL:   "http://localhost:5173",   // Optional: Defaults to this URL
        ViteEntry: "src/main.js",             // Optional: Depends on your frontend setup
    })
    if err != nil {
        panic(err)
    }
    
    // Template with Vite tags
    indexTemplate := `
    <head>
        <meta charset="UTF-8" />
        <title>My Go Application</title>
        {{ .Vite.Tags }}
    </head>
    <body id="app"></body>
    `
  10. Serve prefixed assets in production

    main

    When using AssetsURLPrefix in your vite.Config to avoid path collisions between multiple apps, you must configure your Go router to serve those assets from the correct subdirectory. Use http.StripPrefix to map the prefixed URL path to the actual filesystem location of the assets.

    For an app with AssetsURLPrefix: "/admin-app", the assets are expected at /admin-app/assets/.... You should mount a file server that strips the prefix before looking up the file in the application's distribution filesystem.

    // Assuming app.DistFS contains the 'dist' directories for all apps
    assetsAdminApp, _ := fs.Sub(app.DistFS, "admin-app")
    assetsAdminAppFS := http.FileServer(http.FS(assetsAdminApp))
    
    // Map the prefixed URL to the filesystem
    mux.Handle("/admin-app/assets/", http.StripPrefix("/admin-app", assetsAdminAppFS))
  11. Try the Router Application setup

    main

    For advanced implementations, this example shows a Go backend serving a Vite-based application that utilizes TanStack Router and TanStack Query libraries.

    $ npx degit olivere/vite/examples/router my-router-app
    $ cd my-router-app
    # Follow setup instructions in the example README