• 远程机器环境:Debian 10.6

Visual Studio Code - Remote SSH

远程机器ssh服务端搭建

参考:debian系统下安装ssh服务sshd_config

  1. 安装ssh服务端

    apt-get install openssh-server

  2. 配置ssh(配置文件/etc/ssh/sshd_config)

  3. 重启ssh服务

    service ssh restart

使用Remote SSH插件连接远程机器

  • 先确保本地机器有ssh客户端,在使用之前可以在命令行测试一下连接
  1. 安装Remote SSH插件

  2. 修改配置文件

    1.png

    2.png

    参考ssh_config

  3. 连接到远程机器,远程机器将会自动安装 VSCode-Server,安装目录为 ~/.vscode-server

遇到的坑#1

Bad owner or permissions on C:\Users\USER/.ssh/config

Github Issue

该 Issue 下的一个解决方法

  • 将配置文件路径写到插件设置中即可

    3.png

Docker部署Code-Server

安装方法较多,这里使用 Docker CLI 进行安装,一个脚本直接部署

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/bash
docker run -itd --rm --name code-server \
-p 8080:8080 \
-v "$HOME/project:/root/project" \
-v "$HOME/.vscode-server/extensions:/root/.local/share/code-server/extensions" \
-u "root" \
-e "PASSWORD=yourpassword" \
codercom/code-server:latest \
/bin/bash \
&& \
docker exec code-server \
code-server \
--bind-addr 0.0.0.0:8080 \
--auth password

部分参数原因解释

  • -itd

    主要说明 -d,因为容器需要后台运行

  • --rm

    在容器退出后删除容器,由于需要保存的文件目录(如代码)等已经映射到主机了,不需要担心文件保存的问题

  • -v

    两个 -v 参数分别映射项目目录和上文 VSCode-Server 中安装的插件,这样可以使得插件能够一致(此处忽略兼容性问题)。注意如果用户不同, -v 映射的路径是不一样的

  • -u

    这里直接使用 root 权限,由于 .local/ 目录是由 root 所有,而插件目录 extensions 在其下,因此若想映射主机插件文件夹到此处就必须要 root ,使用其他用户会遇到权限问题。使用 root 可能导致的一个问题是:project 目录及其文件将由 root 所有,主机也需要 root 才能更改文件

  • -e PASSWORD=yourpassword

    由于 code-server 只允许在环境变量或配置文件中设置密码,不能直接传 --password 参数设置密码

  • --bind-addr

    监听地址及端口,注意要和容器开放的端口一致

使用效果

  • 插件一致效果

    4.png

  • 项目路径一致效果

    5.png

遇到的坑#2

权限问题均在终端有显示
部分问题在上文参数解释中已说明

  • 网页访问返回 500

    权限问题

  • 插件没有和主机上的插件一致

    1.权限问题

    2.文件夹映射不正确

文档参考

注意

  • 以下内容均为在特定时间特定环境的个人经验之谈,可能会在以后或不同环境中不适用。

Greasemonkey/Tampermonkey API相关

  • 自某个版本开始有了 GM.* 形式的API,可以用于取代旧版本的 GM_* 形式的API。
    • GM.* 的API函数有些是异步函数,具体请查看文档,而 GM_* 的API函数是同步的。

unsafeWindow

  • 在声明了 @grant unsafeWindow 之后,脚本上下文中的 window 会被替换成一个由插件提供的”沙箱window”。
  • 在沙箱环境下,Worker 以及一些API可能会无法工作。
  • 可以使用 window = unsafeWindow; 的方式脱离沙箱环境,但要保证这行在需要脱离沙箱的代码之前。另外也可以保留一个原来的 window 的引用以备用。

ECMAScript 相关

WorkerDedicatedWorkerGlobalScope

  • Worker 可以通过如下方法来实现从代码直接加载而不用URL以实现跨域加载 Worker

    1
    2
    3
    4
    const content = 'Worker中要执行的代码';
    const url = URL.createObjectURL(new Blob([content], { type: 'text/javascript' }));
    const worker = new Worker(url);
    // ...
  • 参考Web workers without a separate Javascript file?

  • 还有一种可行的从跨域URL加载的方式,简单说就是在上述方法中使用 importScripts 加载启用CORS的域的代码

1
2
3
const URL = 'xxxxxx';
const content = `importScripts(${URL});`;
const worker = new Worker(URL.createObjectURL(new Blob([content], { type: 'text/javascript' })));

SharedWorkerSharedWorkerGlobalScope

  • SharedWorker 在通过上述方式使用时没有效果(但这种方法不会提示错误,是否真的不可用还有待研究),由于同源策略也无法执行你自己的脚本。目前还没有找到一个合理有效的方法在用户脚本中使用 SharedWorker
  • 参考How can I load a shared web worker with a user-script?
  • 注:上述页面中的部分答案可能有用,但这不应该是 SharedWorker 本身应用的场景

ServiceWorkerServiceWorkerGlobalScope

  • ServiceWorkerSharedWorker 没有合理有效的方法在用户脚本中使用,但使用上述方法时均直接提示错误,因此目前这些方法对 ServiceWorker 均不可用

模块化

从URL中加载的方式 import / export

  • 从某个版本开始,各大浏览器实现了动态import,因此可以通过这种方式在用户脚本中从URL加载模块(Module)

  • 示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // 模块中的代码
    export function f () { console.log('here is function f'); }
    export const k = 1;
    export default function func () { console.log('here is function func'); }

    // 用户脚本或其他地方的代码,注意动态import的使用方式和静态import的使用方式有所不同
    const mod = await import(URL);
    console.log(mod.f, mod.f());
    console.log(mod.k);
    console.log(mod.default); // 注意这里,default指代的是用export default导出的东西
  • Web Worker 中暂时无法使用import,参考Web Workers - How To Import Modules

    • Chrome 80 修复了这个bug

直接执行代码的方式 eval / Function / AsyncFunction

  • 如果想要异步加载,需要保证加载过程的代码中的每个异步函数都有正确地await,否则可能导致加载顺序不一致
  • 关于evalFunction性能问题:在 Chrome 中测试得到 eval有最高的效率;在 Firefox 中测试得到 Function 更快。此外,在 Chrome 中的执行速度比 Firefox 整体快了数倍

网页请求相关

CORS

  • 在用户脚本中跨域获取HTTP请求自己的文件可以通过脚本的@resource实现,或把文件挂在代码托管的网站上,因为这些网站通常是默认开启CORS的

  • 如果需要请求他人的文件(如调用API等)可以使用GM.xmlHttpRequest

  • CORS对Worker/SharedWorker/ServiceWorker都不能产生效果,因此你不能通过如下方式从跨域URL加载

    1
    2
    3
    var blockedWorker = new Worker("https://not-example.com/");
    blockedWorker = new SharedWorker("https://not-example.com/");
    navigator.serviceWorker.register('https://not-example.com/sw.js');
  • 参考Why can I fetch this Cross origin file but I can’t create a Worker from it?

  • importScripts受CORS控制,因此可以用这个方式解决上述的问题,见上文

Content-Security-Policy

  • 如果网站启用CSP并且作出限制,用户脚本基本上没法做被限制的操作,不过我目前没有遇到

GM.xmlHttpRequest / XMLHttpRequest / Fetch_API 对比

特性 GM.xmlHttpRequest XMLHttpRequest Fetch_API
跨域请求 油猴控制 CORS控制 CORS控制
修改User-Agent 有效 无效 无效
修改Host 有效 无效 无效
修改Origin 有效 无效 无效
修改Referer 有效 无效 受限
修改Cookie 有效 无效 无效
修改Sec- 有效 无效 无效
HTTP 2 不支持 支持 支持
  • 此外在使用 GM.xmlHttpRequest 的时候要自行填写所有需要的 Header,这可能会带来麻烦和其他风险

  • 表中是否有效的判断是指是否能通过给定的API来打到对应的目的

  • Fetch_API 中的 受限 是指可以修改为同页面下的任意URL

    • 示例
    1
    2
    3
    4
    5
    6
    7
    // 假定在 http://example.com/demo 下进行的请求
    fetch('http://example.com/demo/api', {
    method: 'GET',
    referrerPolicy: 'unsafe-url',
    referrer: 'http://cross-origin.com/balabala' // 在这种情况下,设置的 referrer 无效,最终的 Referrer 不变
    referrer: 'ThisIsReferrer' // 在这种情况下,最终的 Referrer 为 http://example.com/demo/ThisIsReferrer
    });
  • 测试环境为 Chrome 80 下的默认设置,TamperMonkey 4.9

文档参考

安装 Hexo 和 NexT

1
2
3
npm install hexo-cli -g
hexo init
git clone https://github.com/theme-next/hexo-theme-next themes/next

配置 Hexo

参考Hexo Configuration

  • 修改项目根目录下的_config.yml文件
  • 网站信息主要修改 title, subtitle, description, author, timezone, url这几项,其余的稍后修改
  • language: zh-CN的支持是由NexT提供的,默认是没有效果的
  • theme: next其中next取决于你安装在theme下的目录名

配置 NexT

参考NexT Configuration

  1. theme/next目录下复制一份_config.ymlsource/data/next.yml(具体路径取决于你的_config.yml)
  2. 修改next.yml中需要的配置项: 美化相关参考Theme Settings, 第三方服务相关参考Third Party Services
  • 个人建议启用第三方服务中的Math Equations支持以方便书写数学表达式

测试和部署

参考NexT Deployment

本地测试

  • 构建前需要确保至少有一篇Post,否则可能会出现404的情况
1
hexo clean && hexo generate && hexo server --debug

手动部署

  • 在配置文件 _config.yml 的最后加入以下行

    1
    2
    3
    4
    deploy:
    type: git
    repo: # Git仓库路径
    branch: master
  • Git部署需要先安装对应的插件npm install hexo-deployer-git,然后和测试时类似

1
hexo clean && hexo generate && hexo deploy

持续集成

参考Github Action Documentation

  • 页面源代码会被公开

  • 本方法实现的持续集成实际上就是让代码托管帮我们执行上述 手动部署 的过程, 因此需要先配置手动部署的文件

  • 仓库下需要有两个 branch 。其中 master 分支是放生成后的静态页面, 另一个分支(source)放你的源码

  • source 分支根目录下创建 .github/workflows/nodejs.yml 文件, 内容如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    name: Hexo Auto Deploy
    on:
    push:
    branches: [ source ]
    jobs:
    build:
    runs-on: ubuntu-latest
    strategy:
    matrix:
    node-version: [12.x]
    steps:
    - uses: actions/checkout@v2
    - name: Use Node.js ${{ matrix.node-version }}
    uses: actions/setup-node@v1
    with:
    node-version: ${{ matrix.node-version }}
    - run: npm ci
    - name: Build and Deploy
    uses: SeaLoong/hexo-deploy-action@master
    env:
    PERSONAL_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    PUBLISH_REPOSITORY: ${{ github.repository }}
    BRANCH: master
    PUBLISH_DIR: ./public
  • 然后把文件提交到Github仓库即可

使用博客

在上面进行配置的过程中应当已经学会简单使用Hexo了,下面算是一些总结的部分

新建Post

hexo new <title>hexo new post <title>会创建文件于source/_post/<title>.md,其中最开始的内容应当类似如下

1
2
3
4
5
---
title: Hexo+NexT构建博客
date: 2020-04-11 03:23:32
tags: [Hexo, NexT]
---

此外,如果有相关配置的话,可以增加categories,comments等项以设置对应配置的属性

然后写下你要写的内容

提交Post

如果是手动部署就直接执行对应的命令行

如果是持续集成一般只要提交commit即可

  • 在提交之前可以先进行本地测试来预览一下

几个坑

  • 没有Post的时候访问根页面时404
  • 生成Post时出现
1
2
ERROR Render HTML failed: xxx/index.html
TypeError: Cannot read property 'replace' of null

参考https://github.com/hexojs/hexo/issues/3859

还有可能是在配置文件中把一些功能打开但是没用安装对应的依赖导致的(其他报错也可能是这个原因)