Skip to content

Commit

Permalink
cross framework production builds
Browse files Browse the repository at this point in the history
  • Loading branch information
torenware committed Jul 16, 2022
1 parent 82e82b2 commit b0c402c
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 56 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,15 +215,15 @@ As mentioned above, a ViteConfig object must be passed to the `NewVueGlue()` rou
| **FS** | A fs.Embed or fs.DirFS | none; required. |
| **AssetPath** | *Development:* location of your Javascript files<br>*Production:* location of your built Javascript project | *Development:* frontend<br>*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 | src/main.js |
| **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 |

## Caveats

This code isrelatively new; in particular, there may be some configurations you can use in `vite.config.js` that won't work as I expect. If so: [please open an issue on Github](https://github.com/torenware/vite-go/issues). I've posted the code so people can see it, and try things out. I think you'll find it useful.
This code is relatively new; in particular, there may be some configurations you can use in `vite.config.js` that won't work as I expect. If so: [please open an issue on Github](https://github.com/torenware/vite-go/issues). I've posted the code so people can see it, and try things out. I think you'll find it useful.



Expand Down
27 changes: 20 additions & 7 deletions examples/sample-program/Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
JS_DIR=frontend
INSTALL_ONCE=$(JS_DIR)
CONFIG_FILE := vite.config.ts
# VITE_PORT=3000
GO_APP_PORT=4000
VITE_PID=/tmp/vite-script.pid
GO_PID=/tmp/vite-go.pid
Expand All @@ -22,11 +21,16 @@ $(INSTALL_ONCE): run-install-check
run-install-check:
./install-vue.sh

dist: $(CONFIG_FILE) $(JS_DIR)
# we don't even need a config file
# since Vanilla builds lack these.
$(JS_DIR)/dist: $(JS_DIR)
@echo "run javascript build..."
@cd $(JS_DIR); npm run build
@cd $(JS_DIR); node_modules/.bin/vite build --manifest manifest.json

dist/manifest.json dist/assets: dist
$(JS_DIR)/node_modules:
@cd $(JS_DIR); npm install

$(JS_DIR)/dist/manifest.json $(JS_DIR)/dist/assets: $(JS_DIR)/dist

go.mod:
@go mod init vitemodtest
Expand All @@ -44,13 +48,13 @@ dev_go: stop_dev go.sum
@ go run . -pid $(GO_PID) &


build: clean go.sum dist/manifest.json dist/assets test-template.tmpl
build: clean go.sum $(JS_DIR)/dist/manifest.json $(JS_DIR)/dist/assets test-template.tmpl
@echo building go binary...
@go build -o test_program .

preview: build
preview: stop_preview $(JS_DIR)/node_modules build
@echo run test_program
@ ./test_program -env production -assets dist
@ ./test_program -env production -assets $(JS_DIR)/dist -pid /tmp/vite-go.pid

stop_dev:
ifneq (,$(wildcard $(VITE_PID)))
Expand All @@ -65,3 +69,12 @@ ifneq (,$(wildcard $(GO_PID)))
else
@echo Go already stopped
endif

stop_preview:
ifneq (,$(wildcard $(GO_PID)))
@echo Stopping test_program
@! ps -p $$(cat $(GO_PID)) &>/dev/null || kill $$(cat $(GO_PID) 2>/dev/null) > /dev/null
else
@echo Go already stopped
endif

23 changes: 14 additions & 9 deletions examples/sample-program/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"embed"
"encoding/json"
"flag"
"fmt"
"html/template"
Expand Down Expand Up @@ -97,7 +98,8 @@ func main() {
flag.Parse()

// save away our pid if we need to use a makefile to stop
// this process
// this process. You don't need this to use Vite, but it does
// make this test program easier to use.
if pidFile != "" {
pid := strconv.Itoa(os.Getpid())
_ = ioutil.WriteFile(pidFile, []byte(pid), 0644)
Expand All @@ -114,15 +116,16 @@ func main() {

// We pass the file system with the built Vue
// program, and the path from the root of that
// file system to the "assets" directory.t

//config.FS = os.DirFS(assets)
config.FS = dist
// file system to the "assets" directory.
if config.EntryPoint == "production" {
config.FS = os.DirFS("frontend/dist")
} else {
// Use the embed.
config.FS = dist
}
//

if config.Environment == "production" {
if config.AssetsPath == "" {
config.AssetsPath = "dist"
}
config.URLPrefix = "/assets/"
} else if config.Environment == "development" {
log.Printf("pulling defaults using package.json")
Expand All @@ -146,10 +149,12 @@ func main() {
log.Println("could not set up static file server", err)
return
}
mux.Handle("/src/", fsHandler)
mux.Handle(config.URLPrefix, fsHandler)
mux.Handle("/", logRequest(http.HandlerFunc(pageWithAVue)))

log.Println("Starting server on :4000")
generatedConfig, _ := json.MarshalIndent(config, "", " ")
log.Println("Generated Configuration:\n", string(generatedConfig))
err = http.ListenAndServe(":4000", mux)
log.Fatal(err)

Expand Down
93 changes: 58 additions & 35 deletions utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ type JSAppParams struct {
LitVersion string `json:"lit_version,omitempty"`
}

func (vg *ViteConfig) parsePackageJSON() (*PackageJSON, error) {
func (vc *ViteConfig) parsePackageJSON() (*PackageJSON, error) {
// If not set, try and find package.json
path := ""
if _, ok := vg.FS.(embed.FS); ok {
path = vg.AssetsPath + "/"
if _, ok := vc.FS.(embed.FS); ok {
path = vc.AssetsPath + "/"
}
buf, err := fs.ReadFile(vg.FS, path+"package.json")
buf, err := fs.ReadFile(vc.FS, path+"package.json")
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -165,11 +165,15 @@ func analyzePackageJSON(pkgJSON *PackageJSON) *JSAppParams {
// If we do not have type, call it Vanilla
if output.PackageType == "" {
output.IsVanilla = true
// Vite choses entry points anyway
output.PackageType = "vanilla"
// Vite choses entry points anyway. For some
// very odd reason, the JS project is flat,
// and the TS project puts files in src/
// Why? Good question.
if output.HasTypeScript {
output.EntryPoint = "src/main.ts"
} else {
output.EntryPoint = "src/main.js"
output.EntryPoint = "main.js"
}
}

Expand Down Expand Up @@ -219,82 +223,101 @@ func analyzePackageJSON(pkgJSON *PackageJSON) *JSAppParams {
return &output
}

func (vg *ViteConfig) getViteVersion() (string, error) {
func (vc *ViteConfig) getViteVersion() (string, error) {
// If it's set, use it.
if vg.ViteVersion != "" {
return vg.ViteVersion, nil
if vc.ViteVersion != "" {
return vc.ViteVersion, nil
}

if vg.DevDefaults == nil {
if vc.DevDefaults == nil {
return "", errors.New("not Vite project")
}
vg.ViteVersion = vg.DevDefaults.ViteMajorVer
return vg.DevDefaults.ViteMajorVer, nil
vc.ViteVersion = vc.DevDefaults.ViteMajorVer
return vc.DevDefaults.ViteMajorVer, nil

}

func (vg *ViteConfig) SetDevelopmentDefaults() error {
func (vc *ViteConfig) SetDevelopmentDefaults() error {
// Make sure we can find package.json:
if vg.AssetsPath == "" {
vg.AssetsPath = "frontend"
if vc.JSProjectPath == "" {
vc.JSProjectPath = "frontend"
}
pkgJSON, err := vg.parsePackageJSON()
if vc.AssetsPath == "" {
vc.AssetsPath = vc.JSProjectPath
}

pkgJSON, err := vc.parsePackageJSON()
if err != nil {
return err
}

defaults := analyzePackageJSON(pkgJSON)
if defaults == nil {
return errors.New("invalid configuration")
}
vg.DevDefaults = defaults
version, err := vg.getViteVersion()
vc.DevDefaults = defaults
version, err := vc.getViteVersion()
if err != nil {
vg.ViteVersion = DEFAULT_VITE_VERSION
version = vg.ViteVersion
vc.ViteVersion = DEFAULT_VITE_VERSION
version = vc.ViteVersion
}

// Check for anything already set, and if not set,
// use the defaults if they are not set.
if vg.Platform == "" {
vg.Platform = defaults.PackageType
if vc.Platform == "" {
vc.Platform = defaults.PackageType
}

if vg.EntryPoint == "" {
vg.EntryPoint = defaults.EntryPoint
if vc.EntryPoint == "" {
vc.EntryPoint = defaults.EntryPoint
}

if vg.URLPrefix == "" {
if vc.URLPrefix == "" {
// Vite default
vg.URLPrefix = "/src/"
vc.URLPrefix = "/src/"
}

if vg.DevServerPort == "" {
if vc.DevServerPort == "" {
if version == "2" {
vg.DevServerPort = DEFAULT_PORT_V2
vc.DevServerPort = DEFAULT_PORT_V2
} else {
vg.DevServerPort = DEFAULT_PORT_V3
vc.DevServerPort = DEFAULT_PORT_V3
}
}

if vg.DevServerDomain == "" {
vg.DevServerDomain = "localhost"
if vc.DevServerDomain == "" {
vc.DevServerDomain = "localhost"
}

return nil

}

func (vg *ViteConfig) buildDevServerBaseURL() string {
func (vc *ViteConfig) SetProductionDefaults() error {
if vc.JSProjectPath == "" {
vc.JSProjectPath = "frontend"
}
if vc.AssetsPath == "" {
vc.AssetsPath = vc.JSProjectPath + "/dist"
}
if vc.URLPrefix == "" {
vc.URLPrefix = "/assets/"
}

return nil
}

func (vc *ViteConfig) buildDevServerBaseURL() string {
protocol := "http"
if vg.HTTPS {
if vc.HTTPS {
protocol = "https"
}

return fmt.Sprintf(
"%s://%s:%s",
protocol,
vg.DevServerDomain,
vg.DevServerPort,
vc.DevServerDomain,
vc.DevServerPort,
)

}
18 changes: 15 additions & 3 deletions vueglue.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,19 @@ type ViteConfig struct {
FS fs.FS

// DevDefaults is best guess for defaults
DevDefaults *JSAppParams
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

//AssetsPath (typically dist for prod, and your Vue project
// JSProjectPath is where your JS project is relative to the
// root of your project. Default: frontend
JSProjectPath string

//AssetsPath (typically {JSProjectPath}/dist for prod, and your JS project
// directory for dev)
AssetsPath string

Expand Down Expand Up @@ -156,6 +160,11 @@ func NewVueGlue(config *ViteConfig) (*VueGlue, error) {
}

if config.Environment == "production" {
err := config.SetProductionDefaults()
if err != nil {
return nil, err
}

// Get the manifest file
manifestFile := "manifest.json"
contents, err := fs.ReadFile(correctedFS, manifestFile)
Expand All @@ -168,7 +177,10 @@ func NewVueGlue(config *ViteConfig) (*VueGlue, error) {
}

} else {
config.SetDevelopmentDefaults()
err := config.SetDevelopmentDefaults()
if err != nil {
return nil, err
}
glue.BaseURL = config.buildDevServerBaseURL()
glue.MainModule = config.EntryPoint
}
Expand Down

0 comments on commit b0c402c

Please sign in to comment.