Skip to content

Commit

Permalink
Add HTMLFragment helper for minimal integration (#10)
Browse files Browse the repository at this point in the history
This PR introduces a new helper function `HTMLFragment` that generates
the necessary HTML for Vite integration, allowing users to easily incorporate
Vite assets into their own HTML templates.

The new `HTMLFragment` function has the following signature:

```go
func HTMLFragment(config Config) (*Fragment, error)
```

This function generates a struct that returns the necessary
HTML snippets to be injected into the templating solution of your
choice, e.g. `html/template` from Go standard library.

See the [`examples` folder](https://github.com/olivere/vite/tree/main/examples)
for some working code, especially [`examples/helper-function-basic`](https://github.com/olivere/vite/tree/main/examples/helper-function-basic)
and [`router`]([`examples/helper-function-basic`](https://github.com/olivere/vite/tree/main/examples/router).

Close #8
  • Loading branch information
ge3224 authored Sep 2, 2024
1 parent ec8e68d commit c8f2bf8
Show file tree
Hide file tree
Showing 48 changed files with 10,768 additions and 40 deletions.
177 changes: 177 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
package vite

import "io/fs"

// Config is the configuration for the handler.
type Config struct {
// FS is the file system to serve files from. In production, this is
// the Vite output directory, which usually is the "dist" directory.
// In development, this is usually the root directory of the Vite app.
FS fs.FS

// PublicFS is the file system to serve public files from. This is
// usually the "public" directory. It is optional and can be nil.
// If it is nil, we will check if the "public" directory exists in
// the Vite app, and serve files from there. If it does not exist,
// we will not serve any public files. It is only used in development
// mode.
PublicFS fs.FS

// IsDev is true if the server is running in development mode, false
// otherwise.
IsDev bool

// ViteEntry specifies the path to a particular entry point in the Vite
// manifest. This is useful for implementing secondary routes, similar to the
// example provided in the [Multi-Page App] section of the Vite guide.
//
// [Multi-Page App]: https://vitejs.dev/guide/build.html#multi-page-app
ViteEntry string

// ViteURL is the URL of the Vite server, used to load the Vite client
// in development mode (and defaults to http://localhost:5173).
// It is unused in production mode.
ViteURL string

// ViteManifest is the path to the Vite manifest file. This is used in
// production mode to load the manifest file and map the original file
// paths to the transformed file paths. If this is not provided, the
// default path is ".vite/manifest.json".
ViteManifest string

// ViteTemplate specifies a configuration template used to scaffold the Vite
// project. See [Scaffolding Your First Vite Project].
//
// [Scaffolding Your First Vite Project]: https://vitejs.dev/guide/#scaffolding-your-first-vite-project
ViteTemplate Scaffolding
}

// Scaffolding represents various templates provided by Vite that can be used
// to scaffold a Vite project. See [Scaffolding Your First Vite Project].
//
// [Scaffolding Your First Vite Project]: https://vitejs.dev/guide/#scaffolding-your-first-vite-project
type Scaffolding int

const (
// React indicates a Vite template for a React project. This constant can be
// used to identify if a React-specific configuration is needed.
React Scaffolding = 1 + iota

// ReactTs indicates a Vite template for a TypeScript React project. This
// constant can be used to identify if a React-specific configuration is
// needed.
ReactTs

// ReactSWC indicates a Vite template for a React project using SWC as the
// compiler. This constant can be used to identify SWC-specific
// configurations.
ReactSwc

// ReactSWCTs indicates a Vite template for a TypeScript React project using
// SWC as the compiler. This constant can be used to identify SWC-specific
// configurations for TypeScript.
ReactSwcTs

// Vanilla indicates a Vite template for a Vanilla JavaScript project.
// This constant can be used to identify configurations for a basic setup
// without frameworks.
Vanilla

// VanillaTs indicates a Vite template for a Vanilla TypeScript project
// without frameworks. This constant can be used to identify
// TypeScript-specific configurations for a basic setup.
VanillaTs

// Vue indicates a Vite template for a Vue.js project. This constant can be
// used to identify if a Vue-specific configuration is needed.
Vue

// VueTs indicates a Vite template for a TypeScript Vue.js project. This
// constant can be used to identify if a TypeScript Vue-specific
// configuration is needed.
VueTs

// Preact indicates a Vite template for a Preact project. This constant can
// be used to identify if a Preact-specific configuration is needed.
Preact

// PreactTs indicates a Vite template for a TypeScript Preact project. This
// constant can be used to identify if a TypeScript Preact-specific
// configuration is needed.
PreactTs

// Lit indicates a Vite template for a Lit project. This constant can be used
// to identify if a Lit-specific configuration is needed.
Lit

// LitTs indicates a Vite template for a TypeScript Lit project. This
// constant can be used to identify if a TypeScript Lit-specific
// configuration is needed.
LitTs

// Svelte indicates a Vite template for a Svelte project. This constant can
// be used to identify if a Svelte-specific configuration is needed.
Svelte

// SvelteTs indicates a Vite template for a TypeScript Svelte project. This
// constant can be used to identify if a TypeScript Svelte-specific
// configuration is needed.
SvelteTs

// Solid indicates a Vite template for a Solid project. This constant can be
// used to identify if a Solid-specific configuration is needed.
Solid

// SolidTs indicates a Vite template for a TypeScript Solid project. This
// constant can be used to identify if a TypeScript Solid-specific
// configuration is needed.
SolidTs

// Qwik indicates a Vite template for a Qwik project. This constant can be
// used to identify if a Qwik-specific configuration is needed.
Qwik

// QwikTs indicates a Vite template for a TypeScript Qwik project. This
// constant can be used to identify if a TypeScript Qwik-specific
// configuration is needed.
QwikTs

// None indicates that the user has opted out of using a specific
// scaffolding. This constant can be used to specify that no template
// configuration is desired.
None
)

// RequiresPreamble determines if the specific scaffolding requires a
// preamble configuration.
func (s Scaffolding) RequiresPreamble() bool {
switch s {
case React:
return true
case ReactTs:
return true
case ReactSwc:
return true
case ReactSwcTs:
return true
default:
return false
}
}

// Preamble returns the preamble string associated with the Scaffolding. It
// takes a viteURL string as a parameter and returns the appropriate preamble.
func (s Scaffolding) Preamble(viteURL string) string {
switch s {
case React:
return PluginReactPreamble(viteURL)
case ReactTs:
return PluginReactPreamble(viteURL)
case ReactSwc:
return PluginReactPreamble(viteURL)
case ReactSwcTs:
return PluginReactPreamble(viteURL)
default:
return ""
}
}
2 changes: 1 addition & 1 deletion examples/basic/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export default defineConfig({
build: {
// generates .vite/manifest.json in outDir
manifest: true,

emptyOutDir: false,
rollupOptions: {
// overwrite default .html entry
input: "/src/main.tsx",
Expand Down
18 changes: 18 additions & 0 deletions examples/helper-function-basic/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react-hooks/recommended',
],
ignorePatterns: ['dist', '.eslintrc.cjs'],
parser: '@typescript-eslint/parser',
plugins: ['react-refresh'],
rules: {
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
}
28 changes: 28 additions & 0 deletions examples/helper-function-basic/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
pnpm-lock.yaml
dist/*
!dist/README.md
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

tmp
62 changes: 62 additions & 0 deletions examples/helper-function-basic/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Example

This application is created as [described here](https://vitejs.dev/guide/):

```sh
npm create vite@latest example -- --template react-ts
```

## Configure Vite

We changed the `vite.config.ts` to add the generation of the manifest file and made sure to overwrite the main entry point. Here's how the `vite.config.ts` looks after the changes:

```ts
import react from '@vitejs/plugin-react'
import { defineConfig } from 'vite'

// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
build: {
// generates .vite/manifest.json in outDir
manifest: true,

rollupOptions: {
// overwrite default .html entry
input: "/src/main.tsx",
},
},
})
```

## Server side

We then added the [`main.go`](./main.go).

### Development mode

If you want to try development mode, first run a new console and do `npm run dev` in the background: It should start the Vite development server on `http://localhost:5173`.

Now run the Go code as:

```sh
$ go run main.go -dev
Listening on on http://127.0.0.1:8080
```

Open up the URL in your browser and you should see the React app, being rendered by a Go HTML template. Not convinced? Open up development mode and go to the `Console`. You should see a message there, which was embedded by the Go code that rendered the HTML.

Notice that you can now change the HTML and JavaScript/TypeScript code, and Hot Module Reload (HMR) should run just fine and update the page inline.

### Production mode

First make sure to run `npm run build` before using production mode, as the Go code relies on embedding the `dist` directory into the Go binary.

Next, simply run the Go code:

```sh
$ go run main.go
Listening on on http://127.0.0.1:61736
```

Open the URL in your browser, and you're seeing a Go template being rendered with an underlying React app.
8 changes: 8 additions & 0 deletions examples/helper-function-basic/dist/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# `dist` Directory

This directory is used to store the built output from the Vite build process.

In development mode, this directory might be empty if the build process has not
yet been run. The Go application requires at least one file to be present in
this directory to embed its contents using `go:embed`. This README file ensures
the directory is not empty.
Loading

2 comments on commit c8f2bf8

@ClementLaval
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, thanks a lot for your work, it helps me a lot to use InertiaJs with Go!
I would like to know if a release was going to be published for a first version?
Thx 👏

@olivere
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ClementLaval Hi! Happy to help. We merged this PR back into main, ready to be used. Looking forward to feedback.

Please sign in to comment.