diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index ff04ca1b..a8224785 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -8,9 +8,7 @@ on:
jobs:
build-deploy:
name: Build and deploy docs
-
runs-on: ubuntu-latest
-
steps:
- name: Checkout
uses: actions/checkout@v4
diff --git a/.github/workflows/generate-linter-advanced.yml b/.github/workflows/generate-linter-advanced.yml
index cc673d52..b39b8e76 100644
--- a/.github/workflows/generate-linter-advanced.yml
+++ b/.github/workflows/generate-linter-advanced.yml
@@ -5,13 +5,13 @@ on:
workflow_dispatch: {}
jobs:
- framework_matrix:
+ blueprint_matrix:
strategy:
matrix:
- framework: [chi, gin, fiber, gorilla/mux, httprouter, standard-library, echo]
+ backend: [chi, gin, fiber, gorilla/mux, standard-library, echo]
driver: [postgres]
git: [commit]
- advanced: [htmx, githubaction, websocket, tailwind, docker, react]
+ advanced: [githubaction, websocket, docker]
runs-on: ubuntu-latest
steps:
@@ -30,18 +30,12 @@ jobs:
git config --global user.name 'testname'
git config --global user.email 'testemail@users.noreply.github.com'
- - name: Set framework variable
- id: set-proejct-directory
- run: echo "PROJECT_DIRECTORY=${{ matrix.framework }}" | sed 's/\//-/g' >> $GITHUB_ENV
+ - name: Set dir variable
+ id: set-project-directory
+ run: echo "PROJECT_DIRECTORY=${{ matrix.backend }}" | sed 's/\//-/g' >> $GITHUB_ENV
- name: build templates
- run: script -q /dev/null -c "go run main.go create -n ${{ env.PROJECT_DIRECTORY }} -f ${{ matrix.framework}} -d ${{ matrix.driver }} -g ${{ matrix.git}} --advanced --feature ${{ matrix.advanced }}"
-
- - if: ${{ matrix.advanced == 'htmx' || matrix.advanced == 'tailwind' }}
- name: Install Templ & gen templates
- run: |
- go install github.com/a-h/templ/cmd/templ@latest
- /home/runner/go/bin/templ generate -path ${{ env.PROJECT_DIRECTORY }}
+ run: script -q /dev/null -c "go run main.go create -n ${{ env.PROJECT_DIRECTORY }} -b ${{ matrix.backend}} -d ${{ matrix.driver }} -g ${{ matrix.git}} -a --feature ${{ matrix.advanced }}"
- name: golangci-lint
run: |
diff --git a/.github/workflows/generate-linter-core.yml b/.github/workflows/generate-linter-core.yml
index cf1e6045..201d94a8 100644
--- a/.github/workflows/generate-linter-core.yml
+++ b/.github/workflows/generate-linter-core.yml
@@ -5,10 +5,10 @@ on:
workflow_dispatch: {}
jobs:
- framework_matrix:
+ blueprint_matrix:
strategy:
matrix:
- framework: [chi, gin, fiber, gorilla/mux, httprouter, standard-library, echo]
+ backend: [chi, gin, fiber, gorilla/mux, standard-library, echo]
driver: [mysql, postgres, sqlite, mongo, redis, scylla, none]
git: [commit, stage, skip]
@@ -29,12 +29,12 @@ jobs:
git config --global user.name 'testname'
git config --global user.email 'testemail@users.noreply.github.com'
- - name: Set framework variable
- id: set-proejct-directory
- run: echo "PROJECT_DIRECTORY=${{ matrix.framework }}" | sed 's/\//-/g' >> $GITHUB_ENV
+ - name: Set dir variable
+ id: set-project-directory
+ run: echo "PROJECT_DIRECTORY=${{ matrix.backend }}" | sed 's/\//-/g' >> $GITHUB_ENV
- name: build templates
- run: script -q /dev/null -c "go run main.go create -n ${{ env.PROJECT_DIRECTORY }} -f ${{ matrix.framework}} -d ${{ matrix.driver }} -g ${{ matrix.git}}"
+ run: script -q /dev/null -c "go run main.go create -n ${{ env.PROJECT_DIRECTORY }} -b ${{ matrix.backend}} -d ${{ matrix.driver }} -g ${{ matrix.git}}"
- name: golangci-lint
run: |
diff --git a/.github/workflows/generate-linter-frontend.yml b/.github/workflows/generate-linter-frontend.yml
new file mode 100644
index 00000000..55a73e0b
--- /dev/null
+++ b/.github/workflows/generate-linter-frontend.yml
@@ -0,0 +1,54 @@
+name: Linting Generated Blueprints Advanced
+
+on:
+ pull_request: {}
+ workflow_dispatch: {}
+
+jobs:
+ blueprint_matrix:
+ strategy:
+ matrix:
+ backend: [chi, gin, fiber, gorilla/mux, standard-library, echo]
+ driver: [postgres]
+ git: [commit]
+ advanced: [docker]
+ frontendFramework: [htmx, react]
+ frontendAdvanced: [tailwind]
+
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Setup Go
+ uses: actions/setup-go@v5
+ with:
+ go-version: '1.23.x'
+
+ - name: Install golangci-lint
+ run: go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.63.4
+
+ - name: Commit report
+ run: |
+ git config --global user.name 'testname'
+ git config --global user.email 'testemail@users.noreply.github.com'
+
+ - name: Set dir variable
+ id: set-project-directory
+ run: echo "PROJECT_DIRECTORY=${{ matrix.backend }}" | sed 's/\//-/g' >> $GITHUB_ENV
+
+ - name: build templates
+ run: script -q /dev/null -c "go run main.go create -n ${{ env.PROJECT_DIRECTORY }} -b ${{ matrix.backend}} -d ${{ matrix.driver }} -g ${{ matrix.git}} -a --feature ${{ matrix.advanced }} -f --frontend-framework ${{ matrix.frontendFramework }} --frontend-advanced ${{ matrix.frontendAdvanced}}"
+
+ - if: ${{ matrix.frontendFramework == 'htmx'}}
+ name: Install Templ & gen templates
+ run: |
+ go install github.com/a-h/templ/cmd/templ@latest
+ /home/runner/go/bin/templ generate -path ${{ env.PROJECT_DIRECTORY }}
+
+ - name: golangci-lint
+ run: |
+ cd ${{ env.PROJECT_DIRECTORY }}
+ golangci-lint run
+
+ - name: remove templates
+ run: rm -rf ${{ env.PROJECT_DIRECTORY }}
diff --git a/.github/workflows/testcontainers.yml b/.github/workflows/testcontainers.yml
index ec2109e7..45446a8e 100644
--- a/.github/workflows/testcontainers.yml
+++ b/.github/workflows/testcontainers.yml
@@ -24,7 +24,7 @@ jobs:
git config --global user.email 'testemail@users.noreply.github.com'
- name: build ${{ matrix.driver }} template
- run: script -q /dev/null -c "go run main.go create -n ${{ matrix.driver }} -g commit -f fiber -d ${{matrix.driver}}"
+ run: script -q /dev/null -c "go run main.go create -n ${{ matrix.driver }} -g commit -b fiber -d ${{matrix.driver}}"
- name: run ${{ matrix.driver }} integration tests
working-directory: ${{ matrix.driver }}
diff --git a/.github/workflows/update-htmx-version.yml b/.github/workflows/update-htmx-version.yml
index e631ebb9..db53eff6 100644
--- a/.github/workflows/update-htmx-version.yml
+++ b/.github/workflows/update-htmx-version.yml
@@ -13,7 +13,7 @@ jobs:
- name: Get version from file
id: get_version_file
run: |
- VERSION_FILE=$(curl -s https://raw.githubusercontent.com/Melkeydev/go-blueprint/main/cmd/template/advanced/files/htmx/htmx.min.js.tmpl | grep version | awk -F'"' '{print "v" $2}')
+ VERSION_FILE=$(curl -s https://raw.githubusercontent.com/Melkeydev/go-blueprint/main/cmd/template/frontend/files/htmx/htmx.min.js.tmpl | grep version | awk -F'"' '{print "v" $2}')
echo "version file: $VERSION_FILE"
if [[ "$VERSION_FILE" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "version_file=$VERSION_FILE" >> $GITHUB_OUTPUT
@@ -47,27 +47,27 @@ jobs:
- name: dump latest htmx version
if: steps.compare_versions.outputs.release_changed == 'true'
- run: curl -L https://github.com/bigskysoftware/htmx/releases/latest/download/htmx.min.js -o cmd/template/advanced/files/htmx/htmx.min.js
+ run: curl -L https://github.com/bigskysoftware/htmx/releases/latest/download/htmx.min.js -o cmd/template/frontend/files/htmx/htmx.min.js
- name: Prettify code
if: steps.compare_versions.outputs.release_changed == 'true'
run: |
npm install --save-dev --save-exact prettier
- npx prettier --write cmd/template/advanced/files/htmx/htmx.min.js
+ npx prettier --write cmd/template/frontend/files/htmx/htmx.min.js
rm -rf node_modules
rm package-lock.json
rm package.json
- name: Create tmpl after Prettify
if: steps.compare_versions.outputs.release_changed == 'true'
- run: mv cmd/template/advanced/files/htmx/htmx.min.js cmd/template/advanced/files/htmx/htmx.min.js.tmpl
+ run: mv cmd/template/frontend/files/htmx/htmx.min.js cmd/template/frontend/files/htmx/htmx.min.js.tmpl
- name: Create Pull Request
if: steps.compare_versions.outputs.release_changed == 'true'
uses: peter-evans/create-pull-request@v6
with:
- commit-message: update htmx version ${{ steps.get_version_api.outputs.version_api }}
+ commit-message: update htmx ${{ steps.get_version_api.outputs.version_api }}
title: Update htmx to version ${{ steps.get_version_api.outputs.version_api }} [Bot]
- body: New htmx ${{ steps.get_version_api.outputs.version_api }} version is available. This is an automatic PR to update changes.
+ body: New htmx ${{ steps.get_version_api.outputs.version_api }} is available. This is an automatic PR to update changes.
branch: htmx-version-update
base: main
diff --git a/.gitignore b/.gitignore
index 64e19e59..7dabd587 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,4 @@
go-blueprint
+main
+
site
diff --git a/README.md b/README.md
index f2ec319b..fd1997c3 100644
--- a/README.md
+++ b/README.md
@@ -6,22 +6,23 @@
-Go Blueprint is a CLI tool that allows users to spin up a Go project with the corresponding structure seamlessly. It also
-gives the option to integrate with one of the more popular Go frameworks (and the list is growing with new features)!
+Go Blueprint is a CLI tool that allows users to spin up a structured Go project. It also
+gives the option to integrate with one of the more popular backend and fronted frameworks!
### Why Would I use this?
- Easy to set up and install
- Have the entire Go structure already established
- Setting up a Go HTTP server (or Fasthttp with Fiber)
-- Integrate with a popular frameworks
+- Integrates with a popular backend and frontend frameworks
- Focus on the actual code of your application
## Table of Contents
- [Install](#install)
-- [Frameworks Supported](#frameworks-supported)
+- [Backend Frameworks](#backends)
- [Database Support](#database-support)
+- [Frontend Frameworks](#frontend)
- [Advanced Features](#advanced-features)
- [Blueprint UI](#blueprint-ui)
- [Usage Example](#usage-example)
@@ -64,24 +65,40 @@ go-blueprint create
You can also use the provided flags to set up a project without interacting with the UI.
```bash
-go-blueprint create --name my-project --framework gin --driver postgres --git commit
+go-blueprint create -n my-project -b gin -d postgres -g commit
```
See `go-blueprint create -h` for all the options and shorthands.
-
+```bash
+Usage:
+ go-blueprint create [flags]
+
+Flags:
+ -a, --advanced Get prompts for advanced features
+ --feature AdvancedFeatures Advanced feature to use. Allowed values: githubaction, websocket, docker
+ -b, --backend-framework BackendFramework Backend framework to use. Allowed values: chi, gin, fiber, gorilla/mux, standard-library, echo
+ -d, --driver Database Database drivers to use. Allowed values: mysql, postgres, sqlite, mongo, redis, scylla, none
+ -f, --frontend Get prompts for frontend frameworks
+ --frontend-framework Frontendframework Frontend framework to use. Allowed values: htmx, react
+ --frontend-advanced FrontendAdvanced Frontend framework advanced features to use. Allowed values: tailwind
+ -g, --git Git Git to use. Allowed values: commit, stage, skip
+ -h, --help help for create
+ -n, --name string Name of project to create
+```
+
+
-
+
- Frameworks Supported
+ Backend Frameworks
- [Chi](https://github.com/go-chi/chi)
- [Gin](https://github.com/gin-gonic/gin)
- [Fiber](https://github.com/gofiber/fiber)
-- [HttpRouter](https://github.com/julienschmidt/httprouter)
- [Gorilla/mux](https://github.com/gorilla/mux)
- [Echo](https://github.com/labstack/echo)
@@ -94,9 +111,7 @@ See `go-blueprint create -h` for all the options and shorthands.
Database Support
-Go Blueprint now offers enhanced database support, allowing you to choose your preferred database driver during project setup. Use the `--driver` or `-d` flag to specify the database driver you want to integrate into your project.
-
-### Supported Database Drivers
+Go Blueprint now offers enhanced database support, allowing you to choose your preferred database driver during project setup. Use the `-d ` or --driver flag to specify the database driver you want to integrate into your project.
Choose from a variety of supported database drivers:
@@ -107,6 +122,24 @@ Choose from a variety of supported database drivers:
- [Redis](https://github.com/redis/go-redis)
- [ScyllaDB GoCQL](https://github.com/scylladb/gocql)
+
+
+
+
+
+
+ Frontend Frameworks
+
+
+Frontend frameworks and features can be added to your project using the `-f` or `--frontend` flag. This will trigger a prompt to select the desired options.
+
+- [HTMX](https://htmx.org/) support using [Templ](https://templ.guide/)
+- [React](https://react.dev/) frontend written in TypeScript, including an example fetch request to the backend
+
+Aditional features is a multi-option prompt; one or more features can be used at the same time (Currently, Tailwind is the only one that is integrated).
+
+- [Tailwind](https://tailwindcss.com/) css framework
+
@@ -116,18 +149,13 @@ Choose from a variety of supported database drivers:
Advanced Features
-Blueprint is focused on being as minimalistic as possible. That being said, we wanted to offer the ability to add other features people may want without bloating the overall experience.
+You can now use the `-a` or `--advanced` flag when running the `create` command to get access to the following features:
-You can now use the `--advanced` flag when running the `create` command to get access to the following features. This is a multi-option prompt; one or more features can be used at the same time:
-
-- [HTMX](https://htmx.org/) support using [Templ](https://templ.guide/)
- CI/CD workflow setup using [Github Actions](https://docs.github.com/en/actions)
- [Websocket](https://pkg.go.dev/github.com/coder/websocket) sets up a websocket endpoint
-- [Tailwind](https://tailwindcss.com/) css framework
- Docker configuration for go project
-- [React](https://react.dev/) frontend written in TypeScript, including an example fetch request to the backend
-Note: Selecting Tailwind option will automatically select HTMX unless React is explicitly selected
+This is a multi-option prompt; one or more features can be used at the same time.
@@ -152,67 +180,56 @@ Blueprint UI is a web application that allows you to create commands for the CLI
Here's an example of setting up a project with a specific database driver:
```bash
-go-blueprint create --name my-project --framework gin --driver postgres --git commit
+go-blueprint create -n my-project -b gin -d postgres -g commit
```
-Advanced features are accessible with the --advanced flag
+Prompts for Frontend frameworks and features can be triggered with the `-f` flag
```bash
-go-blueprint create --advanced
+go-blueprint create -f
```
-
-Advanced features can be enabled using the `--feature` flag along with the `--advanced` flag.
-
-HTMX:
+or created directly with the `--frontend-framework` and `--frontend-advanced` flags
```bash
-go-blueprint create --advanced --feature htmx
+go-blueprint create -n my-project -b chi -d none -f --frontend-framework react --frontend-advanced tailwind -g commit
```
-CI/CD workflow:
-
-```bash
-go-blueprint create --advanced --feature githubaction
-```
+
+
+
-Websocket:
+Advanced features are accessible with the `-a` flag
```bash
-go-blueprint create --advanced --feature websocket
+go-blueprint create -a
```
-Tailwind:
+Advanced features can be enabled using the `--feature` flag along with the `-a` flag.
```bash
-go-blueprint create --advanced --feature tailwind
+go-blueprint create -n my_project -b standard-library -d mongo -a --feature docker --feature websocket -g commit
```
-Docker:
-
-```bash
-go-blueprint create --advanced --feature docker
-```
+
+
+
-React:
+Frontend and Advanced features can be combined with the `-f` and `-a` flags
```bash
-go-blueprint create --advanced --feature react
+go-blueprint create -af
```
-Or all features at once:
+or
```bash
-go-blueprint create --name my-project --framework chi --driver mysql --advanced --feature htmx --feature githubaction --feature websocket --feature tailwind --feature docker --git commit --feature react
+go-blueprint create -n my_project -b fiber -d mysql -f --frontend-framework htmx --frontend-advanced tailwind -a --feature docker --feature githubaction -g commit
```
-
-
-
-
**Visit [documentation](https://docs.go-blueprint.dev) to learn more about blueprint and its features.**
diff --git a/cmd/create.go b/cmd/create.go
index 8a46bc09..54e0c329 100644
--- a/cmd/create.go
+++ b/cmd/create.go
@@ -22,14 +22,14 @@ import (
const logo = `
- ____ _ _ _
-| _ \| | (_) | |
-| |_) | |_ _ ___ _ __ _ __ _ _ __ | |_
+ ____ _ _ _
+| _ \| | (_) | |
+| |_) | |_ _ ___ _ __ _ __ _ _ __ | |_
| _ <| | | | |/ _ \ '_ \| '__| | '_ \| __|
-| |_) | | |_| | __/ |_) | | | | | | | |_
+| |_) | | |_| | __/ |_) | | | | | | | |
|____/|_|\__,_|\___| .__/|_| |_|_| |_|\__|
- | |
- |_|
+ | |
+ |_|
`
@@ -40,27 +40,38 @@ var (
)
func init() {
- var flagFramework flags.Framework
+ var flagBackendFramework flags.BackendFramework
var flagDBDriver flags.Database
+ var frontendFrameworks flags.FrontendFramework
+ var frontendAdvanced flags.FrontendAdvanced
var advancedFeatures flags.AdvancedFeatures
var flagGit flags.Git
rootCmd.AddCommand(createCmd)
+ // Main flags
createCmd.Flags().StringP("name", "n", "", "Name of project to create")
- createCmd.Flags().VarP(&flagFramework, "framework", "f", fmt.Sprintf("Framework to use. Allowed values: %s", strings.Join(flags.AllowedProjectTypes, ", ")))
+ createCmd.Flags().VarP(&flagBackendFramework, "backend-framework", "b", fmt.Sprintf("Backend framework to use. Allowed values: %s", strings.Join(flags.AllowedBackendFrameworkTypes, ", ")))
createCmd.Flags().VarP(&flagDBDriver, "driver", "d", fmt.Sprintf("Database drivers to use. Allowed values: %s", strings.Join(flags.AllowedDBDrivers, ", ")))
+ createCmd.Flags().VarP(&flagGit, "git", "g", fmt.Sprintf("Git to use. Allowed values: %s", strings.Join(flags.AllowedGitsOptions, ", ")))
+
+ // Frontend flags group
+ createCmd.Flags().BoolP("frontend", "f", false, "Get prompts for frontend frameworks")
+ createCmd.Flags().Var(&frontendFrameworks, "frontend-framework", fmt.Sprintf("Frontend framework to use. Allowed values: %s", strings.Join(flags.AllowedFrontendTypes, ", ")))
+ createCmd.Flags().Var(&frontendAdvanced, "frontend-advanced", fmt.Sprintf("Frontend framework advanced features to use. Allowed values: %s", strings.Join(flags.AllowedFrontendAdvanced, ", ")))
+
+ // Advanced features group
createCmd.Flags().BoolP("advanced", "a", false, "Get prompts for advanced features")
createCmd.Flags().Var(&advancedFeatures, "feature", fmt.Sprintf("Advanced feature to use. Allowed values: %s", strings.Join(flags.AllowedAdvancedFeatures, ", ")))
- createCmd.Flags().VarP(&flagGit, "git", "g", fmt.Sprintf("Git to use. Allowed values: %s", strings.Join(flags.AllowedGitsOptions, ", ")))
}
type Options struct {
- ProjectName *textinput.Output
- ProjectType *multiInput.Selection
- DBDriver *multiInput.Selection
- Advanced *multiSelect.Selection
- Workflow *multiInput.Selection
- Git *multiInput.Selection
+ ProjectName *textinput.Output
+ BackendFramework *multiInput.Selection
+ DBDriver *multiInput.Selection
+ FrontendFramework *multiInput.Selection
+ FrontendAdvanced *multiSelect.Selection
+ Advanced *multiSelect.Selection
+ Git *multiInput.Selection
}
// createCmd defines the "create" command for the CLI
@@ -89,14 +100,19 @@ var createCmd = &cobra.Command{
// VarP already validates the contents of the framework flag.
// If this flag is filled, it is always valid
- flagFramework := flags.Framework(cmd.Flag("framework").Value.String())
+ flagBackendFramework := flags.BackendFramework(cmd.Flag("backend-framework").Value.String())
flagDBDriver := flags.Database(cmd.Flag("driver").Value.String())
+ flagFrontendFremwork := flags.FrontendFramework(cmd.Flag("frontend-framework").Value.String())
flagGit := flags.Git(cmd.Flag("git").Value.String())
options := Options{
- ProjectName: &textinput.Output{},
- ProjectType: &multiInput.Selection{},
- DBDriver: &multiInput.Selection{},
+ ProjectName: &textinput.Output{},
+ BackendFramework: &multiInput.Selection{},
+ DBDriver: &multiInput.Selection{},
+ FrontendFramework: &multiInput.Selection{},
+ FrontendAdvanced: &multiSelect.Selection{
+ Choices: make(map[string]bool),
+ },
Advanced: &multiSelect.Selection{
Choices: make(map[string]bool),
},
@@ -104,18 +120,30 @@ var createCmd = &cobra.Command{
}
project := &program.Project{
- ProjectName: flagName,
- ProjectType: flagFramework,
- DBDriver: flagDBDriver,
- FrameworkMap: make(map[flags.Framework]program.Framework),
- DBDriverMap: make(map[flags.Database]program.Driver),
- AdvancedOptions: make(map[string]bool),
- GitOptions: flagGit,
+ ProjectName: flagName,
+ BackendFramework: flagBackendFramework,
+ DBDriver: flagDBDriver,
+ BackendFrameworkMap: make(map[flags.BackendFramework]program.BackendFramework),
+ DBDriverMap: make(map[flags.Database]program.Driver),
+ FrontendFramework: flagFrontendFremwork,
+ FrontendOptions: make(map[string]bool),
+ AdvancedOptions: make(map[string]bool),
+ GitOptions: flagGit,
}
- steps := steps.InitSteps(flagFramework, flagDBDriver)
+ steps := steps.InitSteps(flagBackendFramework, flagDBDriver, flagFrontendFremwork, flagGit)
fmt.Printf("%s\n", logoStyle.Render(logo))
+ // Frontend option steps:
+ flagFrontend, err := cmd.Flags().GetBool("frontend")
+ if err != nil {
+ log.Fatal("failed to retrieve frontend flag")
+ }
+
+ if flagFrontend {
+ fmt.Println(tipMsgStyle.Render("*** You are in Frontend mode ***\n\n"))
+ }
+
// Advanced option steps:
flagAdvanced, err := cmd.Flags().GetBool("advanced")
if err != nil {
@@ -153,23 +181,23 @@ var createCmd = &cobra.Command{
}
}
- if project.ProjectType == "" {
+ if project.BackendFramework == "" {
isInteractive = true
- step := steps.Steps["framework"]
- tprogram = tea.NewProgram(multiInput.InitialModelMulti(step.Options, options.ProjectType, step.Headers, project))
+ step := steps.Steps["backend-framework"]
+ tprogram = tea.NewProgram(multiInput.InitialModelMulti(step.Options, options.BackendFramework, step.Headers, project))
if _, err := tprogram.Run(); err != nil {
cobra.CheckErr(textinput.CreateErrorInputModel(err).Err())
}
project.ExitCLI(tprogram)
- step.Field = options.ProjectType.Choice
+ step.Field = options.BackendFramework.Choice
// this type casting is always safe since the user interface can
- // only pass strings that can be cast to a flags.Framework instance
- project.ProjectType = flags.Framework(strings.ToLower(options.ProjectType.Choice))
- err := cmd.Flag("framework").Value.Set(project.ProjectType.String())
+ // only pass strings that can be cast to a flags.BackendFramework instance
+ project.BackendFramework = flags.BackendFramework(strings.ToLower(options.BackendFramework.Choice))
+ err := cmd.Flag("backend-framework").Value.Set(project.BackendFramework.String())
if err != nil {
- log.Fatal("failed to set the framework flag value", err)
+ log.Fatal("failed to set the backendFramework flag value", err)
}
}
@@ -191,6 +219,53 @@ var createCmd = &cobra.Command{
}
}
+ if flagFrontend {
+
+ if project.FrontendFramework == "" {
+ isInteractive = true
+ step := steps.Steps["frontend-framework"]
+ tprogram = tea.NewProgram(multiInput.InitialModelMulti(step.Options, options.FrontendFramework, step.Headers, project))
+ if _, err := tprogram.Run(); err != nil {
+ cobra.CheckErr(textinput.CreateErrorInputModel(err).Err())
+ }
+ project.ExitCLI(tprogram)
+
+ project.FrontendFramework = flags.FrontendFramework(strings.ToLower(options.FrontendFramework.Choice))
+ err := cmd.Flag("frontend-framework").Value.Set(project.FrontendFramework.String())
+ if err != nil {
+ log.Fatal("failed to set the frontend flag value", err)
+ }
+ }
+
+ featureFrontend := cmd.Flag("frontend-advanced").Value.String()
+
+ if featureFrontend != "" {
+ featuresFrontendFlagValues := strings.Split(featureFrontend, ",")
+ for _, key := range featuresFrontendFlagValues {
+ project.AdvancedOptions[key] = true
+ }
+ } else {
+ isInteractive = true
+ step := steps.Steps["frontend-advanced"]
+ tprogram = tea.NewProgram((multiSelect.InitialModelMultiSelect(step.Options, options.FrontendAdvanced, step.Headers, project)))
+ if _, err := tprogram.Run(); err != nil {
+ cobra.CheckErr(textinput.CreateErrorInputModel(err).Err())
+ }
+ project.ExitCLI(tprogram)
+ for key, opt := range options.FrontendAdvanced.Choices {
+ project.FrontendOptions[strings.ToLower(key)] = opt
+ err := cmd.Flag("frontend-advanced").Value.Set(strings.ToLower(key))
+ if err != nil {
+ log.Fatal("failed to set the advanced fronted features flag value", err)
+ }
+ }
+ if err != nil {
+ log.Fatal(err)
+ }
+ }
+
+ }
+
if flagAdvanced {
featureFlags := cmd.Flag("feature").Value.String()
@@ -216,7 +291,7 @@ var createCmd = &cobra.Command{
}
}
if err != nil {
- log.Fatal("failed to set the htmx option", err)
+ log.Fatal(err)
}
}
@@ -280,24 +355,21 @@ var createCmd = &cobra.Command{
fmt.Println(endingMsgStyle.Render("\nNext steps:"))
fmt.Println(endingMsgStyle.Render(fmt.Sprintf("• cd into the newly created project with: `cd %s`\n", utils.GetRootDir(project.ProjectName))))
- if options.Advanced.Choices["React"] {
- options.Advanced.Choices["Htmx"] = false
- options.Advanced.Choices["Tailwind"] = false
+ if options.FrontendFramework.Choice == "React" {
fmt.Println(endingMsgStyle.Render("• cd into frontend\n"))
fmt.Println(endingMsgStyle.Render("• npm install\n"))
fmt.Println(endingMsgStyle.Render("• npm run dev\n"))
+ fmt.Println(endingMsgStyle.Render("• or use makefile targents\n"))
}
- if options.Advanced.Choices["Tailwind"] {
- options.Advanced.Choices["Htmx"] = true
- fmt.Println(endingMsgStyle.Render("• Install the tailwind standalone cli if you haven't already, grab the executable for your platform from the latest release on GitHub\n"))
+ if options.FrontendAdvanced.Choices["Tailwind"] && options.FrontendFramework.Choice == "Htmx" {
+ fmt.Println(endingMsgStyle.Render("• Download the tailwind standalone cli with Makefile target\n"))
fmt.Println(endingMsgStyle.Render("• More info about the Tailwind CLI: https://tailwindcss.com/blog/standalone-cli\n"))
}
- if options.Advanced.Choices["Htmx"] {
- options.Advanced.Choices["react"] = false
- fmt.Println(endingMsgStyle.Render("• Install the templ cli if you haven't already by running `go install github.com/a-h/templ/cmd/templ@latest`\n"))
- fmt.Println(endingMsgStyle.Render("• Generate templ function files by running `templ generate`\n"))
+ if options.FrontendFramework.Choice == "Htmx" {
+ fmt.Println(endingMsgStyle.Render("• Install the templ cli `go install github.com/a-h/templ/cmd/templ@latest`\n"))
+ fmt.Println(endingMsgStyle.Render("• Generate templ function files by running `templ generate` or use Makefile for both steps\n"))
}
if isInteractive {
diff --git a/cmd/flags/advancedFeatures.go b/cmd/flags/advancedFeatures.go
index f97d629e..59aac504 100644
--- a/cmd/flags/advancedFeatures.go
+++ b/cmd/flags/advancedFeatures.go
@@ -8,15 +8,12 @@ import (
type AdvancedFeatures []string
const (
- Htmx string = "htmx"
GoProjectWorkflow string = "githubaction"
Websocket string = "websocket"
- Tailwind string = "tailwind"
- React string = "react"
Docker string = "docker"
)
-var AllowedAdvancedFeatures = []string{string(React), string(Htmx), string(GoProjectWorkflow), string(Websocket), string(Tailwind), string(Docker)}
+var AllowedAdvancedFeatures = []string{string(GoProjectWorkflow), string(Websocket), string(Docker)}
func (f AdvancedFeatures) String() string {
return strings.Join(f, ",")
diff --git a/cmd/flags/backendFrameworks.go b/cmd/flags/backendFrameworks.go
new file mode 100644
index 00000000..6407d6c7
--- /dev/null
+++ b/cmd/flags/backendFrameworks.go
@@ -0,0 +1,43 @@
+package flags
+
+import (
+ "fmt"
+ "strings"
+)
+
+type BackendFramework string
+
+// These are all the current backends supported. If you want to add one, you
+// can simply copy and paste a line here. Do not forget to also add it into the
+// AllowedBackendTypes slice too!
+const (
+ Chi BackendFramework = "chi"
+ Gin BackendFramework = "gin"
+ Fiber BackendFramework = "fiber"
+ GorillaMux BackendFramework = "gorilla/mux"
+ StandardLibrary BackendFramework = "standard-library"
+ Echo BackendFramework = "echo"
+)
+
+var AllowedBackendFrameworkTypes = []string{string(Chi), string(Gin), string(Fiber), string(GorillaMux), string(StandardLibrary), string(Echo)}
+
+func (f BackendFramework) String() string {
+ return string(f)
+}
+
+func (f *BackendFramework) Type() string {
+ return "BackendFramework"
+}
+
+func (f *BackendFramework) Set(value string) error {
+ // Contains isn't available in 1.20 yet
+ // if AllowedBackendTypes.Contains(value) {
+ for _, project := range AllowedBackendFrameworkTypes {
+ if project == value {
+ *f = BackendFramework(value)
+ return nil
+ }
+ }
+
+ return fmt.Errorf("BackendFramework to use. Allowed values: %s", strings.Join(AllowedBackendFrameworkTypes, ", "))
+}
diff --git a/cmd/flags/frameworks.go b/cmd/flags/frameworks.go
deleted file mode 100644
index d1d7b59b..00000000
--- a/cmd/flags/frameworks.go
+++ /dev/null
@@ -1,44 +0,0 @@
-package flags
-
-import (
- "fmt"
- "strings"
-)
-
-type Framework string
-
-// These are all the current frameworks supported. If you want to add one, you
-// can simply copy and paste a line here. Do not forget to also add it into the
-// AllowedProjectTypes slice too!
-const (
- Chi Framework = "chi"
- Gin Framework = "gin"
- Fiber Framework = "fiber"
- GorillaMux Framework = "gorilla/mux"
- HttpRouter Framework = "httprouter"
- StandardLibrary Framework = "standard-library"
- Echo Framework = "echo"
-)
-
-var AllowedProjectTypes = []string{string(Chi), string(Gin), string(Fiber), string(GorillaMux), string(HttpRouter), string(StandardLibrary), string(Echo)}
-
-func (f Framework) String() string {
- return string(f)
-}
-
-func (f *Framework) Type() string {
- return "Framework"
-}
-
-func (f *Framework) Set(value string) error {
- // Contains isn't available in 1.20 yet
- // if AllowedProjectTypes.Contains(value) {
- for _, project := range AllowedProjectTypes {
- if project == value {
- *f = Framework(value)
- return nil
- }
- }
-
- return fmt.Errorf("Framework to use. Allowed values: %s", strings.Join(AllowedProjectTypes, ", "))
-}
diff --git a/cmd/flags/frontendAdvanced.go b/cmd/flags/frontendAdvanced.go
new file mode 100644
index 00000000..bda0ae48
--- /dev/null
+++ b/cmd/flags/frontendAdvanced.go
@@ -0,0 +1,35 @@
+package flags
+
+import (
+ "fmt"
+ "strings"
+)
+
+type FrontendAdvanced []string
+
+const (
+ Tailwind string = "tailwind"
+)
+
+var AllowedFrontendAdvanced = []string{string(Tailwind)}
+
+func (f FrontendAdvanced) String() string {
+ return strings.Join(f, ",")
+}
+
+func (f *FrontendAdvanced) Type() string {
+ return "FrontendAdvanced"
+}
+
+func (f *FrontendAdvanced) Set(value string) error {
+ // Contains isn't available in 1.20 yet
+ // if FrontendAdvanced.Contains(value) {
+ for _, frontendAdvancedFeature := range AllowedFrontendAdvanced {
+ if frontendAdvancedFeature == value {
+ *f = append(*f, frontendAdvancedFeature)
+ return nil
+ }
+ }
+
+ return fmt.Errorf("advanced Feature to use. Allowed values: %s", strings.Join(AllowedFrontendAdvanced, ", "))
+}
diff --git a/cmd/flags/frontendFramework.go b/cmd/flags/frontendFramework.go
new file mode 100644
index 00000000..2b53d6af
--- /dev/null
+++ b/cmd/flags/frontendFramework.go
@@ -0,0 +1,39 @@
+package flags
+
+import (
+ "fmt"
+ "strings"
+)
+
+type FrontendFramework string
+
+// These are all the current frameworks supported. If you want to add one, you
+// can simply copy and paste a line here. Do not forget to also add it into the
+// AllowedFrontedTypes slice too!
+const (
+ Htmx FrontendFramework = "htmx"
+ React FrontendFramework = "react"
+)
+
+var AllowedFrontendTypes = []string{string(Htmx), string(React)}
+
+func (f FrontendFramework) String() string {
+ return string(f)
+}
+
+func (f *FrontendFramework) Type() string {
+ return "Frontendframework"
+}
+
+func (f *FrontendFramework) Set(value string) error {
+ // Contains isn't available in 1.20 yet
+ // if AllowedFrontedTypes.Contains(value) {
+ for _, frontendFrameworks := range AllowedFrontendTypes {
+ if frontendFrameworks == value {
+ *f = FrontendFramework(value)
+ return nil
+ }
+ }
+
+ return fmt.Errorf("Frontend framework to use. Allowed values: %s", strings.Join(AllowedFrontendTypes, ", "))
+}
diff --git a/cmd/program/advanced.go b/cmd/program/advanced.go
new file mode 100644
index 00000000..e8105984
--- /dev/null
+++ b/cmd/program/advanced.go
@@ -0,0 +1,40 @@
+package program
+
+import (
+ "bytes"
+ "log"
+ "strings"
+ "text/template"
+
+ "github.com/melkeydev/go-blueprint/cmd/flags"
+ "github.com/melkeydev/go-blueprint/cmd/utils"
+)
+
+func (p *Project) CreateWebsocketImports(appDir string) {
+ websocketDependency := []string{"github.com/coder/websocket"}
+ if p.BackendFramework == flags.Fiber {
+ websocketDependency = []string{"github.com/gofiber/contrib/websocket"}
+ }
+
+ // Websockets require a different package depending on what backend is
+ // choosen. The application calls go mod tidy at the end so we don't
+ // have to here
+ err := utils.GoGetPackage(appDir, websocketDependency)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ importsPlaceHolder := string(p.BackendFrameworkMap[p.BackendFramework].templater.WebsocketImports())
+
+ importTmpl, err := template.New("imports").Parse(importsPlaceHolder)
+ if err != nil {
+ log.Fatalf("CreateWebsocketImports failed to create template: %v", err)
+ }
+ var importBuffer bytes.Buffer
+ err = importTmpl.Execute(&importBuffer, p)
+ if err != nil {
+ log.Fatalf("CreateWebsocketImports failed write template: %v", err)
+ }
+ newImports := strings.Join([]string{string(p.AdvancedTemplates.TemplateImports), importBuffer.String()}, "\n")
+ p.AdvancedTemplates.TemplateImports = newImports
+}
diff --git a/cmd/program/frontend.go b/cmd/program/frontend.go
new file mode 100644
index 00000000..a89e018b
--- /dev/null
+++ b/cmd/program/frontend.go
@@ -0,0 +1,175 @@
+package program
+
+import (
+ "bytes"
+ "fmt"
+ "log"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+ "text/template"
+
+ "github.com/melkeydev/go-blueprint/cmd/flags"
+ "github.com/melkeydev/go-blueprint/cmd/template/frontend"
+)
+
+func (p *Project) CreateViteReactProject(projectPath string) error {
+ if err := checkNpmInstalled(); err != nil {
+ return err
+ }
+
+ originalDir, err := os.Getwd()
+ if err != nil {
+ return fmt.Errorf("failed to get current directory: %w", err)
+ }
+ defer func() {
+ if err := os.Chdir(originalDir); err != nil {
+ fmt.Fprintf(os.Stderr, "failed to change back to original directory: %v\n", err)
+ }
+ }()
+
+ // change into the project directory to run vite command
+ err = os.Chdir(projectPath)
+ if err != nil {
+ fmt.Println("failed to change into project directory: %w", err)
+ }
+
+ // the interactive vite command will not work as we can't interact with it
+ fmt.Println("Installing create-vite (using cache if available)...")
+ cmd := exec.Command("npm", "create", "vite@latest", "frontend", "--",
+ "--template", "react-ts",
+ "--prefer-offline",
+ "--no-fund")
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ if err := cmd.Run(); err != nil {
+ return fmt.Errorf("failed to use create-vite: %w", err)
+ }
+
+ frontendPath := filepath.Join(projectPath, "frontend")
+ if err := os.MkdirAll(frontendPath, 0755); err != nil {
+ return fmt.Errorf("failed to create frontend directory: %w", err)
+ }
+
+ if err := os.Chdir(frontendPath); err != nil {
+ return fmt.Errorf("failed to change to frontend directory: %w", err)
+ }
+
+ srcDir := filepath.Join(frontendPath, "src")
+ if err := os.MkdirAll(srcDir, 0755); err != nil {
+ return fmt.Errorf("failed to create src directory: %w", err)
+ }
+
+ if err := os.WriteFile(filepath.Join(srcDir, "App.tsx"), frontend.ReactAppfile(), 0644); err != nil {
+ return fmt.Errorf("failed to write App.tsx template: %w", err)
+ }
+
+ // Create the global `.env` file from the template
+ err = p.CreateFileWithInjection("", projectPath, ".env", "env")
+ if err != nil {
+ return fmt.Errorf("failed to create global .env file: %w", err)
+ }
+
+ // Read from the global `.env` file and create the frontend-specific `.env`
+ globalEnvPath := filepath.Join(projectPath, ".env")
+ vitePort := "8080" // Default fallback
+
+ // Read the global .env file
+ if data, err := os.ReadFile(globalEnvPath); err == nil {
+ lines := strings.Split(string(data), "\n")
+ for _, line := range lines {
+ if strings.HasPrefix(line, "PORT=") {
+ vitePort = strings.SplitN(line, "=", 2)[1] // Get the backend port value
+ break
+ }
+ }
+ }
+
+ // Use a template to generate the frontend .env file
+ frontendEnvContent := fmt.Sprintf("VITE_PORT=%s\n", vitePort)
+ if err := os.WriteFile(filepath.Join(frontendPath, ".env"), []byte(frontendEnvContent), 0644); err != nil {
+ return fmt.Errorf("failed to create frontend .env file: %w", err)
+ }
+
+ // Handle Tailwind configuration if selected
+ if p.FrontendOptions[string(flags.Tailwind)] && p.FrontendFramework == flags.React {
+ fmt.Println("Installing Tailwind dependencies (using cache if available)...")
+ cmd := exec.Command("npm", "install",
+ "--prefer-offline",
+ "--no-fund",
+ "tailwindcss", "postcss", "autoprefixer")
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ if err := cmd.Run(); err != nil {
+ return fmt.Errorf("failed to install Tailwind: %w", err)
+ }
+
+ fmt.Println("Initializing Tailwind...")
+ cmd = exec.Command("npx", "--prefer-offline", "tailwindcss", "init", "-p")
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ if err := cmd.Run(); err != nil {
+ return fmt.Errorf("failed to initialize Tailwind: %w", err)
+ }
+
+ // use the tailwind config file
+ err = os.WriteFile("tailwind.config.js", frontend.ReactTailwindConfigTemplate(), 0644)
+ if err != nil {
+ return fmt.Errorf("failed to write tailwind config: %w", err)
+ }
+
+ srcDir := filepath.Join(frontendPath, "src")
+ if err := os.MkdirAll(srcDir, 0755); err != nil {
+ return fmt.Errorf("failed to create src directory: %w", err)
+ }
+
+ err = os.WriteFile(filepath.Join(srcDir, "index.css"), frontend.InputCssTemplateReact(), 0644)
+ if err != nil {
+ return fmt.Errorf("failed to update index.css: %w", err)
+ }
+
+ if err := os.WriteFile(filepath.Join(srcDir, "App.tsx"), frontend.ReactTailwindAppfile(), 0644); err != nil {
+ return fmt.Errorf("failed to write App.tsx template: %w", err)
+ }
+
+ if err := os.Remove(filepath.Join(srcDir, "App.css")); err != nil {
+ // Don't return error if file doesn't exist
+ if !os.IsNotExist(err) {
+ return fmt.Errorf("failed to remove App.css: %w", err)
+ }
+ }
+ }
+
+ return nil
+}
+
+func (p *Project) CreateHtmxTemplates() {
+ routesPlaceHolder := ""
+ importsPlaceHolder := ""
+ if p.FrontendFramework == flags.Htmx {
+ routesPlaceHolder += string(p.BackendFrameworkMap[p.BackendFramework].templater.HtmxTemplRoutes())
+ importsPlaceHolder += string(p.BackendFrameworkMap[p.BackendFramework].templater.HtmxTemplImports())
+ }
+
+ routeTmpl, err := template.New("routes").Parse(routesPlaceHolder)
+ if err != nil {
+ log.Fatal(err)
+ }
+ importTmpl, err := template.New("imports").Parse(importsPlaceHolder)
+ if err != nil {
+ log.Fatal(err)
+ }
+ var routeBuffer bytes.Buffer
+ var importBuffer bytes.Buffer
+ err = routeTmpl.Execute(&routeBuffer, p)
+ if err != nil {
+ log.Fatal(err)
+ }
+ err = importTmpl.Execute(&importBuffer, p)
+ if err != nil {
+ log.Fatal(err)
+ }
+ p.FrontendTemplates.TemplateRoutes = routeBuffer.String()
+ p.FrontendTemplates.TemplateImports = importBuffer.String()
+}
diff --git a/cmd/program/helpers.go b/cmd/program/helpers.go
new file mode 100644
index 00000000..bd6f8a05
--- /dev/null
+++ b/cmd/program/helpers.go
@@ -0,0 +1,118 @@
+package program
+
+import (
+ "bytes"
+ "fmt"
+ "log"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "runtime"
+ "text/template"
+
+ tpl "github.com/melkeydev/go-blueprint/cmd/template"
+ "github.com/melkeydev/go-blueprint/cmd/template/advanced"
+)
+
+// CreatePath creates the given directory in the projectPath
+func (p *Project) CreatePath(pathToCreate string, projectPath string) error {
+ path := filepath.Join(projectPath, pathToCreate)
+ if _, err := os.Stat(path); os.IsNotExist(err) {
+ err := os.MkdirAll(path, 0o751)
+ if err != nil {
+ log.Printf("Error creating directory %v\n", err)
+ return err
+ }
+ }
+
+ return nil
+}
+
+// CheckOs checks Operation system and generates MakeFile and `go build` command
+// Based on Project.Unixbase
+func (p *Project) CheckOS() {
+ p.OSCheck = make(map[string]bool)
+
+ if runtime.GOOS != "windows" {
+ p.OSCheck["UnixBased"] = true
+ }
+ if runtime.GOOS == "linux" {
+ p.OSCheck["linux"] = true
+ }
+ if runtime.GOOS == "darwin" {
+ p.OSCheck["darwin"] = true
+ }
+}
+
+func checkNpmInstalled() error {
+ cmd := exec.Command("npm", "--version")
+ if err := cmd.Run(); err != nil {
+ return fmt.Errorf("npm is not installed: %w", err)
+ }
+ return nil
+}
+
+// CreateFileWithInjection creates the given file at the
+// project path, and injects the appropriate template
+func (p *Project) CreateFileWithInjection(pathToCreate string, projectPath string, fileName string, methodName string) error {
+ createdFile, err := os.Create(filepath.Join(projectPath, pathToCreate, fileName))
+ if err != nil {
+ return err
+ }
+
+ defer createdFile.Close()
+
+ switch methodName {
+ case "main":
+ createdTemplate := template.Must(template.New(fileName).Parse(string(p.BackendFrameworkMap[p.BackendFramework].templater.Main())))
+ err = createdTemplate.Execute(createdFile, p)
+ case "server":
+ createdTemplate := template.Must(template.New(fileName).Parse(string(p.BackendFrameworkMap[p.BackendFramework].templater.Server())))
+ err = createdTemplate.Execute(createdFile, p)
+ case "routes":
+ routeFileBytes := p.BackendFrameworkMap[p.BackendFramework].templater.Routes()
+ createdTemplate := template.Must(template.New(fileName).Parse(string(routeFileBytes)))
+ err = createdTemplate.Execute(createdFile, p)
+ case "releaser":
+ createdTemplate := template.Must(template.New(fileName).Parse(string(advanced.Releaser())))
+ err = createdTemplate.Execute(createdFile, p)
+ case "go-test":
+ createdTemplate := template.Must(template.New(fileName).Parse(string(advanced.Test())))
+ err = createdTemplate.Execute(createdFile, p)
+ case "releaser-config":
+ createdTemplate := template.Must(template.New(fileName).Parse(string(advanced.ReleaserConfig())))
+ err = createdTemplate.Execute(createdFile, p)
+ case "database":
+ createdTemplate := template.Must(template.New(fileName).Parse(string(p.DBDriverMap[p.DBDriver].templater.Service())))
+ err = createdTemplate.Execute(createdFile, p)
+ case "db-docker":
+ createdTemplate := template.Must(template.New(fileName).Parse(string(p.DockerMap[p.Docker].templater.Docker())))
+ err = createdTemplate.Execute(createdFile, p)
+ case "integration-tests":
+ createdTemplate := template.Must(template.New(fileName).Parse(string(p.DBDriverMap[p.DBDriver].templater.Tests())))
+ err = createdTemplate.Execute(createdFile, p)
+ case "tests":
+ createdTemplate := template.Must(template.New(fileName).Parse(string(p.BackendFrameworkMap[p.BackendFramework].templater.TestHandler())))
+ err = createdTemplate.Execute(createdFile, p)
+ case "env":
+ if p.DBDriver != "none" {
+
+ envBytes := [][]byte{
+ tpl.GlobalEnvTemplate(),
+ p.DBDriverMap[p.DBDriver].templater.Env(),
+ }
+ createdTemplate := template.Must(template.New(fileName).Parse(string(bytes.Join(envBytes, []byte("\n")))))
+ err = createdTemplate.Execute(createdFile, p)
+
+ } else {
+ createdTemplate := template.Must(template.New(fileName).Parse(string(tpl.GlobalEnvTemplate())))
+ err = createdTemplate.Execute(createdFile, p)
+ }
+ }
+
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/cmd/program/program.go b/cmd/program/program.go
index b5a8465b..45975588 100644
--- a/cmd/program/program.go
+++ b/cmd/program/program.go
@@ -3,42 +3,47 @@
package program
import (
- "bytes"
"fmt"
"log"
"os"
- "os/exec"
"path/filepath"
- "runtime"
"strings"
"text/template"
tea "github.com/charmbracelet/bubbletea"
"github.com/melkeydev/go-blueprint/cmd/flags"
- tpl "github.com/melkeydev/go-blueprint/cmd/template"
"github.com/melkeydev/go-blueprint/cmd/template/advanced"
+ "github.com/melkeydev/go-blueprint/cmd/template/backend"
"github.com/melkeydev/go-blueprint/cmd/template/dbdriver"
"github.com/melkeydev/go-blueprint/cmd/template/docker"
- "github.com/melkeydev/go-blueprint/cmd/template/framework"
+ "github.com/melkeydev/go-blueprint/cmd/template/frontend"
"github.com/melkeydev/go-blueprint/cmd/utils"
)
// A Project contains the data for the project folder
// being created, and methods that help with that process
type Project struct {
- ProjectName string
- Exit bool
- AbsolutePath string
- ProjectType flags.Framework
- DBDriver flags.Database
- Docker flags.Database
- FrameworkMap map[flags.Framework]Framework
- DBDriverMap map[flags.Database]Driver
- DockerMap map[flags.Database]Docker
- AdvancedOptions map[string]bool
- AdvancedTemplates AdvancedTemplates
- GitOptions flags.Git
- OSCheck map[string]bool
+ ProjectName string
+ Exit bool
+ AbsolutePath string
+ BackendFramework flags.BackendFramework
+ DBDriver flags.Database
+ Docker flags.Database
+ FrontendFramework flags.FrontendFramework
+ BackendFrameworkMap map[flags.BackendFramework]BackendFramework
+ DBDriverMap map[flags.Database]Driver
+ DockerMap map[flags.Database]Docker
+ FrontendTemplates FrontendTemplates
+ FrontendOptions map[string]bool
+ AdvancedTemplates AdvancedTemplates
+ AdvancedOptions map[string]bool
+ GitOptions flags.Git
+ OSCheck map[string]bool
+}
+
+type FrontendTemplates struct {
+ TemplateRoutes string
+ TemplateImports string
}
type AdvancedTemplates struct {
@@ -46,9 +51,9 @@ type AdvancedTemplates struct {
TemplateImports string
}
-// A Framework contains the name and templater for a
-// given Framework
-type Framework struct {
+// A Backend Framework contains the name and templater for a
+// given Backend Framework
+type BackendFramework struct {
packageName []string
templater Templater
}
@@ -64,7 +69,7 @@ type Docker struct {
}
// A Templater has the methods that help build the files
-// in the Project folder, and is specific to a Framework
+// in the Project folder, and is specific to a BackendFramework
type Templater interface {
Main() []byte
Server() []byte
@@ -94,7 +99,6 @@ type WorkflowTemplater interface {
var (
chiPackage = []string{"github.com/go-chi/chi/v5"}
gorillaPackage = []string{"github.com/gorilla/mux"}
- routerPackage = []string{"github.com/julienschmidt/httprouter"}
ginPackage = []string{"github.com/gin-gonic/gin"}
fiberPackage = []string{"github.com/gofiber/fiber/v2"}
echoPackage = []string{"github.com/labstack/echo/v4", "github.com/labstack/echo/v4/middleware"}
@@ -120,22 +124,6 @@ const (
gitHubActionPath = ".github/workflows"
)
-// CheckOs checks Operation system and generates MakeFile and `go build` command
-// Based on Project.Unixbase
-func (p *Project) CheckOS() {
- p.OSCheck = make(map[string]bool)
-
- if runtime.GOOS != "windows" {
- p.OSCheck["UnixBased"] = true
- }
- if runtime.GOOS == "linux" {
- p.OSCheck["linux"] = true
- }
- if runtime.GOOS == "darwin" {
- p.OSCheck["darwin"] = true
- }
-}
-
// ExitCLI checks if the Project has been exited, and closes
// out of the CLI if it has
func (p *Project) ExitCLI(tprogram *tea.Program) {
@@ -149,41 +137,36 @@ func (p *Project) ExitCLI(tprogram *tea.Program) {
}
// createFrameWorkMap adds the current supported
-// Frameworks into a Project's FrameworkMap
-func (p *Project) createFrameworkMap() {
- p.FrameworkMap[flags.Chi] = Framework{
+// BackendFrameworks into a Project's BackendFrameworkMap
+func (p *Project) createBackendFrameworkMap() {
+ p.BackendFrameworkMap[flags.Chi] = BackendFramework{
packageName: chiPackage,
- templater: framework.ChiTemplates{},
+ templater: backend.ChiTemplates{},
}
- p.FrameworkMap[flags.StandardLibrary] = Framework{
+ p.BackendFrameworkMap[flags.StandardLibrary] = BackendFramework{
packageName: []string{},
- templater: framework.StandardLibTemplate{},
+ templater: backend.StandardLibTemplate{},
}
- p.FrameworkMap[flags.Gin] = Framework{
+ p.BackendFrameworkMap[flags.Gin] = BackendFramework{
packageName: ginPackage,
- templater: framework.GinTemplates{},
+ templater: backend.GinTemplates{},
}
- p.FrameworkMap[flags.Fiber] = Framework{
+ p.BackendFrameworkMap[flags.Fiber] = BackendFramework{
packageName: fiberPackage,
- templater: framework.FiberTemplates{},
+ templater: backend.FiberTemplates{},
}
- p.FrameworkMap[flags.GorillaMux] = Framework{
+ p.BackendFrameworkMap[flags.GorillaMux] = BackendFramework{
packageName: gorillaPackage,
- templater: framework.GorillaTemplates{},
+ templater: backend.GorillaTemplates{},
}
- p.FrameworkMap[flags.HttpRouter] = Framework{
- packageName: routerPackage,
- templater: framework.RouterTemplates{},
- }
-
- p.FrameworkMap[flags.Echo] = Framework{
+ p.BackendFrameworkMap[flags.Echo] = BackendFramework{
packageName: echoPackage,
- templater: framework.EchoTemplates{},
+ templater: backend.EchoTemplates{},
}
}
@@ -243,6 +226,9 @@ func (p *Project) createDockerMap() {
// CreateMainFile creates the project folders and files,
// and writes to them depending on the selected options
func (p *Project) CreateMainFile() error {
+
+ var err error
+
// check if AbsolutePath exists
if _, err := os.Stat(p.AbsolutePath); os.IsNotExist(err) {
// create directory
@@ -252,18 +238,6 @@ func (p *Project) CreateMainFile() error {
}
}
- // Check if user.email is set.
- emailSet, err := utils.CheckGitConfig("user.email")
- if err != nil {
- return err
- }
-
- if !emailSet && p.GitOptions.String() != flags.Skip {
- fmt.Println("user.email is not set in git config.")
- fmt.Println("Please set up git config before trying again.")
- panic("\nGIT CONFIG ISSUE: user.email is not set in git config.\n")
- }
-
p.ProjectName = strings.TrimSpace(p.ProjectName)
// Create a new directory with the project name
@@ -280,7 +254,7 @@ func (p *Project) CreateMainFile() error {
p.CheckOS()
// Create the map for our program
- p.createFrameworkMap()
+ p.createBackendFrameworkMap()
// Create go.mod
err = utils.InitGoMod(p.ProjectName, projectPath)
@@ -289,11 +263,11 @@ func (p *Project) CreateMainFile() error {
return err
}
- // Install the correct package for the selected framework
- if p.ProjectType != flags.StandardLibrary {
- err = utils.GoGetPackage(projectPath, p.FrameworkMap[p.ProjectType].packageName)
+ // Install the correct package for the selected backend
+ if p.BackendFramework != flags.StandardLibrary {
+ err = utils.GoGetPackage(projectPath, p.BackendFrameworkMap[p.BackendFramework].packageName)
if err != nil {
- log.Printf("Could not install go dependency for the chosen framework %v\n", err)
+ log.Printf("Could not install go dependency for the chosen backend %v\n", err)
return err
}
}
@@ -381,7 +355,7 @@ func (p *Project) CreateMainFile() error {
defer makeFile.Close()
// inject makefile template
- makeFileTemplate := template.Must(template.New("makefile").Parse(string(framework.MakeTemplate())))
+ makeFileTemplate := template.Must(template.New("makefile").Parse(string(backend.MakeTemplate())))
err = makeFileTemplate.Execute(makeFile, p)
if err != nil {
return err
@@ -394,7 +368,7 @@ func (p *Project) CreateMainFile() error {
defer readmeFile.Close()
// inject readme template
- readmeFileTemplate := template.Must(template.New("readme").Parse(string(framework.ReadmeTemplate())))
+ readmeFileTemplate := template.Must(template.New("readme").Parse(string(backend.ReadmeTemplate())))
err = readmeFileTemplate.Execute(readmeFile, p)
if err != nil {
return err
@@ -406,28 +380,20 @@ func (p *Project) CreateMainFile() error {
return err
}
- if p.AdvancedOptions[string(flags.React)] {
- // deselect htmx option automatically since react is selected
- p.AdvancedOptions[string(flags.Htmx)] = false
+ if p.FrontendFramework == flags.React {
if err := p.CreateViteReactProject(projectPath); err != nil {
return fmt.Errorf("failed to set up React project: %w", err)
}
-
- // if everything went smoothly, remove tailwing flag option
- p.AdvancedOptions[string(flags.Tailwind)] = false
}
- if p.AdvancedOptions[string(flags.Tailwind)] {
- // select htmx option automatically since tailwind is selected
- p.AdvancedOptions[string(flags.Htmx)] = true
-
+ if p.FrontendOptions[string(flags.Tailwind)] && p.FrontendFramework == flags.Htmx {
tailwindConfigFile, err := os.Create(fmt.Sprintf("%s/tailwind.config.js", projectPath))
if err != nil {
return err
}
defer tailwindConfigFile.Close()
- tailwindConfigTemplate := advanced.TailwindConfigTemplate()
+ tailwindConfigTemplate := frontend.TailwindConfigTemplate()
err = os.WriteFile(fmt.Sprintf("%s/tailwind.config.js", projectPath), tailwindConfigTemplate, 0o644)
if err != nil {
return err
@@ -449,7 +415,7 @@ func (p *Project) CreateMainFile() error {
}
defer inputCssFile.Close()
- inputCssTemplate := advanced.InputCssTemplate()
+ inputCssTemplate := frontend.InputCssTemplate()
err = os.WriteFile(fmt.Sprintf("%s/%s/styles/input.css", projectPath, cmdWebPath), inputCssTemplate, 0o644)
if err != nil {
return err
@@ -461,14 +427,14 @@ func (p *Project) CreateMainFile() error {
}
defer outputCssFile.Close()
- outputCssTemplate := advanced.OutputCssTemplate()
+ outputCssTemplate := frontend.OutputCssTemplate()
err = os.WriteFile(fmt.Sprintf("%s/%s/assets/css/output.css", projectPath, cmdWebPath), outputCssTemplate, 0o644)
if err != nil {
return err
}
}
- if p.AdvancedOptions[string(flags.Htmx)] {
+ if p.FrontendFramework == flags.Htmx {
// create folders and hello world file
err = p.CreatePath(cmdWebPath, projectPath)
if err != nil {
@@ -481,7 +447,7 @@ func (p *Project) CreateMainFile() error {
defer helloTemplFile.Close()
// inject hello.templ template
- helloTemplTemplate := template.Must(template.New("hellotempl").Parse((string(advanced.HelloTemplTemplate()))))
+ helloTemplTemplate := template.Must(template.New("hellotempl").Parse((string(frontend.HelloTemplTemplate()))))
err = helloTemplTemplate.Execute(helloTemplFile, p)
if err != nil {
return err
@@ -493,7 +459,7 @@ func (p *Project) CreateMainFile() error {
}
defer baseTemplFile.Close()
- baseTemplTemplate := template.Must(template.New("basetempl").Parse((string(advanced.BaseTemplTemplate()))))
+ baseTemplTemplate := template.Must(template.New("basetempl").Parse((string(frontend.BaseTemplTemplate()))))
err = baseTemplTemplate.Execute(baseTemplFile, p)
if err != nil {
return err
@@ -510,7 +476,7 @@ func (p *Project) CreateMainFile() error {
}
defer htmxMinJsFile.Close()
- htmxMinJsTemplate := advanced.HtmxJSTemplate()
+ htmxMinJsTemplate := frontend.HtmxJSTemplate()
err = os.WriteFile(fmt.Sprintf("%s/%s/assets/js/htmx.min.js", projectPath, cmdWebPath), htmxMinJsTemplate, 0o644)
if err != nil {
return err
@@ -522,7 +488,7 @@ func (p *Project) CreateMainFile() error {
}
defer efsFile.Close()
- efsTemplate := template.Must(template.New("efs").Parse((string(advanced.EfsTemplate()))))
+ efsTemplate := template.Must(template.New("efs").Parse((string(frontend.EfsTemplate()))))
err = efsTemplate.Execute(efsFile, p)
if err != nil {
return err
@@ -539,8 +505,8 @@ func (p *Project) CreateMainFile() error {
}
defer efsFile.Close()
- if p.ProjectType == "fiber" {
- helloGoTemplate := template.Must(template.New("efs").Parse((string(advanced.HelloFiberGoTemplate()))))
+ if p.BackendFramework == "fiber" {
+ helloGoTemplate := template.Must(template.New("efs").Parse((string(frontend.HelloFiberGoTemplate()))))
err = helloGoTemplate.Execute(helloGoFile, p)
if err != nil {
return err
@@ -551,7 +517,7 @@ func (p *Project) CreateMainFile() error {
return err
}
} else {
- helloGoTemplate := template.Must(template.New("efs").Parse((string(advanced.HelloGoTemplate()))))
+ helloGoTemplate := template.Must(template.New("efs").Parse((string(frontend.HelloGoTemplate()))))
err = helloGoTemplate.Execute(helloGoFile, p)
if err != nil {
return err
@@ -589,7 +555,7 @@ func (p *Project) CreateMainFile() error {
}
// if the websocket option is checked, a websocket dependency needs to
- // be added to the routes depending on the framework choosen.
+ // be added to the routes depending on the backend choosen.
// Only fiber uses a different websocket library, the other frameworks
// all work with the same one
if p.AdvancedOptions[string(flags.Websocket)] {
@@ -650,20 +616,6 @@ func (p *Project) CreateMainFile() error {
return err
}
- // Create gitignore
- gitignoreFile, err := os.Create(filepath.Join(projectPath, ".gitignore"))
- if err != nil {
- return err
- }
- defer gitignoreFile.Close()
-
- // inject gitignore template
- gitignoreTemplate := template.Must(template.New(".gitignore").Parse(string(framework.GitIgnoreTemplate())))
- err = gitignoreTemplate.Execute(gitignoreFile, p)
- if err != nil {
- return err
- }
-
// Create .air.toml file
airTomlFile, err := os.Create(filepath.Join(projectPath, ".air.toml"))
if err != nil {
@@ -673,7 +625,7 @@ func (p *Project) CreateMainFile() error {
defer airTomlFile.Close()
// inject air.toml template
- airTomlTemplate := template.Must(template.New("airtoml").Parse(string(framework.AirTomlTemplate())))
+ airTomlTemplate := template.Must(template.New("airtoml").Parse(string(backend.AirTomlTemplate())))
err = airTomlTemplate.Execute(airTomlFile, p)
if err != nil {
return err
@@ -691,17 +643,24 @@ func (p *Project) CreateMainFile() error {
return err
}
- nameSet, err := utils.CheckGitConfig("user.name")
- if err != nil {
- return err
- }
-
if p.GitOptions != flags.Skip {
+ nameSet, err := utils.CheckGitConfig("user.name")
+ if err != nil {
+ return err
+ }
+ emailSet, err := utils.CheckGitConfig("user.email")
+ if err != nil {
+ return err
+ }
+
if !nameSet {
- fmt.Println("user.name is not set in git config.")
- fmt.Println("Please set up git config before trying again.")
panic("\nGIT CONFIG ISSUE: user.name is not set in git config.\n")
}
+
+ if !emailSet {
+ panic("\nGIT CONFIG ISSUE: user.email is not set in git config.\n")
+ }
+
// Initialize git repo
err = utils.ExecuteCmd("git", []string{"init"}, projectPath)
if err != nil {
@@ -716,292 +675,28 @@ func (p *Project) CreateMainFile() error {
return err
}
- if p.GitOptions == flags.Commit {
- // Git commit files
- err = utils.ExecuteCmd("git", []string{"commit", "-m", "Initial commit"}, projectPath)
- if err != nil {
- log.Printf("Error committing files to git repo: %v", err)
- return err
- }
- }
- }
- return nil
-}
-
-// CreatePath creates the given directory in the projectPath
-func (p *Project) CreatePath(pathToCreate string, projectPath string) error {
- path := filepath.Join(projectPath, pathToCreate)
- if _, err := os.Stat(path); os.IsNotExist(err) {
- err := os.MkdirAll(path, 0o751)
+ // Create gitignore
+ gitignoreFile, err := os.Create(filepath.Join(projectPath, ".gitignore"))
if err != nil {
- log.Printf("Error creating directory %v\n", err)
return err
}
- }
-
- return nil
-}
-
-// CreateFileWithInjection creates the given file at the
-// project path, and injects the appropriate template
-func (p *Project) CreateFileWithInjection(pathToCreate string, projectPath string, fileName string, methodName string) error {
- createdFile, err := os.Create(filepath.Join(projectPath, pathToCreate, fileName))
- if err != nil {
- return err
- }
-
- defer createdFile.Close()
-
- switch methodName {
- case "main":
- createdTemplate := template.Must(template.New(fileName).Parse(string(p.FrameworkMap[p.ProjectType].templater.Main())))
- err = createdTemplate.Execute(createdFile, p)
- case "server":
- createdTemplate := template.Must(template.New(fileName).Parse(string(p.FrameworkMap[p.ProjectType].templater.Server())))
- err = createdTemplate.Execute(createdFile, p)
- case "routes":
- routeFileBytes := p.FrameworkMap[p.ProjectType].templater.Routes()
- createdTemplate := template.Must(template.New(fileName).Parse(string(routeFileBytes)))
- err = createdTemplate.Execute(createdFile, p)
- case "releaser":
- createdTemplate := template.Must(template.New(fileName).Parse(string(advanced.Releaser())))
- err = createdTemplate.Execute(createdFile, p)
- case "go-test":
- createdTemplate := template.Must(template.New(fileName).Parse(string(advanced.Test())))
- err = createdTemplate.Execute(createdFile, p)
- case "releaser-config":
- createdTemplate := template.Must(template.New(fileName).Parse(string(advanced.ReleaserConfig())))
- err = createdTemplate.Execute(createdFile, p)
- case "database":
- createdTemplate := template.Must(template.New(fileName).Parse(string(p.DBDriverMap[p.DBDriver].templater.Service())))
- err = createdTemplate.Execute(createdFile, p)
- case "db-docker":
- createdTemplate := template.Must(template.New(fileName).Parse(string(p.DockerMap[p.Docker].templater.Docker())))
- err = createdTemplate.Execute(createdFile, p)
- case "integration-tests":
- createdTemplate := template.Must(template.New(fileName).Parse(string(p.DBDriverMap[p.DBDriver].templater.Tests())))
- err = createdTemplate.Execute(createdFile, p)
- case "tests":
- createdTemplate := template.Must(template.New(fileName).Parse(string(p.FrameworkMap[p.ProjectType].templater.TestHandler())))
- err = createdTemplate.Execute(createdFile, p)
- case "env":
- if p.DBDriver != "none" {
-
- envBytes := [][]byte{
- tpl.GlobalEnvTemplate(),
- p.DBDriverMap[p.DBDriver].templater.Env(),
- }
- createdTemplate := template.Must(template.New(fileName).Parse(string(bytes.Join(envBytes, []byte("\n")))))
- err = createdTemplate.Execute(createdFile, p)
-
- } else {
- createdTemplate := template.Must(template.New(fileName).Parse(string(tpl.GlobalEnvTemplate())))
- err = createdTemplate.Execute(createdFile, p)
- }
- }
-
- if err != nil {
- return err
- }
-
- return nil
-}
-
-func (p *Project) CreateViteReactProject(projectPath string) error {
- if err := checkNpmInstalled(); err != nil {
- return err
- }
-
- originalDir, err := os.Getwd()
- if err != nil {
- return fmt.Errorf("failed to get current directory: %w", err)
- }
- defer func() {
- if err := os.Chdir(originalDir); err != nil {
- fmt.Fprintf(os.Stderr, "failed to change back to original directory: %v\n", err)
- }
- }()
-
- // change into the project directory to run vite command
- err = os.Chdir(projectPath)
- if err != nil {
- fmt.Println("failed to change into project directory: %w", err)
- }
-
- // the interactive vite command will not work as we can't interact with it
- fmt.Println("Installing create-vite (using cache if available)...")
- cmd := exec.Command("npm", "create", "vite@latest", "frontend", "--",
- "--template", "react-ts",
- "--prefer-offline",
- "--no-fund")
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
- if err := cmd.Run(); err != nil {
- return fmt.Errorf("failed to use create-vite: %w", err)
- }
-
- frontendPath := filepath.Join(projectPath, "frontend")
- if err := os.MkdirAll(frontendPath, 0755); err != nil {
- return fmt.Errorf("failed to create frontend directory: %w", err)
- }
-
- if err := os.Chdir(frontendPath); err != nil {
- return fmt.Errorf("failed to change to frontend directory: %w", err)
- }
-
- srcDir := filepath.Join(frontendPath, "src")
- if err := os.MkdirAll(srcDir, 0755); err != nil {
- return fmt.Errorf("failed to create src directory: %w", err)
- }
-
- if err := os.WriteFile(filepath.Join(srcDir, "App.tsx"), advanced.ReactAppfile(), 0644); err != nil {
- return fmt.Errorf("failed to write App.tsx template: %w", err)
- }
-
- // Create the global `.env` file from the template
- err = p.CreateFileWithInjection("", projectPath, ".env", "env")
- if err != nil {
- return fmt.Errorf("failed to create global .env file: %w", err)
- }
-
- // Read from the global `.env` file and create the frontend-specific `.env`
- globalEnvPath := filepath.Join(projectPath, ".env")
- vitePort := "8080" // Default fallback
-
- // Read the global .env file
- if data, err := os.ReadFile(globalEnvPath); err == nil {
- lines := strings.Split(string(data), "\n")
- for _, line := range lines {
- if strings.HasPrefix(line, "PORT=") {
- vitePort = strings.SplitN(line, "=", 2)[1] // Get the backend port value
- break
- }
- }
- }
-
- // Use a template to generate the frontend .env file
- frontendEnvContent := fmt.Sprintf("VITE_PORT=%s\n", vitePort)
- if err := os.WriteFile(filepath.Join(frontendPath, ".env"), []byte(frontendEnvContent), 0644); err != nil {
- return fmt.Errorf("failed to create frontend .env file: %w", err)
- }
-
- // Handle Tailwind configuration if selected
- if p.AdvancedOptions[string(flags.Tailwind)] {
- fmt.Println("Installing Tailwind dependencies (using cache if available)...")
- cmd := exec.Command("npm", "install",
- "--prefer-offline",
- "--no-fund",
- "tailwindcss", "postcss", "autoprefixer")
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
- if err := cmd.Run(); err != nil {
- return fmt.Errorf("failed to install Tailwind: %w", err)
- }
-
- fmt.Println("Initializing Tailwind...")
- cmd = exec.Command("npx", "--prefer-offline", "tailwindcss", "init", "-p")
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
- if err := cmd.Run(); err != nil {
- return fmt.Errorf("failed to initialize Tailwind: %w", err)
- }
-
- // use the tailwind config file
- err = os.WriteFile("tailwind.config.js", advanced.ReactTailwindConfigTemplate(), 0644)
- if err != nil {
- return fmt.Errorf("failed to write tailwind config: %w", err)
- }
-
- srcDir := filepath.Join(frontendPath, "src")
- if err := os.MkdirAll(srcDir, 0755); err != nil {
- return fmt.Errorf("failed to create src directory: %w", err)
- }
+ defer gitignoreFile.Close()
- err = os.WriteFile(filepath.Join(srcDir, "index.css"), advanced.InputCssTemplateReact(), 0644)
+ // inject gitignore template
+ gitignoreTemplate := template.Must(template.New(".gitignore").Parse(string(backend.GitIgnoreTemplate())))
+ err = gitignoreTemplate.Execute(gitignoreFile, p)
if err != nil {
- return fmt.Errorf("failed to update index.css: %w", err)
- }
-
- if err := os.WriteFile(filepath.Join(srcDir, "App.tsx"), advanced.ReactTailwindAppfile(), 0644); err != nil {
- return fmt.Errorf("failed to write App.tsx template: %w", err)
+ return err
}
- if err := os.Remove(filepath.Join(srcDir, "App.css")); err != nil {
- // Don't return error if file doesn't exist
- if !os.IsNotExist(err) {
- return fmt.Errorf("failed to remove App.css: %w", err)
+ if p.GitOptions == flags.Commit {
+ // Git commit files
+ err = utils.ExecuteCmd("git", []string{"commit", "-m", "Initial commit"}, projectPath)
+ if err != nil {
+ log.Printf("Error committing files to git repo: %v", err)
+ return err
}
}
-
- // set to false to not re-do in next step
- p.AdvancedOptions[string(flags.Tailwind)] = false
- }
-
- return nil
-}
-func (p *Project) CreateHtmxTemplates() {
- routesPlaceHolder := ""
- importsPlaceHolder := ""
- if p.AdvancedOptions[string(flags.Htmx)] {
- routesPlaceHolder += string(p.FrameworkMap[p.ProjectType].templater.HtmxTemplRoutes())
- importsPlaceHolder += string(p.FrameworkMap[p.ProjectType].templater.HtmxTemplImports())
- }
-
- routeTmpl, err := template.New("routes").Parse(routesPlaceHolder)
- if err != nil {
- log.Fatal(err)
- }
- importTmpl, err := template.New("imports").Parse(importsPlaceHolder)
- if err != nil {
- log.Fatal(err)
- }
- var routeBuffer bytes.Buffer
- var importBuffer bytes.Buffer
- err = routeTmpl.Execute(&routeBuffer, p)
- if err != nil {
- log.Fatal(err)
- }
- err = importTmpl.Execute(&importBuffer, p)
- if err != nil {
- log.Fatal(err)
- }
- p.AdvancedTemplates.TemplateRoutes = routeBuffer.String()
- p.AdvancedTemplates.TemplateImports = importBuffer.String()
-}
-
-func (p *Project) CreateWebsocketImports(appDir string) {
- websocketDependency := []string{"github.com/coder/websocket"}
- if p.ProjectType == flags.Fiber {
- websocketDependency = []string{"github.com/gofiber/contrib/websocket"}
- }
-
- // Websockets require a different package depending on what framework is
- // choosen. The application calls go mod tidy at the end so we don't
- // have to here
- err := utils.GoGetPackage(appDir, websocketDependency)
- if err != nil {
- log.Fatal(err)
- }
-
- importsPlaceHolder := string(p.FrameworkMap[p.ProjectType].templater.WebsocketImports())
-
- importTmpl, err := template.New("imports").Parse(importsPlaceHolder)
- if err != nil {
- log.Fatalf("CreateWebsocketImports failed to create template: %v", err)
- }
- var importBuffer bytes.Buffer
- err = importTmpl.Execute(&importBuffer, p)
- if err != nil {
- log.Fatalf("CreateWebsocketImports failed write template: %v", err)
- }
- newImports := strings.Join([]string{string(p.AdvancedTemplates.TemplateImports), importBuffer.String()}, "\n")
- p.AdvancedTemplates.TemplateImports = newImports
-}
-
-func checkNpmInstalled() error {
- cmd := exec.Command("npm", "--version")
- if err := cmd.Run(); err != nil {
- return fmt.Errorf("npm is not installed: %w", err)
}
return nil
}
diff --git a/cmd/steps/steps.go b/cmd/steps/steps.go
index eacb874b..fa240d0f 100644
--- a/cmd/steps/steps.go
+++ b/cmd/steps/steps.go
@@ -2,7 +2,9 @@
// each step of the CLI
package steps
-import "github.com/melkeydev/go-blueprint/cmd/flags"
+import (
+ "github.com/melkeydev/go-blueprint/cmd/flags"
+)
// A StepSchema contains the data that is used
// for an individual step of the CLI
@@ -25,11 +27,11 @@ type Item struct {
}
// InitSteps initializes and returns the *Steps to be used in the CLI program
-func InitSteps(projectType flags.Framework, databaseType flags.Database) *Steps {
+func InitSteps(projectType flags.BackendFramework, databaseType flags.Database, frontendFrameworkType flags.FrontendFramework, gitType flags.Git) *Steps {
steps := &Steps{
map[string]StepSchema{
- "framework": {
- StepName: "Go Project Framework",
+ "backend-framework": {
+ StepName: "Go Project Backend Framework",
Options: []Item{
{
Title: "Standard-library",
@@ -51,16 +53,12 @@ func InitSteps(projectType flags.Framework, databaseType flags.Database) *Steps
Title: "Gorilla/Mux",
Desc: "Package gorilla/mux implements a request router and dispatcher for matching incoming requests to their respective handler",
},
- {
- Title: "HttpRouter",
- Desc: "HttpRouter is a lightweight high performance HTTP request router for Go",
- },
{
Title: "Echo",
Desc: "High performance, extensible, minimalist Go web framework",
},
},
- Headers: "What framework do you want to use in your Go project?",
+ Headers: "What backend framework do you want to use in your Go project?",
Field: projectType.String(),
},
"driver": {
@@ -92,9 +90,8 @@ func InitSteps(projectType flags.Framework, databaseType flags.Database) *Steps
Headers: "What database driver do you want to use in your Go project?",
Field: databaseType.String(),
},
- "advanced": {
- StepName: "Advanced Features",
- Headers: "Which advanced features do you want?",
+ "frontend-framework": {
+ StepName: "Go Project Database Driver",
Options: []Item{
{
Flag: "React",
@@ -103,9 +100,27 @@ func InitSteps(projectType flags.Framework, databaseType flags.Database) *Steps
},
{
Flag: "Htmx",
- Title: "HTMX/Templ",
+ Title: "Htmx",
Desc: "Add starter HTMX and Templ files. This disables selecting React",
},
+ },
+ Headers: "What frontend framework do you want to use in your Go project?",
+ Field: frontendFrameworkType.String(),
+ },
+ "frontend-advanced": {
+ StepName: "Go Project Database Driver",
+ Options: []Item{
+ {
+ Flag: "Tailwind",
+ Title: "TailwindCSS",
+ Desc: "A utility-first CSS framework",
+ },
+ },
+ Headers: "What frontend advanced feature do you want to use in your Go project?",
+ },
+ "advanced": {
+ StepName: "Advanced Features",
+ Options: []Item{
{
Flag: "GitHubAction",
Title: "Go Project Workflow",
@@ -116,21 +131,16 @@ func InitSteps(projectType flags.Framework, databaseType flags.Database) *Steps
Title: "Websocket endpoint",
Desc: "Add a websocket endpoint",
},
- {
- Flag: "Tailwind",
- Title: "TailwindCSS",
- Desc: "A utility-first CSS framework (selecting this will automatically add HTMX unless React is specified)",
- },
{
Flag: "Docker",
Title: "Docker",
Desc: "Dockerfile and docker-compose generic configuration for go project",
},
},
+ Headers: "Which advanced features do you want?",
},
"git": {
StepName: "Git Repository",
- Headers: "Which git option would you like to select for your project?",
Options: []Item{
{
Title: "Commit",
@@ -145,6 +155,8 @@ func InitSteps(projectType flags.Framework, databaseType flags.Database) *Steps
Desc: "Proceed without initializing a git repository",
},
},
+ Headers: "Which git option would you like to select for your project?",
+ Field: gitType.String(),
},
},
}
diff --git a/cmd/template/advanced/files/docker/docker_compose.yml.tmpl b/cmd/template/advanced/files/docker/docker_compose.yml.tmpl
index 48edb7b4..04be7d8e 100644
--- a/cmd/template/advanced/files/docker/docker_compose.yml.tmpl
+++ b/cmd/template/advanced/files/docker/docker_compose.yml.tmpl
@@ -15,7 +15,7 @@ services:
volumes:
- sqlite_bp:/app/db
{{- end }}
-{{- if .AdvancedOptions.react }}
+{{- if (eq .FrontendFramework "react") }}
frontend:
build:
context: .
diff --git a/cmd/template/advanced/files/docker/dockerfile.tmpl b/cmd/template/advanced/files/docker/dockerfile.tmpl
index c2042ed6..d0ab5814 100644
--- a/cmd/template/advanced/files/docker/dockerfile.tmpl
+++ b/cmd/template/advanced/files/docker/dockerfile.tmpl
@@ -1,6 +1,6 @@
FROM golang:1.23-alpine AS build
-{{- if or (.AdvancedOptions.tailwind) (eq .DBDriver "sqlite") }}
-RUN apk add --no-cache{{- if .AdvancedOptions.tailwind }} curl{{ end }}{{- if (eq .DBDriver "sqlite") }} alpine-sdk{{ end }}
+{{- if or (and .FrontendOptions.tailwind (eq .FrontendFramework "htmx")) (eq .DBDriver "sqlite") }}
+RUN apk add --no-cache{{- if and .FrontendOptions.tailwind (eq .FrontendFramework "htmx") }} curl{{ end }}{{- if (eq .DBDriver "sqlite") }} alpine-sdk{{ end }}
{{- end }}
WORKDIR /app
@@ -10,12 +10,11 @@ RUN go mod download
COPY . .
-{{- if or .AdvancedOptions.htmx .AdvancedOptions.tailwind }}
+{{- if eq .FrontendFramework "htmx" }}
RUN go install github.com/a-h/templ/cmd/templ@latest && \
- templ generate{{- if .AdvancedOptions.tailwind}} && \{{- end}}
+ templ generate{{- if .FrontendOptions.tailwind}} && \{{- end}}
{{- end}}
-
-{{- if .AdvancedOptions.tailwind}}
+{{- if and (.FrontendOptions.tailwind) (eq .FrontendFramework "htmx") }}
curl -sL https://github.com/tailwindlabs/tailwindcss/releases/download/v3.4.10/tailwindcss-linux-x64 -o tailwindcss && \
chmod +x tailwindcss && \
./tailwindcss -i cmd/web/styles/input.css -o cmd/web/assets/css/output.css
@@ -29,7 +28,7 @@ COPY --from=build /app/main /app/main
EXPOSE ${PORT}
CMD ["./main"]
-{{ if .AdvancedOptions.react}}
+{{ if eq .FrontendFramework "react"}}
FROM node:20 AS frontend_builder
WORKDIR /frontend
diff --git a/cmd/template/advanced/files/workflow/github/github_action_goreleaser.yml.tmpl b/cmd/template/advanced/files/workflow/github/github_action_goreleaser.yml.tmpl
index 55ca0a65..5ca5673c 100644
--- a/cmd/template/advanced/files/workflow/github/github_action_goreleaser.yml.tmpl
+++ b/cmd/template/advanced/files/workflow/github/github_action_goreleaser.yml.tmpl
@@ -16,8 +16,8 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v4
with:
- go-version: '1.22.x'
-{{if or ( .AdvancedOptions.htmx ) ( .AdvancedOptions.tailwind )}}
+ go-version: '1.23.x'
+{{if or (eq .FrontendFramework "htmx") (.FrontendOptions.tailwind)}}
- name: Install templ
shell: bash
run: go install github.com/a-h/templ/cmd/templ@latest
diff --git a/cmd/template/advanced/files/workflow/github/github_action_gotest.yml.tmpl b/cmd/template/advanced/files/workflow/github/github_action_gotest.yml.tmpl
index 6d52445b..022365f5 100644
--- a/cmd/template/advanced/files/workflow/github/github_action_gotest.yml.tmpl
+++ b/cmd/template/advanced/files/workflow/github/github_action_gotest.yml.tmpl
@@ -10,8 +10,8 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v4
with:
- go-version: '1.22.x'
-{{if or ( .AdvancedOptions.htmx ) ( .AdvancedOptions.tailwind )}}
+ go-version: '1.23.x'
+{{if or (eq .FrontendFramework "htmx") ( .FrontendOptions.tailwind )}}
- name: Install templ
shell: bash
run: go install github.com/a-h/templ/cmd/templ@latest
diff --git a/cmd/template/advanced/routes.go b/cmd/template/advanced/routes.go
index 3ed424f6..6a6a761e 100644
--- a/cmd/template/advanced/routes.go
+++ b/cmd/template/advanced/routes.go
@@ -4,177 +4,16 @@ import (
_ "embed"
)
-//go:embed files/htmx/hello.templ.tmpl
-var helloTemplTemplate []byte
-
-//go:embed files/htmx/base.templ.tmpl
-var baseTemplTemplate []byte
-
-//go:embed files/tailwind/tailwind.config.js.tmpl
-var tailwindConfigTemplate []byte
-
-//go:embed files/react/tailwind/tailwind.config.js.tmpl
-var reactTailwindConfigTemplate []byte
-
-//go:embed files/react/tailwind/index.css.tmpl
-var inputCssTemplateReact []byte
-
-//go:embed files/react/tailwind/app.tsx.tmpl
-var reactTailwindAppFile []byte
-
-//go:embed files/react/app.tsx.tmpl
-var reactAppFile []byte
-
-//go:embed files/tailwind/input.css.tmpl
-var inputCssTemplate []byte
-
-//go:embed files/tailwind/output.css.tmpl
-var outputCssTemplate []byte
-
-//go:embed files/htmx/htmx.min.js.tmpl
-var htmxMinJsTemplate []byte
-
-//go:embed files/htmx/efs.go.tmpl
-var efsTemplate []byte
-
-//go:embed files/htmx/hello.go.tmpl
-var helloGoTemplate []byte
-
-//go:embed files/htmx/hello_fiber.go.tmpl
-var helloFiberGoTemplate []byte
-
-//go:embed files/htmx/routes/http_router.tmpl
-var httpRouterHtmxTemplRoutes []byte
-
-//go:embed files/htmx/routes/standard_library.tmpl
-var stdLibHtmxTemplRoutes []byte
-
-//go:embed files/htmx/imports/standard_library.tmpl
-var stdLibHtmxTemplImports []byte
-
//go:embed files/websocket/imports/standard_library.tmpl
var stdLibWebsocketImports []byte
-//go:embed files/htmx/routes/chi.tmpl
-var chiHtmxTemplRoutes []byte
-
-//go:embed files/htmx/routes/gin.tmpl
-var ginHtmxTemplRoutes []byte
-
-//go:embed files/htmx/imports/gin.tmpl
-var ginHtmxTemplImports []byte
-
-//go:embed files/htmx/routes/gorilla.tmpl
-var gorillaHtmxTemplRoutes []byte
-
-//go:embed files/htmx/routes/echo.tmpl
-var echoHtmxTemplRoutes []byte
-
-//go:embed files/htmx/routes/fiber.tmpl
-var fiberHtmxTemplRoutes []byte
-
-//go:embed files/htmx/imports/fiber.tmpl
-var fiberHtmxTemplImports []byte
-
//go:embed files/websocket/imports/fiber.tmpl
var fiberWebsocketTemplImports []byte
-func EchoHtmxTemplRoutesTemplate() []byte {
- return echoHtmxTemplRoutes
-}
-
-func GorillaHtmxTemplRoutesTemplate() []byte {
- return gorillaHtmxTemplRoutes
-}
-
-func ChiHtmxTemplRoutesTemplate() []byte {
- return chiHtmxTemplRoutes
-}
-
-func GinHtmxTemplRoutesTemplate() []byte {
- return ginHtmxTemplRoutes
-}
-
-func HttpRouterHtmxTemplRoutesTemplate() []byte {
- return httpRouterHtmxTemplRoutes
-}
-
-func StdLibHtmxTemplRoutesTemplate() []byte {
- return stdLibHtmxTemplRoutes
-}
-
-func StdLibHtmxTemplImportsTemplate() []byte {
- return stdLibHtmxTemplImports
-}
-
func StdLibWebsocketTemplImportsTemplate() []byte {
return stdLibWebsocketImports
}
-func HelloTemplTemplate() []byte {
- return helloTemplTemplate
-}
-
-func BaseTemplTemplate() []byte {
- return baseTemplTemplate
-}
-
-func TailwindConfigTemplate() []byte {
- return tailwindConfigTemplate
-}
-
-func ReactTailwindConfigTemplate() []byte {
- return reactTailwindConfigTemplate
-}
-
-func ReactTailwindAppfile() []byte {
- return reactTailwindAppFile
-}
-
-func ReactAppfile() []byte {
- return reactAppFile
-}
-
-func InputCssTemplateReact() []byte {
- return inputCssTemplateReact
-}
-
-func InputCssTemplate() []byte {
- return inputCssTemplate
-}
-
-func OutputCssTemplate() []byte {
- return outputCssTemplate
-}
-
-func HtmxJSTemplate() []byte {
- return htmxMinJsTemplate
-}
-
-func EfsTemplate() []byte {
- return efsTemplate
-}
-
-func HelloGoTemplate() []byte {
- return helloGoTemplate
-}
-
-func HelloFiberGoTemplate() []byte {
- return helloFiberGoTemplate
-}
-
-func FiberHtmxTemplRoutesTemplate() []byte {
- return fiberHtmxTemplRoutes
-}
-
-func FiberHtmxTemplImportsTemplate() []byte {
- return fiberHtmxTemplImports
-}
-
func FiberWebsocketTemplImportsTemplate() []byte {
return fiberWebsocketTemplImports
}
-
-func GinHtmxTemplImportsTemplate() []byte {
- return ginHtmxTemplImports
-}
diff --git a/cmd/template/framework/chiRoutes.go b/cmd/template/backend/chiRoutes.go
similarity index 83%
rename from cmd/template/framework/chiRoutes.go
rename to cmd/template/backend/chiRoutes.go
index 00fbda87..f004817a 100644
--- a/cmd/template/framework/chiRoutes.go
+++ b/cmd/template/backend/chiRoutes.go
@@ -1,9 +1,10 @@
-package framework
+package backend
import (
_ "embed"
"github.com/melkeydev/go-blueprint/cmd/template/advanced"
+ "github.com/melkeydev/go-blueprint/cmd/template/frontend"
)
//go:embed files/routes/chi.go.tmpl
@@ -33,11 +34,11 @@ func (c ChiTemplates) TestHandler() []byte {
}
func (c ChiTemplates) HtmxTemplImports() []byte {
- return advanced.StdLibHtmxTemplImportsTemplate()
+ return frontend.StdLibHtmxTemplImportsTemplate()
}
func (c ChiTemplates) HtmxTemplRoutes() []byte {
- return advanced.ChiHtmxTemplRoutesTemplate()
+ return frontend.ChiHtmxTemplRoutesTemplate()
}
func (c ChiTemplates) WebsocketImports() []byte {
diff --git a/cmd/template/framework/echoRoutes.go b/cmd/template/backend/echoRoutes.go
similarity index 83%
rename from cmd/template/framework/echoRoutes.go
rename to cmd/template/backend/echoRoutes.go
index cb25939d..1d149afe 100644
--- a/cmd/template/framework/echoRoutes.go
+++ b/cmd/template/backend/echoRoutes.go
@@ -1,9 +1,10 @@
-package framework
+package backend
import (
_ "embed"
"github.com/melkeydev/go-blueprint/cmd/template/advanced"
+ "github.com/melkeydev/go-blueprint/cmd/template/frontend"
)
//go:embed files/routes/echo.go.tmpl
@@ -32,11 +33,11 @@ func (e EchoTemplates) TestHandler() []byte {
}
func (e EchoTemplates) HtmxTemplImports() []byte {
- return advanced.StdLibHtmxTemplImportsTemplate()
+ return frontend.StdLibHtmxTemplImportsTemplate()
}
func (e EchoTemplates) HtmxTemplRoutes() []byte {
- return advanced.EchoHtmxTemplRoutesTemplate()
+ return frontend.EchoHtmxTemplRoutesTemplate()
}
func (e EchoTemplates) WebsocketImports() []byte {
diff --git a/cmd/template/framework/fiberServer.go b/cmd/template/backend/fiberServer.go
similarity index 85%
rename from cmd/template/framework/fiberServer.go
rename to cmd/template/backend/fiberServer.go
index 961e4d91..51d76c7d 100644
--- a/cmd/template/framework/fiberServer.go
+++ b/cmd/template/backend/fiberServer.go
@@ -1,9 +1,10 @@
-package framework
+package backend
import (
_ "embed"
"github.com/melkeydev/go-blueprint/cmd/template/advanced"
+ "github.com/melkeydev/go-blueprint/cmd/template/frontend"
)
//go:embed files/routes/fiber.go.tmpl
@@ -38,11 +39,11 @@ func (f FiberTemplates) TestHandler() []byte {
}
func (f FiberTemplates) HtmxTemplImports() []byte {
- return advanced.FiberHtmxTemplImportsTemplate()
+ return frontend.FiberHtmxTemplImportsTemplate()
}
func (f FiberTemplates) HtmxTemplRoutes() []byte {
- return advanced.FiberHtmxTemplRoutesTemplate()
+ return frontend.FiberHtmxTemplRoutesTemplate()
}
func (f FiberTemplates) WebsocketImports() []byte {
diff --git a/cmd/template/framework/files/README.md.tmpl b/cmd/template/backend/files/README.md.tmpl
similarity index 100%
rename from cmd/template/framework/files/README.md.tmpl
rename to cmd/template/backend/files/README.md.tmpl
diff --git a/cmd/template/framework/files/air.toml.tmpl b/cmd/template/backend/files/air.toml.tmpl
similarity index 81%
rename from cmd/template/framework/files/air.toml.tmpl
rename to cmd/template/backend/files/air.toml.tmpl
index 271c01c2..3447971c 100644
--- a/cmd/template/framework/files/air.toml.tmpl
+++ b/cmd/template/backend/files/air.toml.tmpl
@@ -9,12 +9,12 @@ tmp_dir = "tmp"
delay = 1000
exclude_dir = ["assets", "tmp", "vendor", "testdata", "node_modules"]
exclude_file = []
- exclude_regex = ["_test.go"{{if .AdvancedOptions.htmx}}, ".*_templ.go"{{end}}]
+ exclude_regex = ["_test.go"{{if (eq .FrontendFramework "htmx")}}, ".*_templ.go"{{end}}]
exclude_unchanged = false
follow_symlink = false
full_bin = ""
include_dir = []
- include_ext = ["go", "tpl", "tmpl", "html"{{if .AdvancedOptions.htmx}}, "templ"{{end}}]
+ include_ext = ["go", "tpl", "tmpl", "html"{{if (eq .FrontendFramework "htmx")}}, "templ"{{end}}]
include_file = []
kill_delay = "0s"
log = "build-errors.log"
diff --git a/cmd/template/framework/files/gitignore.tmpl b/cmd/template/backend/files/gitignore.tmpl
similarity index 92%
rename from cmd/template/framework/files/gitignore.tmpl
rename to cmd/template/backend/files/gitignore.tmpl
index d1d2eb5e..e9383df7 100644
--- a/cmd/template/framework/files/gitignore.tmpl
+++ b/cmd/template/backend/files/gitignore.tmpl
@@ -31,7 +31,7 @@ main
# OS X generated file
.DS_Store
-{{if ( .AdvancedOptions.tailwind )}}
+{{if ( .FrontendOptions.tailwind )}}
# Tailwind CSS
cmd/web/assets/css/output.css
diff --git a/cmd/template/framework/files/globalenv.tmpl b/cmd/template/backend/files/globalenv.tmpl
similarity index 100%
rename from cmd/template/framework/files/globalenv.tmpl
rename to cmd/template/backend/files/globalenv.tmpl
diff --git a/cmd/template/framework/files/main/fiber_main.go.tmpl b/cmd/template/backend/files/main/fiber_main.go.tmpl
similarity index 100%
rename from cmd/template/framework/files/main/fiber_main.go.tmpl
rename to cmd/template/backend/files/main/fiber_main.go.tmpl
diff --git a/cmd/template/framework/files/main/main.go.tmpl b/cmd/template/backend/files/main/main.go.tmpl
similarity index 100%
rename from cmd/template/framework/files/main/main.go.tmpl
rename to cmd/template/backend/files/main/main.go.tmpl
diff --git a/cmd/template/framework/files/makefile.tmpl b/cmd/template/backend/files/makefile.tmpl
similarity index 71%
rename from cmd/template/framework/files/makefile.tmpl
rename to cmd/template/backend/files/makefile.tmpl
index 27386e87..d4fe79d6 100644
--- a/cmd/template/framework/files/makefile.tmpl
+++ b/cmd/template/backend/files/makefile.tmpl
@@ -1,9 +1,8 @@
# Simple Makefile for a Go project
+# Build, test and run the application
+all: build test run
-# Build the application
-all: build test
-
-{{- if and (or .AdvancedOptions.htmx .AdvancedOptions.tailwind) (not .AdvancedOptions.react) }}
+{{- if (eq .FrontendFramework "htmx")}}
{{- if .OSCheck.UnixBased }}
templ-install:
@if ! command -v templ > /dev/null; then \
@@ -36,7 +35,7 @@ templ-install:
{{- end }}
{{- end }}
-{{- if and .AdvancedOptions.tailwind (not .AdvancedOptions.react) }}
+{{- if and (.FrontendOptions.tailwind) (not (eq .FrontendFramework "react")) }}
{{- if .OSCheck.UnixBased}}
tailwind-install:
{{ if .OSCheck.linux }}@if [ ! -f tailwindcss ]; then curl -sL https://github.com/tailwindlabs/tailwindcss/releases/download/v3.4.10/tailwindcss-linux-x64 -o tailwindcss; fi{{- end }}
@@ -47,20 +46,30 @@ tailwind-install:
@if not exist tailwindcss.exe powershell -ExecutionPolicy Bypass -Command "Invoke-WebRequest -Uri 'https://github.com/tailwindlabs/tailwindcss/releases/download/v3.4.10/tailwindcss-windows-x64.exe' -OutFile 'tailwindcss.exe'"{{- end }}
{{- end }}
-build:{{- if and .AdvancedOptions.tailwind (not .AdvancedOptions.react) }} tailwind-install{{- end }}{{- if and (or .AdvancedOptions.htmx .AdvancedOptions.tailwind) (not .AdvancedOptions.react) }} templ-install{{- end }}
+build:{{- if and .FrontendOptions.tailwind (not (eq .FrontendFramework "react")) }} tailwind-install{{- end }}{{- if and (or (eq .FrontendFramework "htmx") .FrontendOptions.tailwind) (not (eq .FrontendFramework "react")) }} templ-install{{- end }}
@echo "Building..."
- {{ if and (or .AdvancedOptions.htmx .AdvancedOptions.tailwind) (not .AdvancedOptions.react) }}@templ generate{{- end }}
- {{ if and .AdvancedOptions.tailwind (not .AdvancedOptions.react) }}@{{ if .OSCheck.UnixBased }}./tailwindcss{{ else }}.\tailwindcss.exe{{ end }} -i cmd/web/styles/input.css -o cmd/web/assets/css/output.css{{ end }}
+ {{ if and (or (eq .FrontendFramework "htmx") .FrontendOptions.tailwind) (not (eq .FrontendFramework "react")) }}@templ generate{{- end }}
+ {{ if and .FrontendOptions.tailwind (not (eq .FrontendFramework "react")) }}@{{ if .OSCheck.UnixBased }}./tailwindcss{{ else }}.\tailwindcss.exe{{ end }} -i cmd/web/styles/input.css -o cmd/web/assets/css/output.css{{ end }}
{{ if .OSCheck.UnixBased }}@{{- if and (.AdvancedOptions.docker) (eq .DBDriver "sqlite") }}CGO_ENABLED=1 GOOS=linux {{ end }}go build -o main cmd/api/main.go{{- else }}@go build -o main.exe cmd/api/main.go{{- end }}
# Run the application
-run:
- @go run cmd/api/main.go{{- if .AdvancedOptions.react }} &
- @npm install --prefer-offline --no-fund --prefix ./frontend
- @npm run dev --prefix ./frontend
+run: build
+ @echo "Starting server..."
+ @./main{{- if (eq .FrontendFramework "react") }} & \
+ SERVER_PID=$$!; \
+ sleep 2; \
+ if ps -p $$SERVER_PID > /dev/null; then \
+ echo "Server started successfully"; \
+ cd frontend && \
+ npm install --prefer-offline --no-fund && \
+ npm run dev; \
+ kill $$SERVER_PID; \
+ else \
+ echo "Server failed to start. Check the logs."; \
+ exit 1; \
+ fi
{{- end }}
-
{{- if or .AdvancedOptions.docker (and (ne .DBDriver "none") (ne .DBDriver "sqlite")) }}
{{- if .OSCheck.UnixBased }}
# Create DB container
@@ -106,6 +115,7 @@ itest:
# Clean the binary
clean:
@echo "Cleaning..."
+ @pkill main || true
@rm -f main
# Live Reload
@@ -138,4 +148,4 @@ watch:
}"
{{- end }}
-.PHONY: all build run test clean watch{{- if and (not .AdvancedOptions.react) .AdvancedOptions.tailwind }} tailwind-install{{- end }}{{- if and (ne .DBDriver "none") (ne .DBDriver "sqlite") }} docker-run docker-down itest{{- end }}{{- if and (or .AdvancedOptions.htmx .AdvancedOptions.tailwind) (not .AdvancedOptions.react) }} templ-install{{- end }}
+.PHONY: all build run test clean watch{{- if and (not (eq .FrontendFramework "react")) .FrontendOptions.tailwind }} tailwind-install{{- end }}{{- if and (ne .DBDriver "none") (ne .DBDriver "sqlite") }} docker-run docker-down itest{{- end }}{{- if and (or (eq .FrontendFramework "htmx") .FrontendOptions.tailwind) (not (eq .FrontendFramework "react")) }} templ-install{{- end }}
diff --git a/cmd/template/framework/files/routes/chi.go.tmpl b/cmd/template/backend/files/routes/chi.go.tmpl
similarity index 96%
rename from cmd/template/framework/files/routes/chi.go.tmpl
rename to cmd/template/backend/files/routes/chi.go.tmpl
index 73e46def..91f040e3 100644
--- a/cmd/template/framework/files/routes/chi.go.tmpl
+++ b/cmd/template/backend/files/routes/chi.go.tmpl
@@ -12,6 +12,7 @@ import (
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/go-chi/cors"
+ {{.FrontendTemplates.TemplateImports}}
{{.AdvancedTemplates.TemplateImports}}
)
@@ -35,6 +36,7 @@ func (s *Server) RegisterRoutes() http.Handler {
{{if .AdvancedOptions.websocket}}
r.Get("/websocket", s.websocketHandler)
{{end}}
+ {{.FrontendTemplates.TemplateRoutes}}
{{.AdvancedTemplates.TemplateRoutes}}
return r
diff --git a/cmd/template/framework/files/routes/echo.go.tmpl b/cmd/template/backend/files/routes/echo.go.tmpl
similarity index 95%
rename from cmd/template/framework/files/routes/echo.go.tmpl
rename to cmd/template/backend/files/routes/echo.go.tmpl
index eed481a9..ba1bb091 100644
--- a/cmd/template/framework/files/routes/echo.go.tmpl
+++ b/cmd/template/backend/files/routes/echo.go.tmpl
@@ -10,6 +10,7 @@ import (
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
+ {{.FrontendTemplates.TemplateImports}}
{{.AdvancedTemplates.TemplateImports}}
)
func (s *Server) RegisterRoutes() http.Handler {
@@ -25,6 +26,7 @@ func (s *Server) RegisterRoutes() http.Handler {
MaxAge: 300,
}))
+ {{.FrontendTemplates.TemplateRoutes}}
{{.AdvancedTemplates.TemplateRoutes}}
e.GET("/", s.HelloWorldHandler)
diff --git a/cmd/template/framework/files/routes/fiber.go.tmpl b/cmd/template/backend/files/routes/fiber.go.tmpl
similarity index 95%
rename from cmd/template/framework/files/routes/fiber.go.tmpl
rename to cmd/template/backend/files/routes/fiber.go.tmpl
index 950d3be1..26f8e7c1 100644
--- a/cmd/template/framework/files/routes/fiber.go.tmpl
+++ b/cmd/template/backend/files/routes/fiber.go.tmpl
@@ -9,6 +9,7 @@ import (
{{end}}
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/cors"
+ {{.FrontendTemplates.TemplateImports}}
{{.AdvancedTemplates.TemplateImports}}
)
@@ -30,6 +31,7 @@ func (s *FiberServer) RegisterFiberRoutes() {
s.App.Get("/websocket", websocket.New(s.websocketHandler))
{{end}}
+ {{.FrontendTemplates.TemplateRoutes}}
{{.AdvancedTemplates.TemplateRoutes}}
}
diff --git a/cmd/template/framework/files/routes/gin.go.tmpl b/cmd/template/backend/files/routes/gin.go.tmpl
similarity index 95%
rename from cmd/template/framework/files/routes/gin.go.tmpl
rename to cmd/template/backend/files/routes/gin.go.tmpl
index 774c844c..20622f95 100644
--- a/cmd/template/framework/files/routes/gin.go.tmpl
+++ b/cmd/template/backend/files/routes/gin.go.tmpl
@@ -11,6 +11,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/gin-contrib/cors"
+ {{.FrontendTemplates.TemplateImports}}
{{.AdvancedTemplates.TemplateImports}}
)
@@ -32,6 +33,7 @@ func (s *Server) RegisterRoutes() http.Handler {
r.GET("/websocket", s.websocketHandler)
{{end}}
+ {{.FrontendTemplates.TemplateRoutes}}
{{.AdvancedTemplates.TemplateRoutes}}
return r
diff --git a/cmd/template/framework/files/routes/gorilla.go.tmpl b/cmd/template/backend/files/routes/gorilla.go.tmpl
similarity index 96%
rename from cmd/template/framework/files/routes/gorilla.go.tmpl
rename to cmd/template/backend/files/routes/gorilla.go.tmpl
index 90dc5aeb..f71b005f 100644
--- a/cmd/template/framework/files/routes/gorilla.go.tmpl
+++ b/cmd/template/backend/files/routes/gorilla.go.tmpl
@@ -10,6 +10,7 @@ import (
{{end}}
"github.com/gorilla/mux"
+ {{.FrontendTemplates.TemplateImports}}
{{.AdvancedTemplates.TemplateImports}}
)
@@ -27,6 +28,7 @@ func (s *Server) RegisterRoutes() http.Handler {
r.HandleFunc("/websocket", s.websocketHandler)
{{end}}
+ {{.FrontendTemplates.TemplateRoutes}}
{{.AdvancedTemplates.TemplateRoutes}}
return r
diff --git a/cmd/template/framework/files/routes/standard_library.go.tmpl b/cmd/template/backend/files/routes/standard_library.go.tmpl
similarity index 97%
rename from cmd/template/framework/files/routes/standard_library.go.tmpl
rename to cmd/template/backend/files/routes/standard_library.go.tmpl
index 34564f0c..319bfcd7 100644
--- a/cmd/template/framework/files/routes/standard_library.go.tmpl
+++ b/cmd/template/backend/files/routes/standard_library.go.tmpl
@@ -9,6 +9,7 @@ import (
"time"
{{end}}
+ {{.FrontendTemplates.TemplateImports}}
{{.AdvancedTemplates.TemplateImports}}
)
@@ -23,6 +24,7 @@ func (s *Server) RegisterRoutes() http.Handler {
{{if .AdvancedOptions.websocket}}
mux.HandleFunc("/websocket", s.websocketHandler)
{{end}}
+ {{.FrontendTemplates.TemplateRoutes}}
{{.AdvancedTemplates.TemplateRoutes}}
// Wrap the mux with CORS middleware
diff --git a/cmd/template/framework/files/server/fiber.go.tmpl b/cmd/template/backend/files/server/fiber.go.tmpl
similarity index 100%
rename from cmd/template/framework/files/server/fiber.go.tmpl
rename to cmd/template/backend/files/server/fiber.go.tmpl
diff --git a/cmd/template/framework/files/server/standard_library.go.tmpl b/cmd/template/backend/files/server/standard_library.go.tmpl
similarity index 100%
rename from cmd/template/framework/files/server/standard_library.go.tmpl
rename to cmd/template/backend/files/server/standard_library.go.tmpl
diff --git a/cmd/template/framework/files/tests/default-test.go.tmpl b/cmd/template/backend/files/tests/default-test.go.tmpl
similarity index 100%
rename from cmd/template/framework/files/tests/default-test.go.tmpl
rename to cmd/template/backend/files/tests/default-test.go.tmpl
diff --git a/cmd/template/framework/files/tests/echo-test.go.tmpl b/cmd/template/backend/files/tests/echo-test.go.tmpl
similarity index 100%
rename from cmd/template/framework/files/tests/echo-test.go.tmpl
rename to cmd/template/backend/files/tests/echo-test.go.tmpl
diff --git a/cmd/template/framework/files/tests/fiber-test.go.tmpl b/cmd/template/backend/files/tests/fiber-test.go.tmpl
similarity index 100%
rename from cmd/template/framework/files/tests/fiber-test.go.tmpl
rename to cmd/template/backend/files/tests/fiber-test.go.tmpl
diff --git a/cmd/template/framework/files/tests/gin-test.go.tmpl b/cmd/template/backend/files/tests/gin-test.go.tmpl
similarity index 100%
rename from cmd/template/framework/files/tests/gin-test.go.tmpl
rename to cmd/template/backend/files/tests/gin-test.go.tmpl
diff --git a/cmd/template/framework/ginRoutes.go b/cmd/template/backend/ginRoutes.go
similarity index 83%
rename from cmd/template/framework/ginRoutes.go
rename to cmd/template/backend/ginRoutes.go
index 1a952d5e..9319e36d 100644
--- a/cmd/template/framework/ginRoutes.go
+++ b/cmd/template/backend/ginRoutes.go
@@ -1,9 +1,10 @@
-package framework
+package backend
import (
_ "embed"
"github.com/melkeydev/go-blueprint/cmd/template/advanced"
+ "github.com/melkeydev/go-blueprint/cmd/template/frontend"
)
//go:embed files/routes/gin.go.tmpl
@@ -33,11 +34,11 @@ func (g GinTemplates) TestHandler() []byte {
}
func (g GinTemplates) HtmxTemplImports() []byte {
- return advanced.GinHtmxTemplImportsTemplate()
+ return frontend.GinHtmxTemplImportsTemplate()
}
func (g GinTemplates) HtmxTemplRoutes() []byte {
- return advanced.GinHtmxTemplRoutesTemplate()
+ return frontend.GinHtmxTemplRoutesTemplate()
}
func (g GinTemplates) WebsocketImports() []byte {
diff --git a/cmd/template/framework/gorillaRoutes.go b/cmd/template/backend/gorillaRoutes.go
similarity index 83%
rename from cmd/template/framework/gorillaRoutes.go
rename to cmd/template/backend/gorillaRoutes.go
index aa2711ff..b928bef9 100644
--- a/cmd/template/framework/gorillaRoutes.go
+++ b/cmd/template/backend/gorillaRoutes.go
@@ -1,9 +1,10 @@
-package framework
+package backend
import (
_ "embed"
"github.com/melkeydev/go-blueprint/cmd/template/advanced"
+ "github.com/melkeydev/go-blueprint/cmd/template/frontend"
)
//go:embed files/routes/gorilla.go.tmpl
@@ -33,11 +34,11 @@ func (g GorillaTemplates) TestHandler() []byte {
}
func (g GorillaTemplates) HtmxTemplImports() []byte {
- return advanced.StdLibHtmxTemplImportsTemplate()
+ return frontend.StdLibHtmxTemplImportsTemplate()
}
func (g GorillaTemplates) HtmxTemplRoutes() []byte {
- return advanced.GorillaHtmxTemplRoutesTemplate()
+ return frontend.GorillaHtmxTemplRoutesTemplate()
}
func (g GorillaTemplates) WebsocketImports() []byte {
diff --git a/cmd/template/framework/httpRoutes.go b/cmd/template/backend/httpRoutes.go
similarity index 85%
rename from cmd/template/framework/httpRoutes.go
rename to cmd/template/backend/httpRoutes.go
index b0170a82..56307c5c 100644
--- a/cmd/template/framework/httpRoutes.go
+++ b/cmd/template/backend/httpRoutes.go
@@ -1,9 +1,10 @@
-package framework
+package backend
import (
_ "embed"
"github.com/melkeydev/go-blueprint/cmd/template/advanced"
+ "github.com/melkeydev/go-blueprint/cmd/template/frontend"
)
//go:embed files/routes/standard_library.go.tmpl
@@ -36,11 +37,11 @@ func (s StandardLibTemplate) TestHandler() []byte {
}
func (s StandardLibTemplate) HtmxTemplImports() []byte {
- return advanced.StdLibHtmxTemplImportsTemplate()
+ return frontend.StdLibHtmxTemplImportsTemplate()
}
func (s StandardLibTemplate) HtmxTemplRoutes() []byte {
- return advanced.StdLibHtmxTemplRoutesTemplate()
+ return frontend.StdLibHtmxTemplRoutesTemplate()
}
func (s StandardLibTemplate) WebsocketImports() []byte {
diff --git a/cmd/template/framework/main.go b/cmd/template/backend/main.go
similarity index 97%
rename from cmd/template/framework/main.go
rename to cmd/template/backend/main.go
index 0611822b..b314ee70 100644
--- a/cmd/template/framework/main.go
+++ b/cmd/template/backend/main.go
@@ -1,6 +1,6 @@
// Package template provides utility functions that
// help with the templating of created files.
-package framework
+package backend
import (
_ "embed"
diff --git a/cmd/template/docker/files/docker-compose/mongo.tmpl b/cmd/template/docker/files/docker-compose/mongo.tmpl
index 9da016df..9c14e268 100644
--- a/cmd/template/docker/files/docker-compose/mongo.tmpl
+++ b/cmd/template/docker/files/docker-compose/mongo.tmpl
@@ -21,7 +21,7 @@ services:
networks:
- blueprint
{{- end }}
-{{- if and .AdvancedOptions.react .AdvancedOptions.docker }}
+{{- if and (eq .FrontendFramework "react") (.AdvancedOptions.docker) }}
frontend:
build:
context: .
diff --git a/cmd/template/docker/files/docker-compose/mysql.tmpl b/cmd/template/docker/files/docker-compose/mysql.tmpl
index ad748567..166cac8f 100644
--- a/cmd/template/docker/files/docker-compose/mysql.tmpl
+++ b/cmd/template/docker/files/docker-compose/mysql.tmpl
@@ -22,7 +22,7 @@ services:
networks:
- blueprint
{{- end }}
-{{- if and .AdvancedOptions.react .AdvancedOptions.docker }}
+{{- if and (eq .FrontendFramework "react") (.AdvancedOptions.docker) }}
frontend:
build:
context: .
diff --git a/cmd/template/docker/files/docker-compose/postgres.tmpl b/cmd/template/docker/files/docker-compose/postgres.tmpl
index 638f31a3..6953d51f 100644
--- a/cmd/template/docker/files/docker-compose/postgres.tmpl
+++ b/cmd/template/docker/files/docker-compose/postgres.tmpl
@@ -23,7 +23,7 @@ services:
networks:
- blueprint
{{- end }}
-{{- if and .AdvancedOptions.react .AdvancedOptions.docker }}
+{{- if and (eq .FrontendFramework "react") (.AdvancedOptions.docker) }}
frontend:
build:
context: .
diff --git a/cmd/template/docker/files/docker-compose/redis.tmpl b/cmd/template/docker/files/docker-compose/redis.tmpl
index 73bdf48a..73d0b7bb 100644
--- a/cmd/template/docker/files/docker-compose/redis.tmpl
+++ b/cmd/template/docker/files/docker-compose/redis.tmpl
@@ -21,7 +21,7 @@ services:
networks:
- blueprint
{{- end }}
-{{- if and .AdvancedOptions.react .AdvancedOptions.docker }}
+{{- if and (eq .FrontendFramework "react") (.AdvancedOptions.docker) }}
frontend:
build:
context: .
diff --git a/cmd/template/docker/files/docker-compose/scylla.tmpl b/cmd/template/docker/files/docker-compose/scylla.tmpl
index 682a0193..15468ec7 100644
--- a/cmd/template/docker/files/docker-compose/scylla.tmpl
+++ b/cmd/template/docker/files/docker-compose/scylla.tmpl
@@ -24,7 +24,7 @@ services:
networks:
- blueprint
{{- end }}
-{{- if and .AdvancedOptions.react .AdvancedOptions.docker }}
+{{- if and (eq .FrontendFramework "react") (.AdvancedOptions.docker) }}
frontend:
build:
context: .
@@ -67,4 +67,4 @@ volumes:
{{- if .AdvancedOptions.docker }}
networks:
blueprint:
-{{- end }}
\ No newline at end of file
+{{- end }}
diff --git a/cmd/template/framework/files/routes/http_router.go.tmpl b/cmd/template/framework/files/routes/http_router.go.tmpl
deleted file mode 100644
index 5a494d9e..00000000
--- a/cmd/template/framework/files/routes/http_router.go.tmpl
+++ /dev/null
@@ -1,103 +0,0 @@
-package server
-
-import (
- "encoding/json"
- "log"
- "net/http"
- {{if .AdvancedOptions.websocket}}
- "fmt"
- "time"
- {{end}}
-
- "github.com/julienschmidt/httprouter"
- {{.AdvancedTemplates.TemplateImports}}
-)
-
-func (s *Server) RegisterRoutes() http.Handler {
- r := httprouter.New()
-
- // Wrap all routes with CORS middleware
- corsWrapper := s.corsMiddleware(r)
-
- r.HandlerFunc(http.MethodGet, "/", s.HelloWorldHandler)
- {{if ne .DBDriver "none"}}
- r.HandlerFunc(http.MethodGet, "/health", s.healthHandler)
- {{end}}
- {{if .AdvancedOptions.websocket}}
- r.HandlerFunc(http.MethodGet, "/websocket", s.websocketHandler)
- {{end}}
- {{.AdvancedTemplates.TemplateRoutes}}
-
- return corsWrapper
-}
-
-// CORS middleware
-func (s *Server) corsMiddleware(next http.Handler) http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- // CORS headers
- w.Header().Set("Access-Control-Allow-Origin", "*") // Use "*" for all origins, or replace with specific origins
- w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, PATCH")
- w.Header().Set("Access-Control-Allow-Headers", "Accept, Authorization, Content-Type, X-CSRF-Token")
- w.Header().Set("Access-Control-Allow-Credentials", "false") // Set to "true" if credentials are needed
-
- // Handle preflight OPTIONS requests
- if r.Method == http.MethodOptions {
- w.WriteHeader(http.StatusNoContent)
- return
- }
-
- next.ServeHTTP(w, r)
- })
-}
-
-func (s *Server) HelloWorldHandler(w http.ResponseWriter, r *http.Request) {
- resp := make(map[string]string)
- resp["message"] = "Hello World"
-
- jsonResp, err := json.Marshal(resp)
- if err != nil {
- log.Fatalf("error handling JSON marshal. Err: %v", err)
- }
-
- _, _ = w.Write(jsonResp)
-}
-
-{{if ne .DBDriver "none"}}
-func (s *Server) healthHandler(w http.ResponseWriter, r *http.Request) {
- jsonResp, err := json.Marshal(s.db.Health())
-
- if err != nil {
- log.Fatalf("error handling JSON marshal. Err: %v", err)
- }
-
- _, _ = w.Write(jsonResp)
-}
-{{end}}
-
-{{if .AdvancedOptions.websocket}}
-func (s *Server) websocketHandler(w http.ResponseWriter, r *http.Request) {
- socket, err := websocket.Accept(w, r, nil)
-
- if err != nil {
- log.Printf("could not open websocket: %v", err)
- _, _ = w.Write([]byte("could not open websocket"))
- w.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- defer socket.Close(websocket.StatusGoingAway, "server closing websocket")
-
- ctx := r.Context()
- socketCtx := socket.CloseRead(ctx)
-
- for {
- payload := fmt.Sprintf("server timestamp: %d", time.Now().UnixNano())
- err := socket.Write(socketCtx, websocket.MessageText, []byte(payload))
- if err != nil {
- break
- }
- time.Sleep(time.Second * 2)
- }
-}
-{{end}}
-
diff --git a/cmd/template/framework/routerRoutes.go b/cmd/template/framework/routerRoutes.go
deleted file mode 100644
index f9e92133..00000000
--- a/cmd/template/framework/routerRoutes.go
+++ /dev/null
@@ -1,44 +0,0 @@
-package framework
-
-import (
- _ "embed"
-
- "github.com/melkeydev/go-blueprint/cmd/template/advanced"
-)
-
-//go:embed files/routes/http_router.go.tmpl
-var httpRouterRoutesTemplate []byte
-
-//go:embed files/tests/default-test.go.tmpl
-var httpRouterTestHandlerTemplate []byte
-
-// RouterTemplates contains the methods used for building
-// an app that uses [github.com/julienschmidt/httprouter]
-type RouterTemplates struct{}
-
-func (r RouterTemplates) Main() []byte {
- return mainTemplate
-}
-func (r RouterTemplates) Server() []byte {
- return standardServerTemplate
-}
-
-func (r RouterTemplates) Routes() []byte {
- return httpRouterRoutesTemplate
-}
-
-func (r RouterTemplates) TestHandler() []byte {
- return httpRouterTestHandlerTemplate
-}
-
-func (r RouterTemplates) HtmxTemplImports() []byte {
- return advanced.StdLibHtmxTemplImportsTemplate()
-}
-
-func (r RouterTemplates) HtmxTemplRoutes() []byte {
- return advanced.HttpRouterHtmxTemplRoutesTemplate()
-}
-
-func (r RouterTemplates) WebsocketImports() []byte {
- return advanced.StdLibWebsocketTemplImportsTemplate()
-}
diff --git a/cmd/template/advanced/files/htmx/base.templ.tmpl b/cmd/template/frontend/files/htmx/base.templ.tmpl
similarity index 66%
rename from cmd/template/advanced/files/htmx/base.templ.tmpl
rename to cmd/template/frontend/files/htmx/base.templ.tmpl
index 1bbce906..d3d149c0 100644
--- a/cmd/template/advanced/files/htmx/base.templ.tmpl
+++ b/cmd/template/frontend/files/htmx/base.templ.tmpl
@@ -2,7 +2,7 @@ package web
templ Base() {
-
+
@@ -10,8 +10,8 @@ templ Base() {
-
-
+
+
{ children... }
diff --git a/cmd/template/advanced/files/htmx/efs.go.tmpl b/cmd/template/frontend/files/htmx/efs.go.tmpl
similarity index 100%
rename from cmd/template/advanced/files/htmx/efs.go.tmpl
rename to cmd/template/frontend/files/htmx/efs.go.tmpl
diff --git a/cmd/template/advanced/files/htmx/hello.go.tmpl b/cmd/template/frontend/files/htmx/hello.go.tmpl
similarity index 100%
rename from cmd/template/advanced/files/htmx/hello.go.tmpl
rename to cmd/template/frontend/files/htmx/hello.go.tmpl
diff --git a/cmd/template/advanced/files/htmx/hello.templ.tmpl b/cmd/template/frontend/files/htmx/hello.templ.tmpl
similarity index 69%
rename from cmd/template/advanced/files/htmx/hello.templ.tmpl
rename to cmd/template/frontend/files/htmx/hello.templ.tmpl
index 35d97466..68b90888 100644
--- a/cmd/template/advanced/files/htmx/hello.templ.tmpl
+++ b/cmd/template/frontend/files/htmx/hello.templ.tmpl
@@ -3,15 +3,15 @@ package web
templ HelloForm() {
@Base() {
}
}
templ HelloPost(name string) {
-
+
Hello, { name }
}
diff --git a/cmd/template/advanced/files/htmx/hello_fiber.go.tmpl b/cmd/template/frontend/files/htmx/hello_fiber.go.tmpl
similarity index 100%
rename from cmd/template/advanced/files/htmx/hello_fiber.go.tmpl
rename to cmd/template/frontend/files/htmx/hello_fiber.go.tmpl
diff --git a/cmd/template/advanced/files/htmx/htmx.min.js.tmpl b/cmd/template/frontend/files/htmx/htmx.min.js.tmpl
similarity index 100%
rename from cmd/template/advanced/files/htmx/htmx.min.js.tmpl
rename to cmd/template/frontend/files/htmx/htmx.min.js.tmpl
diff --git a/cmd/template/advanced/files/htmx/imports/fiber.tmpl b/cmd/template/frontend/files/htmx/imports/fiber.tmpl
similarity index 100%
rename from cmd/template/advanced/files/htmx/imports/fiber.tmpl
rename to cmd/template/frontend/files/htmx/imports/fiber.tmpl
diff --git a/cmd/template/advanced/files/htmx/imports/gin.tmpl b/cmd/template/frontend/files/htmx/imports/gin.tmpl
similarity index 100%
rename from cmd/template/advanced/files/htmx/imports/gin.tmpl
rename to cmd/template/frontend/files/htmx/imports/gin.tmpl
diff --git a/cmd/template/advanced/files/htmx/imports/standard_library.tmpl b/cmd/template/frontend/files/htmx/imports/standard_library.tmpl
similarity index 100%
rename from cmd/template/advanced/files/htmx/imports/standard_library.tmpl
rename to cmd/template/frontend/files/htmx/imports/standard_library.tmpl
diff --git a/cmd/template/advanced/files/htmx/routes/chi.tmpl b/cmd/template/frontend/files/htmx/routes/chi.tmpl
similarity index 100%
rename from cmd/template/advanced/files/htmx/routes/chi.tmpl
rename to cmd/template/frontend/files/htmx/routes/chi.tmpl
diff --git a/cmd/template/advanced/files/htmx/routes/echo.tmpl b/cmd/template/frontend/files/htmx/routes/echo.tmpl
similarity index 100%
rename from cmd/template/advanced/files/htmx/routes/echo.tmpl
rename to cmd/template/frontend/files/htmx/routes/echo.tmpl
diff --git a/cmd/template/advanced/files/htmx/routes/fiber.tmpl b/cmd/template/frontend/files/htmx/routes/fiber.tmpl
similarity index 100%
rename from cmd/template/advanced/files/htmx/routes/fiber.tmpl
rename to cmd/template/frontend/files/htmx/routes/fiber.tmpl
diff --git a/cmd/template/advanced/files/htmx/routes/gin.tmpl b/cmd/template/frontend/files/htmx/routes/gin.tmpl
similarity index 100%
rename from cmd/template/advanced/files/htmx/routes/gin.tmpl
rename to cmd/template/frontend/files/htmx/routes/gin.tmpl
diff --git a/cmd/template/advanced/files/htmx/routes/gorilla.tmpl b/cmd/template/frontend/files/htmx/routes/gorilla.tmpl
similarity index 100%
rename from cmd/template/advanced/files/htmx/routes/gorilla.tmpl
rename to cmd/template/frontend/files/htmx/routes/gorilla.tmpl
diff --git a/cmd/template/advanced/files/htmx/routes/http_router.tmpl b/cmd/template/frontend/files/htmx/routes/http_router.tmpl
similarity index 100%
rename from cmd/template/advanced/files/htmx/routes/http_router.tmpl
rename to cmd/template/frontend/files/htmx/routes/http_router.tmpl
diff --git a/cmd/template/advanced/files/htmx/routes/standard_library.tmpl b/cmd/template/frontend/files/htmx/routes/standard_library.tmpl
similarity index 100%
rename from cmd/template/advanced/files/htmx/routes/standard_library.tmpl
rename to cmd/template/frontend/files/htmx/routes/standard_library.tmpl
diff --git a/cmd/template/advanced/files/react/app.tsx.tmpl b/cmd/template/frontend/files/react/app.tsx.tmpl
similarity index 100%
rename from cmd/template/advanced/files/react/app.tsx.tmpl
rename to cmd/template/frontend/files/react/app.tsx.tmpl
diff --git a/cmd/template/advanced/files/react/tailwind/app.tsx.tmpl b/cmd/template/frontend/files/react/tailwind/app.tsx.tmpl
similarity index 100%
rename from cmd/template/advanced/files/react/tailwind/app.tsx.tmpl
rename to cmd/template/frontend/files/react/tailwind/app.tsx.tmpl
diff --git a/cmd/template/advanced/files/react/tailwind/index.css.tmpl b/cmd/template/frontend/files/react/tailwind/index.css.tmpl
similarity index 100%
rename from cmd/template/advanced/files/react/tailwind/index.css.tmpl
rename to cmd/template/frontend/files/react/tailwind/index.css.tmpl
diff --git a/cmd/template/advanced/files/react/tailwind/tailwind.config.js.tmpl b/cmd/template/frontend/files/react/tailwind/tailwind.config.js.tmpl
similarity index 100%
rename from cmd/template/advanced/files/react/tailwind/tailwind.config.js.tmpl
rename to cmd/template/frontend/files/react/tailwind/tailwind.config.js.tmpl
diff --git a/cmd/template/advanced/files/tailwind/input.css.tmpl b/cmd/template/frontend/files/tailwind/input.css.tmpl
similarity index 100%
rename from cmd/template/advanced/files/tailwind/input.css.tmpl
rename to cmd/template/frontend/files/tailwind/input.css.tmpl
diff --git a/cmd/template/advanced/files/tailwind/output.css.tmpl b/cmd/template/frontend/files/tailwind/output.css.tmpl
similarity index 100%
rename from cmd/template/advanced/files/tailwind/output.css.tmpl
rename to cmd/template/frontend/files/tailwind/output.css.tmpl
diff --git a/cmd/template/advanced/files/tailwind/tailwind.config.js.tmpl b/cmd/template/frontend/files/tailwind/tailwind.config.js.tmpl
similarity index 100%
rename from cmd/template/advanced/files/tailwind/tailwind.config.js.tmpl
rename to cmd/template/frontend/files/tailwind/tailwind.config.js.tmpl
diff --git a/cmd/template/frontend/routes.go b/cmd/template/frontend/routes.go
new file mode 100644
index 00000000..8a221301
--- /dev/null
+++ b/cmd/template/frontend/routes.go
@@ -0,0 +1,166 @@
+package frontend
+
+import (
+ _ "embed"
+)
+
+//go:embed files/htmx/hello.templ.tmpl
+var helloTemplTemplate []byte
+
+//go:embed files/htmx/base.templ.tmpl
+var baseTemplTemplate []byte
+
+//go:embed files/tailwind/tailwind.config.js.tmpl
+var tailwindConfigTemplate []byte
+
+//go:embed files/react/tailwind/tailwind.config.js.tmpl
+var reactTailwindConfigTemplate []byte
+
+//go:embed files/react/tailwind/index.css.tmpl
+var inputCssTemplateReact []byte
+
+//go:embed files/react/tailwind/app.tsx.tmpl
+var reactTailwindAppFile []byte
+
+//go:embed files/react/app.tsx.tmpl
+var reactAppFile []byte
+
+//go:embed files/tailwind/input.css.tmpl
+var inputCssTemplate []byte
+
+//go:embed files/tailwind/output.css.tmpl
+var outputCssTemplate []byte
+
+//go:embed files/htmx/htmx.min.js.tmpl
+var htmxMinJsTemplate []byte
+
+//go:embed files/htmx/efs.go.tmpl
+var efsTemplate []byte
+
+//go:embed files/htmx/hello.go.tmpl
+var helloGoTemplate []byte
+
+//go:embed files/htmx/hello_fiber.go.tmpl
+var helloFiberGoTemplate []byte
+
+//go:embed files/htmx/routes/http_router.tmpl
+var httpRouterHtmxTemplRoutes []byte
+
+//go:embed files/htmx/routes/standard_library.tmpl
+var stdLibHtmxTemplRoutes []byte
+
+//go:embed files/htmx/imports/standard_library.tmpl
+var stdLibHtmxTemplImports []byte
+
+//go:embed files/htmx/routes/chi.tmpl
+var chiHtmxTemplRoutes []byte
+
+//go:embed files/htmx/routes/gin.tmpl
+var ginHtmxTemplRoutes []byte
+
+//go:embed files/htmx/imports/gin.tmpl
+var ginHtmxTemplImports []byte
+
+//go:embed files/htmx/routes/gorilla.tmpl
+var gorillaHtmxTemplRoutes []byte
+
+//go:embed files/htmx/routes/echo.tmpl
+var echoHtmxTemplRoutes []byte
+
+//go:embed files/htmx/routes/fiber.tmpl
+var fiberHtmxTemplRoutes []byte
+
+//go:embed files/htmx/imports/fiber.tmpl
+var fiberHtmxTemplImports []byte
+
+func EchoHtmxTemplRoutesTemplate() []byte {
+ return echoHtmxTemplRoutes
+}
+
+func GorillaHtmxTemplRoutesTemplate() []byte {
+ return gorillaHtmxTemplRoutes
+}
+
+func ChiHtmxTemplRoutesTemplate() []byte {
+ return chiHtmxTemplRoutes
+}
+
+func GinHtmxTemplRoutesTemplate() []byte {
+ return ginHtmxTemplRoutes
+}
+
+func HttpRouterHtmxTemplRoutesTemplate() []byte {
+ return httpRouterHtmxTemplRoutes
+}
+
+func StdLibHtmxTemplRoutesTemplate() []byte {
+ return stdLibHtmxTemplRoutes
+}
+
+func StdLibHtmxTemplImportsTemplate() []byte {
+ return stdLibHtmxTemplImports
+}
+
+func HelloTemplTemplate() []byte {
+ return helloTemplTemplate
+}
+
+func BaseTemplTemplate() []byte {
+ return baseTemplTemplate
+}
+
+func TailwindConfigTemplate() []byte {
+ return tailwindConfigTemplate
+}
+
+func ReactTailwindConfigTemplate() []byte {
+ return reactTailwindConfigTemplate
+}
+
+func ReactTailwindAppfile() []byte {
+ return reactTailwindAppFile
+}
+
+func ReactAppfile() []byte {
+ return reactAppFile
+}
+
+func InputCssTemplateReact() []byte {
+ return inputCssTemplateReact
+}
+
+func InputCssTemplate() []byte {
+ return inputCssTemplate
+}
+
+func OutputCssTemplate() []byte {
+ return outputCssTemplate
+}
+
+func HtmxJSTemplate() []byte {
+ return htmxMinJsTemplate
+}
+
+func EfsTemplate() []byte {
+ return efsTemplate
+}
+
+func HelloGoTemplate() []byte {
+ return helloGoTemplate
+}
+
+func HelloFiberGoTemplate() []byte {
+ return helloFiberGoTemplate
+}
+
+func FiberHtmxTemplRoutesTemplate() []byte {
+ return fiberHtmxTemplRoutes
+}
+
+func FiberHtmxTemplImportsTemplate() []byte {
+ return fiberHtmxTemplImports
+}
+
+func GinHtmxTemplImportsTemplate() []byte {
+ return ginHtmxTemplImports
+}
diff --git a/cmd/template/globalEnv.go b/cmd/template/globalEnv.go
index 9645fb69..b44c2ecc 100644
--- a/cmd/template/globalEnv.go
+++ b/cmd/template/globalEnv.go
@@ -4,7 +4,7 @@ import (
_ "embed"
)
-//go:embed framework/files/globalenv.tmpl
+//go:embed backend/files/globalenv.tmpl
var globalEnvTemplate []byte
func GlobalEnvTemplate() []byte {
diff --git a/cmd/utils/utils.go b/cmd/utils/utils.go
index 7ba4dd34..ad09cdf1 100644
--- a/cmd/utils/utils.go
+++ b/cmd/utils/utils.go
@@ -19,30 +19,79 @@ const ProgramName = "go-blueprint"
func NonInteractiveCommand(use string, flagSet *pflag.FlagSet) string {
nonInteractiveCommand := fmt.Sprintf("%s %s", ProgramName, use)
- visitFn := func(flag *pflag.Flag) {
- if flag.Name != "help" {
- if flag.Name == "feature" {
- featureFlagsString := ""
- // Creates string representation for the feature flags to be
- // concatenated with the nonInteractiveCommand
- for _, k := range strings.Split(flag.Value.String(), ",") {
- if k != "" {
- featureFlagsString += fmt.Sprintf(" --feature %s", k)
- }
- }
- nonInteractiveCommand += featureFlagsString
- } else if flag.Value.Type() == "bool" {
+ // Helper function to get flag prefix (-n or --name)
+ getFlagPrefix := func(flag *pflag.Flag) string {
+ if flag.Shorthand != "" {
+ return fmt.Sprintf("-%s", flag.Shorthand)
+ }
+ return fmt.Sprintf("--%s", flag.Name)
+ }
+
+ // name flag
+ flagSet.VisitAll(func(flag *pflag.Flag) {
+ if flag.Name == "name" && flag.Value.String() != "" {
+ nonInteractiveCommand = fmt.Sprintf("%s %s %s", nonInteractiveCommand,
+ getFlagPrefix(flag), flag.Value.String())
+ }
+ })
+
+ // main flags (excluding name, git, feature, frontend-advanced, and advanced)
+ flagSet.VisitAll(func(flag *pflag.Flag) {
+ if flag.Name != "help" && flag.Name != "feature" &&
+ flag.Name != "frontend-advanced" && flag.Name != "git" &&
+ flag.Name != "name" && flag.Name != "advanced" {
+ if flag.Value.Type() == "bool" {
if flag.Value.String() == "true" {
- nonInteractiveCommand = fmt.Sprintf("%s --%s", nonInteractiveCommand, flag.Name)
+ nonInteractiveCommand = fmt.Sprintf("%s %s", nonInteractiveCommand,
+ getFlagPrefix(flag))
}
} else {
- nonInteractiveCommand = fmt.Sprintf("%s --%s %s", nonInteractiveCommand, flag.Name, flag.Value.String())
+ if flag.Value.String() != "" {
+ nonInteractiveCommand = fmt.Sprintf("%s %s %s", nonInteractiveCommand,
+ getFlagPrefix(flag), flag.Value.String())
+ }
}
}
+ })
+
+ // frontend-advanced flags
+ flagSet.VisitAll(func(flag *pflag.Flag) {
+ if flag.Name == "frontend-advanced" && flag.Value.String() != "" {
+ nonInteractiveCommand = fmt.Sprintf("%s %s %s", nonInteractiveCommand,
+ getFlagPrefix(flag), flag.Value.String())
+ }
+ })
+
+ // advanced flag and features together
+ var hasAdvanced bool
+ flagSet.VisitAll(func(flag *pflag.Flag) {
+ if flag.Name == "advanced" && flag.Value.String() == "true" {
+ hasAdvanced = true
+ nonInteractiveCommand = fmt.Sprintf("%s %s", nonInteractiveCommand,
+ getFlagPrefix(flag))
+ }
+ })
+
+ if hasAdvanced {
+ flagSet.VisitAll(func(flag *pflag.Flag) {
+ if flag.Name == "feature" {
+ featureFlags := strings.Split(flag.Value.String(), ",")
+ for _, k := range featureFlags {
+ if k != "" {
+ nonInteractiveCommand = fmt.Sprintf("%s --feature %s", nonInteractiveCommand, k)
+ }
+ }
+ }
+ })
}
- flagSet.SortFlags = false
- flagSet.VisitAll(visitFn)
+ // git flag
+ flagSet.VisitAll(func(flag *pflag.Flag) {
+ if flag.Name == "git" && flag.Value.String() != "" {
+ nonInteractiveCommand = fmt.Sprintf("%s %s %s", nonInteractiveCommand,
+ getFlagPrefix(flag), flag.Value.String())
+ }
+ })
return nonInteractiveCommand
}
diff --git a/contributors.yml b/contributors.yml
index 74c13442..aa5407a0 100644
--- a/contributors.yml
+++ b/contributors.yml
@@ -17,7 +17,9 @@
- briancbarrow
- arafays
- LrsK
+- alexandear
- juleszs
+- Sakelig
- vadhe
- Patel-Raj
- PrajvalBadiger
@@ -25,12 +27,10 @@
- pellizzetti
- Owbird
- Jamlie
-- alexandear
- NimishKashyap
- narasaka
- mubashiroliyantakath
- abhishekmj303
-- Sakelig
- reavessm
- young-steveo
- sibteali786
@@ -39,6 +39,7 @@
- vsnaichuk
- Waldeedle
- jpx40
+- leakedmemory
- nhlmg93
- rustafariandev
- s0up4200
diff --git a/docs/docs/advanced-flag/advanced-flag.md b/docs/docs/advanced-flag/advanced-flag.md
index 124ef6b9..0ecefedb 100644
--- a/docs/docs/advanced-flag/advanced-flag.md
+++ b/docs/docs/advanced-flag/advanced-flag.md
@@ -1,9 +1,6 @@
# Advanced Flag in Blueprint
-The `--advanced` flag in Blueprint serves as a switch to enable additional features during project creation. It is applied with the `create` command and unlocks the following features:
-
-- **HTMX Support using Templ:**
-Enables the integration of HTMX support for dynamic web pages using Templ.
+The `--advanced` or `-a` flag in Blueprint serves as a switch to enable additional features during project creation. It is applied with the `create` command and unlocks the following features:
- **CI/CD Workflow Setup using GitHub Actions:**
Automates the setup of a CI/CD workflow using GitHub Actions.
@@ -11,31 +8,19 @@ Automates the setup of a CI/CD workflow using GitHub Actions.
- **Websocket Support:**
WebSocket endpoint that sends continuous data streams through the WS protocol.
-- **Tailwind:**
-Adds Tailwind CSS support to the project.
-
- **Docker:**
Docker configuration for go project.
-- **React:**
-Frontend written in TypeScript, including an example fetch request to the backend.
-
-
To utilize the `--advanced` flag, use the following command:
```bash
-go-blueprint create --name --framework --driver --advanced
+go-blueprint create -n -b -driver -a
```
-By including the `--advanced` flag, users can choose one or all of the advanced features. The flag enhances the simplicity of Blueprint while offering flexibility for users who require additional functionality.
-
-To recreate the project using the same configuration semi-interactively, use the following command:
-```bash
-go-blueprint create --name my-project --framework chi --driver mysql --advanced
-```
+By including the `--advanced` flag, users can choose one or all of the advanced features. The flag enhances the simplicity of Blueprint while offering flexibility for users who require additional functionality.
Non-Interactive Setup is also possible:
```bash
-go-blueprint create --name my-project --framework chi --driver mysql --advanced --feature htmx --feature githubaction --feature websocket --feature tailwind
+go-blueprint create -n my_project -b standard-library -d redis -a --feature docker --feature githubaction --feature websocket -g commit
```
diff --git a/docs/docs/advanced-flag/goreleaser.md b/docs/docs/advanced-flag/goreleaser.md
index 43f1f2c5..b1c1dcb3 100644
--- a/docs/docs/advanced-flag/goreleaser.md
+++ b/docs/docs/advanced-flag/goreleaser.md
@@ -32,7 +32,7 @@ The job outlined in this workflow includes the following steps:
Fetches the project's codebase from the repository.
2. **Go Setup:**
- Configures the Go environment with version 1.21.x.
+ Configures the Go environment with version 1.23.x.
3. **Build and Test:**
Builds the project using `go build` and runs tests across all packages (`./...`) using `go test`.
diff --git a/docs/docs/advanced-flag/websocket.md b/docs/docs/advanced-flag/websocket.md
index c7bea3ad..64e36a10 100644
--- a/docs/docs/advanced-flag/websocket.md
+++ b/docs/docs/advanced-flag/websocket.md
@@ -1,4 +1,4 @@
-A `/websocket` endpoint is added in `routes.go` to facilitate websocket connections. Upon accessing this endpoint, the server establishes a websocket connection and begins transmitting timestamp messages at 2-second intervals. WS is utilized across all Go-blueprint supported frameworks. This simple implementation showcases how flexible project is.
+A `/websocket` endpoint is added in `routes.go` to facilitate websocket connections. Upon accessing this endpoint, the server establishes a websocket connection and begins transmitting timestamp messages at 2-second intervals. WS is utilized across all Go-blueprint supported backends. This simple implementation showcases how flexible project is.
### Code Implementation
diff --git a/docs/docs/blueprint-core/frameworks.md b/docs/docs/blueprint-core/backend-frameworks.md
similarity index 59%
rename from docs/docs/blueprint-core/frameworks.md
rename to docs/docs/blueprint-core/backend-frameworks.md
index 00aa84df..48aa6018 100644
--- a/docs/docs/blueprint-core/frameworks.md
+++ b/docs/docs/blueprint-core/backend-frameworks.md
@@ -1,11 +1,11 @@
-Created project can utilizes several Go web frameworks to handle HTTP routing and server functionality. The chosen frameworks are:
+Created project can utilizes several Go web backends to handle HTTP routing and server functionality. The chosen backends are:
-1. [**Chi**](https://github.com/go-chi/chi): Lightweight and flexible router for building Go HTTP services.
-2. [**Echo**](https://github.com/labstack/echo): High-performance, extensible, minimalist Go web framework.
-3. [**Fiber**](https://github.com/gofiber/fiber): Express-inspired web framework designed to be fast, simple, and efficient.
-4. [**Gin**](https://github.com/gin-gonic/gin): A web framework with a martini-like API, but with much better performance.
+1. [**Standard-library**](https://pkg.go.dev/std): Offers a vast collection of packages and functions.
+2. [**Chi**](https://github.com/go-chi/chi): Lightweight and flexible router for building Go HTTP services.
+3. [**Gin**](https://github.com/gin-gonic/gin): A web framework with a martini-like API, but with much better performance.
+4. [**Fiber**](https://github.com/gofiber/fiber): Express-inspired web framework designed to be fast, simple, and efficient.
5. [**Gorilla/mux**](https://github.com/gorilla/mux): A powerful URL router and dispatcher for Golang.
-6. [**HttpRouter**](https://github.com/julienschmidt/httprouter): A high-performance HTTP request router that scales well.
+6. [**Echo**](https://github.com/labstack/echo): High-performance, extensible, minimalist Go web framework.
## Project Structure
diff --git a/docs/docs/blueprint-core/db-drivers.md b/docs/docs/blueprint-core/db-drivers.md
index f34c72d0..eded11fa 100644
--- a/docs/docs/blueprint-core/db-drivers.md
+++ b/docs/docs/blueprint-core/db-drivers.md
@@ -1,10 +1,10 @@
To extend the project with database functionality, users can choose from a variety of Go database drivers. Each driver is tailored to work with specific database systems, providing flexibility based on project requirements:
-1. [Mongo](https://go.mongodb.org/mongo-driver): Provides necessary tools for connecting and interacting with MongoDB databases.
-2. [Mysql](https://github.com/go-sql-driver/mysql): Enables seamless integration with MySQL databases.
-3. [Postgres](https://github.com/jackc/pgx/): Facilitates connectivity to PostgreSQL databases.
-4. [Redis](https://github.com/redis/go-redis): Provides tools for connecting and interacting with Redis.
-5. [Sqlite](https://github.com/mattn/go-sqlite3): Suitable for projects requiring a lightweight, self-contained database. and interacting with Redis
+1. [Mysql](https://github.com/go-sql-driver/mysql): Enables seamless integration with MySQL databases.
+2. [Postgres](https://github.com/jackc/pgx/): Facilitates connectivity to PostgreSQL databases.
+3. [Sqlite](https://github.com/mattn/go-sqlite3): Suitable for projects requiring a lightweight, self-contained database.
+4. [Mongo](https://go.mongodb.org/mongo-driver): Provides necessary tools for connecting and interacting with MongoDB databases.
+5. [Redis](https://github.com/redis/go-redis): Provides tools for connecting and interacting with Redis.
6. [ScyllaDB](https://github.com/scylladb/gocql): Facilitates connectivity to ScyllaDB databases.
## Updated Project Structure
diff --git a/docs/docs/blueprint-ui.md b/docs/docs/blueprint-ui.md
deleted file mode 100644
index a7f9e203..00000000
--- a/docs/docs/blueprint-ui.md
+++ /dev/null
@@ -1,7 +0,0 @@
-The Blueprint UI is a crucial component of the Go Blueprint ecosystem, providing a user-friendly interface for creating CLI commands and visualizing project structures.
-
-By visiting the Blueprint UI website at [go-blueprint.dev](https://go-blueprint.dev), users can interact with a visual representation of their project setup before executing commands.
-
-
-
-This enhances the overall experience of using Go Blueprint by providing a visual representation of project setups and simplifying the command generation process. Check Blueprint UI [code](https://github.com/briancbarrow/go-blueprint-htmx).
diff --git a/docs/docs/creating-project/project-init.md b/docs/docs/creating-project/project-init.md
index 9eae177c..044a3977 100644
--- a/docs/docs/creating-project/project-init.md
+++ b/docs/docs/creating-project/project-init.md
@@ -6,7 +6,7 @@ After installing the Go-Blueprint CLI tool, you can create a new project with th
go-blueprint create
```
-This command will interactively guide you through the project setup process, allowing you to choose the project name, framework, and database driver.
+This command will interactively guide you through the project setup process, allowing you to choose the project name, backend, and database driver.

@@ -15,62 +15,48 @@ This command will interactively guide you through the project setup process, all
For a non-interactive setup, you can use flags to provide the necessary information during project creation. Here's an example:
```
-go-blueprint create --name my-project --framework gin --driver postgres --git commit
+go-blueprint create -n my-project -b chi -d postgres -g commit
```
In this example:
-- `--name`: Specifies the name of the project (replace "my-project" with your desired project name).
-- `--framework`: Specifies the Go framework to be used (e.g., "gin").
-- `--driver`: Specifies the database driver to be integrated (e.g., "postgres").
-- `--git`: Specifies the git configuration option of the project (e.g., "commit").
+- `-n` or `--name`: Specifies the name of the project (replace "my-project" with your desired project name).
+- `-b` or `--backend-framework`: Specifies the Go backend to be used (e.g., "gin").
+- `-d` or `--driver`: Specifies the database driver to be integrated (e.g., "postgres").
+- `-g` or `--git`: Specifies the git configuration option of the project (e.g., "commit").
Customize the flags according to your project requirements.
-## Advanced Flag
+## Frontend Frameworks and Features
-By including the `--advanced` flag, users can choose one or all of the advanced features, HTMX, GitHub Actions for CI/CD, Websocket, Docker and TailwindCSS support, during the project creation process. The flag enhances the simplicity of Blueprint while offering flexibility for users who require additional functionality.
+To include frontend frameworks and features in your project, you can use the `-f` flag to trigger the prompt:
```bash
-go-blueprint create --advanced
+go-blueprint create -f
```
-To recreate the project using the same configuration semi-interactively, use the following command:
+
+
+## Advanced Flag
+
+By including the `-a` or `--advanced` flag, users can choose one or all of the advanced features, GitHub Actions for CI/CD, Websocket and Docker, during the project creation process. The flag enhances the simplicity of Blueprint while offering flexibility for users who require additional functionality.
+
```bash
-go-blueprint create --name my-project --framework chi --driver mysql --git commit --advanced
+go-blueprint create -a
```
-This approach opens interactive mode only for advanced features, which allow you to choose the one or combination of available features.

-## Non-Interactive Setup
-
-Advanced features can be enabled using the `--feature` flag along with the `--advanced` flag:
+## Combining Flags
-HTMX:
-```bash
-go-blueprint create --advanced --feature htmx
-```
+Frontend and Advanced features can be combined with the `-f` and `-a` flags
-CI/CD workflow:
```bash
-go-blueprint create --advanced --feature githubaction
+go-blueprint create -af
```
-Websocket:
-```bash
-go-blueprint create --advanced --feature websocket
-```
-TailwindCSS:
-```bash
-go-blueprint create --advanced --feature tailwind
-```
-Docker:
-```bash
-go-blueprint create --advanced --feature docker
-```
+or
-Or all features at once:
```bash
-go-blueprint create --name my-project --framework chi --driver mysql --git commit --advanced --feature htmx --feature githubaction --feature websocket --feature tailwind --feature docker
+go-blueprint create -n my_project -b fiber -d mysql -f --frontend-framework htmx --frontend-advanced tailwind -a --feature docker --feature githubaction -g commit
```
diff --git a/docs/docs/endpoints-test/redis.md b/docs/docs/endpoints-test/redis.md
index ee375da7..c9af846b 100644
--- a/docs/docs/endpoints-test/redis.md
+++ b/docs/docs/endpoints-test/redis.md
@@ -113,56 +113,6 @@ The `Sample Output` is dynamic and unstructured since it depends on the raw map.
}
```
-- `XML serialization/deserialization`
-
-```xml
-
-
- up
- Redis connection pool utilization is high
-
- 7.0.15
- standalone
- 10
-
-
- 22.38
- 0.02
-
-
- 46.57
- 0.05
-
-
- 1130.00
- 1.10
-
- 1.98%
-
- 6 days, 3 hours, 37 minutes, 20 seconds
-
- 6
- 3
- 37
- 20
-
-
-
- 10
- 2
- 0
- 4
- 9
- 5
- 0
- 62.50%
-
- 26
-
-
-
-```
-
## Code Implementation
```go
diff --git a/docs/docs/endpoints-test/server.md b/docs/docs/endpoints-test/server.md
index ff788f2e..f0ad4b38 100644
--- a/docs/docs/endpoints-test/server.md
+++ b/docs/docs/endpoints-test/server.md
@@ -23,7 +23,7 @@ Sample Output:
{"message": "Hello World"}
```
If the server is running and it is healthy, you should see the message 'Hello World' in the response.
-Also, depending on the framework you are using, there will be logs in the terminal:
+Also, depending on the backend you are using, there will be logs in the terminal:
```bash
make run
diff --git a/docs/docs/advanced-flag/htmx-templ.md b/docs/docs/frontend/htmx-templ.md
similarity index 100%
rename from docs/docs/advanced-flag/htmx-templ.md
rename to docs/docs/frontend/htmx-templ.md
diff --git a/docs/docs/advanced-flag/react-vite.md b/docs/docs/frontend/react-vite.md
similarity index 90%
rename from docs/docs/advanced-flag/react-vite.md
rename to docs/docs/frontend/react-vite.md
index 01de8afe..1a2eb5f5 100644
--- a/docs/docs/advanced-flag/react-vite.md
+++ b/docs/docs/frontend/react-vite.md
@@ -1,6 +1,6 @@
This template provides a minimal setup for getting React working with Vite for the frontend and go on the backend. It allows you to easily integrate React with Tailwind CSS and Vite for fast development.
-The React advanced flag can be combined with the Tailwind flag for enhanced styling capabilities.
+The React fronted flag can be combined with the Tailwind flag for enhanced styling capabilities.
## Project Structure
@@ -66,10 +66,21 @@ You can extend the `vite.config.ts` to include additional configurations as need
The make run target will start the Go server in the backend, install frontend dependencies, and run the Vite development server for the frontend.
```bash
-run:
- @go run cmd/api/main.go &
- @npm install --prefix ./frontend
- @npm run dev --prefix ./frontend
+run: build
+ @echo "Starting server..."
+ @./main & \
+ SERVER_PID=$$!; \
+ sleep 2; \
+ if ps -p $$SERVER_PID > /dev/null; then \
+ echo "Server started successfully"; \
+ cd frontend && \
+ npm install --prefer-offline --no-fund && \
+ npm run dev; \
+ kill $$SERVER_PID; \
+ else \
+ echo "Server failed to start. Check the logs."; \
+ exit 1; \
+ fi
```
After running this command, you can verify the connection between the frontend and backend by checking the console. You can also fetch data from the backend to test the integration.
@@ -78,7 +89,7 @@ After running this command, you can verify the connection between the frontend a
## Dockerfile
-Combine React advanced flag with Docker flag to get Docker and docker-compose configuration and run them with:
+Combine React flag with advanced Docker flag to get Docker and docker-compose configuration and run them with:
```bash
make docker-run
@@ -217,7 +228,7 @@ The `VITE_PORT` in .env refers `PORT` from .env in project root ( for backend ).
## Notes
-- First time running the project creation with Tailwind can take longer (~10 mins) as npm needs to download and cache all packages
+- The first time running project creation with Tailwind may take longer as npm needs to download and cache all packages.
- Subsequent runs will be faster as they utilize npm's cache, which we enforce during project creation.
diff --git a/docs/docs/advanced-flag/tailwind.md b/docs/docs/frontend/tailwind.md
similarity index 89%
rename from docs/docs/advanced-flag/tailwind.md
rename to docs/docs/frontend/tailwind.md
index 0d2e4b66..a8fc318a 100644
--- a/docs/docs/advanced-flag/tailwind.md
+++ b/docs/docs/frontend/tailwind.md
@@ -1,6 +1,6 @@
-Tailwind is closely coupled with the advanced HTMX flag, and HTMX will be automatically used if you select Tailwind in your project.
+Tailwind is closely coupled with the fronted HTMX and React flags.
-We do not introduce outside dependencies automatically, and you need compile output.css (file is empty by default) with the Tailwind CLI tool.
+For HTMX we do not introduce outside dependencies automatically, and you need compile output.css (file is empty by default) with the Tailwind CLI tool.
The project tree would look like this:
```bash
diff --git a/docs/docs/index.md b/docs/docs/index.md
index 39e0fd00..d9585c57 100644
--- a/docs/docs/index.md
+++ b/docs/docs/index.md
@@ -7,7 +7,7 @@ hide:

-Powerful CLI tool designed to streamline the process of creating Go projects with a robust and standardized structure. Not only does Go Blueprint facilitate project initialization, but it also offers seamless integration with popular Go frameworks, allowing you to focus on your application's code from the very beginning.
+Powerful CLI tool designed to streamline the process of creating Go projects with a robust and standardized structure. Not only does Go Blueprint facilitate project initialization, but it also offers seamless integration with popular Go backends, frontend frameworks, allowing you to focus on your application's code from the very beginning.
## Why Choose Go Blueprint?
@@ -15,81 +15,31 @@ Powerful CLI tool designed to streamline the process of creating Go projects wit
- **Pre-established Go Project Structure**: Save time and effort by having the entire Go project structure set up automatically. No need to worry about directory layouts or configuration files.
-- **HTTP Server Configuration Made Easy**: Whether you prefer Go's standard library HTTP package, Chi, Gin, Fiber, HttpRouter, Gorilla/mux or Echo, Go Blueprint caters to your server setup needs.
+- **HTTP Server Configuration Made Easy**: Whether you prefer Go's standard library HTTP package, Chi, Gin, Fiber, Gorilla/mux or Echo, Go Blueprint caters to your server setup needs.
- **Focus on Your Application Code**: With Go Blueprint handling the project scaffolding, you can dedicate more time and energy to developing your application logic.
## Project Structure
-Here's an overview of the project structure created by Go Blueprint when all options are utilized:
+By visiting the Blueprint UI website at [go-blueprint.dev](https://go.blueprint.dev), you can interact with a visual representation of the project setup before executing commands. It provides a user-friendly interface for creating CLI commands and visualizing project structures.
-```bash
-/ (Root)
-├── .github/
-│ └── workflows/
-│ ├── go-test.yml # GitHub Actions workflow for running tests.
-│ └── release.yml # GitHub Actions workflow for releasing the application.
-├── cmd/
-│ ├── api/
-│ │ └── main.go # Main file for starting the server.
-│ └── web/
-│ ├── styles/ # only for generating css will not be served public
-│ │ └── input.css # Tailwind input file for compiling output.css with CLI when HTMX is used
-│ ├── assets/
-│ │ ├── css/
-│ │ │ └── output.css # Generated CSS file.
-│ │ └── js/
-│ │ └── htmx.min.js # HTMX library for dynamic HTML content.
-│ ├── base.templ # Base HTML template file.
-│ ├── base_templ.go # Generated Go code for base template.
-│ ├── efs.go # Includes assets into compiled binary.
-│ ├── hello.go # Logic for handling "hello" form.
-│ ├── hello.templ # Template file for the "hello" endpoint.
-│ └── hello_templ.go # Generated Go code for the "hello" template.
-├── frontend/ # React advanced flag. Excludes HTMX.
-│ ├── node_modules/ # Node dependencies.
-│ ├── public/
-│ │ ├── index.html
-│ │ └── favicon.ico
-│ ├── src/ # React source files.
-│ │ ├── App.tsx # Main React component.
-│ │ ├── assets/ # React assets directory
-│ │ │ └── logo.svg
-│ │ ├── components/ # React components directory.
-│ │ │ ├── Header.tsx
-│ │ │ └── Footer.tsx
-│ │ ├── styles/ # CSS/SCSS styles directory.
-│ │ │ └── global.css
-│ │ └── index.tsx # Main entry point for React
-│ ├── eslint.config.js # ESLint configuration file.
-│ ├── index.html # Base HTML template.
-│ ├── package.json # Node.js package configuration.
-│ ├── package-lock.json # Lock file for Node.js dependencies.
-│ ├── README.md # README file for the React project.
-│ ├── tsconfig.app.json # TypeScript configuration for the app.
-│ ├── tsconfig.json # Root TypeScript configuration.
-│ ├── tsconfig.node.json # TypeScript configuration for Node.js.
-│ └── vite.config.ts # Vite configuration file.
-├── internal/
-│ ├── database/
-│ │ ├── database_test.go # File containing integration tests for the database operations.
-│ │ └── database.go # File containing functions related to database operations.
-│ └── server/
-│ ├── routes.go # File defining HTTP routes.
-│ ├── routes_test.go # Test file for testing HTTP handlers.
-│ └── server.go # Main server logic.
-├── .air.toml # Configuration file for Air, a live-reload utility.
-├── docker-compose.yml # Docker Compose configuration.
-├── Dockerfile # Dockerfile configuration for the Go project.
-├── .env # Environment configuration file.
-├── .gitignore # File specifying which files and directories to ignore in Git.
-├── go.mod # Go module file for managing dependencies.
-├── .goreleaser.yml # Configuration file for GoReleaser, a tool for building and releasing binaries.
-├── go.sum # Go module file containing checksums for dependencies.
-├── Makefile # Makefile for defining and running commands.
-├── tailwind.config.js # Tailwind CSS configuration file for HTMX.
-└── README.md # Project's README file containing essential information about the project.
+
-```
+Execute go-blueprint create -h to see all the options and shorthands
-This structure provides a comprehensive organization of your project, separating source code, tests, configurations and documentation.
+```bash
+Usage:
+ go-blueprint create [flags]
+
+Flags:
+ -a, --advanced Get prompts for advanced features
+ --feature AdvancedFeatures Advanced feature to use. Allowed values: githubaction, websocket, docker
+ -b, --backend-framework BackendFramework Backend framework to use. Allowed values: chi, gin, fiber, gorilla/mux, standard-library, echo
+ -d, --driver Database Database drivers to use. Allowed values: mysql, postgres, sqlite, mongo, redis, scylla, none
+ -f, --frontend Get prompts for frontend frameworks
+ --frontend-framework Frontendframework Frontend framework to use. Allowed values: htmx, react
+ --frontend-advanced FrontendAdvanced Frontend framework advanced features to use. Allowed values: tailwind
+ -g, --git Git Git to use. Allowed values: commit, stage, skip
+ -h, --help help for create
+ -n, --name string Name of project to create
+```
diff --git a/docs/docs/public/blueprint_1.png b/docs/docs/public/blueprint_1.png
index 093ababd..85370ffa 100644
Binary files a/docs/docs/public/blueprint_1.png and b/docs/docs/public/blueprint_1.png differ
diff --git a/docs/docs/public/blueprint_advanced.png b/docs/docs/public/blueprint_advanced.png
index 5177e0be..0865fd7d 100644
Binary files a/docs/docs/public/blueprint_advanced.png and b/docs/docs/public/blueprint_advanced.png differ
diff --git a/docs/docs/public/blueprint_frontend.png b/docs/docs/public/blueprint_frontend.png
new file mode 100644
index 00000000..4a14a8cf
Binary files /dev/null and b/docs/docs/public/blueprint_frontend.png differ
diff --git a/docs/docs/public/blueprint_ui.png b/docs/docs/public/blueprint_ui.png
index e7bbfa4a..32284f5a 100644
Binary files a/docs/docs/public/blueprint_ui.png and b/docs/docs/public/blueprint_ui.png differ
diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml
index b9ece5be..97370b46 100644
--- a/docs/mkdocs.yml
+++ b/docs/mkdocs.yml
@@ -31,22 +31,22 @@ theme:
nav:
- Home: index.md
- Installation: installation.md
- - Blueprint UI: blueprint-ui.md
- Project creation & default config:
- Project init: creating-project/project-init.md
- Makefile: creating-project/makefile.md
- Air: creating-project/air.md
- Blueprint Core:
- - Frameworks: blueprint-core/frameworks.md
+ - Backend Frameworks: blueprint-core/backend-frameworks.md
- DB Drivers: blueprint-core/db-drivers.md
+ - Frontend:
+ - HTMX and Templ: frontend/htmx-templ.md
+ - React & Vite (TypeScript): frontend/react-vite.md
+ - Tailwind CSS: frontend/tailwind.md
- Advanced Flag:
- AF Usage: advanced-flag/advanced-flag.md
- - HTMX and Templ: advanced-flag/htmx-templ.md
- - Tailwind CSS: advanced-flag/tailwind.md
- GoReleaser & GoTest CI: advanced-flag/goreleaser.md
- Websocket: advanced-flag/websocket.md
- Docker: advanced-flag/docker.md
- - React & Vite (TypeScript): advanced-flag/react-vite.md
- Testing endpoints:
- Server: endpoints-test/server.md
- DB Health Endpoints:
diff --git a/public/frameworks.gif b/public/backends.gif
similarity index 100%
rename from public/frameworks.gif
rename to public/backends.gif
diff --git a/public/blueprint_1.png b/public/blueprint_1.png
index 093ababd..85370ffa 100644
Binary files a/public/blueprint_1.png and b/public/blueprint_1.png differ
diff --git a/public/blueprint_advanced.png b/public/blueprint_advanced.png
index 5177e0be..0865fd7d 100644
Binary files a/public/blueprint_advanced.png and b/public/blueprint_advanced.png differ
diff --git a/public/blueprint_frontend.png b/public/blueprint_frontend.png
new file mode 100644
index 00000000..4a14a8cf
Binary files /dev/null and b/public/blueprint_frontend.png differ
diff --git a/public/frontend.gif b/public/frontend.gif
new file mode 100644
index 00000000..2361b9dc
Binary files /dev/null and b/public/frontend.gif differ