跳到主要内容

· 阅读需 5 分钟
Bowen Zhang

安装 Windows Termial

https://github.com/microsoft/terminal

在 PowerShell 中设置 Powerline

https://docs.microsoft.com/en-us/windows/terminal/tutorials/powerline-setup

安装 Cascadia Mono PL 字体

https://github.com/microsoft/cascadia-code/releases

使用notepad $PROFILE打开编辑文本

设置启动后导入 posh-git, oh-my-posh ,

设置主题 powerline:Set-PoshPrompt paradox

Import-Module posh-git
Import-Module oh-my-posh
Set-PoshPrompt paradox

注意事项

使用 Set-Theme 会报错:Set-Theme : 无法将“Set-Theme”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。

原因:oh-my-posh v3 不支持 Set-Theme 命令 ,需要使用 Set-PoshPrompt -Theme xxx

解决方案:https://www.icode9.com/content-4-866063.html

官网介绍:https://ohmyposh.dev/docs/upgrading/

官方是使用 Get-PoshThemes 查看支持主题;

分屏操作

https://docs.microsoft.com/zh-cn/windows/terminal/panes

配置

settting.json

// This file was initially generated by Windows Terminal 1.6.10571.0
// It should still be usable in newer versions, but newer versions might have additional
// settings, help text, or changes that you will not see unless you clear this file
// and let us generate a new one for you.

// To view the default settings, hold "alt" while clicking on the "Settings" button.
// For documentation on these settings, see: https://aka.ms/terminal-documentation
{
"$schema": "https://aka.ms/terminal-profiles-schema",

"defaultProfile": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",

// You can add more global application settings here.
// To learn more about global settings, visit https://aka.ms/terminal-global-settings

// If enabled, selections are automatically copied to your clipboard.
"copyOnSelect": true,

// If enabled, formatted data is also copied to your clipboard
"copyFormatting": true,

// A profile specifies a command to execute paired with information about how it should look and feel.
// Each one of them will appear in the 'New Tab' dropdown,
// and can be invoked from the commandline with `wt.exe -p xxx`
// To learn more about profiles, visit https://aka.ms/terminal-profile-settings
"profiles": {
"defaults": {
// Put settings here that you want to apply to all profiles.
"startingDirectory": null,
"fontFace": "MesloLGM Nerd Font",
"fontSize": 12
},
"list": [
{
// Make changes here to the powershell.exe profile.
"guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
"name": "Windows PowerShell",
"commandline": "powershell.exe",
"hidden": false,
// 浅色主题
// "acrylicOpacity": 0.7,
// "colorScheme" : "Frost",
// "cursorColor" : "#000000",
// "fontFace" : "Cascadia Code PL",
// "useAcrylic": true
// 深色主题
"acrylicOpacity": 0.7,
"colorScheme": "Vintage",
"cursorColor": "#FFFFFD",
"fontFace": "MesloLGM Nerd Font",
"useAcrylic": true
},
{
"guid": "{3ef3d962-7a99-4b13-93b6-b92a4d42a2e0}",
"hidden": false,
"name": "bash",
"commandline": "C:\\Program Files\\Git\\bin\\bash.exe",
"colorScheme": "Raspberry",
"cursorColor": "#FFFFFF",
// "fontFace" : "Cascadia Code PL",
"padding": "5, 5, 5, 5",
"suppressApplicationTitle": true,
"tabTitle": "bash"
},
{
// Make changes here to the cmd.exe profile.
"guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}",
"name": "命令提示符",
"commandline": "cmd.exe",
"hidden": false,
"closeOnExit": true,
"colorScheme": "Retro",
"cursorColor": "#FFFFFF",
"cursorShape": "filledBox",
"fontSize": 16,
"padding": "5, 5, 5, 5",
"tabTitle": "Command Prompt",
"fontFace": "PxPlus IBM VGA8",
"experimental.retroTerminalEffect": true
},
{
"guid": "{2c4de342-38b7-51cf-b940-2309a097f518}",
"hidden": false,
"name": "Ubuntu",
// "source": "Windows.Terminal.Wsl",
"colorScheme": "Raspberry",
"cursorColor": "#FFFFFF",
"fontFace": "MesloLGM Nerd Font",
"padding": "5, 5, 5, 5",
"suppressApplicationTitle": true,
"tabTitle": "Ubuntu"
},
{
"guid": "{574e775e-4f2a-5b96-ac1e-a2962a402336}",
"hidden": false,
"name": "PowerShell",
"source": "Windows.Terminal.PowershellCore",
"acrylicOpacity": 0.7,
"colorScheme": "Vintage",
"cursorColor": "#FFFFFD",
"fontFace": "MesloLGM Nerd Font",
"useAcrylic": true
},
{
"guid": "{b453ae62-4e3d-5e58-b989-0a998ec441b8}",
"hidden": true,
"name": "Azure Cloud Shell",
"source": "Windows.Terminal.Azure"
}
]
},

// Add custom color schemes to this array.
// To learn more about color schemes, visit https://aka.ms/terminal-color-schemes
"schemes": [
// 毛玻璃
{
"name": "Frost",
"background": "#FFFFFF",
"black": "#3C5712",
"blue": "#17b2ff",
"brightBlack": "#749B36",
"brightBlue": "#27B2F6",
"brightCyan": "#13A8C0",
"brightGreen": "#89AF50",
"brightPurple": "#F2A20A",
"brightRed": "#F49B36",
"brightWhite": "#741274",
"brightYellow": "#991070",
"cyan": "#3C96A6",
"foreground": "#000000",
"green": "#6AAE08",
"purple": "#991070",
"red": "#8D0C0C",
"white": "#6E386E",
"yellow": "#991070"
},
// 复古
{
"name": "Retro",
"background": "#000000",
"black": "#00ff00",
"blue": "#00ff00",
"brightBlack": "#00ff00",
"brightBlue": "#00ff00",
"brightCyan": "#00ff00",
"brightGreen": "#00ff00",
"brightPurple": "#00ff00",
"brightRed": "#00ff00",
"brightWhite": "#00ff00",
"brightYellow": "#00ff00",
"cyan": "#00ff00",
"foreground": "#00ff00",
"green": "#00ff00",
"purple": "#00ff00",
"red": "#00ff00",
"white": "#00ff00",
"yellow": "#00ff00"
},
// ubuntu
{
"name": "Raspberry",
"background": "#3C0315",
"black": "#282A2E",
"blue": "#0170C5",
"brightBlack": "#676E7A",
"brightBlue": "#80c8ff",
"brightCyan": "#8ABEB7",
"brightGreen": "#B5D680",
"brightPurple": "#AC79BB",
"brightRed": "#BD6D85",
"brightWhite": "#FFFFFD",
"brightYellow": "#FFFD76",
"cyan": "#3F8D83",
"foreground": "#FFFFFD",
"green": "#76AB23",
"purple": "#7D498F",
"red": "#BD0940",
"white": "#FFFFFD",
"yellow": "#E0DE48"
}
],

// Add custom actions and keybindings to this array.
// To unbind a key combination from your defaults.json, set the command to "unbound".
// To learn more about actions and keybindings, visit https://aka.ms/terminal-keybindings
"actions": [
// Copy and paste are bound to Ctrl+Shift+C and Ctrl+Shift+V in your defaults.json.
// These two lines additionally bind them to Ctrl+C and Ctrl+V.
// To learn more about selection, visit https://aka.ms/terminal-selection
{ "command": { "action": "copy", "singleLine": false }, "keys": "ctrl+c" },
{ "command": "paste", "keys": "ctrl+v" },

// Press Ctrl+Shift+F to open the search box
{ "command": "find", "keys": "ctrl+f" },
{ "command": "duplicateTab", "keys": "ctrl+shift+d" },
// Press Alt+Shift+D to open a new pane.
// - "split": "auto" makes this pane open in the direction that provides the most surface area.
// - "splitMode": "duplicate" makes the new pane use the focused pane's profile.
// To learn more about panes, visit https://aka.ms/terminal-panes
{
"command": {
"action": "splitPane",
"split": "vertical",
"splitMode": "duplicate"
},
"keys": "shift+tab"
},
{
"command": {
"action": "splitPane",
"split": "horizontal",
"splitMode": "duplicate"
},
"keys": "alt+shift+-"
},
{
"command": {
"action": "splitPane",
"split": "auto",
"splitMode": "duplicate"
},
"keys": "alt+shift+d"
},
{ "command": "closePane", "keys": "shift+w" }
]
}

添加注册列表(右键菜单)

https://blog.csdn.net/u011532601/article/details/106305373/

使用别人写好的 bat 程序

下载地址:https://github.com/BroJenuel/Explorer-Context-Menu-Integration-for-windows-terminal

手动配置右键打开

  • Win+R 输入 regedit 进入注册表目录 HKEY_CLASSES_ROOT\Directory\Background\shell

在这里新建一个项命名为 WT 并设置(默认)值为你想要的名称,比如 Windows Terminal Here

  • 再新建字符串值 Icon 即显示图标,并将值设设置 C:\ProgramFiles\WindowsApps\Microsoft.WindowsTerminal`version`\WindowsTerminal.exe

    Win10 系统下 WindowsApps 文件夹拒绝访问如何获取权限:

    http://www.xitongcheng.com/jiaocheng/win10_article_45151.html

  • 注意:version值看你安装的具体版本,可通过 Everything 搜索查证,或者设置为 cmd 的图标 C:\Windows\System32\cmd.exe 免去更新的麻烦,再或者设置你自己的图标,这个不影响使用

  • 如有需要的话可以将这个命令置顶,则添加新字符串值 Position,值为 Top

  • 然后再新建一个项 command,默认值%USERPROFILE%\AppData\Local\Microsoft\WindowsApps\wt.exe

  • 注意:如失效,可将%USERPROFILE%改为指定用户目录如 C:\Users`username,并注销重启,username`记得改成自己的用户名

一般出现 explorer.exe 错误多是没有用管理员权限写入导致的

注意:自动添加的右键菜单会出现复制窗口但工作目录变的情况

删除程序自带的右键菜单

github 上有对应的 issues:https://github.com/microsoft/terminal/issues/8105

😓 看来大家都不喜欢程序自动添加的右键菜单

完成后记得重新启动资源管理器

问题:

https://github.com/microsoft/terminal/issues/9806

powershell.exe 中的普通空格

image-20210414173814189

在 Windows terminal 中空格变成 

image-20210414172703793

解决

更换Oh my Posh官方推荐字体:https://ohmyposh.dev/docs/fonts/

使用Meslo LGM NF

image03

setting.json

  "fontFace" : "MesloLGM Nerd Font",

修改 vscode 终端字体

setting.json

"terminal.integrated.fontFamily": "MesloLGSDZ Nerd Font"

注意:vscode 只能使用等宽字体 所以得单独设置

Git bash 乱码问题

解决:https://www.cnblogs.com/ssrs-wanghao/articles/9216955.html

我就用下面命令一下解决

    git config --global core.quotepath false

· 阅读需 2 分钟
Bowen Zhang

typora 结合 PicGo 设置 github 图床

详细教程:https://blog.csdn.net/beichuchuanyue/article/details/105493948

最近一直在用 ubuntu 所以令行) 实现直接使用 picgo-core (命上传图片

picgo-core 配置文件

如果配置好了 picgo app 直接把 iconfig 粘进来就行

{
"picBed": {
"current": "github",
// 具体配置
"github": {
"branch": "分支",
"customUrl": "https://raw.githubusercontent.com/用户名/仓库/分支",
"path": "img/", //具体文件夹`路径/`
"repo": "zhangbowen-github/my-gallery", // `/用户名/仓库`
"token": "sdfasdfasdfasdf" //Settings -> Developer settings -> Personal access tokens->创建 全选
},
"uploader": "github"
},
"settings": {
"shortKey": {
"picgo:upload": {
"enable": true,
"key": "CommandOrControl+Shift+P",
"name": "upload",
"label": "快捷上传"
}
},
"server": {
"enable": true,
"host": "127.0.0.1",
"port": 36677 //端口号不要改
},
"showUpdateTip": true,
"pasteStyle": "markdown",
"autoRename": true,
"rename": false,
"autoStart": true,
"miniWindowOntop": false,
"checkBetaUpdate": true
},
"picgoPlugins": {},
"debug": true,
"PICGO_ENV": "GUI",
"needReload": false
}

注意上传同名图片会导致失败

常见报错:https://blog.csdn.net/qq754772661/article/details/111385955

PicGo 设置 gitee(码云)图床

详细教程

// 具体配置
"gitee": {
"branch": "master",
"customPath": "default",
"customUrl": "https://gitee.com/zhangbowen-1/my-gallery/raw/master",
"path": "/img",// `/路径`
"repo": "zhangbowen-1/my-gallery/img",// `/用户名/仓库/路径`
"token": "asdfasdfdfasdfasdfsadfasd" // 设置-》私人令牌-》生产新令牌
}

typora 结合 PicGo 设置 smms 图床

  • smms 注册账号
  • smms Dashboard 找到 API Token 获取 token
  • npm 全局安装 picgo
  • 修改 picgo 配置文件
  • 修改 typora 设置偏好 图像 上传服务设定 修改为 自定义命令 (custom command) 命令 :picgo upload

· 阅读需 2 分钟
Bowen Zhang

SheetJS js-xlsx 中文文档: https://github.com/rockboom/SheetJS-docs-zh-CN

下面是对工作簿能见度的描述文档

数据表能见度

Excel 支持将表格隐藏在更低的标签栏。表格数据存储文件内,但是 UI 不容易让它可以使用。标准的隐藏表格会被显示在"Unhide"菜单内。Excel 也有"very hidden"表格,这些表格不能被显示在菜单内。只可以通过 Vb 编辑器访问。

能见度的设置被存储在表格属性数组的Hidden属性当中。

ValueDefinition
0Visible
1Hidden
2Very Hidden

更多详情请查看https://rawgit.com/SheetJS/test_files/master/sheet_visibility.xlsx:

> wb.Workbook.Sheets.map(function(x) { return [x.name, x.Hidden] })
[ [ 'Visible', 0 ], [ 'Hidden', 1 ], [ 'VeryHidden', 2 ] ]

非 Excel 格式不支持"Very Hidden"状态。测试一个数据比哦啊是否可见的最好方式是检查是否Hidden属性为逻辑 truth:

> wb.Workbook.Sheets.map(function(x) { return [x.name, !x.Hidden] })
[ [ 'Visible', true ], [ 'Hidden', false ], [ 'VeryHidden', false ] ]

文档上对工作簿隐藏有说明,但是没有具体的隐藏方法,尝试直接修改工作簿的Hidden属性,没有任何效果, 但是皇天不负有心人, 通过查看 源码 发现了实现工作簿隐藏的方法

XLSX.utils.book_set_sheet_visibility 方法

下面是源码中方法的定义

/* set sheet visibility (visible/hidden/very hidden) */
utils.book_set_sheet_visibility = function (wb, sh, vis) {
get_default(wb, "Workbook", {});
get_default(wb.Workbook, "Sheets", []);

var idx = wb_sheet_idx(wb, sh);
// $FlowIgnore
get_default(wb.Workbook.Sheets, idx, {});

switch (vis) {
case 0:
case 1:
case 2:
break;
default:
throw new Error("Bad sheet visibility setting " + vis);
}
// $FlowIgnore
wb.Workbook.Sheets[idx].Hidden = vis;
};

方法分别传入三个参数:

  • 工作表对象,
  • 工作簿在工作簿数组中的下标,
  • 需要设置的Hidden属性的值 (0,1,2)

工作表对象生成方法见文档,下面用workbook表示,工作簿在工作簿数组中的下标,可以通过 workbook.SheetNames 找到对应的下标

具体实现:

  // 隐藏采购员表   因为整个xlsx的使用是以class实现的这里截取隐藏工作表的方法
hideBuyerSheet(){
let indexs = [];
for (const [i,name] of this.workbook.SheetNames.entries()) {
if(/采购员/.test(name)){ //找到所有带采购员名称的表的下标
indexs.push(i);
}
}
for (const i of indexs) {
// 将对应下标的工作簿隐藏
XLSX.utils.book_set_sheet_visibility(this.workbook, i, 1);
}
}

· 阅读需 12 分钟
Bowen Zhang

文章原地址

前言

简单来说,node 是跨平台的,那么对于任何的 node 模块理论也是应该是跨平台的。然而,有些 node 模块直接或间接使用原生 C/C++代码,这些东西要跨平台,就需要使用源码根据实际的操作平台环境进行原生模块编译。SQLite3 就是一个经典的原生模块,让我们以安装该模块为例,探索一下安装原生模块的流程。

项目建立

建立一个简单的 node 项目,我们开始安装SQLite3

$ mkdir sqlite3-install-demo
$ cd sqlite3-install-demo
$ npm init
# 初始化项目
Press ^C at any time to quit.
package name: (projects) sqlite3-install-demo
version: (1.0.0)
description:
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC) MIT
About to write to D:\Projects\package.json:

{
"name": "sqlite3-install-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "MIT"
}

安装SQLite3

$ npm install -S sqlite3

完成命令执行后,你会看到命令行界面出现了如下的几行重要的输出:

...
> sqlite3@5.0.0 install D:\Projects\sqlite3-install-demo\node_modules\sqlite3
> node-pre-gyp install --fallback-to-build

node-pre-gyp WARN Using request for node-pre-gyp https download
...

啪一下,很快啊!我们就迎来了第一个东西node-pre-gyp,但是提到了node-pre-gyp,我们不得不提及node-gyp,然后又不得不提及gyp

gyp 与 node-gyp 与 node-pre-gyp

什么是 gyp?

gyp 全称Generate Your Projects(构建你的项目)。wiki 的解释如下,自行翻译:

GYP (generate your projects) is a build automation tool. GYP was created by Google to generate native IDE project files (such as Visual Studio Code and Xcode) for building the Chromium web browser and is licensed as open source software using the BSD software license.

重点在于,它是一套用于生成原生 IDE 项目文件的自动化构建工具,处理 C/C++项目,同类型的有 CMake、ninja 等自动构建工具。

什么是 node-gyp?

直接给出stackoverflow高票回答:

node-gyp is a tool which compiles Node.js Addons. Node.js Addons are native Node.js Modules, written in C or C++, which therefore need to be compiled on your machine. After they are compiled with tools like node-gyp, their functionality can be accessed via require(), just as any other Node.js Module.

简单来说,node 是跨平台的,那么对于任何的 node 模块理论也是应该是跨平台的。然而,有些 node 模块直接或间接使用原生 C/C++代码,这些东西要跨平台,就需要使用源码根据实际的操作平台环境进行原生模块编译。那么我们需要下载源码文件,通过 node-gyp 生成一定结构的代码项目让我们能够require引入(譬如,Windows 下会生成vcxproj,再调用MSBuild进行编译,以生成 Windows 下的动态链接库,最后打包为一个原生 node 模块)。这个知乎回答的每一条可以看看:传送门

什么是 node-pre-gyp?

上面node-gyp固然相当方便了,但是每一次安装 node 原生模块的时候,都需要根据平台(Windows、Linux、macOS 以及对应的 x86、x64、arm64 等等)进行源码编译,这样做费时费力。为什么不一开始就针对这些平台编译好了做成二进制制品发布呢?反正一般来说主流的平台架构就那么一些(Windows、Linux、macOS)。所以node-pre--gyp就帮我们做了这件事。原生模块开发者将代码编译生成各个平台架构的二进制包直接发布到node-pre-gyp上,当我们的 node 项目安装原生模块时候。处理流程就是首先去node-pre-gyp上找有没有当前平台的组件包,有的话直接拉取使用,如果没有则进行原生编译。

node-pre-gyp一些重要参数(不全):

  • -C/--directory: run the command in this directory
  • --build-from-source: build from source instead of using pre-built binary
  • --fallback-to-build: fallback to building from source if pre-built binary is not available
  • --target=0.4.0: Pass the target node or node-webkit version to compile against
  • --target_arch=ia32: Pass the target arch and override the host arch. Valid values are 'ia32','x64', or arm.
  • --target_platform=win32: Pass the target platform and override the host platform. Valid values are linux, darwin, win32, sunos, freebsd, openbsd, and aix.

对于--fallback-to-build这个参数:如果二进制不可获取则直接从源码编译,即从node-pre-gyp又回到node-gyp。所以你才会在上文看到安装 sqlite3 的时候,会有--fallback-to-build

于是乎,当我们进行 node 原生模块安装的时候,一般会有如下的流程:

  1. 针对当前平台架构优先考虑node-pre-gyp方式进行安装,但是为了防止无法获取针对对应平台编译好的二进制包(网络原因、暂时没有对应平台的二进制包),进入第 2 步;
  2. 下载原生模块源码,然后使用node-gyp进行项目构建,得到与平台相关的源码项目文件(Windows 则生成vcxproj项目,Linux 下是Makefile);在这个过程,node-gyp会使用Python进行自动化构建操作,这也是为什么有些朋友安装 node 原生模块的时候,会报错找不到Python
  3. 调用平台对应的编译工具进行编译。在 Windows 的环境下,node-gyp会查找本地的MSBuild/CL等编译工具,而这些编译工具又一般在Visual Studio安装的时候,也一并安装在了机器上。这就是为什么有些朋友没有安装Visual Studio的时候,会报错。

探索 SQLite3 的安装流程

npm install

为什么我们安装sqlite3的时候,会调用node-pre-gyp命令呢?进入项目目录/node_modules/sqlite3/文件夹,让我们查看一下package.json中的scripts部分:

{
...
"repository": {
"type": "git",
"url": "git://github.com/mapbox/node-sqlite3.git"
},
"scripts": {
"install": "node-pre-gyp install --fallback-to-build", // install
"pack": "node-pre-gyp package",
"pretest": "node test/support/createdb.js",
"test": "mocha -R spec --timeout 480000"
},
"version": "5.0.0"
}

答案显而易见了,install脚本中执行了node-pre-gyp install --fallback-to-build命令。

这就不得不提到npm的安装流程是。当我们进行npm install xxx的时候,npm首先下载xxx的包。下载完成后,若package.json中的 scripts 中存在install属性,则会立刻调用。至于scripts中的其他固定脚本:testpreinstallpostinstall等等作用以及scripts的高级用法,请直接查阅scripts | npm Docs (npmjs.com)

所以本此sqlite3前期安装的过程为:

  1. npm下载在仓库中的sqlite3npm 包;
  2. 执行${your_projects}/node_modules/sqlite3/package.json中的install脚本,即node-pre-gyp install --fallback-to-build

于是乎,安装进入到了一个新的环节:node-pre-gyp install。当然,若你没有全局安装node-pre-gyp,它会由npm帮你安装到${your_projects}/node_modules/中,并且通过node-pre-gyp/package.json中的bin元素,建立软连接到${your_projects}/node_modules/.bin中。这样,node\npm环境中就有了node-pre-gyp命令可以使用。至于package.json#bin的作用,详细参考官方文档package.json | npm Docs (npmjs.com)

node-pre-gyp install

node-pre-gyp在上述的安装流程中,已经能够被我们在 CLI 中所使用。查看node_modules/node-pre-gyp/bin/node-pre-gyp文件(下文都将省略${your_projects}/),用文本的形式打开。就是node-pre-gypCLI 的执行过程,脚本中的主要内容为最后一行:

// start running the given commands!
run();

检查该函数的定义:

function run() {
var command = prog.todo.shift();
if (!command) {
// done!
completed = true;
log.info("ok");
return;
}

prog.commands[command.name](command.args, function (err) {
if (err) {
log.error(command.name + " error");
log.error("stack", err.stack);
errorMessage();
log.error("not ok");
console.log(err.message);
return process.exit(1);
}
var args_array = [].slice.call(arguments, 1);
if (args_array.length) {
console.log.apply(console, args_array);
}
// now run the next command in the queue
process.nextTick(run);
});
}

prog是什么?该文件往上查看定义,原来是:

var node_pre_gyp = require("../"); // 上一个目录作为模块引入
var log = require("npmlog");

/**
* Process and execute the selected commands.
*/

var prog = new node_pre_gyp.Run(); // 来自于node_pre_gyp中的Run,而node_pre_gyp在上方

继续检查上一个目录,发现并没又indes.js文件,熟悉npm的朋友应该知道要去看package.json中的main元素了:

...
"license": "BSD-3-Clause",
"main": "./lib/node-pre-gyp.js", // 模块是这个文件
"name": "node-pre-gyp",
...

查阅lib/node-pre-gyp.js代码中的 Run:

function Run() {
var self = this;

this.commands = {};

commands.forEach(function (command) {
self.commands[command] = function (argv, callback) {
log.verbose("command", command, argv);
return require("./" + command)(self, argv, callback); // 这里是核心
};
});
}

核心功能就是引入当前所在目录下的模块进行执行。例如,本次调用的是node-pre-gyp install,则会require(./install),检查一下node-pre-gyp.js目录下,果然存在该js文件。继续阅读install.js源码。里面有几个函数的定义。咱们先不看内容,把函数名列举出来,猜测一下作用:

// 去下载平台编译好的二进制?
function download(uri,opts,callback) {...}
// 把下载好的二进制放到对应目录?
function place_binary(from,to,opts,callback) {...}
// 进行构建。难道是没有下载,就调用node-gyp源码编译?
// 还有,node-pre-gyp又--fallback-to-build参数,也会调用这个?
function do_build(gyp,argv,callback) {...}
// 打印回退出现的异常
function print_fallback_error(err,opts,package_json) {...}
// 安装,核心没跑了
function install(gyp, argv, callback) {...}

首先看download的调用点是在place_binary中:

function place_binary(from,to,opts,callback) { // place_binary函数
download(from,opts,function(err,req) { // 调用了download
if (err) return callback(err);
if (!req) return callback(new Error("empty req"));
...
}
...
}

再看place_binary调用点是在install中:

function install(gyp, argv, callback) {
// 省略部分...
var should_do_source_build =
source_build === package_json.name ||
source_build === true ||
source_build === "true";
if (should_do_source_build) {
// 源码编译
log.info("build", "requesting source compile");
return do_build(gyp, argv, callback);
} else {
// 省略部分...
mkdirp(to, function (err) {
if (err) {
after_place(err);
} else {
place_binary(from, to, opts, after_place); // 调用点
}
});
// 省略部分...
}
// 省略部分...
}

通过上述分析,整个大的处理流程如下:

  1. 进入install函数
  2. 检查是否需要build-from-source。是则进,入do_build分支,进行源码编译;否则进入步骤 3。
  3. 检查是否启用--fallback-to-build参数,设定是否启用标志位。
  4. 解析编译好的二进制文件的选项配置,譬如二进制文件存放地址,也就是通过请求下载对应二进制包的地址,以及各种各样参数。所以说,为什么下载很慢,我们后文会重点关注下载地址。

下载二进制包

img

根据流程,接下来我们进一步检查versioning.js文件,找到其中的evaluate函数,分析最后的hosted_tarball路径:

img

hosted_tarball路径主要分为两个部分:1、hosted_path;2、package_name

hosted_path

经过源码分析来源路径为:

img

我们自底向上分析。

host变量取决于从环境变量中检查名称为'npm_config_' + opts.module_name + '_binary_host_mirror'的环境变量。如果不存在,则使用package_json.binary.host。正常使用的时候,我们并不会设定环境变量,所以这里就进入package_json.binary进行获取。这个package_jsonevaluate函数被调用时候传入的,在node-pre-gyp/install.js中能够看到:

img

一开始分析的时候,看到这里,本人以为package_json就是node-pre-gyp/package.json,于是本人去检查该json发现很奇怪,并没有 binary 属性,更别提 host 了。一番思考才明白,node-pre-gyp install的运行时调用者是谁呀?不是应该是sqlite3吗?所以这个地方的require('./package.json')实际上是指代的是sqlite3/package.json。查看sqlite3/package.json,果然发现了对应的元素:

img

binary属性中,我们还能看到remote_path也在其中。

至此,hosted_path我们完成了简单的分析,我们可以得出一个结论:

node-pre-gyp下载二进制文件的路径,优先来源于对应模块的镜像地址,该镜像地址通过配置'npm_config_' + 模块名 + '_binary_host_mirror'来实现自定义;在没有定义镜像地址的情况下,读取模块package.json中的 binary 属性信息。

当然,读者可以根据具体情况再进一步分析源码。

package_name

其实,对于hosted_path的分析,我们也容易分析package_name了。

img

自底向上分析,来自于sqlite3/package.jsonbinary属性中的package_name,内容见上图分析host

失败处理

--fallback-to-build参数表明了是否进行失败后下载源码进行编译,源码不再分析。

从源码构建

build.js

当我们提供了参数--build-from-source或是在下载编译好的二进制到本地出错的时提供了参数--fallback-to-build。node-pre-gyp 将进入do_build模块,进行源码编译。

function do_build(gyp,argv,callback) {
var args = ['rebuild'].concat(argv);
gyp.todo.push( { name: 'build', args: args } );
process.nextTick(callback);
}

代码中,gyp由调用 install 的时候,传入:

img

那么我们又将回到调用 install 的地方。实际上,gyp 就是 node-pre-gyp.js 导出的模块:

img

也就是说在do_build中进行操作就是,放置了一个build任务在队列中。所以我们按照先前的分析,直接去看build.js

img

看源码调用了当前模块中的do_build,且其中最核心的就是compile模块:

img

util/compile.js

进入 compile 模块,直接找到对应的run_gyp函数,代码很短,不难看出进行构建调用了node-gyp

img

上述代码,会先考略node-webkit构建。但是我们核心的还是使用node-gyp,所以 else 中,会进行node-gyp的工具的检查工作。最后调用命令行执行node-gyp。于是,node 原生模块的安装工作,进入了新的阶段:node-gyp

node-gyp build

上文提到我们已经进入了node-gyp的范畴,会调用node-gyp build操作。当然,这个命令同样是在安装node-gyp依赖的时候已经完成了安装,并且进行node_modules/.bin/软连接操作。

...
"bin": {
"node-gyp": "bin/node-gyp.js"
},
...

我们进入该js进行分析

img

实际上,node-gyp这段的命令行代码,和node-pre-gyp非常相似!所以我们也不去深入分析调用命令行了。直接在 lib 文件夹下面的build.js。在该js中,核心的方法为:

function build (gyp, argv, callback) {
...
}

在该方法中,还编写了几个内部函数,作为了功能的划分:

// function build (gyp, argv, callback) 内部函数
/**
* Load the "config.gypi" file that was generated during "configure".
*/
function loadConfigGypi () {...}
/**
* On Windows, find the first build/*.sln file.
*/
function findSolutionFile () {...}
/**
* Uses node-which to locate the msbuild / make executable.
*/
function doWhich () {...}
/**
* Search for the location of "msbuild.exe" file on Windows.
*/
function findMsbuild () {...}
/**
* Actually spawn the process and compile the module.
*/
function doBuild () {...}
/**
* Invoked after the make/msbuild command exits.
*/
function onExit (code, signal) {...}

不得不说,build写的真心不错,看起来很舒服。这里为了方便读者快速阅读,我整理这些函数的调用图:

img

整个调用流程图个人认为足够进行安装的时候的一场分析了。至于每个内部函数的功能,有空继续更新本文吧。

· 阅读需 1 分钟
Bowen Zhang

SheetJS js-xlsx 中文文档: https://github.com/rockboom/SheetJS-docs-zh-CN

使用步骤

  // 从头开始创建工作簿
var wb = XLSX.utils.book_new();
/**
* 创建工作表
* aoa_to_sheet 二维数组
* json_to_sheet 对象数组
* table_to_sheet tableDOM
*/
let ws= XLSX.utils.json_to_sheet(json);
// 把工作表添加到工作簿中
XLSX.utils.book_append_sheet(wb, ws, "sheet");
// 写入 (node)
XLSX.writeFile(wb, path.resolve(__dirname, "./test.xlsx"), {
type: "buffer",
Props: { Author: "author" },
});

merges 的使用

........
// 设置单元格合并
data["!merges"] = [{
s: {//s为开始
c: 1,//开始列
r: 0//可以看成开始行,实际是取值范围
},
e: {//e结束
c: 4,//结束列
r: 0//结束行
}
}];
........

· 阅读需 2 分钟
Bowen Zhang

关于 axios 上传文件超时的问题记录

问题

前端上传一个 7M 文件,上传一半连接中断,后端是 java, 报了一个 tomcat 的问题,让我一直以为是后端断开连接

但是postman却可以上传(postman没有设置连接超时)

本地调试发现无法进入后端断点 (进入超时状态) 但是后端本地可以进入(后端因为是本地地址没有进入超时状态)

我想了好久也没有想明白为什么(没有想到是前端超时断开连接 后端让我帮忙看问题 唉!!! 我一直以为是后端兄弟的问题 让后端兄弟找了好久 结果却是前端的问题 唉!!!)

// axios
const service = axios.create({
// 公共接口
baseURL: config[config["mode"]].basicURL,
timeout: 5000, // 0 永不超时
});
// 设置了 5秒就超时

如果仔细看看 axios 返回的错误信息就可以直接是超时问题 timeout of 5000ms exceeded

解决

增大超时时间

const service = axios.create({
// 公共接口
baseURL: config[config["mode"]].basicURL,
timeout: 60000, // 0 永不超时
});

添加请求错误日志 打印详细错误信息


// 3.响应拦截器
service.interceptors.response.use(
(response) => {
return Promise.resolve(response.data);
},
(error) => {
const { response } = error;
let errMsg = response
? // 使用服务返回错误信息
fmtError(response.data.code) || response.data.message || response.status
: // 使用 axios 返回的错误信息
`${error.message ? ":" + error.message : ""}`;
logger("response error").error(errMsg);
return Promise.reject(error);
}
);

每次出现问题后先看看前端报错信息 再进行分析 上传大文件时尽量不设置超时

· 阅读需 2 分钟
Bowen Zhang

hexo官方文档

注意事项

编辑好 md 文档先在hexo server 运行一下在提交 github

Markdown 使用时() { } 都需要转义 否者会报错

每次提交 github 自动构建前,要重启一下 hexo server 然后看看没有报错 ,再进行提交

next 主题注意事项

canvas_ribbon 和 tree 需要配合在 CDN 中添加 git 默认不上传 lib 下的文件

关于报错

image-20200725160508488

没有任何提示 哪个文件,挨个改动回退试试,原来是因为_config.yml这里直接写中文是不行的,中文需要引号包裹

social:
# 微博: http://weibo.com/your-user-name 这里不能使用中文 确使用方式如下 地址后是图标
"微博": http://weibo.com/your-user-name || fab fa-weibo
"知乎": http://www.zhihu.com/people/your-user-name || fab fa-zhihu

Next 主题文章老是自动滚到底部评论区的问题

原因 : 设置了 utterances

utterances:
enable: true

解决: 取消 utterances

utterances:
enable: false

hexo 4.2.1 升级至 6.2.0 Next 7.8.0 升级至 8.12.1

hexo 升级

npm i -g npm-check # 检查之前安装的插件,都有哪些是可以升级的 

# cd hexo 目录
npm-check # 检查那些依赖能够升级 并把 package.json 版本号升级到最新
npm update # 安装升级

Next 升级

升级官方文档

安装

# cd hexo 目录
npm i hexo-theme-next

修改配置文件位置

themes/next/_config.yml 复制到 hexo目录/_config.next.yml

备份原主题

themes/next 改为 themes/next-old

运行

运行hexo cleanhexo s检查站点是否正常工作