使用go的工具链开发前端(React)

562 阅读4分钟

前言

  前几个月在github发现了一个go编译成js的方案gopherjs,就萌生了一个想法,用go开发前端。gopherjs的功能是将go代码转换成js代码,类似babel的功能,将go的代码转换成抽象语法树,因为go是强类型语言,所以gopherjs也提供了类似ts的特性,类型校验,提供了基本的go开发js的基础方案。依托这个方案实现的开源方案比较有名的vecty,有点类似react和vue的方案,也有react的go的实现方案myitcv.io/react,我的想法也是依托于这个方案为基础对现有的go的工具链改造使得开发的体验接近于现在的前端开发。

基本工具链

  现测试版本仅支持linux的arm64、amd64、386的平台,别的平台需要自行进行编译,可以参考Go源码编译,除了Gox以外都可以通过go build构建对应平台的版本。

Gox

  该版本是支持gox写法的go标准库版本,是基于go的1.18.1版本,因为go1.18版本引入了泛型。本次调整主要标准库涉及到了go/scanner、go/ast、go/parser、go/types、go/printer,提供go对gox语法糖的扫描、ast的转换、类型校验和代码格式化,提供了类似babel和ts的功能的基础。

Gopls(Gox)

  该工具是支持gox写法的gopls,即支持gox的语法提示和代码检查的lsp工具。主要调整的是lsp中的cache包,加入了对gox文件的代码检查、代码补全,同时提供了gox类似eslint的代码格式化功能,暂不支持eslint类似的配置功能,该功能还待完善。

Staticcheck(Gox)

  该工具与gopls的功能类似,但其只提供gox静态代码的检查功能,是基于go-tools通过新的go的标准库构建,保存时对代码进行静态检查。

ReactGen(Gox)

  该工具提供基本的gox脚手架的功能,是原myitcv.io/react提供的思路开发的新的模板脚手架,之后可能会追加多个模板。

Gopherjs(Gox)

  该工具是在原gopherjs的基础上开发,提供了gox代码的编译、sass代码的整合和对gox代码的注入实现开发环境下的热更新机制,同时保留了go和js的生态,支持go动态引用js库和file-loader的能力,也丰富了原有的js打包功能,类似webpack的功能。

VSCode-gox

  该工具提供了vscode中支持gox文件的标签的提示。

开发环境部署

// Linux,以arm64为例
cd /usr/local && wget https://github.com/zq2820/go/releases/download/gox1.18.1.beta1/gox-1.18.1-arm64.zip && unzip gox-1.18.1-arm64.zip

// 配置go的环境变量模板,实际情况根据自己的来 
export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin

export GO111MODULE=on
export GOPATH=$HOME/go
export GOPROXY=https://proxy.golang.com.cn,direct
export GOROOT=/usr/local/go
export GOTOOLDIR=/usr/local/go/pkg/tool/linux_arm64

// 配置工具链
// 工具需放在$GOPATH下的bin
wget https://github.com/zq2820/tools/releases/download/gopls%2Fv0.10.0-beta1/gopls-linux-arm64.zip
// 自行编译
wget https://github.com/zq2820/tools/archive/refs/tags/gopls/v0.10.0-beta1.zip
unzip v0.10.0-beta1.zip
cd tools-gopls-v0.10.0-beta1 && go mod tidy
cd gopls && go build

wget https://github.com/zq2820/go-tools/releases/download/v0.4.0-1.dev/staticcheck-linux-arm64.zip
// 自行编译
wget https://github.com/zq2820/go-tools/archive/refs/tags/v0.4.0-1.dev.zip
unzip v0.4.0-1.dev.zip
cd go-tools-0.4.0-1.dev && go mod tidy
cd cmd/staticcheck && go build

wget https://github.com/zq2820/x/releases/download/0.1.0-beta1/reactGen-linux-arm64.zip
// 自行编译
wget https://github.com/zq2820/x/archive/refs/tags/0.1.0-beta1.zip
unzip 0.1.0-beta1.zip
cd x-0.1.0-beta1 && go mod tidy
cd react/cmd/reactGen && go build

// gopherjs因为用了libsass,libsass涉及到了cgo,所以对应不同平台下需要自行编译
wget https://github.com/zq2820/gopherjs/archive/refs/tags/v1.17.3-beta1.zip
unzip v1.17.3-beta1.zip
cd gopherjs-1.17.3-beta1 && go mod tidy && go build

// 别的可以在vscode内自行安装

创建默认模板项目

reactGen -init minimal -name helloworld

// 项目结构
.
├── go.mod
├── go.sum
├── LICENSE
├── packages
│   ├── package.json // 需要额外依赖的js库
│   ├── package-lock.json
│   ├── webpack.dev.config.js
│   └── webpack.prod.config.js
├── public
│   ├── favicon.ico
│   └── index.html
└── src
    ├── app
    │   ├── app.gox // 类组件的example
    │   └── app.module.scss // scss的文件
    ├── assets
    │   ├── 3b87e950352ac65c5eb643ddf9f2b21192138ae8.png
    │   └── logo.svg
    ├── common.css
    ├── fun
    │   └── index.gox // 函数式组件的example
    ├── main.gox // 类似react的入口文件
    └── utils
        ├── index.go // 引用三方库的例子
        └── promise.go // 封装promise的例子
        
// 安装依赖
go mod tidy
cd packages && npm i

// 运行项目
// dev 8888端口
gopherjs build . -w
// prod
gopherjs build . -o ./dist

运行后的样子

1667791393321.jpg

vscode开发代码提示

  需要把gox文件的语法模式改为Go。 iShot_2022-11-07_12.04.22.2022-11-07 12_08_54.gif

dev开发热更新

iShot_2022-11-07_13.41.20.2022-11-07 13_46_02.gif

性能与原生React的对比

  编译demo时大概的速度保持在2秒左右编译并且启动devServer(macbookpro m1 docker情况),在没有缓存和并发的情况下的速度还是可以的。

iShot_2022-11-08_11.28.54.2022-11-08 13_35_33.gif

  左Gox右React原生

1667802434424.jpg

  两者在相同react版本(16.9.0)下进行对比,两者的差距还是比较明显。前者的React是全量引入,后者是treeshaking后,而且前者还有对go代码的转换上的开销,打包后的大小差距较为明显,所以内存占用上还是差强人意。

总结

  该方案的可行性还是相对可行,但现在的工具链开发还没有很完善,例如gopls的稳定性并没有这么强,需要使用定制的go的标准库会破坏现有的开发环境,还是建议在docker内玩,之后可能会出一个DockerFile提高可玩耍的能力,详细的实现过程等之后慢慢补,有任何问题欢迎交流。