标题有点绕口哈。作为开发者,VSCode这款IDE应该无人不知,无人不晓吧。但是很多人并不知道VSCode还有一个Web版本,也就是在浏览器中在线编码。要实现在线编码就需要无数强大的服务器集群来支撑,而构建一个VSCode for web来预览代码,则像普通web网站一样,所有用户公用一个服务器资源--------------------引
在github上已经有前辈开源了一个非常火的项目Github1s,用户在检索github优秀项目的时候,通常做法是把代码clone到本地,然后打开VSCode浏览代码。而有了Github1s,只需要把github域名改成github1s即可在线预览github代码。举例:
github项目:https://github.com/microsoft/vscode/
预览代码:https://github1s.com/microsoft/vscode/
基于此项目,我便提出了ISSUE给作者,希望支持Gogs系统:
此外,近期我自己抽空实现了基于Gogs平台的 VSCode for web 的集成开发,为了表示对Github1s项目的尊敬,本项目命名为 Gogs1s,并记录一下踩的坑。
修改 Gogs 的模板文件 templates/repo/home.tmpl,嵌入一个 Gogs1s 的链接:
<a class="ui basic icon button poping up clipboard" href="http://code.git.yoqi.me{{.RepoLink}}" target="_blank">
<i class="octicon octicon-file-submodule"></i>
<img src="/img/hot.svg" style="position: absolute;height: 10px;width: 10px;top: 0px;right: 3px;">
</a>
效果如下:
当点击这个按钮,即可打开 Gogs1s 预览当前项目的源码:
要想开发 Gogs1s,首先需要了解 VSCode 的启动流程,以及 VSCode 虚拟文件系统。当然还需要了解 VSCode 的编译,运行。这些可以查看我以往的文章。
项目结构主要有一下三部分:
(1)src/vs 里面是对 VSCode 源码的更改:
workbench.ts 添加一个 IHomeIndicator ,这样可以跳转到Gogs项目,在Gogs项目点击预览按钮又可以回到 Gogs1s,这样体验就很好了:
添加上面代码后,就可以实现左上角的跳转到Gogs项目的按钮:
(2)修改自定义通知
当然,这个功能可以不需要。
(3)显示版本名称
这里我并没有基于最新版的VSCode来开发,而是:
git clone --depth 1 -b 1.52.1 https://github.com/microsoft/vscode.git vscode
在执行 yarn 安装依赖的时候,需要执行postinstall.sh, 这个时候 clone VSCode 源码,而我这边基于VSCode 1.52.1 官方版本开发:
这样当我们查看版本的时候就可以如下显示:
(4)设置 gogs1s 文件协议
当我们在浏览器访问 gogs1s://owner/repo 的时候,Gogs1s检测到这个协议的URL则会正确解析。
(5)gogs1s插件的开发
和 github1s 插件类似,通过复制 vscode.proposed.d.ts 实现 VSCode实验性的 API。这里主要是对文件的读,搜索等功能的实现。
具体实现在 gogs1sfs.ts中,定义了 File 和 Directory 两个类:
而 file 和 directory不再是本地文件,而是需要网络请求,通过 Gogs API 获取,为此定义一个统一的fetch方法:
fetch方法中,统一在 header 中设置 token,Gogs API 必须携带token,否则统一返回401无权限。
接下来在 api.ts中实现 readGitHubDirectory 和 readGitHubFile 两个方法,从而可以从gogs平台获取文件和目录:
1、Gogs 是一个小型的代码管理系统,API很不完善。诸如分支,Tag,验证Token等都没有相应的API,要体验更多功能,只能使用 Gitea了。
2、目前 readGitHubDirectory 存在一个问题,只能获取根目录,而这个 API 问题一直存在:
3、为了消除黑人歧视,默认master分支改为main分支。这个在gogs上也有问题,当HEAD不是master分支的时候 API 获取结果为空。
4、gogs可能还有诸多bug。。。
最近不断赶紧更新,Gogs1s迎来了新的版本。有要学习 VSCode开发的小伙伴可以在这篇博文中学点知识,以防掉坑。
(1)发布@jianboy/vscode-web 依赖
之前项目打包每次都需要编译 vscode,而这个十分耗时(十多分钟),但是大部分开发工作都是基于扩展开发,所以全新架构项目,抽离 vscode 编译部分代码为依赖,发布到 npm 托管:@jianboy/vscode-web - npm (npmjs.com)
之后每次构建gogs1s项目只花费1分钟,自动打包:
为了打包尽量小,这里排除了*.map文件:
- name: build
run: |
yarn build
- name: tar dist
run: |
tar -zcf dist.tar.gz --exclude='*.map' dist
- name: artifact
uses: actions/upload-artifact@v2
with:
name: ${{runner.OS}}-artifact
path: |
dist.tar.gz
构建的时候需要注意分步骤构建,原来是一个项目构建所有步骤,而现在是分为 gogs1s 项目和 @jianboy/vscode-web 两个项目:
gogs1s项目中,只需要构建 gogs1s 插件,并整合@jianboy/vscode-web依赖,这个在第二部分介绍。
@jianboy/vscode-web项目,只需要构建 vscode 和内置插件:
function main() {
cd ${APP_ROOT}
rsync -a resources/gulp-gogs1s.js lib/vscode
cd lib/vscode
yarn gulp compile-build
yarn gulp optimize --gulpfile ./gulp-gogs1s.js
yarn gulp minify --gulpfile ./gulp-gogs1s.js
echo "build vscode done!"
}
(2)gogs1s插件更新
首先需要在 package.json 中添加依赖:
"devDependencies": {
"@jianboy/vscode-web": "1.1.10",
}
接下来,只需要构建gogs1s插件即可:
function main() {
rm -rf "${APP_ROOT}/dist"
cd "${APP_ROOT}/scripts"
./build/build-gogs1s-extensions.sh
./package.sh
echo "all build done!"
}
注意package.sh,这个命令,打包需要把 vscode 内置插件和gogs1s插件整合:
function main() {
cd "${APP_ROOT}/scripts"
./package/copy-extensions.sh
./package/copy-node_modules.sh
./package/copy-resources.sh
node ./package/generate-config.js
echo "all copy done!"
}
执行 node ./package/generate-config.js 生成 extensions.json 文件。
(3)readGitHubDirectory 功能更新
之前介绍到 gogs 项目的api不完善。GET /repos/:owner/:repo/git/trees/:sha 这个接口一直只能获取根目录的几个文件夹,这个Bug一直存在。
多次查看API文档之后,我决定采用 GET /repos/:username/:reponame/contents/:path 这个接口来替代上述接口的功能。
git/trees 接口可以一次性返回整个项目的结构,有些项目比较大可能会拖垮系统(这也可能是作者不愿更新这个功能的原因吧)。
contents/:path 接口比较强大(乱),:path参数可以是一个目录,也可以是一个文件,目录则返回当前目录的所有文件;文件则返回文件的内容。
//目录和文件同一个接口,目录返回list,接口返回object
export const readGitHubDirectory = (owner: string, repo: string, ref: string, path: string) => {
let url = "";
if (path == null || path == "/") {
url = `https://git.yoqi.me/api/v1/repos/${owner}/${repo}/contents?ref=${ref}`;
} else {
url = `https://git.yoqi.me/api/v1/repos/${owner}/${repo}/contents/${path}?ref=${ref}`;
}
return fetch(url).catch(handleRequestError);
// return fetch(`https://git.yoqi.me/api/v1/repos/${owner}/${repo}/git/trees/${ref}`).catch(handleRequestError);
};
export const readGitHubFile = (owner: string, repo: string, ref: string, path: string) => {
let url = "";
if (path == null || path == "/") {
url = `https://git.yoqi.me/api/v1/repos/${owner}/${repo}/contents?ref=${ref}`;
} else {
url = `https://git.yoqi.me/api/v1/repos/${owner}/${repo}/contents/${path}?ref=${ref}`;
}
return fetch(url).catch(handleRequestError);
};
所以有意思的就来了, readGitHubDirectory 和 readGitHubFile 两个方法调用同一个接口,方法体也一样,获取内容就返回即可。
当读取 readGitHubDirectory 结果后,需要保存 insertGitHubRESTEntryToDirectory:
const insertGitHubRESTEntryToDirectory = (githubEntry: GithubRESTEntry, baseDirectory: Directory) => {
const pathParts = githubEntry.path.split('/').filter(Boolean);
const fileName = pathParts.pop();
let current = baseDirectory;
if (!(current.entries || (current.entries = new Map<string, Entry>())).get(fileName)) {
const entryUri = Uri.joinPath(current.uri, current.name);
current.entries.set(fileName, (githubEntry.type === 'tree' || githubEntry.type === 'dir') ? new Directory(entryUri, fileName) : new File(entryUri, fileName));
}
const entry: Entry = current.entries.get(fileName);
entry.sha = githubEntry.sha;
(entry.type === FileType.File) && (entry.size = githubEntry.size!);
};
由于调用 contents/:path 这个接口返回的是一个数组,且返回的每个数组元素(目录中的文件)的type类型不再是”tree“,而是dir和file,所以为了兼容原始接口,需要扩充 GithubRESTEntry 中type的类型:
interface GithubRESTEntry {
path: string;
type: 'tree' | 'blob' |'dir' | 'file';
sha: string;
size?: number;
}
(4)CDN资源加速
VSCode web 还是很大的,编译后项目有60M,2000多个文件:
考虑到服务器带宽比较小,初始打开的时候会很慢。为此将部分较大的js等资源发布到cdn上:
比如 static\vscode\vs\workbench\workbench.web.api.js 这个js压缩后有7.7M,每次都打开项目需要请求。而其他小文件可能加载很少,所以就没必要CDN托管。我这里只选取大于100K的文件,有68个。那么只需要把这个68个文件CDN加速,整个Gogs1s项目就体验很好了。
那么这里有一个细节,怎么按照原始目录抽离指定的68个文件呢?
第一步:先把大于100k的文件路径复制出来:
第二步:在所有目录前面增加 git add:
第三步:应该知道我要做什么了吧,首先对当前目录进行版本管理。复制上面的作为一个批处理命令,在cmd命令行中执行。
第四步:执行完之后,就可以使用小乌龟导出当前提交的文件,小乌龟会按照原始目录结构导出:
第五步:这里我以ftp的形式启动 阿里 OSS:
接下来使用 filezilla 等ftp工具上传即可:
由于我在已经把 OSS 结合 CDN了,所以上传后,就可以使用 CDN 请求了,这些就不是本文的内容了。
博客地址:http://blog.yoqi.me/?p=17522
这篇文章还没有评论