vitgo

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 22, 2022 License: MIT Imports: 14 Imported by: 0

README

VitGo

Vite + Go + No Deps

VitGo is a Go module that lets you serve your Vite project from a Go-based web server.

  • Steps
  1. Build your vite project

  2. Specific where to find the dist/ directory

  3. Then the module figures out how to load the generated vite application into a web page.

Installation

go get -u github.com/botwayorg/vitgo

Getting It Into Your Go Project

The first requirement is to use ViteJS's tooling for your JavaScript code. The easiest thing to do is either to start out this way, or to create a new project and move your files into the directory that Vite creates. Using NPM:

# npm
npm create vite@latest

# yarn
yarn create vite@latest

# pnpm
pnpm create vite@latest

You will need to position your source files and the generated dist/ directory so Go can find your project, the manifest.json file that describes it, and the assets that Vite generates for you. You may need to change your vite.config.js file (vite.config.ts if you prefer using Typescript) to make sure the manifest file is generated as well. Here's what I'm using:

/**
 * @type {import('vite').UserConfig}
 */
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";

export default defineConfig({
  plugins: [vue()],
  build: {
    manifest: "manifest.json",
    rollupOptions: {
      input: {
        main: "src/main.ts",
      },
    },
  },
});

This, however, is more than you need. A minimal config file would be:

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  build: {
    manifest: "manifest.json",
  },
});

The essential piece here is the vue plugin (or whatever plugin you need instead for React, Preact or Svelte) and the build.manifest line, since vitgo needs the manifest file to be present in order to work correctly.

package main

import (
    "embed"
    "html/template"
    "net/http"

    "github.com/botwayorg/vitgo"
)

//go:embed "dist"
var dist embed.FS

var vitGo *vitgo.VitGo

func main() {
    // Production configuration.
    config := &vitgo.ViteConfig{
	   Environment: "production",
	   AssetsPath:  "dist",
	   EntryPoint:  "src/main.js",
	   Platform:    "react",
	   FS:          os.DirFS("frontend"),
    }

    // Development configuration
    config := &vitgo.ViteConfig{
	   Environment: "development",
	   AssetsPath:  "frontend",
	   EntryPoint:  "src/main.js",
	   Platform:    "react",
	   FS:          os.DirFS("frontend"),
    }

    // Parse the manifest and get a struct that describes
    // where the assets are.
    vgo, err := vitgo.NewVitGo(config)
    if err != nil {
        // bail!
    }

    vitGo = vgo

    // and set up your routes and start your server....
}

func MyHandler(w http.ResponseWriter, r *http.Request) {
    // Now you can pass the vgo object to an HTML template
    ts, err := template.ParseFiles("path/to/your-template.tmpl")
    if err != nil {
  	    // better handle this...
    }

    ts.Execute(respWriter, vitGo)
}

You will also need to serve your javascript, css and images used by your javascript code to the web. You can use a solution like http.FileServer, or the wrapper the library implements that configures this for you:

// using the standard library's multiplexer:
mux := http.NewServeMux()

// Set up a file server for our assets.
fsHandler, err := vgo.FileServer()
if err != nil {
    log.Println("could not set up static file server", err)

    return
}

mux.Handle("/src/", fsHandler)

Some router implementations may alternatively require you to do something more like:

// chi router
mux := chi.NewMux()

...

mux.Handle("/src/*", fsHandler)

YMMV :-)

Templates

Your template gets the needed tags and links by declaring the vgo object in your template and calling RenderTags on, as so:

<!doctype html>
<html lang="en">

{{ $vue := . }}
    <head>
        <meta charset="utf-8">
        <title>Home - Vue Loader Test</title>

        {{ if $vue }}
          {{ $vue.RenderTags }}
        {{ end }}
    </head>
    <body>
      <div id="app"></div>
    </body>
</html>

You should check that the vgo ($vue in our example) is actually defined as I do here, since it will be nil unless you inject it into your template.

Configuration

VitGo is fairly smart about your Vite Javascript project, and will examine your package.json file on start up. If you do not override the standard settings in your vite.config.js file, vitgo will probably choose to do the appropriate thing.

As mentioned above, a ViteConfig object must be passed to the NewVitGo() routine, with anything you want to override. Here are the major fields and how to use them:

Field Purpose Default Setting
Environment What mode you want vite to run in. development
FS A fs.Embed or fs.DirFS none; required.
JSProjectPath Path to your Javascript files frontend
AssetPath Location of the built distribution directory Production: dist
Platform Any platform supported by Vite. vue and react are known to work; other platforms may work if you adjust the other configurations correctly. Based upon your package.json settings.
EntryPoint Entry point script for your Javascript Best guess based on package.json
ViteVersion Vite major version ("2" or "3") Best guess based on your package.json file in your project. If you want to make sure, specify the version you want.
DevServerPort Port the dev server will listen on; typically 3000 in version 2, 5173 in version 3 Best guess based on version
DevServerDomain Domain serving assets. localhost
HTTPS Whether the dev server serves HTTPS false

Documentation

Index

Constants

View Source
const (
	DEFAULT_VITE_VERSION = "3"
	DEFAULT_PORT_V2      = "3000"
	DEFAULT_PORT_V3      = "5173"
)

Variables

View Source
var (
	ErrNoEntryPoint        = errors.New("manifest lacked entry point")
	ErrNoInputFile         = errors.New("expected import file name")
	ErrManifestBadlyFormed = errors.New("manifest has unexpected format")
	ErrManifestDNF         = errors.New("vue distribution directory not found")
)

Functions

This section is empty.

Types

type JSAppParams

type JSAppParams struct {
	JSHash        string `json:"hash"`
	ViteVersion   string `json:"vite_version"`
	ViteMajorVer  string `json:"vite_major_version"`
	PackageType   string `json:"package_type"`
	MajorVer      string `json:"major_version,omitempty"`
	EntryPoint    string `json:"entry_point"`
	HasTypeScript bool   `json:"has_ts"`
	IsVanilla     bool   `json:"is_vanilla,omitempty"`
	VueVersion    string `json:"vue_version,omitempty"`
	ReactVersion  string `json:"react_version,omitempty"`
	PreactVersion string `json:"preact_version,omitempty"`
	SvelteVersion string `json:"svelte_version,omitempty"`
	LitVersion    string `json:"lit_version,omitempty"`
}

type PackageJSON

type PackageJSON struct {
	Name            string            `json:"name"`
	Version         string            `json:"version"`
	Type            string            `json:"type"`
	Scripts         map[string]string `json:"scripts"`
	Dependencies    map[string]string `json:"dependencies"`
	DevDependencies map[string]string `json:"devDependencies"`
}

type VitGo

type VitGo struct {
	// Environment. This controls whether the library will
	// configure the host for hot updating, or whether it
	// needs to configure loading of a dist/ directory.
	Environment string

	// Entry point for JS
	MainModule string

	// BaseURL is the base URL for the dev server.
	// Default is http://localhost:5173
	BaseURL string

	// JS Dependencies / Vendor libs
	Imports []string

	// Bundled CSS
	CSSModule []string

	// Target JS Platform
	Platform string

	// A file system or embed that points to the Vue/Vite dist
	// directory (production) or the javascript src directory
	// (development)
	DistFS fs.FS

	// DevServer is the URI of the Vite development server
	DevServer string

	// JSProjectPath is the location of the JS project.
	JSProjectPath string

	// AssetPath is the relative path from the JSDirectory.
	AssetPath string

	// Debug mode
	Debug bool
}

type VitGo summarizes a manifest file, and points to the assets.

func NewVitGo

func NewVitGo(config *ViteConfig) (*VitGo, error)

NewVitGo finds the manifest in the supplied file system and returns a vgo object.

func ParseManifest

func ParseManifest(contents []byte) (*VitGo, error)

ParseManifest imports and parses a manifest returning a vgo object.

func (*VitGo) DevServerRedirector

func (vg *VitGo) DevServerRedirector() http.Handler

Redirector for dev server

func (*VitGo) FileServer

func (vg *VitGo) FileServer() (http.Handler, error)

FileServer is a customized version of http.FileServer that can handle either an embed.FS or a os.DirFS fs.FS. Since development directories used for hot updates can contain dot files (potentially with sensitive information) the code checks to make sure that dot files are not served.

func (*VitGo) RenderTags

func (vg *VitGo) RenderTags() (template.HTML, error)

RenderTags genarates the HTML tags that link a rendered Go template with any Vue assets that need to be loaded.

type ViteConfig

type ViteConfig struct {
	// FS is the filesystem where assets can be loaded.
	FS fs.FS

	// DevDefaults is best guess for defaults
	DevDefaults *JSAppParams `json:"-"`

	// Environment (development|production). In development mode,
	// the package sets up hot reloading. In production, the
	// package builds the Vue/Vuex production files and embeds them
	// in the Go app.
	Environment string

	// JSProjectPath is where your JS project is relative to the
	// root of your project. Default: frontend
	JSProjectPath string

	//AssetsPath relative to the JSProjectPath. Empty for dev, dist for prod
	AssetsPath string

	// "2" or "3". If not set, we try to guess by looking
	// at package.json
	ViteVersion string

	// DevServerDomain is what domain the dev server appears on.
	// Default is localhost.
	DevServerDomain string

	// DevServerPort is what port the dev server will appear on.
	// Default depends upon the ViteVersion.
	DevServerPort string

	// HTTPS is whether the dev server is encrypted or not.
	// Default is false.
	HTTPS bool

	// URLPrefix (/assets/ for prod, /src/ for dev)
	URLPrefix string

	// Platform (vue|react|svelte) is the target platform.
	// Default is "vue"
	Platform string

	// Entry point: as configured in vite.config.js. Typically
	// src/main.js or src/main.ts.
	EntryPoint string
}

type ViteConfig passes info needed to generate the library's output.

func (*ViteConfig) SetDevelopmentDefaults

func (vc *ViteConfig) SetDevelopmentDefaults() error

func (*ViteConfig) SetProductionDefaults

func (vc *ViteConfig) SetProductionDefaults() error

type WriterWrapper

type WriterWrapper struct {
	Writer  http.ResponseWriter
	RetCode int
}

Logger writes out status codes:

func NewRespWriter

func NewRespWriter(w http.ResponseWriter) *WriterWrapper

func (*WriterWrapper) Header

func (w *WriterWrapper) Header() http.Header

func (*WriterWrapper) Write

func (w *WriterWrapper) Write(buf []byte) (int, error)

func (*WriterWrapper) WriteHeader

func (w *WriterWrapper) WriteHeader(status int)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL