搭建一个网站开发框架并不简单,至少要满足以下几个要点:
- 前端:
- 要有Webpack编译服务,支持ES6语法,能
npm install
,能import
- 开发模式自动更新,改一下JS代码页面能马上自动刷新,有热更新HMR
- 能够顺利访问后端API服务获取数据,方便调试接口
- 要有Webpack编译服务,支持ES6语法,能
- 后端:
- 静态文件服务
npm run build
编译好的页面要能正常访问,往往要配置Nginx、Apache - 动态开发路由服务
npm run dev
的时候也能访问实时更新 - 自带接口API路由服务,让前端能够调试API,获取数据
- 静态文件服务
对于新手来说,安装node、npm和golang并不困难,但配置webpack.config.json一大堆就很头疼,然后还要配置Nginx静态文件服务和接口代理、开发代理,然后再配置Golang开发环境,搞不好几个小时就没了,可能没熬到最后成功,大部分就放弃了...
如果你是在MacOS苹果系统下想快速搭建一个网站开发框架,可以复制下面代码,保存为a.sh
然后终端执行sh a.sh
,输入任意文件夹名比如myweb
,十几秒,满足以上要点的完整前后端框架就运行起来了,你可以立即编写前端web/src/index.js
代码,页面自动刷新,也可以直接编写main.go
撰写自己的api接口,然后go run main.go
1秒重启API服务。
推荐直接在VSCode中运行sh命令,默认会弹出终端窗口启动页面开发测试服务,运行在8080端口。你可以随时关掉它,进入web文件夹,
npm run dev
重新启动。
Golang服务器默认运行在8081端口,会自动代理静态文件到dev服务器,如果需要代理到build好的静态服务器,请自行修改代码
http.HandleFunc("/api", APIHandler)
变为http.HandleFunc("/api", StaticFileHandler)
,重启即可,要做为正式服务器使用,你需要修改端口8081变为80。
不需要Nginx或者其他,这个Golang程序自带网站静态文件路由功能,无需任何设置。这样做的另一个好处就是文件服务和API接口都由Golang运行在同一端口,可以避免跨域不同源问题。
确认node、npm、go安装完成且命令可用,然后复制下面代码,保存为a.sh
放到任意目录,sh a.sh
运行。
#!/bin/bash
# 需要修改为可执行文件 chmod +x CreateGoWebProject.sh
# 然后 sh CreateGoWebProject.sh
# Part1:创建golang项目
# 切换到国内镜像
go env -w GO111MODULE=on
go env -w GOPROXY=https://mirrors.aliyun.com/goproxy/,direct
# 提示用户输入项目名称
read -p "请输入项目名称: " project_name
# 检查用户是否输入了项目名称
if [ -z "$project_name" ]; then
echo "项目名称不能为空。"
exit 1
fi
# 创建项目目录并进入
mkdir "$project_name" && cd "$project_name"
# 初始化项目
go mod init "$project_name"
# 创建main.go文件
echo 'package main
import (
"encoding/json"
"fmt"
"net/http"
"net/http/httputil"
"net/url"
"os"
"path/filepath"
)
func main() {
// 创建路由器
http.HandleFunc("/api", APIHandler)
http.HandleFunc("/", ProxyHandler)
// 启动服务器
fmt.Println("Server is running at http://localhost:8081")
if err := http.ListenAndServe(":8081", nil); err != nil {
fmt.Printf("Error starting server: %v", err)
}
}
// APIHandler 处理 /api 请求
func APIHandler(w http.ResponseWriter, r *http.Request) {
jsonData, _ := json.Marshal(map[string]string{
"message": "API response",
"status": "200",
})
w.Header().Set("Content-Type", "application/json")
w.Write(jsonData)
}
// ProxyHandler 处理所有其他请求并代理到 localhost:8080
func ProxyHandler(w http.ResponseWriter, r *http.Request) {
target := "http://localhost:8080"
targetURL, _ := url.Parse(target)
proxy := httputil.NewSingleHostReverseProxy(targetURL)
proxy.ServeHTTP(w, r)
}
// StaticFileHandler 处理所有其他请求并提供静态文件服务,正式服务器使用
func StaticFileHandler(w http.ResponseWriter, r *http.Request) {
staticDir := "./web/dist"
filePath := filepath.Join(staticDir, r.URL.Path)
// 检查文件是否存在
if _, err := os.Stat(filePath); os.IsNotExist(err) {
http.NotFound(w, r)
return
}
// 提供静态文件服务
http.ServeFile(w, r, filePath)
}'> main.go
# Part2:创建ES6-Web项目
# 创建项目目录并进入
mkdir "web" && cd "web"
# 初始化 npm 项目
npm init -y
# 安装开发所需的依赖
npm install --save-dev @babel/core @babel/cli @babel/preset-env webpack webpack-cli webpack-dev-server babel-loader html-webpack-plugin
# 创建 Babel 配置文件
echo '{
"presets": ["@babel/preset-env"]
}' > .babelrc
# 创建 Webpack 配置文件
echo 'const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: "./src/index.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "dist"),
clean: true,
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
},
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
],
devServer: {
static: {
directory: path.join(__dirname, "dist"),
},
compress: true,
port: 8080,
open: false, // 自动打开浏览器
client: {
logging: "error", // 禁用客户端日志
},
devMiddleware: {
stats: "errors-only", // 只输出错误信息
},
},
mode: "development",
};' > webpack.config.js
# 创建项目结构
mkdir src
echo 'if (!window.isInitialized) {
window.isInitialized = true
const greet = async () => {
const hellostr = `Hello ES6!`
const root = document.getElementById(`root`)
root.innerHTML = `<h1>${hellostr}</h1><p>${new Date()}</p>`
console.log(hellostr)
fetch(`/api`)
.then(resp => resp.json())
.then((resp) => {
console.log(`/api:`, resp)
})
}
greet()
}' > src/index.js
echo '<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ES6 Project</title>
</head>
<body>
<div id="root"></div>
<script src="bundle.js"></script>
</body>
</html>' > src/index.html
# 添加构建和启动脚本到 package.json
npx json -I -f package.json -e 'this.scripts={"build":"webpack","dev":"webpack serve"}'
# Part3:启动服务
# 查找并杀死占用8080端口的进程
for port in 8080 8081; do
echo "Killing processes on port $port..."
lsof -i tcp:$port | grep LISTEN | awk '{print $2}' | xargs kill -9
done
# 新窗口启动Web开放服务器
CUR_PATH=$(pwd)
osascript <<EOF
tell application "Terminal"
do script "cd \"$CUR_PATH\" && npm run dev"
activate
end tell
EOF
# 启动Golang服务器
echo "\n站点服务正在启动,请打开下面网址查看:http://localhost:8081"
cd .. && go run main.go
END