windows 下 npm 拉取 github 仓库问题

npm拉私有仓库报错:git@github.com: Permission denied (publickey) 怎么办呢?

npm 拉私有仓库报错无权限问题

$ npm i https://github.com/littlewrite/frameless-titlebar@v2.1.4-reatv18
npm WARN config global `--global`, `--local` are deprecated. Use `--location=global` instead.
npm ERR! code 128
npm ERR! An unknown git error occurred
npm ERR! command git --no-replace-objects ls-remote ssh://git@github.com/littlewrite/frameless-titlebar@v2.1.4-reatv18.git
npm ERR! git@github.com: Permission denied (publickey).
npm ERR! fatal: Could not read from remote repository.
npm ERR!
npm ERR! Please make sure you have the correct access rights
npm ERR! and the repository exists.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\wojia\AppData\Local\npm-cache\_logs\2022-07-27T03_44_39_166Z-debug-0.log

解决否

已解决

解决方案

  1. 在本地 生成 ssh key,然后添加到 github 配置。
  2. 添加到本地项目
  3. windows 下要启动一个啥 服务
  4. 可以开始 npm install 了, 带上https:// 后缀 .git ,如果要制定tag 再添加 #V1.0.0

参考

  • https://docs.github.com/cn/authentication/troubleshooting-ssh/error-permission-denied-publickey
  • https://www.zhihu.com/question/21402411
  • https://stackoverflow.com/questions/17846529/could-not-open-a-connection-to-your-authentication-agent
  • https://github.com/npm/npm/issues/14447

用前端构建工具打包后端服务,我到底经历什么

node.js 能用 wepack打包么?node.js 代码可以打包成一个js 文件么?来这里看看吧

看到这个 标题,是的,我本是个后端,最近要写点 node.js, 之前写前端,知道 npm build 一下,那么用 javascript 写的后端程序也要 npm build 吧,好的,作为个 gopher , 带着对 javascript 的刻板印象就开干了。

我本 gopher,奈何没有一个会前端的老婆,就自己干前端了,如果干的不对,请及时纠正

项目背景

还是简单介绍下项目背景,屏幕前专业前端同学可以先猜猜这样干行还是不行,行的话,该怎么做。

这个程序运行的 node.js 端,提供一个简单的 http 服务,内部逻辑涉及:

  1. toml2json
  2. curl-to-go
  3. toml-to-go
  4. toml2xml
  5. xml2json
  6. json2toml

这些逻辑,可用内建包能解决,有些依赖第三方包,例如:

  1. json2toml
  2. object-to-xml

还有些组件,未提交到npm,也未做模块化处理,需要把代码找出来,单独处理,例如:

  1. curl-to-go
  2. toml-to-go

这些第三方包,感觉都是运行在前端环境的,(刚开始,我只是通过npm拉下来,也不知道能不能运行在 node.js 上,npm 也没指明这些包在前后端 runtime 兼容性)现在我想用 webpack 将其所有的代码打包成一个 js 文件,并能运行在 node.js 环境,

好,问题和背景如上。

别说:node.js 打什么包!

钟薛高 你还要不要

开整

我面临如下问题:

  1. 如何引入前端 包
  2. 如何引入 未模块化改造的包
  3. 如何让 webpack 编译的成果在 node.js 环境也能运行

关于第一个问题,首先得搞清楚在 Javascriptimportrequire 区别。

import 与 require 区别

require/exports 属于社区自己选举出的方案。import/export 属于是 ECMAScript 规范。

这里我们用到了 webpack , 那么就得使用 import/export 作为代码引入语法。所以,对 curl-to-go 代码改一下,在最后新增:

function curlToGo(curl) {
...
}

+ export default curlToGo;

这样就解决了,各个js文件组合问题。

第二个问题,需要弄清楚,node.js 的包管理机制

node.js 模块

node.js 模块管理,用的是 require ,由于我需要用 node.js 起一个 http 服务,需要使用 require 语句引入 http 模块。

但这还没完,webpack 是不能很好区分,哪些是外部依赖,哪些是内部依赖。所以这里需要告知 webpack :

module.exports = {

    target: "node", 

    }

第三个问题,那就随缘了,build之后,run一下试试咯。

最终 webpack 配置如下。

--- a/webpack.config.js
+++ b/webpack.config.js
@@ -1,5 +1,6 @@
 const path = require('path');
 const webpack = require('webpack');
+var fs = require("fs")

 /*
  * 引入 ParallelUglifyPlugin 插件
@@ -13,9 +14,20 @@ const PATHS = {
     build: path.join(__dirname, 'build'),
 };

+var nodeModules = {};
+fs.readdirSync('node_modules')
+    .filter(function(x) {
+        return ['.bin'].indexOf(x) === -1;
+    })
+    .forEach(function(mod) {
+        nodeModules[mod] = 'commonjs ' + mod;
+    });
+
 module.exports = {
     mode: 'development',
     devtool: false, // 编译成果 保留换行
+    target: "node",
+    externals: nodeModules,
     entry: {
         entry: path.join(__dirname, 'src/index.js'),
     },

最后

又是折腾前端的一天,哦不,是好几天。

javascript 和 node.js 包都放在 npm 里,有点让人搞不清楚适用环境,当然,这次引入的包都没有调用底层 API,所以,没出现兼容性问题。

importrequire 傻傻分不清楚,CommonJS, ES6ES5 各种标准算是给我好好上了一课。

好了,简单聊到这,不是太难的东西,只是表达一下一个刚入门前端的人碰到这些问题后的,“幸”路历程。

参考

  • https://zhuanlan.zhihu.com/p/28483358
  • https://sazzer.github.io/blog/2015/05/12/Javascript-modules-ES5-vs-ES6/
  • https://juejin.cn/post/6896397110078504973
  • https://zh.quish.tv/how-package-nodejs-application-using-webpack
  • https://blog.anymelon.com/2020/05-22-nodejs-webpack-record/
  • https://www.zhihu.com/question/56820346

Golang 非主流 打包静态资源方案

Golang除了使用Go1.16的 embed 和 go-bindata,还有什么静态资源打包方案呢?如果go版本低于1.16,又不想引入外部依赖,如何打包静态资源到go-build制品里呢?来瞅瞅

说到往 Go 程序里面打包进其他非 *.go 资源,在 Go1.16 之前有 go-bindata 第三方开源支持。

Go1.16 引入了新特性 embed,不依赖第三方就能嵌入静态资源权限。

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

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

背景

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

都说到这了,就介绍下 go-mod-graph-chart ,它是一个 将 go mod graph 命令输出的文本可视化 命令行 工具(类似于graphviz),在项目目录下执行go 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 代码里。

很不巧在2020年底时, Go1.16 embed 还未推出 ,但我要解决这个问题。go-bindata 在当时无疑是最受欢迎的方案,但会引入第三方依赖。这个时候,我代码洁癖上来了,之前我用gin做了http服务,后来发现项目只引入了 gin,我把gin换成内置的 http 服务 后,就变成无依赖的项目了。所以,我想继续保持 no dependency 。我感觉这个功能应该不难,自己也能写啊。

git.go.mod

实现思路

前端打包,有一步是把所有的 *.js 文件集成到一个 js 文件。并把最终输出的 js 文件名写到 index.html 文件里作为入口js

Go 静态资源打包,就是把其他类型的文件序列化后,保存到 Go代码 里的静态变量里。

Golang 程序在对外提供http服务时,当收到静态资源请求时,就会去读取对应变量,输出到http响应体中,并在 http heder 中设置对应的 Content-Type

那么如果想办法干预下输出流程,让其写 main.js, index.html 文件,改为将内容写入到 go 代码的两个变量,就可以实现 Go 打包静态资源了。

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的官网,转了一圈,发现官方提供了plugin,通过自定义插件,可以影响其构建流程。

这里在plugin,获取到了构建结果,通过遍历构建结果,获取到了对于字符串,以及文件名,然后我们又插入了一个新的构建结果 go_static.go,这里面包含前面的 main.js, index.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 build 就能把最新的静态资源打包进 go_static.go 文件内了。再执行 go build -o main main.go go代码和静态资源就打包到一个可执行文件内了。

对了!这个 webpack plugin 没发布到 npm ,你如果要用直接把源码抄过去就行了。中间遇到集成问题,可以看看 https://github.com/PaulXu-cn/go-mod-graph-chart ,这个项目实际有在用。

最后

总的来说,这次是从前端构建这边来解决了go打包静态资源问题,算是横跨 GoWebPack,这方案算是比较小众,基本属于:

  1. gopher 不想碰前端
  2. 前端为什么要给 gowebpack plugin

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

好了,我是个爱折腾的 gohper,这次填了一个我自己制造的坑。如果大家也喜欢捣鼓点不一样的东西,欢迎一起交流。

qrcode

参考

  • https://xie.infoq.cn/article/0e69354f6d1c866193f76cea9
  • https://mp.weixin.qq.com/s/eqquyrWN0CqEzmwXquRlAA
  • https://github.com/go-bindata/go-bindata
  • https://github.com/PaulXu-cn/go-mod-graph-chart
  • https://graphviz.org/
  • https://webpack.js.org/