国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

11. 搭建較通用的GoWeb開發(fā)腳手架

這篇具有很好參考價(jià)值的文章主要介紹了11. 搭建較通用的GoWeb開發(fā)腳手架。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

代碼地址:https://gitee.com/lymgoforIT/bluebell

導(dǎo)言

有了前述知識(shí)的基礎(chǔ)后,我們便可以開始搭建基本腳手架了。

腳手架應(yīng)該包含如下信息:

  1. 較好的代碼管理、即清晰的目錄結(jié)構(gòu),層次分明。
  2. 配置文件管理和加載。
  3. 日志組件初始化和加載。
  4. Redis初始化和加載。
  5. MySQL初始化和加載。
  6. 路由拆分管理。
  7. 中間件使用。
  8. 服務(wù)啟動(dòng)。

有了腳手架之后,后續(xù)的CRUD就比較簡(jiǎn)單啦。

本文完成后總體目錄結(jié)構(gòu)如下
11. 搭建較通用的GoWeb開發(fā)腳手架,# 風(fēng)鈴草博客系統(tǒng),golang
注意:我們主要關(guān)注的是后端邏輯,所以涉及前端的static和templates兩個(gè)目錄沒有過多介紹,可以直接從代碼倉(cāng)庫(kù)獲取即可。

最關(guān)鍵的是main文件,畢竟它是整個(gè)程序的入口,我們的main文件應(yīng)該足夠清晰,讓人一眼就能看出做了哪些事情,大致結(jié)構(gòu)如下:

package main

func main() {
	// 1. 加載配置

	// 2. 初始化日志

	// 3. 初始化MySQL連接

	// 4. 初始化Redis連接

	// 5. 初始化gin框架內(nèi)置的校驗(yàn)器使用的翻譯器
	
	// 6. 注冊(cè)路由

	// 7. 啟動(dòng)服務(wù)(優(yōu)雅關(guān)機(jī)和重啟)
}

一、加載配置

首先我們應(yīng)該定義一個(gè)config.yaml配置文件,將相關(guān)配置寫到里面

config/config.yaml

name: "bluebell"
mode: "release"
port: 8084
version: "v0.0.1"

log:
  level: "info"
  filename: "web_app.log"
  max_size: 200
  max_age: 30
  max_backups: 7

mysql:
  host: "127.0.0.1"
  port: 3306
  user: "root"
  password: "root"
  dbname: "bluebell"
  max_open_conns: 200
  max_idle_conns: 50

redis:
  host: "127.0.0.1"
  port: 6379
  password: ""
  db: 0
  pool_size: 100

由于我們后續(xù)是要將配置加載到一個(gè)全局結(jié)構(gòu)體對(duì)象中,然后各個(gè)地方使用這個(gè)全局變量讀取配置的,所以很自然的想到,我們應(yīng)該定義對(duì)應(yīng)的配置結(jié)構(gòu)體,并提供一個(gè)全局變量以及相應(yīng)的初始化函數(shù)。

setting/setting.go

package setting

import (
	"fmt"

	"github.com/fsnotify/fsnotify"
	"github.com/spf13/viper"
)

var Conf = new(AppConfig)

type AppConfig struct {
	Name    string `mapstructure:"name"`
	Mode    string `mapstructure:"mode"`
	Version string `mapstructure:"version"`
	Port    int    `mapstructure:"port"`

	*LogConfig   `mapstructure:"log"`
	*MySQLConfig `mapstructure:"mysql"`
	*RedisConfig `mapstructure:"redis"`
}

type LogConfig struct {
	Level      string `mapstructure:"level"`
	Filename   string `mapstructure:"filename"`
	MaxSize    int    `mapstructure:"max_size"`
	MaxAge     int    `mapstructure:"max_age"`
	MaxBackups int    `mapstructure:"max_backups"`
}

type MySQLConfig struct {
	Host         string `mapstructure:"host"`
	Port         int    `mapstructure:"port"`
	User         string `mapstructure:"user"`
	Password     string `mapstructure:"password"`
	DB           string `mapstructure:"dbname"`
	MaxOpenConns int    `mapstructure:"max_open_conns"`
	MaxIdleConns int    `mapstructure:"max_idle_conns"`
}

type RedisConfig struct {
	Host         string `mapstructure:"host"`
	Port         int    `mapstructure:"port"`
	Password     string `mapstructure:"password"`
	DB           int    `mapstructure:"db"`
	PoolSize     int    `mapstructure:"pool_size"`
	MinIdleConns int    `mapstructure:"min_idle_conns"`
}

func Init(filePath string) (err error) {
	// 方式1:直接指定配置文件路徑(相對(duì)路徑或者絕對(duì)路徑)
	// 相對(duì)路徑:相對(duì)執(zhí)行的可執(zhí)行文件的相對(duì)路徑
	//viper.SetConfigFile("./conf/config.yaml")
	// 絕對(duì)路徑:系統(tǒng)中實(shí)際的文件路徑
	//viper.SetConfigFile("/Users/liwenzhou/Desktop/bluebell/conf/config.yaml")

	// 方式2:指定配置文件名和配置文件的位置,viper自行查找可用的配置文件
	// 配置文件名不需要帶后綴
	// 配置文件位置可配置多個(gè)
	//viper.SetConfigName("config") // 指定配置文件名(不帶后綴)
	//viper.AddConfigPath(".") // 指定查找配置文件的路徑(這里使用相對(duì)路徑)
	//viper.AddConfigPath("./conf")      // 指定查找配置文件的路徑(這里使用相對(duì)路徑)

	// 基本上是配合遠(yuǎn)程配置中心使用的,告訴viper當(dāng)前的數(shù)據(jù)使用什么格式去解析
	//viper.SetConfigType("json")

	viper.SetConfigFile(filePath)

	err = viper.ReadInConfig() // 讀取配置信息到viper中
	if err != nil {
		fmt.Printf("viper.ReadInconfig failed,err:%v\n", err)
		return
	}

	// 把讀取到的配置信息反序列化到 Conf 全局變量中
	if err := viper.Unmarshal(Conf); err != nil {
		fmt.Printf("viper.Unmarshal failed,err:%v\n", err)
	}

	viper.WatchConfig()
	viper.OnConfigChange(func(in fsnotify.Event) {
		fmt.Println("配置文件修改了")
		if err := viper.Unmarshal(Conf); err != nil {
			fmt.Printf("viper.Unmarshal failed,err:%v\n", err)
		}
	})
	
	return
}

二、初始化日志

我們?cè)擁?xiàng)目使用之前介紹的Zap作為日志組件,并會(huì)仿照Gin中的LoggerRecovery中間件,寫自己的中間件替換掉Gin自帶的。如下

logger/logger.go

package logger

import (
	"bluebell/setting"
	"net"
	"net/http"
	"net/http/httputil"
	"os"
	"runtime/debug"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/natefinch/lumberjack"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

var lg *zap.Logger

// Init 初始化lg
func Init(cfg *setting.LogConfig, mode string) (err error) {
	writeSyncer := getLogWriter(cfg.Filename, cfg.MaxSize, cfg.MaxBackups, cfg.MaxAge)
	encoder := getEncoder()
	var l = new(zapcore.Level)
	err = l.UnmarshalText([]byte(cfg.Level))
	if err != nil {
		return
	}
	var core zapcore.Core
	if mode == "dev" {
		// 進(jìn)入開發(fā)模式,日志輸出到終端
		consoleEncoder := zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig())
		core = zapcore.NewTee(
			zapcore.NewCore(encoder, writeSyncer, l),
			zapcore.NewCore(consoleEncoder, zapcore.Lock(os.Stdout), zapcore.DebugLevel),
		)
	} else {
		core = zapcore.NewCore(encoder, writeSyncer, l)
	}

	lg = zap.New(core, zap.AddCaller())

	// 使用 lg 替換zap中的全局L,從而外部可以直接使用zap.L().Info記錄日志,而不是logger.lg.Info
	zap.ReplaceGlobals(lg)
	zap.L().Info("init logger success")
	return
}

func getEncoder() zapcore.Encoder {
	encoderConfig := zap.NewProductionEncoderConfig()
	encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
	encoderConfig.TimeKey = "time"
	encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
	encoderConfig.EncodeDuration = zapcore.SecondsDurationEncoder
	encoderConfig.EncodeCaller = zapcore.ShortCallerEncoder
	return zapcore.NewJSONEncoder(encoderConfig)
}

func getLogWriter(filename string, maxSize, maxBackup, maxAge int) zapcore.WriteSyncer {
	lumberJackLogger := &lumberjack.Logger{
		Filename:   filename,
		MaxSize:    maxSize,
		MaxBackups: maxBackup,
		MaxAge:     maxAge,
	}
	return zapcore.AddSync(lumberJackLogger)
}

// GinLogger 接收gin框架默認(rèn)的日志
func GinLogger() gin.HandlerFunc {
	return func(c *gin.Context) {
		start := time.Now()
		path := c.Request.URL.Path
		query := c.Request.URL.RawQuery
		c.Next()

		cost := time.Since(start)
		lg.Info(path,
			zap.Int("status", c.Writer.Status()),
			zap.String("method", c.Request.Method),
			zap.String("path", path),
			zap.String("query", query),
			zap.String("ip", c.ClientIP()),
			zap.String("user-agent", c.Request.UserAgent()),
			zap.String("errors", c.Errors.ByType(gin.ErrorTypePrivate).String()),
			zap.Duration("cost", cost),
		)
	}
}

// GinRecovery recover掉項(xiàng)目可能出現(xiàn)的panic,并使用zap記錄相關(guān)日志
func GinRecovery(stack bool) gin.HandlerFunc {
	return func(c *gin.Context) {
		defer func() {
			if err := recover(); err != any(nil) {
				// Check for a broken connection, as it is not really a
				// condition that warrants a panic stack trace.
				var brokenPipe bool
				if ne, ok := any(err).(*net.OpError); ok {
					if se, ok := ne.Err.(*os.SyscallError); ok {
						if strings.Contains(strings.ToLower(se.Error()), "broken pipe") || strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") {
							brokenPipe = true
						}
					}
				}

				httpRequest, _ := httputil.DumpRequest(c.Request, false)
				if brokenPipe {
					lg.Error(c.Request.URL.Path,
						zap.Any("error", err),
						zap.String("request", string(httpRequest)),
					)
					// If the connection is dead, we can't write a status to it.
					c.Error(any(err).(error)) // nolint: errcheck
					c.Abort()
					return
				}

				if stack {
					lg.Error("[Recovery from panic]",
						zap.Any("error", err),
						zap.String("request", string(httpRequest)),
						zap.String("stack", string(debug.Stack())),
					)
				} else {
					lg.Error("[Recovery from panic]",
						zap.Any("error", err),
						zap.String("request", string(httpRequest)),
					)
				}
				c.AbortWithStatus(http.StatusInternalServerError)
			}
		}()
		c.Next()
	}
}

三、初始化MySQL連接

使用Gorm,初始化代碼如下

dao/mysql/mysql.go

package mysql

import (
	"bluebell/setting"
	"fmt"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

var db *gorm.DB

func Init(cfg *setting.MySQLConfig) (err error) {
	dsn := fmt.Sprintf("%s:%s@(%s:%d)/%s?charset=utf8mb4&parseTime=true&loc=Local", cfg.User, cfg.Password, cfg.Host, cfg.Port, cfg.DB)
	db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		panic(any("failed to connect to db"))
	}

	sqlDB, err := db.DB()
	if err != nil {
		panic(any("create table err"))
	}
	// SetMaxIdleConns sets the maximum number of connections in the idle connection pool.
	sqlDB.SetMaxIdleConns(cfg.MaxIdleConns)

	// SetMaxOpenConns sets the maximum number of open connections to the database.
	sqlDB.SetMaxOpenConns(cfg.MaxOpenConns)

	return nil
}

四、初始化Redis連接

與初始化MySQL非常類似

dao/redis/redis.go

package redis

import (
	"bluebell/setting"
	"fmt"

	"github.com/go-redis/redis"
)
var (
	client * redis.Client
	Nil = redis.Nil
)

func Init(cfg *setting.RedisConfig) (err error) {
	client = redis.NewClient(&redis.Options{
		Addr:         fmt.Sprintf("%s:%d", cfg.Host, cfg.Port),
		Password:     cfg.Password, // no password set
		DB:           cfg.DB,       // use default DB
		PoolSize:     cfg.PoolSize,
		MinIdleConns: cfg.MinIdleConns,
	})

	// 注:使用Val()不會(huì)返回錯(cuò)誤,出錯(cuò)時(shí)返回零值,使用Result則可以根據(jù)返回的error判斷是否出錯(cuò)了
	_, err = client.Ping().Result()
	if err != nil {
		fmt.Println("init redis failed")
		return err
	}
	
	return nil 
}

五、初始化gin框架內(nèi)置的校驗(yàn)器使用的翻譯器

由于我們會(huì)使用validator組件進(jìn)行gin的參數(shù)校驗(yàn),所以為了錯(cuò)誤提示信息更為友好,需要初始化翻譯器。
controller/validator.go

package controller

import (
	"bluebell/models"
	"fmt"
	"reflect"
	"strings"

	"github.com/gin-gonic/gin/binding"
	"github.com/go-playground/locales/en"
	"github.com/go-playground/locales/zh"
	ut "github.com/go-playground/universal-translator"
	"github.com/go-playground/validator/v10"
	enTranslations "github.com/go-playground/validator/v10/translations/en"
	zhTranslations "github.com/go-playground/validator/v10/translations/zh"
)

// 定義一個(gè)全局翻譯器T
var trans ut.Translator

// InitTrans 初始化翻譯器
func InitTrans(locale string) (err error) {
	// 修改gin框架中的Validator引擎屬性,實(shí)現(xiàn)自定制
	if v, ok := binding.Validator.Engine().(*validator.Validate); ok {

		// 注冊(cè)一個(gè)獲取json tag的自定義方法
		v.RegisterTagNameFunc(func(fld reflect.StructField) string {
			name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
			if name == "-" {
				return ""
			}
			return name
		})

		// 為SignUpParam注冊(cè)自定義校驗(yàn)方法
		v.RegisterStructValidation(SignUpParamStructLevelValidation, models.ParamSignUp{})

		zhT := zh.New() // 中文翻譯器
		enT := en.New() // 英文翻譯器

		// 第一個(gè)參數(shù)是備用(fallback)的語言環(huán)境
		// 后面的參數(shù)是應(yīng)該支持的語言環(huán)境(支持多個(gè))
		// uni := ut.New(zhT, zhT) 也是可以的
		uni := ut.New(enT, zhT, enT)

		// locale 通常取決于 http 請(qǐng)求頭的 'Accept-Language'
		var ok bool
		// 也可以使用 uni.FindTranslator(...) 傳入多個(gè)locale進(jìn)行查找
		trans, ok = uni.GetTranslator(locale)
		if !ok {
			return fmt.Errorf("uni.GetTranslator(%s) failed", locale)
		}

		// 注冊(cè)翻譯器
		switch locale {
		case "en":
			err = enTranslations.RegisterDefaultTranslations(v, trans)
		case "zh":
			err = zhTranslations.RegisterDefaultTranslations(v, trans)
		default:
			err = enTranslations.RegisterDefaultTranslations(v, trans)
		}
		return
	}
	return
}

// removeTopStruct 去除提示信息中的結(jié)構(gòu)體名稱
func removeTopStruct(fields map[string]string) map[string]string {
	res := map[string]string{}
	for field, err := range fields {
		res[field[strings.Index(field, ".")+1:]] = err
	}
	return res
}

// SignUpParamStructLevelValidation 自定義SignUpParam結(jié)構(gòu)體校驗(yàn)函數(shù)
func SignUpParamStructLevelValidation(sl validator.StructLevel) {
	su := sl.Current().Interface().(models.ParamSignUp)

	if su.Password != su.RePassword {
		// 輸出錯(cuò)誤提示信息,最后一個(gè)參數(shù)就是傳遞的param
		sl.ReportError(su.RePassword, "re_password", "RePassword", "eqfield", "password")
	}
}

其中我們?yōu)樽?cè)參數(shù)ParamSignUp校驗(yàn)做了自定義校驗(yàn),用到了注冊(cè)參數(shù),所以這里也把model定義一下。

models/params.go

package models

// ParamSignUp 注冊(cè)請(qǐng)求參數(shù)
type ParamSignUp struct {
	Username   string `json:"username" binding:"required"`
	Password   string `json:"password" binding:"required"`
	RePassword string `json:"re_password" binding:"required,eqfield=Password"`
}

六、注冊(cè)路由

注冊(cè)路由用到了我們之前介紹的路由拆分和管理技巧。

package router

import (
	"bluebell/logger"
	"net/http"

	"github.com/gin-gonic/gin"
)

func SetupRouter(mode string) *gin.Engine {
	if mode == gin.ReleaseMode {
		gin.SetMode(gin.ReleaseMode) // gin 設(shè)置成發(fā)布模式
	}

	r := gin.New()
	// 使用我們自定義的兩個(gè)中間件
	r.Use(logger.GinLogger(), logger.GinRecovery(true))

	// 加載首頁(yè)html文件
	r.LoadHTMLFiles("./templates/index.html")
	// 加載靜態(tài)文件
	r.Static("/static", "./static")

	r.GET("/ping", func(c *gin.Context) {
		c.String(http.StatusOK, "pong")
	})

	r.GET("/", func(c *gin.Context) {
		c.HTML(http.StatusOK, "index.html", nil)
	})

	r.NoRoute(func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"msg": "404",
		})
	})
	return r
}

七、 啟動(dòng)服務(wù)

main.go

package main

import (
	"bluebell/controller"
	"bluebell/dao/mysql"
	"bluebell/dao/redis"
	"bluebell/logger"
	"bluebell/router"
	"bluebell/setting"
	"fmt"
	"os"
)

func main() {
	if len(os.Args) < 2 {
		fmt.Println("need config file. eg:bluebell config.yaml")
		return
	}

	// 1. 加載配置
	if err := setting.Init(os.Args[1]); err != nil {
		fmt.Printf("load config failed,err:%v\n", err)
		return
	}

	// 2. 初始化日志
	if err := logger.Init(setting.Conf.LogConfig, setting.Conf.Mode); err != nil {
		fmt.Printf("init logger failed,err:%v\n", err)
		return
	}

	// 3. 初始化MySQL連接
	if err := mysql.Init(setting.Conf.MySQLConfig); err != nil {
		fmt.Printf("init mysql failed,err:%v\n", err)
	}

	// 4. 初始化Redis連接
	if err := redis.Init(setting.Conf.RedisConfig); err != nil {
		fmt.Printf("init redis failed,err:%v\n", err)
	}

	// 5. 初始化gin框架內(nèi)置的校驗(yàn)器使用的翻譯器
	if err := controller.InitTrans("zh"); err != nil {
		fmt.Printf("init validator trans failed, err:%v\n", err)
		return
	}

	// 6. 注冊(cè)路由
	r := router.SetupRouter(setting.Conf.Mode)

	// 7. 啟動(dòng)服務(wù)(優(yōu)雅關(guān)機(jī)和重啟)
	err := r.Run(fmt.Sprintf(":%d", setting.Conf.Port))
	if err != nil {
		fmt.Printf("run server failed, err:%v\n", err)
		return
	}
}

八、測(cè)試運(yùn)行

運(yùn)行前需要先保證MySQL中已經(jīng)建立了對(duì)應(yīng)的bluebell庫(kù),然后Redis服務(wù)端時(shí)開啟的。

首先我們需要使用go build編譯項(xiàng)目,在項(xiàng)目路徑下執(zhí)行go build即可,編譯成功會(huì)出現(xiàn)一個(gè)可執(zhí)行文件,如下
11. 搭建較通用的GoWeb開發(fā)腳手架,# 風(fēng)鈴草博客系統(tǒng),golang

隨后我們傳入配置文件路徑執(zhí)行,可以看到啟動(dòng)后,沒有報(bào)錯(cuò)且光標(biāo)一直在閃爍,便是項(xiàng)目啟動(dòng)成功且在8084端口監(jiān)聽了(可通過Ctrl+C退出程序)。此外,我們也能看到產(chǎn)生了日志文件web_app.log
11. 搭建較通用的GoWeb開發(fā)腳手架,# 風(fēng)鈴草博客系統(tǒng),golang
通過瀏覽器訪問也成功了

11. 搭建較通用的GoWeb開發(fā)腳手架,# 風(fēng)鈴草博客系統(tǒng),golang
還可以訪問一下首頁(yè)看看,訪問成功!只是目前還沒有業(yè)務(wù)數(shù)據(jù),所以是一個(gè)非常簡(jiǎn)單的空頁(yè)面而已。
11. 搭建較通用的GoWeb開發(fā)腳手架,# 風(fēng)鈴草博客系統(tǒng),golang

九:注意事項(xiàng)

項(xiàng)目中我們使用了os.Args接收參數(shù),實(shí)際也可以使用flag。那么為什么要運(yùn)行時(shí)傳配置文件路徑,而不是直接在代碼中用相對(duì)路徑寫死呢?

原因是項(xiàng)目運(yùn)行時(shí)的基準(zhǔn)目錄,是以執(zhí)行運(yùn)行程序所在目錄為準(zhǔn)的,也就是說,編譯后產(chǎn)生了.exe文件,我們?nèi)绾畏诺搅似渌夸浵氯?zhí)行,代碼中寫死配置文件讀取目錄的話可能就讀不到了,因?yàn)槁窂讲粚?duì)了。但是讓用戶自己指定目錄,在執(zhí)行時(shí)保證指定路徑下配置文件存在,就可以正常執(zhí)行。文章來源地址http://www.zghlxwxcb.cn/news/detail-839918.html

到了這里,關(guān)于11. 搭建較通用的GoWeb開發(fā)腳手架的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • VUE2 腳手架搭建

    VUE2 腳手架搭建

    M : Model 模型層(業(yè)務(wù)邏輯層)主要包含 JS 代碼,用于管理業(yè)務(wù)邏輯的實(shí)現(xiàn) V : View 視圖層 主要包含 HTML/CSS 代碼,用于管理 UI 的展示 VM : ViewModel (視圖模型層)用于將 data 與視圖層的 Dom 進(jìn)行動(dòng)態(tài)綁定 ①腳手架環(huán)境安裝 制作web項(xiàng)目,從小作坊狀態(tài)轉(zhuǎn)向工程化開發(fā)的狀態(tài)

    2024年02月09日
    瀏覽(101)
  • 從腳手架搭建到部署訪問路程梳理

    1、vue-cli 起文件: 2、配置 webpack :打包配置等,env文件( 處理線上和測(cè)試的ip), https://www.ibashu.cn/news/show_377892.html 3、樣式:封裝 style :組件(element-ui) 其他類似的css js文件封裝:(單位的處理,初始化參數(shù)的處理deepclone 等 4、模塊組件:封裝(傳參的處理 5、數(shù)據(jù)請(qǐng)求:

    2024年02月17日
    瀏覽(16)
  • 腳手架開發(fā)流程詳解

    創(chuàng)建npm項(xiàng)目 創(chuàng)建腳手架入口文件,最上方添加 配置package.json,添加bin屬性 編寫腳手架代碼 將腳手架發(fā)布到npm 安裝腳手架 使用腳手架 分包:將復(fù)雜的系統(tǒng)拆分成若干個(gè)模塊 命令注冊(cè): 參數(shù)解析 options全稱:–version、–help options簡(jiǎn)寫:-V、-h 帶params的options: --path /Users/sam/D

    2024年02月07日
    瀏覽(24)
  • Vue3 腳手架搭建項(xiàng)目詳細(xì)過程

    Vue3 腳手架搭建項(xiàng)目詳細(xì)過程

    如果之前安裝了2.0的腳手架,要先卸載掉,輸入:npm uninstall vue-cli -g 進(jìn)行全局卸載 然后重新安裝:npm install @vue/cli -g 由于 git bash 來執(zhí)行命令的時(shí)候無法使用鍵盤上下鍵來進(jìn)行選項(xiàng)選擇,所以我們要使用? cmd / powershell,這里使用 cmd 1.vue create + 項(xiàng)目名稱 ?2.模板選擇,通過鍵

    2024年02月06日
    瀏覽(94)
  • 和chatgpt學(xué)架構(gòu)01-搭建項(xiàng)目腳手架

    今年3月份以來,chatgpt就熱度不減。有了這種聊天機(jī)器人,就可以很方便的幫助我們提高。無論是我們獨(dú)立創(chuàng)業(yè)還是做項(xiàng)目外包,擁有一套自己可以把握的腳手架還是必備的能力。 過去如果靠自己摸索,組裝這么一套腳手架還是費(fèi)事費(fèi)力的。一個(gè)是涉及技術(shù)比較多,既要架構(gòu)

    2024年02月16日
    瀏覽(25)
  • 前端如何搭建腳手架并在本地運(yùn)行

    前端如何搭建腳手架并在本地運(yùn)行

    在開始搭建前,確保本機(jī)安裝了node,為避免奇奇怪怪的問題 建議node版本16以上 使用過vue ,react,angular的同學(xué)都知道 ,應(yīng)該對(duì)腳手架有一定的理解,比如vue-cli的 vue create myApp ,其中vue 就是vue-cli聲明的一個(gè)命令,下來我們創(chuàng)建一個(gè)項(xiàng)目并聲明自己的命令。 創(chuàng)建一個(gè)空的文件夾

    2024年02月20日
    瀏覽(30)
  • 微信小程序入門04-后端腳手架搭建

    微信小程序入門04-后端腳手架搭建

    我們上一篇已經(jīng)介紹了權(quán)限系統(tǒng)的庫(kù)表搭建,光有表還是不夠的,我們還需要有一個(gè)后臺(tái)系統(tǒng)和數(shù)據(jù)庫(kù)進(jìn)行交互。搭建后臺(tái)的時(shí)候既需要選擇使用什么語言,也需要選擇框架。 框架分為前端框架和后端框架。在第一篇微信開發(fā)者工具搭建的時(shí)候我們其實(shí)前端框架已經(jīng)選擇好了

    2024年02月05日
    瀏覽(28)
  • 使用命令行方式搭建uni-app + Vue3 + Typescript + Pinia + Vite + Tailwind CSS + uv-ui開發(fā)腳手架

    使用命令行方式搭建uni-app + Vue3 + Typescript + Pinia + Vite + Tailwind CSS + uv-ui開發(fā)腳手架

    項(xiàng)目代碼以上傳至碼云,項(xiàng)目地址:https://gitee.com/breezefaith/uniapp-vue3-ts-scaffold 近日心血來潮想做一個(gè)開源項(xiàng)目,目標(biāo)是做一款可以適配多端、功能完備的模板工程,包含后臺(tái)管理系統(tǒng)和前臺(tái)系統(tǒng),開發(fā)者基于此項(xiàng)目進(jìn)行裁剪和擴(kuò)展來完成自己的功能開發(fā)。但前臺(tái)系統(tǒng)花樣繁多

    2024年01月20日
    瀏覽(28)
  • 前端架構(gòu): 腳手架框架之yargs的11種基礎(chǔ)核心特性的應(yīng)用教程

    腳手架框架之yargs的基礎(chǔ)核心特性與應(yīng)用 1 )概述 yargs 是腳手架當(dāng)中使用量非常大的一個(gè)框架 進(jìn)入它的npm官網(wǎng): https://www.npmjs.com/package/yargs 目前版本: 17.7.2 Weekly Downloads: 71,574,188 (動(dòng)態(tài)數(shù)據(jù)) 最近更新:last month (github) 說明這是一個(gè)比較優(yōu)質(zhì)的庫(kù) 2 )對(duì) yargs 的應(yīng)用 準(zhǔn)備一個(gè)腳手

    2024年02月21日
    瀏覽(18)
  • 搭建SpringBoot多模塊微服務(wù)項(xiàng)目腳手架(一)

    搭建SpringBoot多模塊微服務(wù)項(xiàng)目腳手架(一)

    這篇文章介紹下搭建SpringBoot多模塊項(xiàng)目腳手架,他最大的優(yōu)點(diǎn)就是配套了開發(fā)微服務(wù)業(yè)務(wù)所有的附屬產(chǎn)品,可以直接開發(fā)業(yè)務(wù)節(jié)省了搭建環(huán)境時(shí)間。 因?yàn)槟_手架內(nèi)容很多,因此將它設(shè)計(jì)為一個(gè)系列介紹,共分為三篇文章。 第一篇文章 搭建SpringBoot多模塊微服務(wù)框架 第二篇文

    2024年02月09日
    瀏覽(19)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包