Skip to content

Commit

Permalink
feat: implement base functionality (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
jrschumacher authored Aug 8, 2024
1 parent 13e500a commit 7a43e1e
Show file tree
Hide file tree
Showing 38 changed files with 4,695 additions and 2 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# tests
coverage.out
coverage.html
9 changes: 9 additions & 0 deletions .trunk/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
*out
*logs
*actions
*notifications
*tools
plugins
user_trunk.yaml
user.yaml
tmp
2 changes: 2 additions & 0 deletions .trunk/configs/.markdownlint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Prettier friendly markdownlint config (all formatting rules disabled)
extends: markdownlint/style/prettier
7 changes: 7 additions & 0 deletions .trunk/configs/.yamllint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
rules:
quoted-strings:
required: only-when-needed
extra-allowed: ["{|}"]
key-duplicates: {}
octal-values:
forbid-implicit-octal: true
14 changes: 14 additions & 0 deletions .trunk/configs/svgo.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module.exports = {
plugins: [
{
name: "preset-default",
params: {
overrides: {
removeViewBox: false, // https://github.com/svg/svgo/issues/1128
sortAttrs: true,
removeOffCanvasPaths: true,
},
},
},
],
};
40 changes: 40 additions & 0 deletions .trunk/trunk.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# This file controls the behavior of Trunk: https://docs.trunk.io/cli
# To learn more about the format of this file, see https://docs.trunk.io/reference/trunk-yaml
version: 0.1
cli:
version: 1.22.2
# Trunk provides extensibility via plugins. (https://docs.trunk.io/plugins)
plugins:
sources:
- id: trunk
ref: v1.6.1
uri: https://github.com/trunk-io/plugins
# Many linters and tools depend on runtimes - configure them here. (https://docs.trunk.io/runtimes)
runtimes:
enabled:
- [email protected]
# This is the section where you manage your linters. (https://docs.trunk.io/check/configuration)
lint:
ignore:
- linters: [ALL]
paths:
- examples/**
enabled:
- [email protected]
- git-diff-check
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
actions:
disabled:
- trunk-announce
- trunk-check-pre-push
- trunk-fmt-pre-commit
enabled:
- trunk-upgrade-available
15 changes: 15 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Launch Package",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${fileDirname}"
}
]
}
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
# Go Vite Env
# Go SPA Serve

Go SPA Serve is a simple package that serves static files specifically focused on serving single page applications (SPA).
Generally, this can be used to instead of the stdlib `http.FileServer`, but the main use case is to serve a SPA with a
single entry point (e.g. `index.html`) and let the client-side router handle the rest.

In addition to serving static files, this package also provides a way to load environment variables from a Go struct at
runtime by injecting them into the head tag of the served HTML file.

## Problem

Vite is a fantastic build tool, but it doesn't support loading environment variables at runtime.
This becomes quite a problem when you build a single image for multiple environments or need to
build images for on-premises deployments where you can't bake in the environment variables.

This package provides a way to load environment variables from a Go struct at runtime.
## Code Coverage

[![codecov](https://codecov.io/gh/jrschumacher/go-spaserve/graph/badge.svg?token=W99WAK10IX)](https://codecov.io/gh/jrschumacher/go-spaserve)
8 changes: 8 additions & 0 deletions codecov.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
coverage:
status:
project:
default:
# basic
target: auto #default
threshold: 5
base: auto
60 changes: 60 additions & 0 deletions copyFilesys.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package spaserve

import (
"errors"
"io"
"io/fs"

"github.com/psanford/memfs"
)

// OnHookFunc is a function that can be used to modify the data of a file before it is written to the memfs.
// The function should return the modified data and an error if one occurred.
type OnHookFunc func(path string, data []byte) ([]byte, error)

func CopyFileSys(filesys fs.FS, onHook OnHookFunc) (*memfs.FS, error) {
mfs := memfs.New()
err := fs.WalkDir(filesys, ".", func(path string, d fs.DirEntry, err error) error {
if err != nil {
return errors.Join(ErrUnexpectedWalkError, err)
}

// create dir and continue
if d.IsDir() {
if err := mfs.MkdirAll(path, 0o755); err != nil {
return errors.Join(ErrCouldNotMakeDir, err)
}
return nil
}

// open file
f, err := filesys.Open(path)
if err != nil {
return errors.Join(ErrCouldNotOpenFile, err)
}
defer f.Close()

// read file
data, err := io.ReadAll(f)
if err != nil {
return errors.Join(ErrCouldNotReadFile, err)
}

// run onHook
if onHook != nil {
data, err = onHook(path, data)
if err != nil {
return err
}
}

// write file to memfs
if err := mfs.WriteFile(path, data, fs.ModeAppend); err != nil {
return errors.Join(ErrCouldNotWriteFile, err)
}

return nil
})

return mfs, err
}
21 changes: 21 additions & 0 deletions errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package spaserve

import "errors"

// injectWebEnv.InjectWindowVars
var ErrCouldNotMarshalConfig = errors.New("could not marshal config")
var ErrNoIndexFound = errors.New("no index.html found")
var ErrUnexpectedWalkError = errors.New("unexpected walk error")
var ErrCouldNotOpenFile = errors.New("could not open file")
var ErrCouldNotReadFile = errors.New("could not read file")
var ErrCouldNotAppendToIndex = errors.New("could not append to index")
var ErrCouldNotMakeDir = errors.New("could not make dir")
var ErrCouldNotWriteFile = errors.New("could not write file")
var ErrCouldNotParseNamespace = errors.New("namespace must match regex: ^[a-zA-Z_][a-zA-Z0-9_]*$")
var ErrNoNamespace = errors.New("no namespace provided")

// injectWebEnv.appendToIndex
var ErrCouldNotParseIndex = errors.New("could not parse index")
var ErrCouldNotFindHead = errors.New("could not find <head> tag")
var ErrCouldNotAppendScript = errors.New("could not append script")
var ErrCouldNotWriteIndex = errors.New("could not write index")
4 changes: 4 additions & 0 deletions example/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package main

func main() {
}
18 changes: 18 additions & 0 deletions example/ui/.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 },
],
},
}
24 changes: 24 additions & 0 deletions example/ui/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
30 changes: 30 additions & 0 deletions example/ui/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# React + TypeScript + Vite

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.

Currently, two official plugins are available:

- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh

## Expanding the ESLint configuration

If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:

- Configure the top-level `parserOptions` property like this:

```js
export default {
// other rules...
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
project: ['./tsconfig.json', './tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: __dirname,
},
}
```

- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked`
- Optionally add `plugin:@typescript-eslint/stylistic-type-checked`
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list
Empty file added example/ui/global.ts
Empty file.
13 changes: 13 additions & 0 deletions example/ui/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
Loading

0 comments on commit 7a43e1e

Please sign in to comment.