Go*.goGo1.16
Go1.16embed

然而在项目中,以上两种方案我都没用,转而自研了一套方案。

不想听我bb心路历程的,直接跳到 开整 环节看最终实现。

背景

在2021年初,我在参与的项目 go-mod-graph-chart 时,需要把前端资源集成到一个由Go语言构建的 命令行 程序中。

go mod graphgo mod graph

命令输出结果如下:

$ go mod graph
go-learn github.com/antlabs/pcurl@v0.0.7
go-learn github.com/bxcodec/faker/v3@v3.6.0
go-learn github.com/go-sql-driver/mysql@v1.5.0
go-learn github.com/jinzhu/copier@v0.3.5
go-learn github.com/pingcap/parser@v0.0.0-20220118030345-6a854bcbd929
go-learn github.com/smartystreets/goconvey@v1.7.2
go-learn golang.org/x/text@v0.3.7
go-learn moul.io/http2curl@v1.0.0
github.com/antlabs/pcurl@v0.0.7 github.com/gin-contrib/gzip@v0.0.1
github.com/antlabs/pcurl@v0.0.7 github.com/gin-gonic/gin@v1.6.3
github.com/antlabs/pcurl@v0.0.7 github.com/guonaihong/clop@v0.0.9
github.com/antlabs/pcurl@v0.0.7 github.com/guonaihong/gout@v0.0.12
github.com/antlabs/pcurl@v0.0.7 github.com/stretchr/testify@v1.6.1
github.com/pingcap/parser@v0.0.0-20220118030345-6a854bcbd929 github.com/cznic/golex@v0.0.0-20181122101858-9c343928389c
github.com/pingcap/parser@v0.0.0-20220118030345-6a854bcbd929 github.com/cznic/mathutil@v0.0.0-20181122101859-297441e03548
...

而使用 gmchart 这个工具,将其可视化为多级树状结构。

如下图:

gmchart-show

graphviz*.go
Go1.16 embedgo-bindataginginhttp

git.go.mod

实现思路

*.jsjsjsindex.htmljs
GoGo代码
GolanghttphederContent-Type
main.jsindex.htmlgoGo
package gostatic

var IndexHtml = `<!DOCTYPE html>^M
<html lang="en">^M
</html>

var MainJs = `echo "hello";`

var Favicon = `data:image/ico;base64,AAABAAEAmpsAAAEAIAT...`

开整

项目前端构建用到了 webpack,那就在这上面动动手脚了。

一个 gopher 想要去动 webpack?有点自不量力
webpack
plugingo_static.gomain.jsindex.html
pack-all-in-go-plugin.js
class PackAllInGoPlugin {
  apply(compiler) {
    // emit is asynchronous hook, tapping into it using tapAsync, you can use tapPromise/tap(synchronous) as well
    compiler.hooks.emit.tapAsync('PackAllInGoPlugin', (compilation, callback) => {
      // Create a header string for the generated file:
      var filelist = '';
      var indexHtml, mainJs;
      var goCode = `package godist

func GetFile(file string) string {
  switch {
  case \`index.html\` == file:
    return IndexHtml
  case \`main.js\` == file:
    return MainJs
  case \`favicon.ico\` == file:
    return Favicon
  default:
    return ""
  }
}

var IndexHtml = \`--index.html--\`

var MainJs = \`--main.js--\`

var Favicon = \`favicon.ico\``

      // Loop through all compiled assets,
      // adding a new line item for each filename.
      for (var filename in compilation.assets) {
        if ("main.js" == filename) {
          let jsCode = compilation.assets[filename].source()
          let jsCodeString = jsCode.slice();
          jsCodeString = jsCodeString.replace(/\`/g, "\` + \"\`\" + \`")
          goCode = goCode.replace('--main.js--', jsCodeString)
        } else if ("index.html") {
          let htmlCode = compilation.assets[filename].source()
          goCode = goCode.replace('--index.html--', htmlCode)
        }
      }

      // 将这个列表作为一个新的文件资源,插入到 webpack 构建中:
      compilation.assets['../godist/static.go'] = {
        source: function() {
          return goCode;
        },
        size: function() {
          return goCode.length;
        }
      };

      callback();
    });
  }
}

module.exports = PackAllInGoPlugin;
webpack
/*
 * 引入自定义插件
 */
const PackAllInGoPlugin = require('./plugin/pack-all-in-go-plugin');

...

config = {
    pulbins: [
    ...
        new PackAllInGoPlugin({options: true})
    ],
}
npm run buildgo build -o main main.gogo
对了!这个 webpack plugin 没发布到 npm ,你如果要用直接把源码抄过去就行了。中间遇到集成问题,可以看看 https://github.com/PaulXu-cn/... ,这个项目实际有在用。

最后

goGoWebPack
gophergowebpack plugin

我也预见了,这方法也就少数人用用,想试试直接copy代码就行,这个小玩意,就不单独开"坑"了。

gohper

qrcode

参考