├── README.md ├── assets └── mac │ ├── iterm2-recv-zmodem.sh │ └── iterm2-send-zmodem.sh ├── img ├── error_extract-text-webpack-plugin.png ├── error_jest_syntax_error_unexpected_token_import.png ├── error_this_is_not_a_function.png ├── error_unkown_word.png ├── fecli-pre.png ├── fecli.png ├── github_create_a_action1.png ├── github_create_a_action2.png ├── jest_file.png ├── jest_file_after.png └── mac │ └── lrzsz │ ├── lrzsz1.png │ ├── lrzsz2.png │ ├── lrzsz3.jpg │ ├── lrzsz4.jpg │ └── lrzsz5.jpg ├── mac ├── Mac_命令行登录_Linux_无需密码的配置.md ├── lrzsz.md ├── mac.md ├── mac使用.md └── node:_No_such_file_or_directory.md ├── qa ├── No Xcode or CLT version detected.md ├── Running_Gradle_task_assembleDebug_Forever.md ├── android_avd_system.md ├── axios_get_diy_headers.md ├── could_not_resolve_hostname.md ├── error_extract-text-webpack-plugin.md ├── error_jest_syntax_error_unexpected_token_import.md ├── error_this[NS]_is_not_a_function.md ├── error_unknown_word.md ├── flutter_android_keeps_stopping.md ├── flutter_android_launch_image.md ├── ios_not_support_embedding.md ├── jest_file.md ├── libcrypto.so.6:_cannot_open_shared_object_file.md └── webpack4-extract-css.md ├── react ├── Typescript_中使用_antd.form.create.md └── size_which_is_declared.md ├── utils ├── fe6cli.md ├── github_create_a_action.md └── set_taobao.md └── vue ├── cpt_tlp_introduce.md └── vue_icon_component.md /README.md: -------------------------------------------------------------------------------- 1 | # blog 2 | >技术博客,不定时更新 3 | 4 | ## Vue 系 5 | 6 | * [**你不知道的 Vue 的图标组件**][1-1] 7 | * [**从零开始搭建前端脚手架**][2-1] 8 | 9 | ## React 系 10 | 11 | * [**Typescript 中使用 antd.form.create**][6-1] 12 | 13 | ## 工具篇 14 | 15 | * [**从零开始搭建前端脚手架**][2-1] 16 | * [**webpack 4 提取 CSS 等样式文件**][2-2] 17 | * [**从零搭建 Vue.js 组件库模板**][2-3] 18 | * [**设置国内镜像**][2-4] 19 | * [**在 GitHub 配置 Actions**][5-1] 20 | * [**Linux 或 Mac 命令行手册**][5-2] 21 | * [**lerna 命令集锦**][5-3] 22 | 23 | ## 问题篇 24 | 25 | * [**Unknown word**][3-1] 26 | * [**Module build failed: Error: "extract-text-webpack-plugin" loader**][3-2] 27 | * [**this[NS] is not a function**][3-3] 28 | * [**jest SyntaxError: Unexpected token import**][3-4] 29 | * [**jest 测试覆盖报告 File 中并没有测试的文件**][3-5] 30 | * [**No Xcode or CLT version detected**][3-6] 31 | * [**libcrypto.so.6: cannot open shared object file**][3-7] 32 | * [**Could not resolve hostname**][3-8] 33 | * [**axios拿不到自定义的header头**][3-9] 34 | * [**Android AVD system**][3-10] 35 | * [**Running Gradle task 'assembleDebug' Forever**][3-11] 36 | * [**flutter android keeps stopping**][3-12] 37 | * [**flutter android 启动图撑满屏幕**][3-13] 38 | * [**Trying to embed a platform view but the PrerollContext does not support embedding**][3-14] Flutter 的 webview 插件使用的 iOS 配置 39 | * [**Plugin project :url_launcher_web not found.**][3-15] 40 | * [**linux配置docker报错:ImportError: No module named yum**][3-16] 41 | 42 | ## Mac 篇 43 | 44 | * [**从零开始配置一台 mac 电脑(前端方向)**][4-1] 45 | * [**mac 使用**][4-2] 46 | * [**Mac 命令行登录 Linux 无需密码的配置**][4-3] 47 | * [**iTerm2 使用 lrzsz 上传下载文件**][4-4] 48 | * [**node: No such file or directory**][4-5] 49 | 50 | ## 手册 51 | 52 | * [**docker 在 centos**][7-1] 53 | 54 | [1-1]: https://github.com/iq9891/blog/issues/10 55 | 56 | [2-1]: https://github.com/iq9891/blog/issues/2 57 | [2-2]: https://github.com/iq9891/blog/issues/4 58 | [2-3]: https://github.com/iq9891/blog/issues/9 59 | [2-4]: https://github.com/iq9891/blog/issues/18 60 | 61 | [3-1]: https://github.com/iq9891/blog/issues/3 62 | [3-2]: https://github.com/iq9891/blog/issues/5 63 | [3-3]: https://github.com/iq9891/blog/issues/6 64 | [3-4]: https://github.com/iq9891/blog/issues/7 65 | [3-5]: https://github.com/iq9891/blog/issues/8 66 | [3-6]: https://github.com/iq9891/blog/issues/17 67 | [3-7]: https://github.com/iq9891/blog/issues/20 68 | [3-8]: https://github.com/iq9891/blog/issues/16 69 | [3-9]: https://github.com/iq9891/blog/issues/24 70 | [3-10]: https://github.com/iq9891/blog/issues/27 71 | [3-11]: https://github.com/iq9891/blog/issues/28 72 | [3-12]: https://github.com/iq9891/blog/issues/29 73 | [3-13]: https://github.com/iq9891/blog/issues/30 74 | [3-14]: https://github.com/iq9891/blog/issues/31 75 | [3-15]: https://github.com/iq9891/blog/issues/32 76 | [3-16]: https://github.com/iq9891/blog/issues/35 77 | 78 | [4-1]: https://github.com/iq9891/blog/issues/11 79 | [4-2]: https://github.com/iq9891/blog/issues/12 80 | [4-3]: https://github.com/iq9891/blog/issues/21 81 | [4-4]: https://github.com/iq9891/blog/issues/25 82 | [4-5]: https://github.com/iq9891/blog/issues/26 83 | 84 | [5-1]: https://github.com/iq9891/blog/issues/19 85 | [5-2]: https://github.com/iq9891/blog/issues/34 86 | [5-3]: https://github.com/iq9891/blog/issues/33 87 | 88 | [6-1]: https://github.com/iq9891/blog/issues/22 89 | 90 | [7-1]: https://github.com/iq9891/blog/issues/36 91 | -------------------------------------------------------------------------------- /assets/mac/iterm2-recv-zmodem.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 这个脚本来自 github,删掉了一些 ** 言论。 3 | 4 | osascript -e 'tell application "iTerm2" to version' > /dev/null 2>&1 && NAME=iTerm2 || NAME=iTerm 5 | if [[ $NAME = "iTerm" ]]; then 6 | FILE=$(osascript -e 'tell application "iTerm" to activate' -e 'tell application "iTerm" to set thefile to choose folder with prompt "Choose a folder to place received files in"' -e "do shell script (\"echo \"&(quoted form of POSIX path of thefile as Unicode text)&\"\")") 7 | else 8 | FILE=$(osascript -e 'tell application "iTerm2" to activate' -e 'tell application "iTerm2" to set thefile to choose folder with prompt "Choose a folder to place received files in"' -e "do shell script (\"echo \"&(quoted form of POSIX path of thefile as Unicode text)&\"\")") 9 | fi 10 | 11 | if [[ $FILE = "" ]]; then 12 | echo Cancelled. 13 | # Send ZModem cancel 14 | echo -e \\x18\\x18\\x18\\x18\\x18 15 | sleep 1 16 | echo 17 | echo \# Cancelled transfer 18 | else 19 | cd "$FILE" 20 | /usr/local/bin/rz -E -e -b --bufsize 4096 21 | sleep 1 22 | echo 23 | echo 24 | echo \# Sent \-\> $FILE 25 | fi -------------------------------------------------------------------------------- /assets/mac/iterm2-send-zmodem.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 这个脚本来自 github,删掉了一些 ** 言论。 3 | 4 | osascript -e 'tell application "iTerm2" to version' > /dev/null 2>&1 && NAME=iTerm2 || NAME=iTerm 5 | if [[ $NAME = "iTerm" ]]; then 6 | FILE=`osascript -e 'tell application "iTerm" to activate' -e 'tell application "iTerm" to set thefile to choose file with prompt "Choose a file to send"' -e "do shell script (\"echo \"&(quoted form of POSIX path of thefile as Unicode text)&\"\")"` 7 | else 8 | FILE=`osascript -e 'tell application "iTerm2" to activate' -e 'tell application "iTerm2" to set thefile to choose file with prompt "Choose a file to send"' -e "do shell script (\"echo \"&(quoted form of POSIX path of thefile as Unicode text)&\"\")"` 9 | fi 10 | if [[ $FILE = "" ]]; then 11 | echo Cancelled. 12 | # Send ZModem cancel 13 | echo -e \\x18\\x18\\x18\\x18\\x18 14 | sleep 1 15 | echo 16 | echo \# Cancelled transfer 17 | else 18 | /usr/local/bin/sz "$FILE" -e -b 19 | sleep 1 20 | echo 21 | echo \# Received $FILE 22 | fi -------------------------------------------------------------------------------- /img/error_extract-text-webpack-plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iq9891/blog/10b3369f81ab06b31980011f144ae41d1e802780/img/error_extract-text-webpack-plugin.png -------------------------------------------------------------------------------- /img/error_jest_syntax_error_unexpected_token_import.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iq9891/blog/10b3369f81ab06b31980011f144ae41d1e802780/img/error_jest_syntax_error_unexpected_token_import.png -------------------------------------------------------------------------------- /img/error_this_is_not_a_function.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iq9891/blog/10b3369f81ab06b31980011f144ae41d1e802780/img/error_this_is_not_a_function.png -------------------------------------------------------------------------------- /img/error_unkown_word.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iq9891/blog/10b3369f81ab06b31980011f144ae41d1e802780/img/error_unkown_word.png -------------------------------------------------------------------------------- /img/fecli-pre.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iq9891/blog/10b3369f81ab06b31980011f144ae41d1e802780/img/fecli-pre.png -------------------------------------------------------------------------------- /img/fecli.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iq9891/blog/10b3369f81ab06b31980011f144ae41d1e802780/img/fecli.png -------------------------------------------------------------------------------- /img/github_create_a_action1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iq9891/blog/10b3369f81ab06b31980011f144ae41d1e802780/img/github_create_a_action1.png -------------------------------------------------------------------------------- /img/github_create_a_action2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iq9891/blog/10b3369f81ab06b31980011f144ae41d1e802780/img/github_create_a_action2.png -------------------------------------------------------------------------------- /img/jest_file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iq9891/blog/10b3369f81ab06b31980011f144ae41d1e802780/img/jest_file.png -------------------------------------------------------------------------------- /img/jest_file_after.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iq9891/blog/10b3369f81ab06b31980011f144ae41d1e802780/img/jest_file_after.png -------------------------------------------------------------------------------- /img/mac/lrzsz/lrzsz1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iq9891/blog/10b3369f81ab06b31980011f144ae41d1e802780/img/mac/lrzsz/lrzsz1.png -------------------------------------------------------------------------------- /img/mac/lrzsz/lrzsz2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iq9891/blog/10b3369f81ab06b31980011f144ae41d1e802780/img/mac/lrzsz/lrzsz2.png -------------------------------------------------------------------------------- /img/mac/lrzsz/lrzsz3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iq9891/blog/10b3369f81ab06b31980011f144ae41d1e802780/img/mac/lrzsz/lrzsz3.jpg -------------------------------------------------------------------------------- /img/mac/lrzsz/lrzsz4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iq9891/blog/10b3369f81ab06b31980011f144ae41d1e802780/img/mac/lrzsz/lrzsz4.jpg -------------------------------------------------------------------------------- /img/mac/lrzsz/lrzsz5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iq9891/blog/10b3369f81ab06b31980011f144ae41d1e802780/img/mac/lrzsz/lrzsz5.jpg -------------------------------------------------------------------------------- /mac/Mac_命令行登录_Linux_无需密码的配置.md: -------------------------------------------------------------------------------- 1 | # Mac 命令行登录 Linux 无需密码的配置 2 | 3 | ## 正常的命令行登录 4 | 5 | ``` 6 | ssh 用户名@192.168.1.XXX 7 | ``` 8 | 9 | 之后还得输入密码,那么如何不输入密码快捷键搞定呢? 10 | 11 | ## 无需密码的命令行登录配置 12 | 13 | 1. 编写 `login.exp` 文件,内容如下: 14 | 15 | ``` 16 | #!/usr/bin/expect 17 | 18 | set timeout 30 19 | spawn ssh [lindex $argv 0]@[lindex $argv 1] -p [lindex $argv 3] 20 | expect { 21 | "(yes/no)?" 22 | {send "yes\n";exp_continue} 23 | "password:" 24 | {send "[lindex $argv 2]\n"} 25 | } 26 | interact 27 | ``` 28 | 29 | 2. 将 `login.exp` 放到 `/usr/local/bin/` 目录下 30 | 3. 使用 31 | 32 | - 点击 iTerm2 -> preferences -> profiles 33 | - 点击左下的 `+` 34 | - 编辑 Name 快捷键(Shortcut key) 35 | - 在 `Send text at start` 中 `login.exp 用户名 ip 密码 端口` , 如 `login.exp iq9891 192.168.1.XXX 123 22` 36 | - 退出,然后按快捷键测试,完成 -------------------------------------------------------------------------------- /mac/lrzsz.md: -------------------------------------------------------------------------------- 1 | # iTerm2 使用 lrzsz 上传下载文件 2 | 3 | ## 安装 4 | > 需要提前安装 Iterm2 和 Homebrew 5 | 6 | ``` 7 | # 本地 Mac 安装 8 | brew install lrzsz 9 | 10 | # 远程服务器安装 11 | yum install -y lrzsz 12 | apt-get install lrzsz 13 | ``` 14 | 15 | ## 配置 16 | 17 | 1. 下载触发脚本 18 | > 将他们拷贝到/usr/local/bin文件夹中 19 | 20 | ``` 21 | sudo su 22 | 23 | wget https://raw.githubusercontent.com/iq9891/blog/master/assets/mac/iterm2-send-zmodem.sh 24 | wget https://raw.githubusercontent.com/iq9891/blog/master/assets/mac/iterm2-recv-zmodem.sh 25 | 26 | mv iterm2-send-zmodem.sh /usr/local/bin 27 | mv iterm2-recv-zmodem.sh /usr/local/bin 28 | 29 | chmod 777 /usr/local/bin/iterm2-* 30 | ``` 31 | 32 | 2. 在iTerm 2添加Triggers 33 | > ❗️ 温馨提示: 要是有不同的 Profiles 要记得在不同的 Profiles 里面在添加一遍,不然不起作用 34 | 35 | ![i1](../img/mac/lrzsz/lrzsz1.png) 36 | 37 | ![i2](../img/mac/lrzsz/lrzsz2.png) 38 | 39 | 上图每栏的配置具体如下: 40 | 41 | ``` 42 | # 第一条 43 | Regular expression: rz waiting to receive.\*\*B0100 44 | Action: Run Silent Coprocess 45 | Parameters: /usr/local/bin/iterm2-send-zmodem.sh 46 | Instant: checked 47 | 48 | # 第二条 49 | Regular expression: \*\*B00000000000000 50 | Action: Run Silent Coprocess 51 | Parameters: /usr/local/bin/iterm2-recv-zmodem.sh 52 | Instant: checked 53 | ``` 54 | 55 | ## 应用 56 | 57 | 1. 登录远程服务器 58 | > expect is the reason why lrzsz can't be used. 59 | If you don't use expect for ssh auto-logging, the lrzsz works. 60 | 61 | ``` 62 | # ❗️不能使用expect 来实现ssh 自动登录, 需要手工登录或者 so 来登录 63 | 64 | ssh root@XXX.XXX.XXX.XXX -p 9922 65 | ``` 66 | 67 | 2. 上传文件至远程服务器 68 | 69 | ![i3](../img/mac/lrzsz/lrzsz3.jpg) 70 | 71 | ![i4](../img/mac/lrzsz/lrzsz4.jpg) 72 | 73 | - 在远程服务器执行 `rz` 命令 74 | - 在弹窗中选择文件上传即可 75 | 76 | 3. 下载远程服务器的文件至本地 77 | 78 | ![i5](../img/mac/lrzsz/lrzsz5.jpg) 79 | 80 | - 在远程服务器执行 `sz filename` 命令(将 filename 下载到本地) 81 | - 在弹窗中选择要下载到本地的目录 -------------------------------------------------------------------------------- /mac/mac.md: -------------------------------------------------------------------------------- 1 | # 从零开始配置一台 mac 电脑(前端方向) 2 | 3 | 正所谓一个好的前端必须手里有些好用的工具。我认为前端标配应该是顶配 MAC pro 15 寸电脑,苹果鼠标,机械键盘等。那么对于刚有实力从 Windows 过度到 Mac 的同学可能一时不知道怎么用 Mac 才是正确的高逼格的姿势,怎么配置一个面向前端的 Mac 电脑。下面就为大家揭晓从零开始一步一步让大家飞起来。 4 | 5 | 1. 开机 6 | 2. 选择语言 7 | 3. 选择键盘 8 | 4. 链接 wifi 9 | 5. 登录 apple 账号 10 | 6. 配置一些个人喜好,如触控板等 11 | 7. 下载 [xcode](https://itunes.apple.com/cn/app/xcode/id497799835?mt=12) ,用于辅助 brew 工具 12 | 8. 安装一些必备软件 13 | - [谷歌](https://www.google.cn/chrome/index.html) 14 | - [火狐](http://www.firefox.com.cn/) 15 | - [微信](https://mac.weixin.qq.com/) 16 | - [钉钉](https://tms.dingtalk.com/markets/dingtalk/download?spm=a3140.8736650.757160.4.7f155c8c3Wcmny&lwfrom=20180509160455304) 17 | - QQ 18 | - 编辑器 19 | - [atom](https://atom.io/) 20 | - sublime text 21 | - [Brackets](http://brackets.io/) 22 | - [vscode](https://code.visualstudio.com/) 23 | - 设计软件 24 | - [photoshop](https://www.photoshop.com/products) 25 | - [sketch](https://www.sketchapp.com/) 26 | - 微信开发者工具 27 | - [worktile](https://worktile.com/client) 或 [tower](https://tower.im/) 28 | - postman 29 | - [谷歌插件](https://chrome.google.com/webstore/detail/postman/fhbjgbiflinjbdggehcddcbncdddomop?hl=en) 30 | - [官网](https://www.getpostman.com/) 31 | 9. [iTerm2](https://iterm2.com/) 命令行工具 32 | 10. [oh-my-zsh](https://github.com/robbyrussell/oh-my-zsh) 命令行主题,内置各种快捷键 33 | 11. [brew](http://brew.sh/) 命令行安装工具 34 | 12. [git](https://git-scm.com/downloads) 代码版本控制 35 | 13. [nvm](https://github.com/creationix/nvm) Node.js 控制版本 36 | 14. [yarn](https://yarn.bootcss.com/docs/install.html) 37 | 15. [tig](https://github.com/jonas/tig) 查看 commit 信息的工具 38 | 16. [cz-cli](https://github.com/commitizen/cz-cli) 规范 commit 信息的工具 39 | 17. [VirtualBox](https://www.virtualbox.org/wiki/Downloads) mac 上的虚拟机,只为调试 IE 40 | -------------------------------------------------------------------------------- /mac/mac使用.md: -------------------------------------------------------------------------------- 1 | # mac 使用 2 | 3 | ## 对应关系 4 | 5 | |mac|win| 6 | |---|---| 7 | |command(cmd)|ctrl| 8 | |control|alt| 9 | |option+cmd+i|f12 (谷歌中查找元素)| 10 | 11 | ## 与 win 不一样的地方 12 | 13 | 1. 点击选中文件夹,按 **回车** 可重命名文件夹名字 14 | 2. 安装软件 15 | - dmg 结尾的文件,打开之后拖动到 Applications 16 | - 命令行运行, 如 `brew install git` , 安装 git 软件 17 | 18 | ## 快捷键 19 | 20 | ### mac 的快捷方式 21 | 22 | |命令|功能| 23 | |----|----| 24 | |cmd + q|关上整个软件(如 关上 atom),不在后台执行| 25 | |cmd + w|关上整个软件(如 关上 atom),在后台执行| 26 | |cmd + tab + ]|切换软件标签 向右| 27 | |cmd + tab + [|切换软件标签 向左| 28 | |cmd + tab|切换当前软件运行窗口| 29 | 30 | 31 | ### 在命令行中 32 | 33 | > iterm2 打开左侧的 ~ 是 用户 目录 34 | 35 | #### iterm2 命令 36 | 37 | |命令|功能| 38 | |----|----| 39 | |`ll`|查看当前目录的文件夹级别| 40 | |`ls`|查看当前目录的文件夹| 41 | |`open .`|打开命令行所在目录| 42 | |`rm -rf node_modules`|删除当前目录中的 **node_modules** 文件| 43 | |`mkdir test`|创建 test 文件夹| 44 | |`touch test.md`|创建 test.md 文件| 45 | |`mv test test1`|讲 test 文件夹名字改成 test1| 46 | |`tig`|查看 commit 提交信息, [安装 tig](https://github.com/iq9891/blog/issues/11)| 47 | |`pwd`|查看当前路径| 48 | 49 | #### 快捷键 50 | 51 | |命令|功能| 52 | |----|----| 53 | |`cmd + d`|同标签内打开新建一个分栏 竖版| 54 | |`cmd + shift + d`|同标签内打开新建一个分栏 横版| 55 | |`cmd + t`|新建一个窗口切换用| 56 | |cmd + shift + `[`( 或 `]` )|切换不同窗口 57 | |cmd + `[`( 或 `]` )|切换同标签内的不同分栏 (cmd + shift + d 之后)| 58 | |`cmd + 数字`|切换到数字窗口,如 cmd + 1 , 切换到 窗口 1| 59 | |`tab`|可以直接快速选择某一个文件,类似补全| 60 | |`cmd + +`|放大| 61 | |`cmd + -`|放小| 62 | |`control + a`|光标到最前面| 63 | |`control + e`|光标到最后面| 64 | 65 | ## git 在 o-my-zsh 中的使用 66 | 67 | |命令|缩写| 68 | |----|----| 69 | |git commit|gc| 70 | |git add|ga| 71 | |git push|gp| 72 | |git fetch|gf| 73 | |git merge|gm| 74 | |git checkout|gco| 75 | |git status|gst| 76 | |git diff|gd| 77 | |git remote|gr| 78 | 79 | ### vim 80 | 81 | |命令|缩写| 82 | |----|----| 83 | |`: + x`|不保存退出| 84 | |`: + w + q`|保存退出| 85 | 86 | ### 常用的 shell 工具整理 87 | 88 | - [tldr](https://github.com/tldr-pages/tldr) - 查看 linux命令帮助(Too long, Don't read), usage: `tldr ssh` 89 | - [autojump](https://github.com/wting/autojump) - 快速切换常用目录, usage: `j dir_name` 90 | - [ag](https://github.com/ggreer/the_silver_searcher) - 搜索工具, usage: `ag '\/#\/'` 91 | - [fuck](https://github.com/nvbn/thefuck) - 纠正工具. 上一行输入错了, usage: `fuck`, 输出正确的。 92 | - [k](https://github.com/supercrabtree/k) - zsh 插件,需要用 zsh 的安装方式安装,brew 不起作用。命令行美化工具, 常用在git 仓库内 93 | ``` 94 | ll # 原样式查看 95 | k # 美化样式查看 96 | ``` 97 | - [so](https://github.com/ca0gu0/so) - SSH远程登录工具 98 | - [hr](https://github.com/LuRsT/hr) - 用于在终端展示分行符 99 | - [tcplstat](https://github.com/calvinwilliams/tcplstat) - 网络监控工具 100 | - [cz-cli](https://github.com/commitizen/cz-cli) - git commit 工具 101 | - [tig](https://github.com/jonas/tig) - git log 查看工具 102 | -------------------------------------------------------------------------------- /mac/node:_No_such_file_or_directory.md: -------------------------------------------------------------------------------- 1 | # node: No such file or directory 2 | 3 | 4 | 5 | 几年前,第一次玩 mac ,所以多年前不小心没卸载 node ,直接安装的 nvm ,结果导致切换版本总是报下面的错误; 6 | 7 | ``` 8 | nvm is not compatible with the npm config "prefix" option: currently set to "/Users/XXX/.nvm/versions/node/v0.12.7" 9 | Run `nvm use --delete-prefix v4.6.2` to unset it. 10 | ``` 11 | 12 | 当时处理的问题是直接把原装 node 卸载,结果一直在命令行工具启动的时候,node 都找不到。今天终于找到了办法,记录一下。 13 | 14 | 解决方案: 15 | 16 | 将 nvm 管理的所要用的 node 软链到程序目录,每次打开就找到了 17 | 18 | ``` 19 | ln –s .nvm/versions/node/v13.14.0/bin/node /usr/local/bin/node 20 | ``` -------------------------------------------------------------------------------- /qa/No Xcode or CLT version detected.md: -------------------------------------------------------------------------------- 1 | # No Xcode or CLT version detected 2 | 3 | ## 问题 4 | 5 | ``` 6 | gyp: No Xcode or CLT version detected! 7 | gyp ERR! configure error 8 | gyp ERR! stack Error: `gyp` failed with exit code: 1 9 | gyp ERR! stack at ChildProcess.onCpExit (/Users/lee/lee/lib/vue/vue-cli/node_modules/node-gyp/lib/configure.js:351:16) 10 | gyp ERR! stack at ChildProcess.emit (events.js:193:13) 11 | gyp ERR! stack at Process.ChildProcess._handle.onexit (internal/child_process.js:255:12) 12 | gyp ERR! System Darwin 19.2.0 13 | gyp ERR! command "/Users/lee/.nvm/versions/node/v11.15.0/bin/node" "/Users/lee/lee/lib/vue/vue-cli/node_modules/.bin/node-gyp" "rebuild" "--release" 14 | gyp ERR! cwd /Users/lee/lee/lib/vue/vue-cli/node_modules/fibers 15 | gyp ERR! node -v v11.15.0 16 | gyp ERR! node-gyp -v v5.0.5 17 | gyp ERR! not ok 18 | node-gyp exited with code: 1 19 | Please make sure you are using a supported platform and node version. If you 20 | would like to compile fibers on this machine please make sure you have setup your 21 | build environment-- 22 | Windows + OS X instructions here: https://github.com/nodejs/node-gyp 23 | Ubuntu users please run: `sudo apt-get install g++ build-essential` 24 | ``` 25 | 26 | ## 复现步骤 27 | 28 | 更新 XCode 之后,重新用 yarn 安装依赖 29 | 30 | ## 问题 31 | 32 | 遇到问题,首先执行 `sudo xcode-select --install` ,但是并没有成功,报错如下: 33 | 34 | ``` 35 | xcode-select: error: command line tools are already installed, use "Software Update" to install updates 36 | ``` 37 | 38 | 上面的问题是因为已经安装了,所以得先执行 `sudo rm -rf /Library/Developer/CommandLineTools` 39 | 40 | ## 完整解决步骤 41 | 42 | 1. `sudo rm -rf /Library/Developer/CommandLineTools` 43 | 2. `xcode-select --install` 44 | -------------------------------------------------------------------------------- /qa/Running_Gradle_task_assembleDebug_Forever.md: -------------------------------------------------------------------------------- 1 | # Running Gradle task 'assembleDebug' Forever 2 | 3 | ## 问题 4 | 5 | 运行 安卓 模拟器的时候 `Running Gradle task 'assembleDebug' Forever` 一直在跑,很慢很慢。 6 | 7 | ## 解决 8 | 9 | 打开目录 `android/app/build.gradle` 文件中 `compileSdkVersion` 字段都设置为最新 SDK 版本,当前是 29 。设置之后速度飞快。 -------------------------------------------------------------------------------- /qa/android_avd_system.md: -------------------------------------------------------------------------------- 1 | # Android AVD system 2 | 3 | ## 问题 4 | 5 | 启动项目的时候,选择安卓模拟器的时候,报如下错误: 6 | 7 | ``` 8 | No suitable Android AVD system images are available. You may need to install these using sdkmanager, for example: sdkmanager "system-images;android-27;google_apis_playstore;x86" 9 | ``` 10 | 11 | ## 解决 12 | 13 | 用 Android Studio 安装一个安卓模拟器即可 -------------------------------------------------------------------------------- /qa/axios_get_diy_headers.md: -------------------------------------------------------------------------------- 1 | # axios拿不到自定义的header头 2 | 3 | 用axios发送请求获取reponse header中的数据,需要提前在后台添加设置过滤器头部配置、自定义头部属性、并打开过滤器。 4 | 然后就是前端发送请求,然后获取reponse headers里面的自定义属性。然后发现获取的永远是下面的几个属性: 5 | 6 | ``` 7 | Object { 8 | cache-control:"private, must-revalidate", 9 | content-type:"application/json" 10 | } 11 | ``` 12 | 13 | 查看 Network ,发现 ajax 请求中 header 头中确实有 Authorization 字段。如果想让浏览器能访问到其他的 响应头的话:***需要在服务器上设置 Access-Control-Expose-Headers*** 14 | 15 | ``` 16 | Access-Control-Expose-Headers : 'Authorization' 17 | ``` 18 | 19 | 设置之后,即可好使,如下图: 20 | 21 | ![结果](https://user-images.githubusercontent.com/5716990/80055743-04f37580-8555-11ea-8e8c-5697e02e7ceb.png) -------------------------------------------------------------------------------- /qa/could_not_resolve_hostname.md: -------------------------------------------------------------------------------- 1 | # Could not resolve hostname 2 | 3 | > ssh: Could not resolve hostname github.com: nodename nor servname provided, or not known 4 | fatal: 无法读取远程仓库。 5 | 请确认您有正确的访问权限并且仓库存在。 6 | 7 | ***问题分析***: 网络出现了问题 8 | 9 | ***解决方案***: 重连网络,网络稳定之后再试。 -------------------------------------------------------------------------------- /qa/error_extract-text-webpack-plugin.md: -------------------------------------------------------------------------------- 1 | # Module build failed: Error: "extract-text-webpack-plugin" loader 2 | 3 | 最近配置 webpack 4 的时候遇到有关 `extract-text-webpack-plugin` 的问题。 4 | 5 | ## 操作环境 6 | 7 | - 开发环境: OS X El Capitan 10.11.6 8 | - 开发工具: [Atom](https://atom.io) 9 | - node: v9.11.1 10 | - npm: 5.0.3 11 | - webpack: 4.5.0 12 | - postcss-loader: 2.1.3 13 | - css-loader: 0.28.11 14 | - node-sass: 4.8.3 15 | - sass-loader: 7.0.1 16 | - extract-text-webpack-plugin: 'next' 17 | 18 | ## 报错信息⤵️ 19 | 20 | ``` 21 | ERROR in ./src/assets/styles/views/home.scss 22 | Module build failed: Error: "extract-text-webpack-plugin" loader is used without the corresponding plugin, refer to https://github.com/webpack/extract-text-webpack-plugin for the usage example 23 | at Object.pitch (/Users/lee/lee/vue-spa-template/tpltest3/node_modules/extract-text-webpack-plugin/dist/loader.js:59:11) 24 | @ ./src/main.js 2:0-39 25 | @ multi babel-polyfill ./src/main.js 26 | 27 | ERROR in ./node_modules/em-fe/dist/css/emfe.css 28 | Module build failed: Error: "extract-text-webpack-plugin" loader is used without the corresponding plugin, refer to https://github.com/webpack/extract-text-webpack-plugin for the usage example 29 | at Object.pitch (/Users/lee/lee/vue-spa-template/tpltest3/node_modules/extract-text-webpack-plugin/dist/loader.js:59:11) 30 | @ ./src/main.js 4:0-33 31 | @ multi babel-polyfill ./src/main.js 32 | ``` 33 | 34 | ![Module build failed: Error: "extract-text-webpack-plugin" loader](https://raw.githubusercontent.com/iq9891/blog/master/img/error_extract-text-webpack-plugin.png) 35 | 36 | ## 解决方案 37 | 38 | `extract-text-webpack-plugin` 并没有对 webpack 4 进行处理,所以替换成 `mini-css-extract-plugin` 即可。 39 | 40 | ## 源码 41 | 42 | 更全的配置,请移步 [176f224](https://github.com/iq9891/vue-spa-template/commit/176f224a224c48840fc589991e141f856e030953) 。 43 | -------------------------------------------------------------------------------- /qa/error_jest_syntax_error_unexpected_token_import.md: -------------------------------------------------------------------------------- 1 | # jest SyntaxError: Unexpected token import 2 | 3 | 配置 jest 进行单元测试的时候,如果 `jest SyntaxError: Unexpected token import`。那么肯定是 JavaScript 的语法没有降级处理。 4 | 5 | ## 操作环境 6 | 7 | - 开发环境: OS X El Capitan 10.11.6 8 | - 开发工具: [Atom](https://atom.io) 9 | - node: v9.11.1 10 | - npm: 5.0.3 11 | - webpack: 4.5.0 12 | - jest: 22.4.3 13 | 14 | ## 报错信息⤵️ 15 | 16 | ``` 17 | > jest 18 | 19 | FAIL water/icon/icon.test.js 20 | ● Test suite failed to run 21 | 22 | /Users/lee/lee/component-template/water/icon/icon.test.js:2 23 | import { mount } from 'vue-test-utils'; 24 | ^^^^^^ 25 | 26 | SyntaxError: Unexpected token import 27 | 28 | at ScriptTransformer._transformAndBuildScript (node_modules/jest-runtime/build/script_transformer.js:316:17) 29 | ``` 30 | 31 | ![jest SyntaxError: Unexpected token import](https://raw.githubusercontent.com/iq9891/blog/master/img/error_jest_syntax_error_unexpected_token_import.png) 32 | 33 | ## 解决方案 34 | 35 | 如果文件中有高级语法需要用 babel-jest 兼容处理,并且 babel 配置中不能有 [modules](https://babeljs.cn/docs/plugins/preset-env/#modules) 字段。 36 | 37 | ### 解决之前 38 | 39 | ``` 40 | // package.json 41 | "jest": { 42 | "transform": { 43 | ".*\\.(vue)$": "/node_modules/vue-jest" 44 | } 45 | }, 46 | ``` 47 | 48 | ``` 49 | // .babelrc 50 | { 51 | "presets": [ 52 | ["env", { 53 | "modules": false, 54 | // other config 55 | }] 56 | ] 57 | } 58 | ``` 59 | 60 | ### 解决之后 61 | 62 | ``` 63 | // package.json 64 | "jest": { 65 | "transform": { 66 | ".*\\.(vue)$": "/node_modules/vue-jest", 67 | ".*\\.(js)$": "/node_modules/babel-jest" 68 | } 69 | }, 70 | ``` 71 | 72 | ``` 73 | // .babelrc 74 | { 75 | "presets": [ 76 | ["env", { 77 | // other config 78 | }] 79 | ] 80 | } 81 | ``` 82 | 83 | ## 源码 84 | 85 | 更全的配置,请移步 [component-template](https://github.com/fe6/component-template) 。 86 | -------------------------------------------------------------------------------- /qa/error_this[NS]_is_not_a_function.md: -------------------------------------------------------------------------------- 1 | # this[NS] is not a function 2 | 3 | 最近配置 webpack 4 的时候遇到有关 `mini-css-extract-plugin` 的问题。 4 | 5 | ## 操作环境 6 | 7 | - 开发环境: OS X El Capitan 10.11.6 8 | - 开发工具: [Atom](https://atom.io) 9 | - node: v9.11.1 10 | - npm: 5.0.3 11 | - webpack: 4.5.0 12 | - postcss-loader: 2.1.3 13 | - css-loader: 0.28.11 14 | - node-sass: 4.8.3 15 | - sass-loader: 7.0.1 16 | - mini-css-extract-plugin: 0.4.0 17 | 18 | ## 报错信息⤵️ 19 | 20 | ``` 21 | ERROR in ./src/views/Home.vue (./node_modules/mini-css-extract-plugin/dist/loader.js!./node_modules/css-loader?{"minimize":true,"sourceMap":true}!./node_modules/vue-loader/lib/style-compiler?{"optionsId":"0","vue":true,"scoped":false,"sourceMap":false}!./node_modules/sass-loader/lib/loader.js?{"sourceMap":true}!./node_modules/vue-loader/lib/selector.js?type=styles&index=0!./src/views/Home.vue) 22 | Module build failed: TypeError: this[NS] is not a function 23 | at childCompiler.runAsChild (/Users/lee/lee/vue-spa-template/tpltest7/node_modules/mini-css-extract-plugin/dist/loader.js:147:15) 24 | at compile (/Users/lee/lee/vue-spa-template/tpltest7/node_modules/webpack/lib/Compiler.js:242:11) 25 | at hooks.afterCompile.callAsync.err (/Users/lee/lee/vue-spa-template/tpltest7/node_modules/webpack/lib/Compiler.js:487:14) 26 | at AsyncSeriesHook.eval [as callAsync] (eval at create (/Users/lee/lee/vue-spa-template/tpltest7/node_modules/tapable/lib/HookCodeFactory.js:24:12), :24:1) 27 | at AsyncSeriesHook.lazyCompileHook [as _callAsync] (/Users/lee/lee/vue-spa-template/tpltest7/node_modules/tapable/lib/Hook.js:35:21) 28 | at compilation.seal.err (/Users/lee/lee/vue-spa-template/tpltest7/node_modules/webpack/lib/Compiler.js:484:30) 29 | at AsyncSeriesHook.eval [as callAsync] (eval at create (/Users/lee/lee/vue-spa-template/tpltest7/node_modules/tapable/lib/HookCodeFactory.js:24:12), :6:1) 30 | at AsyncSeriesHook.lazyCompileHook [as _callAsync] (/Users/lee/lee/vue-spa-template/tpltest7/node_modules/tapable/lib/Hook.js:35:21) 31 | at hooks.optimizeAssets.callAsync.err (/Users/lee/lee/vue-spa-template/tpltest7/node_modules/webpack/lib/Compilation.js:966:35) 32 | at AsyncSeriesHook.eval [as callAsync] (eval at create (/Users/lee/lee/vue-spa-template/tpltest7/node_modules/tapable/lib/HookCodeFactory.js:24:12), :6:1) 33 | at AsyncSeriesHook.lazyCompileHook [as _callAsync] (/Users/lee/lee/vue-spa-template/tpltest7/node_modules/tapable/lib/Hook.js:35:21) 34 | at hooks.optimizeChunkAssets.callAsync.err (/Users/lee/lee/vue-spa-template/tpltest7/node_modules/webpack/lib/Compilation.js:957:32) 35 | at _err0 (eval at create (/Users/lee/lee/vue-spa-template/tpltest7/node_modules/tapable/lib/HookCodeFactory.js:24:12), :11:1) 36 | at /Users/lee/lee/vue-spa-template/tpltest7/node_modules/uglifyjs-webpack-plugin/dist/index.js:334:11 37 | at _class.runTasks (/Users/lee/lee/vue-spa-template/tpltest7/node_modules/uglifyjs-webpack-plugin/dist/uglify/index.js:63:9) 38 | at UglifyJsPlugin.optimizeFn (/Users/lee/lee/vue-spa-template/tpltest7/node_modules/uglifyjs-webpack-plugin/dist/index.js:253:16) 39 | @ ./src/views/Home.vue 2:2-356 40 | @ ./src lazy ^\.\/.*$ namespace object 41 | @ ./src/tools/loadcomponents.js 42 | @ ./src/routers/index.js 43 | @ ./src/main.js 44 | @ multi babel-polyfill ./src/main.js 45 | 46 | ERROR in ./src/App.vue (./node_modules/mini-css-extract-plugin/dist/loader.js!./node_modules/css-loader?{"minimize":true,"sourceMap":true}!./node_modules/vue-loader/lib/style-compiler?{"optionsId":"0","vue":true,"scoped":false,"sourceMap":false}!./node_modules/sass-loader/lib/loader.js?{"sourceMap":true}!./node_modules/vue-loader/lib/selector.js?type=styles&index=0!./src/App.vue) 47 | Module build failed: TypeError: this[NS] is not a function 48 | at childCompiler.runAsChild (/Users/lee/lee/vue-spa-template/tpltest7/node_modules/mini-css-extract-plugin/dist/loader.js:147:15) 49 | at compile (/Users/lee/lee/vue-spa-template/tpltest7/node_modules/webpack/lib/Compiler.js:242:11) 50 | at hooks.afterCompile.callAsync.err (/Users/lee/lee/vue-spa-template/tpltest7/node_modules/webpack/lib/Compiler.js:487:14) 51 | at AsyncSeriesHook.eval [as callAsync] (eval at create (/Users/lee/lee/vue-spa-template/tpltest7/node_modules/tapable/lib/HookCodeFactory.js:24:12), :24:1) 52 | at AsyncSeriesHook.lazyCompileHook [as _callAsync] (/Users/lee/lee/vue-spa-template/tpltest7/node_modules/tapable/lib/Hook.js:35:21) 53 | at compilation.seal.err (/Users/lee/lee/vue-spa-template/tpltest7/node_modules/webpack/lib/Compiler.js:484:30) 54 | at AsyncSeriesHook.eval [as callAsync] (eval at create (/Users/lee/lee/vue-spa-template/tpltest7/node_modules/tapable/lib/HookCodeFactory.js:24:12), :6:1) 55 | at AsyncSeriesHook.lazyCompileHook [as _callAsync] (/Users/lee/lee/vue-spa-template/tpltest7/node_modules/tapable/lib/Hook.js:35:21) 56 | at hooks.optimizeAssets.callAsync.err (/Users/lee/lee/vue-spa-template/tpltest7/node_modules/webpack/lib/Compilation.js:966:35) 57 | at AsyncSeriesHook.eval [as callAsync] (eval at create (/Users/lee/lee/vue-spa-template/tpltest7/node_modules/tapable/lib/HookCodeFactory.js:24:12), :6:1) 58 | at AsyncSeriesHook.lazyCompileHook [as _callAsync] (/Users/lee/lee/vue-spa-template/tpltest7/node_modules/tapable/lib/Hook.js:35:21) 59 | at hooks.optimizeChunkAssets.callAsync.err (/Users/lee/lee/vue-spa-template/tpltest7/node_modules/webpack/lib/Compilation.js:957:32) 60 | at _err0 (eval at create (/Users/lee/lee/vue-spa-template/tpltest7/node_modules/tapable/lib/HookCodeFactory.js:24:12), :11:1) 61 | at /Users/lee/lee/vue-spa-template/tpltest7/node_modules/uglifyjs-webpack-plugin/dist/index.js:334:11 62 | at _class.runTasks (/Users/lee/lee/vue-spa-template/tpltest7/node_modules/uglifyjs-webpack-plugin/dist/uglify/index.js:63:9) 63 | at UglifyJsPlugin.optimizeFn (/Users/lee/lee/vue-spa-template/tpltest7/node_modules/uglifyjs-webpack-plugin/dist/index.js:253:16) 64 | @ ./src/App.vue 2:2-346 65 | @ ./src/main.js 66 | @ multi babel-polyfill ./src/main.js 67 | ``` 68 | 69 | ![this[NS] is not a function](https://raw.githubusercontent.com/iq9891/blog/master/img/error_this_is_not_a_function.png) 70 | 71 | ## 解决方案 72 | 73 | `mini-css-extract-plugin` 使用的必须有 loader ,有调用。但如果光有 loader ,没有调用,那么就会报上面的错误。怎么解决呢?加上调用就可以了 74 | 75 | ``` 76 | // build/webpack.prod.conf.js 77 | 78 | var MiniCssExtractPlugin = require("mini-css-extract-plugin"); 79 | 80 | var webpackConfig = merge(baseWebpackConfig, { 81 | // other options... 82 | plugins: [ 83 | // 提取 84 | new MiniCssExtractPlugin({ 85 | filename: utils.assetsPath('css/[name].[contenthash].css') 86 | }) 87 | ] 88 | }) 89 | ``` 90 | 91 | ## 源码 92 | 93 | 更全的配置,请移步 [176f224](https://github.com/iq9891/vue-spa-template/commit/176f224a224c48840fc589991e141f856e030953) 。 94 | -------------------------------------------------------------------------------- /qa/error_unknown_word.md: -------------------------------------------------------------------------------- 1 | # Module build failed: ModuleBuildError: Module build failed: Syntax Error (13:4) Unknown word 2 | 3 | 最近配置 webpack 4 的时候遇到一个经典的问题困扰我一天,关键词 `Unknown word` 。 4 | 5 | ## 操作环境 6 | 7 | - 开发环境: OS X El Capitan 10.11.6 8 | - 开发工具: [Atom](https://atom.io) 9 | - node: v9.11.1 10 | - npm: 5.0.3 11 | - webpack: 4.5.0 12 | - postcss-loader: 2.1.3 13 | - css-loader: 0.28.11 14 | - node-sass: 4.8.3 15 | - sass-loader: 7.0.1 16 | 17 | ## 报错信息⤵️ 18 | 19 | ``` 20 | ERROR in ./src/style/iconfont.scss 21 | Module build failed: ModuleBuildError: Module build failed: Syntax Error 22 | 23 | (13:4) Unknown word 24 | 25 | 11 | } 26 | 12 | 27 | > 13 | .#{$font-prefix}font { 28 | | ^ 29 | 14 | font-family: $font-name !important; 30 | 15 | -webkit-font-smoothing: antialiased; 31 | 32 | at runLoaders (/Users/lee/lee/vcmd/node_modules/webpack/lib/NormalModule.js:244:20) 33 | at /Users/lee/lee/vcmd/node_modules/loader-runner/lib/LoaderRunner.js:364:11 34 | at /Users/lee/lee/vcmd/node_modules/loader-runner/lib/LoaderRunner.js:230:18 35 | at context.callback (/Users/lee/lee/vcmd/node_modules/loader-runner/lib/LoaderRunner.js:111:13) 36 | at Promise.resolve.then.then.catch (/Users/lee/lee/cpt-vue-fe6-iq9891/vue-icon/node_modules/postcss-loader/lib/index.js:196:44) 37 | at 38 | @ ./src/style/index.ts 1:0-25 39 | ``` 40 | ![ModuleBuildError: Module build failed: Syntax Error Unknown word](https://raw.githubusercontent.com/iq9891/blog/master/img/error_unkown_word.png) 41 | 42 | ## 解决方案 43 | 44 | 从上面报错得知是有关样式编译的时候报错的,所以主要检查一下关于样式打包的情况。 **有可能 postcss 解析不了 sass 的语法** 。 45 | 46 | > 代码来自 webpack 4 配置文件的 module 部分。 MiniCssExtractPlugin 是提炼样式的组件 [mini-css-extract-plugin](https://github.com/webpack-contrib/mini-css-extract-plugin) 。 `resolve` 是获取文件的路径。 47 | 48 | ### 解决之前 49 | 50 | ``` 51 | module: { 52 | rules: [ 53 | { 54 | test: /.scss$/, 55 | use: [ 56 | MiniCssExtractPlugin.loader, 57 | 'cache', 'css', 'sass', { 58 | loader: 'postcss', 59 | options: { 60 | config: { 61 | path: resolve('.postcssrc.js') 62 | } 63 | } 64 | }, 65 | ] 66 | }, 67 | ] 68 | } 69 | ``` 70 | 71 | ### 解决之后 72 | 73 | ``` 74 | module: { 75 | rules: [ 76 | { 77 | test: /.scss$/, 78 | use: [ 79 | MiniCssExtractPlugin.loader, 80 | 'cache', 'css', { 81 | loader: 'postcss', 82 | options: { 83 | config: { 84 | path: resolve('.postcssrc.js') 85 | } 86 | } 87 | }, 'sass', 88 | ] 89 | }, 90 | ] 91 | } 92 | ``` 93 | 94 | ## 源码 95 | 96 | 更全的配置,请移步 [76445c0](https://github.com/fe6/vcmd/commit/76445c0a232097fb47d4d9612b2dcda08777aca4) 。 97 | -------------------------------------------------------------------------------- /qa/flutter_android_keeps_stopping.md: -------------------------------------------------------------------------------- 1 | # flutter android keeps stopping 2 | 3 | ## 环境 4 | 5 | - mac catalina 10.15.5 6 | - flutter 1.17.3 7 | - dart 2.8.4 8 | - vs code 1.45.1 9 | - 安卓模拟器 Pixel 3a XL API 29 10 | - flutter 应用名字 [first_flutter](https://github.com/iq9891/first_flutter) 11 | 12 | # 问题 13 | 14 | 最近修改 Android 启动图片,在网上海搜了很多解决方案,在 [launch_background.xml](https://github.com/iq9891/first_flutter/blob/master/android/app/src/main/res/drawable/launch_background.xml) 中配置如下代码: 15 | 16 | ``` 17 | 18 | 19 | 20 | 21 | true 22 | false 23 | 24 | 25 | 29 | 30 | 31 | ``` 32 | 33 | 启动安卓的时候就报错了报错如下: 34 | 35 | ``` 36 | first_flutter keeps stopping 37 | ``` 38 | 39 | 截图如下: 40 | 41 | ![flutter android keeps stopping](https://user-images.githubusercontent.com/5716990/83975308-c871b280-a925-11ea-83e8-d6f2e63f4420.jpg) 42 | 43 | 解决方案: 44 | 45 | 对比新建的 flutter 项目,发现下面两句不生效导致的安卓报错,去掉即可 46 | 47 | ``` 48 | true 49 | false 50 | ``` 51 | -------------------------------------------------------------------------------- /qa/flutter_android_launch_image.md: -------------------------------------------------------------------------------- 1 | # flutter android 启动图撑满屏幕 2 | 3 | ## 问题 4 | 5 | 怎么让配置的安卓启动图片撑满屏幕? 原来的代码如下 6 | 7 | ``` 8 | 12 | ``` 13 | 14 | ## 解决 15 | 16 | 去掉 `android:gravity="center"` 代码即可 17 | 18 | ``` 19 | 22 | ``` -------------------------------------------------------------------------------- /qa/ios_not_support_embedding.md: -------------------------------------------------------------------------------- 1 | # Trying to embed a platform view but the PrerollContext does not support embedding 2 | 3 | ## 环境 4 | 5 | * [Dart](https://www.dartcn.com/) 2.8.4 6 | * [Flutter](https://flutter.cn/) 1.17.3 7 | * macOS Catalina 10.15.5 8 | * vs code 1.46.0 9 | 10 | # 问题 11 | 12 | iOS 模拟的时候,vs code 控制台抛出: `Trying to embed a platform view but the PrerollContext does not support embedding` 13 | 14 | ![image](https://user-images.githubusercontent.com/5716990/84481651-f873d980-acc8-11ea-973a-1adb88f39241.png) 15 | 16 | 17 | # 解决方案 18 | 19 | 1. 在 `ios/Runner/Info.plist` 中,添加如下代码: 20 | 21 | ``` 22 | io.flutter.embedded_views_preview 23 | 24 | ``` 25 | 26 | 2. 重启 vs code 和 模拟器,即可生效 27 | 28 | -------------------------------------------------------------------------------- /qa/jest_file.md: -------------------------------------------------------------------------------- 1 | # jest 测试覆盖报告 File 中并没有测试的文件 2 | 3 | jest 编写单元测之后,查看测试报告 File 中并没有包含测试的 vue 文件。 4 | 5 | ## 情景描述 6 | 7 | 待测试文件 Icon.vue ,测试报告如下图⤵️ 8 | 9 | ![jest 测试覆盖报告中并没有测试的文件](https://raw.githubusercontent.com/iq9891/blog/master/img/jest_file.png) 10 | 11 | ## 解决方案 12 | 13 | 困扰我一天的问题,究竟出在哪里了,我查看了网上流传的各种 vue 的案例,都没啥问题。于是我仔细检查了一下我要测试 Icon.vue 文件。却发现了其中的奥妙所在。发现加上 data 这个方法之后,神奇般的就加入了这个文件 14 | 15 | ### 解决之前 16 | 17 | ``` 18 | 21 | 26 | ``` 27 | 28 | ### 解决之后 29 | 30 | ``` 31 | 34 | 42 | ``` 43 | 44 | ### 最终想要的结果 45 | 46 | 加入 data 参数之后,测试报告中神奇般的出现了 Icon.vue 文件。 47 | 48 | ![jest 测试覆盖报告中并没有测试的文件](https://raw.githubusercontent.com/iq9891/blog/master/img/jest_file_after.png) 49 | 50 | 51 | ## 操作环境 52 | 53 | - 开发环境: OS X El Capitan 10.11.6 54 | - 开发工具: [Atom](https://atom.io) 55 | - node: v9.11.1 56 | - npm: 5.0.3 57 | - babel-jest: 22.4.3 58 | - jest: 22.4.3 59 | - jest-serializer-vue: 1.0.0 60 | - vue: 2.5.16 61 | - vue-jest: 2.5.0 62 | - webpack: 4.6.0 63 | 64 | ## 源码 65 | 66 | 更全的配置,请移步 [component-template](https://github.com/fe6/component-template) 。 67 | -------------------------------------------------------------------------------- /qa/libcrypto.so.6:_cannot_open_shared_object_file.md: -------------------------------------------------------------------------------- 1 | # libcrypto.so.6: cannot open shared object file 2 | 3 | ## 问题 4 | 5 | `error while loading shared libraries: libcrypto.so.6: cannot open shared object file: No such file or directory` 6 | 7 | ## 环境 8 | 9 | **CentOS** 10 | 11 | ## 解决方案 12 | 13 | - `yum install libcrypto.so.6` 安装模块 14 | - `cd /usr/lib64` 进入目录 15 | - `ll *ssl*` 查看 16 | - `ln -s libssl.so.1.0.1e libssl.so.6` 软链 17 | - `ll *libcrypto*` 检测是否成功 -------------------------------------------------------------------------------- /qa/webpack4-extract-css.md: -------------------------------------------------------------------------------- 1 | # webpack 4 提取 CSS 等样式文件 2 | 3 | `extract-text-webpack-plugin` ,只支持 webpack 4 以下提取 CSS 文件,那么 webpack 4 怎么办呢?下面就为大家详细介绍 webpack 4 提取 CSS 文件的配置方法。 4 | 5 | ``` 6 | yarn add mini-css-extract-plugin 7 | ``` 8 | 9 | ## 普通项目配置 10 | 11 | > 需要注意的是 `MiniCssExtractPlugin.loader` 和 `style-loader` 由于某种原因不能共存。 12 | 13 | ``` 14 | // webpack.config.js 15 | 16 | var MiniCssExtractPlugin = require("mini-css-extract-plugin"); 17 | 18 | module.exports = { 19 | // other options... 20 | module: { 21 | rules: [ 22 | { 23 | test: /.scss$/, 24 | use: [ 25 | MiniCssExtractPlugin.loader, 26 | 'css', 'sass', 27 | ] 28 | }, 29 | ] 30 | }, 31 | plugins: [ 32 | new MiniCssExtractPlugin({ 33 | filename: 'style.css' 34 | }) 35 | ] 36 | } 37 | ``` 38 | 39 | ## Vue.js 全家桶的配置 40 | 41 | >这里只展示关于提取 CSS 的代码。 42 | 43 | ``` 44 | // build/webpack.prod.conf.js 45 | 46 | var MiniCssExtractPlugin = require("mini-css-extract-plugin"); 47 | 48 | var webpackConfig = merge(baseWebpackConfig, { 49 | // other options... 50 | plugins: [ 51 | // 提取 52 | new MiniCssExtractPlugin({ 53 | filename: utils.assetsPath('css/[name].[contenthash].css') 54 | }) 55 | ] 56 | }) 57 | ``` 58 | 59 | ``` 60 | // build/utils.js 61 | 62 | var MiniCssExtractPlugin = require("mini-css-extract-plugin"); 63 | 64 | // other options... 65 | if (options.extract) { 66 | return [MiniCssExtractPlugin.loader].concat(loaders) 67 | } else { 68 | return ['vue-style-loader'].concat(loaders) 69 | } 70 | ``` 71 | 72 | ## 源码 73 | 74 | 更全的配置,请移步 [176f224](https://github.com/iq9891/vue-spa-template/commit/176f224a224c48840fc589991e141f856e030953) 。 75 | -------------------------------------------------------------------------------- /react/Typescript_中使用_antd.form.create.md: -------------------------------------------------------------------------------- 1 | # Typescript 中使用 antd.form.create 2 | 3 | Typescript 中使用 antd.form.create ,总是报错,经多方查找学习,记录如下问题及解决方案。 4 | 5 | ## 报错内容如下 6 | 7 | ``` 8 | TS2322: Type '{ dataSource: any[]; variableSource: any[]; chosenType: string; isMultiple: boolean; onAddConfigValue: () => void; hasRelatedComponent: boolean; onChangeRelatedComponent: (status: any) => void; onChangeConfigValueStatus: (id: any) => () => void; onUpdateConfigValue: (id: any) => () => void; onDeleteConfigValue: (id:...' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes, "wrappedComponentRef">, any, any>> & Readonly<...> & Readonly<...>'. 9 | Property 'dataSource' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes, "wrappedComponentRef">, any, any>> & Readonly<...> & Readonly<...>'. 10 | ``` 11 | 12 | ## 解决办法如下: 13 | 14 | 1. `import {FormComponentProps} from 'antd/lib/form/Form';` 15 | 16 | 2. 17 | ``` 18 | interface CreateNoticeModalProps extends FormComponentProps { 19 | isShow: boolean 20 | onCancel: any 21 | onOk: any 22 | } 23 | ``` 24 | 25 | 3. `class Test extends React.Component {}` 26 | 27 | 4. 最关键的 28 | `export default Form.create()(CreateNoticeModal)` 29 | -------------------------------------------------------------------------------- /react/size_which_is_declared.md: -------------------------------------------------------------------------------- 1 | # 不能将类型“string”分配给类型“"default" | "small" | "large"” 2 | 3 | ## 报错 4 | 5 | `TS2322: Type 'string' is not assignable to type '"default" | "small" | "large"'` 6 | 7 | ![image](https://user-images.githubusercontent.com/5716990/79195634-2f607700-7e61-11ea-9cae-e22b4f555eae.png) 8 | 9 | ## 依赖 10 | 11 | - TypeScript 3.8.3 12 | - andt 3.26.15 13 | 14 | ## 解决 15 | 16 | 因为属性中有没有用的属性混合在一起,整理一下 paginationConfig 属性即可。 -------------------------------------------------------------------------------- /utils/fe6cli.md: -------------------------------------------------------------------------------- 1 | # 从零开始搭建前端脚手架 2 | 3 | Vue.js 是目前比较流行的前端框架之一,那么开发一个基于 Vue.js 的组件是每个前端的心愿。在每次开发新的 Vue.js 组件的时候,都会做的事情有下面几项: 4 | - 创建项目目录 5 | - git 初始化 6 | - npm 初始化 7 | - 搭建开发环境 8 | - 语法检测 9 | - 代码编译 10 | - 代码打包 11 | - 本地预览及热重载 12 | - 搭建生产环境 13 | - 语法检测 14 | - 代码编译 15 | - 代码打包及压缩 16 | - 持续集成的配置 17 | 18 | 那么为什么不把这些工作有效的提炼出来,让他一键生成呢?目前一键生成的工具有很多,如 [yeoman](http://yeoman.io/) 等。yeoman 搭建项目需要提供 yeoman 的脚手架包 。 yeoman 的脚手架包本质上就是一个具备完整文件结构的项目样板,用户需要手动地把这些脚手架包下载到本地,然后 yeoman 就会根据这些脚手架包自动生成各种不同的项目。 19 | 20 | yeoman 固然好用,但总是多了一步很是麻烦,还得下载脚手架包。市面上还流行 cli 技术,就是针对远程仓库的模板根据一些配置拉取到本地。显然 cli 的模式很好,不用下载就可以。我们依据这个原理自己搭建了一款叫做 [fecli](https://github.com/fe6/fecli) 的脚手架。 21 | 22 | ## 技术栈 23 | 24 | - 开发环境: OS X El Capitan 10.11.6 25 | - 开发工具: [Atom](https://atom.io) 26 | - [Node.js](https://nodejs.org):整个脚手架的运行环境。本脚手架的 Node.js 版本: 9.11.1 。 27 | - [es6](http://es6.ruanyifeng.com): JavaScript 的新语法。 28 | - [commander](https://www.npmjs.com/package/commander):TJ大神开发的工具,能够更好地组织和处理命令行的输入。本脚手架的 commander 版本: 2.15.1 。 29 | - [co](https://www.npmjs.com/package/co):异步流程控制工具。本脚手架的 co 版本: 4.6.0 。 30 | - [co-prompt](https://www.npmjs.com/package/co-prompt):分步接收用户的输入。本脚手架的 co-prompt 版本: 1.0.0 。 31 | - [chalk](https://www.npmjs.com/package/chalk):色彩丰富的终端工具。本脚手架的 chalk 版本: 2.3.2 。 32 | - [ora](https://www.npmjs.com/package/ora):典雅的终端微调器,可以控制终端输出。本脚手架的 ora 版本: 2.0.0 。 33 | 34 | ## 项目核心 35 | 36 | 一张图说明整体的架构。⤵️ 37 | 38 | ![fecli 架构图](https://raw.githubusercontent.com/iq9891/blog/master/img/fecli.png) 39 | 40 | ### 关于模板 41 | 42 | **模板** 就是未来拉取下来的东西。这个模板里往往会有一些环境的配置,语法检测的配置,单元测试的配置,持续集成的配置等。 43 | 44 | 模板的相关信息会存放在 **templates.json** 文件中。用户也可以通过一些命令操作 **templates.json** 中的内容。 45 | 46 | ### 脚手架的文件结构 47 | 48 | ``` bash 49 | . 50 | ├── bin/ # 运行命令的入口文件 51 | │ └── ... 52 | ├── lib/ # 核心代码 53 | │   ├── table.js # 模板列表表格形式的封装 54 | │   ├── tip.js # 终端提示信息的封装 55 | │   ├── cli/ # 命令管理 56 | │   │   └── ... 57 | │   └── cmd/ # 命令操作 58 | │   │   └── ... 59 | ├── public/ # 命令预览 60 | │   └── ... 61 | └── templates.json # 模板管理 62 | ``` 63 | 64 | ## 配置全局使用 65 | 66 | 新建一个目录 `mkdir fecli` ,并进入 `cd fecli` 。然后 npm 初始化一下 `npm init` 。 为了可以全局使用,我们需要在 **package.json** 里面设置一下: 67 | 68 | ``` 69 | "bin": { 70 | "fe": "./bin/fe.js" 71 | }, 72 | ``` 73 | 74 | 本地调试的时候,在项目根目录下执行: `npm link` 。 75 | 即可把 **fecli** 命令绑定到全局,以后就可以直接以 **fe** 作为命令开头。 76 | 77 | ## 入口文件的设置 78 | 79 | 在 package.json 里面写入依赖并执行 `npm install` 或者 `yarn install`: 80 | 81 | ``` 82 | "dependencies": { 83 | "chalk": "^2.3.2", 84 | "co": "^4.6.0", 85 | "co-prompt": "^1.0.0", 86 | "commander": "^2.15.1", 87 | "ora": "^2.0.0" 88 | } 89 | ``` 90 | 91 | 在根目录下建立 **\bin** 文件夹,在里面建立一个 [`fe.js`](https://github.com/fe6/fecli/blob/master/bin/fe.js) 文件。这个 **bin/fe.js** 文件是整个脚手架的入口文件,所以我们首先对它进行编写。 92 | 93 | 首先是一些初始化的代码,很简单就是引用了一下命令管理的文件([lib/cli/index.js](https://github.com/fe6/fecli/blob/master/lib/cli/index.js)): 94 | 95 | ``` 96 | require('../lib/cli/'); 97 | ``` 98 | 99 | 100 | ## 命令管理 ([lib/cli/index.js](https://github.com/fe6/fecli/blob/master/lib/cli/index.js)) 101 | 102 | 首先是一些初始化的事情: 103 | 104 | ``` 105 | const program = require('commander'); 106 | const packageInfo = require('../../package.json'); 107 | 108 | 109 | program 110 | .version(packageInfo.version) 111 | ``` 112 | 113 | 我们通过 **commander** 来设置不同的命令。 **command** 方法是设置命令的名字。 **description** 方法是设置描述。 **alias** 方法是设置简写。 **action** 方法是设置回调。 114 | 115 | ``` 116 | program 117 | .command('init') // fe init 118 | .description('生成一个项目') 119 | .alias('i') // 简写 120 | .action(() => { 121 | require('../cmd/init')(); 122 | }); 123 | 124 | program 125 | .command('add') // fe add 126 | .description('添加新模板') 127 | .alias('a') // 简写 128 | .action(() => { 129 | require('../cmd/add')(); 130 | }); 131 | 132 | program 133 | .command('list') // fe list 134 | .description('查看模板列表') 135 | .alias('l') // 简写 136 | .action(() => { 137 | require('../cmd/list')(); 138 | }); 139 | 140 | program 141 | .command('delete') // fe delete 142 | .description('删除模板') 143 | .alias('d') // 简写 144 | .action(() => { 145 | require('../cmd/delete')(); 146 | }); 147 | ``` 148 | 149 | 如果没有参数,运行帮助方法。接下来是解析 program.args 中的参数: 150 | 151 | ``` 152 | program.parse(process.argv); 153 | 154 | if(!program.args.length){ 155 | program.help() 156 | } 157 | ``` 158 | 159 | 运行 `fe` 之后的结果: 160 | 161 | ![运行 fe 结果](https://raw.githubusercontent.com/iq9891/blog/master/img/fecli-pre.png) 162 | 163 | **commander** 的具体使用方法在这里就不展开了,可以直接到[官网](https://github.com/tj/commander.js/)去看详细的文档。 164 | 165 | 166 | ## 处理用户输入 167 | 168 | 在项目根目录下建立 **/lib/cmd** 文件夹,专门用来存放命令处理文件。 169 | 在根目录下建立 **templates.json** 文件并写入如下内容,用来存放模版信息: 170 | 171 | ``` 172 | {"tpl":{}} 173 | ``` 174 | 175 | ### 添加模板 (`fe add`) 176 | 177 | >进入 /lib/cmd 并新建 [add.js](https://github.com/fe6/fecli/blob/master/lib/cmd/add.js) 文件。 178 | 179 | ``` 180 | 'use strict' 181 | const co = require('co'); 182 | const prompt = require('co-prompt'); 183 | const fs = require('fs'); 184 | 185 | const table = require('../table'); 186 | const tip = require('../tip'); 187 | const tpls = require('../../templates'); 188 | 189 | const writeFile = (err) => { 190 | // 处理错误 191 | if (err) { 192 | console.log(err); 193 | tip.fail('请重新运行!'); 194 | process.exit(); 195 | } 196 | 197 | table(tpls); 198 | tip.suc('新模板添加成功!'); 199 | process.exit(); 200 | }; 201 | 202 | const resolve = (result) => { 203 | const { tplName, gitUrl, branch, description, } = result; 204 | // 避免重复添加 205 | if (!tpls[tplName]) { 206 | tpls[tplName] = {}; 207 | tpls[tplName]['url'] = gitUrl.replace(/[\u0000-\u0019]/g, ''); // 过滤unicode字符 208 | tpls[tplName]['branch'] = branch; 209 | tpls[tplName]['description'] = description; 210 | } else { 211 | tip.fail('模板已经存在!'); 212 | process.exit(); 213 | }; 214 | 215 | // 把模板信息写入templates.json 216 | fs.writeFile(__dirname + '/../../templates.json', JSON.stringify(tpls), 'utf-8', writeFile); 217 | }; 218 | 219 | module.exports = () => { 220 | co(function *() { 221 | // 分步接收用户输入的参数 222 | const tplName = yield prompt('模板名字: '); 223 | const gitUrl = yield prompt('Git https 链接: '); 224 | const branch = yield prompt('Git 分支: '); 225 | const description = yield prompt('模板描述: '); 226 | return new Promise((resolve, reject) => { 227 | resolve({ 228 | tplName, 229 | gitUrl, 230 | branch, 231 | description, 232 | }); 233 | }); 234 | }).then(resolve); 235 | }; 236 | ``` 237 | 238 | ### 删除模板 (`fe delete`) 239 | 240 | >进入 /lib/cmd 并新建 [delete.js](https://github.com/fe6/fecli/blob/master/lib/cmd/delete.js) 文件。 241 | 242 | ``` 243 | 'use strict' 244 | const co = require('co'); 245 | const prompt = require('co-prompt'); 246 | const fs = require('fs'); 247 | 248 | const table = require('../table'); 249 | const tip = require('../tip'); 250 | const tpls = require('../../templates'); 251 | 252 | const writeFile = (err) => { 253 | if (err) { 254 | console.log(err); 255 | tip.fail('请重新运行!'); 256 | process.exit(); 257 | } 258 | tip.suc('新模板删除成功!'); 259 | 260 | if (JSON.stringify(tpls) !== '{}') { 261 | table(tpls); 262 | } else { 263 | tip.info('还未添加模板!'); 264 | } 265 | 266 | process.exit(); 267 | }; 268 | 269 | const resolve = (tplName) => { 270 | // 删除对应的模板 271 | if (tpls[tplName]) { 272 | delete tpls[tplName]; 273 | } else { 274 | tip.fail('模板不经存在!'); 275 | process.exit(); 276 | } 277 | 278 | // 写入template.json 279 | fs.writeFile(__dirname + '/../../templates.json', JSON.stringify(tpls), 'utf-8', writeFile); 280 | }; 281 | 282 | module.exports = () => { 283 | co(function *() { 284 | // 分步接收用户输入的参数 285 | const tplName = yield prompt('模板名字: '); 286 | return new Promise((resolve, reject) => { 287 | resolve(tplName); 288 | }); 289 | }).then(resolve); 290 | }; 291 | ``` 292 | 293 | ### 初始化项目 (`fe init`) 294 | 295 | >进入 /lib/cmd 并新建 [init.js](https://github.com/fe6/fecli/blob/master/lib/cmd/init.js) 文件。 296 | 297 | ``` 298 | 'use strict' 299 | // 操作命令行 300 | const exec = require('child_process').exec; 301 | const co = require('co'); 302 | const ora = require('ora'); 303 | const prompt = require('co-prompt'); 304 | 305 | const tip = require('../tip'); 306 | const tpls = require('../../templates'); 307 | 308 | const spinner = ora('正在生成...'); 309 | 310 | const execRm = (err, projectName) => { 311 | spinner.stop(); 312 | 313 | if (err) { 314 | console.log(err); 315 | tip.fail('请重新运行!'); 316 | process.exit(); 317 | } 318 | 319 | tip.suc('初始化完成!'); 320 | tip.info(`cd ${projectName} && npm install`); 321 | process.exit(); 322 | }; 323 | 324 | const download = (err, projectName) => { 325 | if (err) { 326 | console.log(err); 327 | tip.fail('请重新运行!'); 328 | process.exit(); 329 | } 330 | // 删除 git 文件 331 | exec('cd ' + projectName + ' && rm -rf .git', (err, out) => { 332 | execRm(err, projectName); 333 | }); 334 | } 335 | 336 | const resolve = (result) => { 337 | const { tplName, url, branch, projectName, } = result; 338 | // git命令,远程拉取项目并自定义项目名 339 | const cmdStr = `git clone ${url} ${projectName} && cd ${projectName} && git checkout ${branch}`; 340 | 341 | spinner.start(); 342 | 343 | exec(cmdStr, (err) => { 344 | download(err, projectName); 345 | }); 346 | }; 347 | 348 | module.exports = () => { 349 | co(function *() { 350 | // 处理用户输入 351 | const tplName = yield prompt('模板名字: '); 352 | const projectName = yield prompt('项目名字: '); 353 | 354 | if (!tpls[tplName]) { 355 | tip.fail('模板不存在!'); 356 | process.exit(); 357 | } 358 | 359 | return new Promise((resolve, reject) => { 360 | resolve({ 361 | tplName, 362 | projectName, 363 | ...tpls[tplName], 364 | }); 365 | }); 366 | }).then(resolve); 367 | } 368 | ``` 369 | 370 | ### 显示模板列表 (`fe list`) 371 | 372 | >进入 /lib/cmd 并新建 [list.js](https://github.com/fe6/fecli/blob/master/lib/cmd/list.js) 文件。 373 | 374 | ``` 375 | 'use strict' 376 | const table = require('../table'); 377 | 378 | module.exports = () => { 379 | table(require('../../templates')); 380 | process.exit(); 381 | }; 382 | ``` 383 | 384 | 现在我们的 **fecli** 脚手架工具已经搭建好了,一起来尝试一下吧! 385 | 386 | ## 使用测试 387 | 388 | - `fe add` 添加模板 389 | 390 | ![fe add 运行结果](https://github.com/fe6/fecli/raw/master/public/add.gif) 391 | 392 | - `fe delete` 添加模板 393 | 394 | ![fe delete 运行结果](https://github.com/fe6/fecli/raw/master/public/delete.gif) 395 | 396 | - `fe list` 添加模板 397 | 398 | ![fe list 运行结果](https://github.com/fe6/fecli/raw/master/public/list.gif) 399 | 400 | - `fe init` 添加模板 401 | 402 | ![fe init 运行结果](https://github.com/fe6/fecli/raw/master/public/init.gif) 403 | 404 | ## 项目源码 405 | 406 | 更多源码信息请移步 [fecli](https://github.com/fe6/fecli) 。 407 | -------------------------------------------------------------------------------- /utils/github_create_a_action.md: -------------------------------------------------------------------------------- 1 | # 在 GitHub 配置 Actions 2 | 3 | ## 什么是 Actions 4 | 5 | Actions 是前几年 GitHub 新推出的一个功能,就像是一种工作流。 Actions 可以进行代码审查,可以测试代码,还以干更多的事情,很多大厂的开源项目中都配置了 Actions 。 6 | 7 | ## 初始化一个项目 8 | 9 | 现在,我们有一个项目。这个项目很简单。有一个 Flat 方法的 JavaScript 文件,还有一个简单的 Sass 文件。在 Package.json 中配置了语法检测和单元测试的 Scripts 。今天我们就一起配置一个能够代码检查,单元测试,发送单元测试报告的 Actions 。 10 | 11 | ## 初始化 Actions 12 | 13 | 点击仓库导航中的 ***Actions*** 按钮,就会出现如下页面。上面是要保存的文件名字,我们把它修改成 `ci.yml` 。下面分两栏,左边就是我们要编写的 Actions 脚本的地方,右面是 Actions 市场,里面有很多不错的 Actions 。 14 | 15 | [参考代码](https://github.com/fe6/test-actions/commit/d8d1bbc57ca9d70398997f4f042067be4db6b86a) 16 | 17 | [Actions 运行结果](https://github.com/fe6/test-actions/commit/d8d1bbc57ca9d70398997f4f042067be4db6b86a/checks?check_suite_id=392173571) 18 | 19 | ![初始化 Actions](./img/github_create_a_action1.png) 20 | 21 | ## Actions 中的关键词 22 | 23 | 要写 Actions ,就要了解 Actions 中的关键词。 24 | 25 | |关键词|描述| 26 | |----|----| 27 | |name|当前 Actions 的名字| 28 | |on|触发 Actions 的操作,如 push (本地提交代码) , pull_request (合并代码)| 29 | |jobs|工作流的名字,下面会分很多的工作流| 30 | |runs-on|运行系统| 31 | |steps|操作步骤| 32 | 33 | ## 配置语法检测 34 | 35 | 我们把语法检测命名为 **lint** 。修改 **jobs** 中的代码。代码如下: 36 | 37 | ``` Bash 38 | name: CI 39 | 40 | on: [push] 41 | 42 | jobs: 43 | lint: 44 | runs-on: ubuntu-latest # 添加 ubuntu-latest 的运行系统 45 | steps: 46 | - uses: actions/checkout@v1 # 获取到最新代码 47 | - uses: actions/setup-node@v1 # 设置 Node 版本 48 | with: # 用 49 | node-version: '12.x' # Node 12.x 版本 50 | - uses: borales/actions-yarn@v2.0.0 # 采用 yarn 安装依赖 51 | with: 52 | cmd: install # 将运行 `yarn install` 命令 53 | - name: Get yarn cache # 设置当前工作流名字 54 | id: yarn-cache # 缓存的 ID 55 | run: echo "::set-output name=dir::$(yarn cache dir)" # 运行命令 56 | 57 | - uses: actions/cache@v1 58 | with: 59 | path: ${{ steps.yarn-cache.outputs.dir }} 60 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 61 | restore-keys: | 62 | ${{ runner.os }}-yarn- 63 | - uses: borales/actions-yarn@v2.0.0 64 | with: 65 | cmd: lint # 将运行 `yarn lint` 命令 66 | ``` 67 | 68 | [Actions 运行结果](https://github.com/fe6/test-actions/commit/da6bbeae046078e1550b98d118105d9ed982a8fc/checks?check_suite_id=392201612) 69 | 70 | ## 配置单元测试 71 | 72 | 在配置之前,我们现需要配置一下 **secrets.CODECOV_TOKEN** 。 **secrets.CODECOV_TOKEN** 是从 codecov 网站上获取的,需要加到项目中。具体步骤如下图所示: 73 | 74 | ![GitHub 配置 secrets.CODECOV_TOKEN](./img/github_create_a_action2.png) 75 | 76 | 我们把语法检测命名为 **test** 。修改 **jobs** 中的代码。代码如下: 77 | 78 | ``` Bash 79 | jobs: 80 | test: 81 | runs-on: ubuntu-latest # 添加 ubuntu-latest 的运行系统 82 | steps: 83 | - uses: actions/checkout@v1 # 获取到最新代码 84 | - uses: actions/setup-node@v1 # 设置 Node 版本 85 | with: # 用 86 | node-version: '12.x' # Node 12.x 版本 87 | - uses: borales/actions-yarn@v2.0.0 # 采用 yarn 安装依赖 88 | with: 89 | cmd: install # 将运行 `yarn install` 命令 90 | - name: Get yarn cache # 设置当前工作流名字 91 | id: yarn-cache # 缓存的 ID 92 | run: echo "::set-output name=dir::$(yarn cache dir)" # 运行命令 93 | 94 | - uses: actions/cache@v1 95 | with: 96 | path: ${{ steps.yarn-cache.outputs.dir }} 97 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 98 | restore-keys: | 99 | ${{ runner.os }}-yarn- 100 | - uses: borales/actions-yarn@v2.0.0 101 | with: 102 | cmd: test # 将运行 `yarn test` 命令 103 | - name: Upload coverage to Codecov # 设置当前工作流名字 104 | id: coverage-codecov 105 | uses: codecov/codecov-action@v1.0.5 106 | with: 107 | name: test-action # 上传报告的名字 108 | token: ${{ secrets.CODECOV_TOKEN }} # 秘钥 109 | file: ./coverage/clover.xml # 生成的单元测试 110 | flags: unittests # 单元测试 标识 111 | yml: ./codecov.yml # codecov 的配置 112 | fail_ci_if_error: true # 上传单元报告失败是否整个 Actions 失败 113 | ``` 114 | 115 | [Actions 运行结果](https://github.com/fe6/test-actions/commit/9782191b3a33be667d144bc3cb599d076d18cd7b/checks?check_suite_id=392239135) 116 | 117 | GitHub 美丽的 Actions 就为大家介绍到这里。今天,我们一起认识了 Actions ,并且又尝试的配置了一些 Actions。文中的一些讲解只是我目前的简单理解,欢迎大家狂喷哟。 118 | 119 | 完!感谢! 120 | -------------------------------------------------------------------------------- /utils/set_taobao.md: -------------------------------------------------------------------------------- 1 | # 设置国内镜像 2 | 3 | 由于国内网速的无敌慢,所以国内镜像就显得尤为重要。 4 | 5 | ## yarn 相关 6 | 7 | #### 设置镜像 8 | 9 | 1. 命令: 10 | 11 | ``` 12 | yarn config set registry https://registry.npm.taobao.org 13 | ``` 14 | 15 | 2. 结果: 16 | 17 | ``` 18 | yarn config v1.21.1 19 | success Set "registry" to "https://registry.npm.taobao.org". 20 | ✨ Done in 0.05s. 21 | ``` 22 | 23 | #### 获取镜像 24 | 25 | 1. 命令: 26 | 27 | ``` 28 | yarn config get registry 29 | ``` 30 | 31 | 2. 结果: 32 | 33 | ``` 34 | https://registry.yarnpkg.com 35 | ``` 36 | 37 | ## npm 相关 38 | 39 | #### 设置镜像 40 | 41 | 设置淘宝命令: `npm config set registry https://registry.npm.taobao.org` 42 | 设置 npm 命令: `npm config set registry http://registry.npmjs.org` 43 | 44 | 45 | #### 获取镜像 46 | 47 | 命令: `npm config get registry` 48 | 49 | #### 二进制包镜像(可选择添加) 50 | 51 | ``` 52 | npm set chromedriver_cdnurl http://cdn.npm.taobao.org/dist/chromedriver # chromedriver 二进制包镜像 53 | npm set operadriver_cdnurl http://cdn.npm.taobao.org/dist/operadriver # operadriver 二进制包镜像 54 | npm set phantomjs_cdnurl http://cdn.npm.taobao.org/dist/phantomjs # phantomjs 二进制包镜像 55 | npm set sass_binary_site http://cdn.npm.taobao.org/dist/node-sass # node-sass 二进制包镜像 56 | npm set electron_mirror http://cdn.npm.taobao.org/dist/electron/ # electron 二进制包镜像 57 | ``` -------------------------------------------------------------------------------- /vue/cpt_tlp_introduce.md: -------------------------------------------------------------------------------- 1 | # 从零搭建 Vue.js 组件库模板 2 | 3 | 最近市面上流行很多很多 Vue.js 的组件库,那么众多组件库是如何搭建的?搭建组件库都需要注意哪些?组件库中都有哪些功能?下面就为大家一一揭晓。如果想略过下面罗里吧嗦的介绍,可以直接移步 [component-template](https://github.com/fe6/component-template) 看源码。 4 | 5 | ## 一些功能 6 | 7 | - 官网搭建 8 | - 源码打包配置 9 | - 源码压缩配置 10 | - 样式打包 11 | - 利用 jest 单元测试的配置 12 | - 持续化继承的配置 13 | 14 | ## 搭建组件库需要注意些什么 15 | 16 | 一个好的组件库,离不开完整的 **开发系统** 。一个好的组件库,离不开完整的 **打包系统** 。一个好的组件库离不开完善的代码 **规范检查系统** 。一个好的组件,离不开完整高覆盖的 **单元测试** 。一个好的组件库离不开很好的 **自动化集成系统** 。组件库有这么多功能,那么每一次搭建组件库,就要配置一次,显然不是明智之举。我们可以将骨干部分提炼出来,变成模板。利用 [fecli](https://github.com/fe6/fecli) 脚手架一键拉取。 17 | 18 | ### 开发系统 19 | 20 | 一个良好的开发系统应该不仅仅包括组件的开发系统,还更应该包括官网的开发系统。 21 | 22 | 早年间我开发过一个组件库 [EM-FE](https://github.com/em-fe/EM-FE) 。现在再看这个库的显然不是很专业。官网和组件并不在里面,维护起来并不是很方便。新组建的建设,不仅编写组件,更要更新独立的官网的 api 及 demo 。如果要是放在一起,那么在编写组件的时候就顺便写好了 demo ,弄好的 api 。并不用移步组件库的官网仓库再维护一遍。 23 | 24 | 新的开发系统很简单,分为 `water` 和 `site` 两个目录。 `water` 目录则是组件的源码文件夹。 `site` 则是官网的源码文件夹。这样在开发组件的过程中,也可以编写 demo 了。 25 | 26 | ## 打包系统 27 | 28 | 一个良好的打包系统,不仅能打包组件库,还能打包官网。组件库不仅实现整体打包,还支持按需加载。官网打包直接继承组件库的东西即可。有关 api 的编写,我选择了 markdown 。直接读取 markdown 文件渲染到官网中。之所以选择 markdown 来编写 api 。考虑到其很流行,可以直接在 github 上编写,利于维护。 29 | 30 | ## 规范检查系统 31 | 32 | 一个良好的组件库还应该有配套的语法检测功能,好处就是代码统一。多人开发的代码,形如一人。 33 | 34 | ## 单元测试 35 | 36 | 良好的组件库必须要稳定,那么怎么做到稳定呢?开发人员在开发过程中的自测是很必要的。但是有些时候开发人员也不一定能面面俱到,这时候就应该引入单元测试了。有时候修改了一个紧急 bug ,上线之后却发现以前好好的功能缺不能用了,有了单元测试,则会避免这样的事情发生。 37 | 38 | ## 自动化集成系统 39 | 40 | 良好的组件库系统应该有一套完整的上线配置。这就需要自动化集成系统了。有了这套系统,我们可以检测依赖包的安全系数。我们可以不用每次手动的发版组件库,不用手动的发布官网,我们不用手动的单元测试。 41 | 42 | ## 组件库模板的好处 43 | 44 | - 即拉即得,即得即用 45 | - 一次配置,永远可用 46 | - 结构明确,风格统一 47 | 48 | ## 如何使用组件库模板 49 | 50 | 请移步 [从零开始搭建前端脚手架](https://github.com/iq9891/blog/issues/2) 。 51 | 52 | ## 源码 53 | 54 | 更全的配置,请移步 [component-template](https://github.com/fe6/component-template) 。 55 | -------------------------------------------------------------------------------- /vue/vue_icon_component.md: -------------------------------------------------------------------------------- 1 | # 你不知道的 Vue 的图标组件 2 | 3 | 封装一个图标组件,可以配置某一个图标,可以设置是否旋转,可以追加字体图标。特点简单实用,灵活可配。 4 | 5 | ## 一个 Vue 的文件 6 | 7 | ### 共有 class 8 | 9 | 封装一个图标组件首先从一个 vue 文件开始,其主要的结构就是一个 `i` 标签。最关键的就是这个 class 名的配置。有一个共有的 w-icon 类名负责自定义字体,这个字体就是从字体图标工具中下载的包括自定义字体图标的字体,还包括一些共有的样式。 10 | 11 | ### 定义字体图标的 class 12 | 13 | 光有一个共有的类名可不行,不同的字体图标是通过不同的 class 名配置的,我们得需要一个 prop 来设置显示的字体图标,我们把这个 prop 设定为 `type` ,类型为 `String` 。如果不传类型的时候,我们就不显示这个 icon 。 14 | 15 | ### 设定是否旋转的 class 16 | 17 | 这里有一个高级功能那就是可配置的旋转动画。我们需要一个 prop 来设置是否需要旋转动画,我们把这个 prop 设定为 `spin` ,类型为 `Boolean` 。如果为 true ,那么我们就让它转起来。 18 | 19 | ### 设定 class 的前缀参数 20 | 21 | w-icon 默认前缀为 `w` ,如果您需要扩展字体图标,或者需要自定义样式,我们为您提供了一个 prop 。专为此事而行,这个 prop 我们设定为 `prefix` ,类型为 `String` ,默认为 `w` 。 22 | 23 | ### vue 组件源码奉上 24 | 25 | ``` 26 | 34 | 35 | 51 | ``` 52 | 53 | ## 一个 SCSS 的文件 54 | 55 | 我们已经有一个像样的 vue 文件,那么我们还需要让 vue 的 icon 组件美起来的样式文件。这里我们选择的预处理器为 SCSS 。在这个样式文件中,我们需要做三件事⤵️ 56 | 57 | - 声明字体图标的字体 58 | - 设置共有样式 w-font 59 | - 设置字体图片类型的众多样式,如 w-loading 等 60 | - 设置旋转动画类型 `w-spin` 61 | - 设置旋转动画 62 | 63 | ### 声明字体图标的字体 64 | 65 | 这里我们利用 CSS3 的自定义字体的属性来完成这项使命。需要注意的是根据不同浏览器支持的字体后缀来做好适配。 66 | 67 | ### 设置共有样式 w-font 68 | 69 | 声明好字体之后,就可以用了。用法和普通设置字体是一样的,名字就用之前咱们设置好的就可以了。除了设置字体之外,我们还需要做一些特殊处理。如居中等。设置 text-rendering 为 optimizeLegibility 。它使得对于某些字体(例如,Microsoft的Calibri,Candara,Constantia和Corbel或DejaVu字体系列),文本中的连字(ff,fi,fl等)小于20px。 70 | 71 | ### 设置字体图片类型的众多样式 72 | 73 | 这个就是根据导出的字体图标,在 before 伪元素中设置字体图标的内容即可。如果有共同特点,如 w-loading1 , w-loading2 等,可以实用 sass 中的循环来优化写法。 74 | 75 | ### 设置旋转动画类型 `w-spin` 76 | 77 | 这里使用了 CSS3 中的 动画属性 (animation) 。让它执行 loadingCircle 动画,并且无线的匀速执行下去,每次动画时间为 1 秒。 78 | 79 | ### 设置旋转动画 80 | 81 | 利用 `@keyframes` 关键字声明一个动画,名为 loadingCircle 。在最开始的时候旋转基点定为图标中心点,并旋转角度为 0 度。在最结束的时候定义旋转基点定为图标中心点,并旋转角度为 1 圈( trun )。 82 | 83 | ### scss 样式源码奉上 84 | 85 | ``` 86 | $font-name: "iconfont"; 87 | $font-version: 1524475512080; 88 | $font-prefix: 'w-'; 89 | $font-path: './icon/font/'; 90 | 91 | @font-face { 92 | font-family: $font-name; 93 | src: url('#{$font-path}iconfont.eot?t=#{$font-version}'); 94 | src: 95 | url('#{$font-path}iconfont.eot?t=#{$font-version}#iefix') format('embedded-opentype'), 96 | url("#{$font-path}iconfont.woff?t=#{$font-version}") format("woff"), 97 | url('#{$font-path}iconfont.ttf?t=#{$font-version}') format('truetype'), 98 | url('#{$font-path}iconfont.svg?t=#{$font-version}#iconfont') format('svg'); 99 | } 100 | 101 | .#{$font-prefix}font { 102 | font-family: $font-name !important; 103 | -webkit-font-smoothing: antialiased; 104 | -moz-osx-font-smoothing: grayscale; 105 | display: inline-block; 106 | font-style: normal; 107 | vertical-align: baseline; 108 | text-align: center; 109 | text-transform: none; 110 | line-height: 1; 111 | text-rendering: optimizeLegibility; 112 | } 113 | 114 | .#{$font-prefix}back::before { content: "\e934"; } 115 | 116 | .#{$font-prefix}forward::before { content: "\e94d"; } 117 | 118 | $font-list: "\e66a" "\e668" "\e669" "\e667"; 119 | // 循环 $font-list 并设置类名 120 | // 其中 index 方法是获取索引 121 | @each $font-item in $font-list { 122 | .#{$font-prefix}loading#{index($font-list, $font-item)}::before { 123 | content: $font-item; 124 | } 125 | } 126 | 127 | .#{$font-prefix}spin::before { 128 | display: inline-block; 129 | animation: loadingCircle 1s infinite linear; 130 | } 131 | 132 | @keyframes loadingCircle { 133 | 0% { 134 | transform-origin: 50% 50%; 135 | transform: rotate(0deg); 136 | } 137 | 138 | to { 139 | transform-origin: 50% 50%; 140 | transform: rotate(1turn); 141 | } 142 | } 143 | ``` 144 | 145 | ## 注册 w-icon 组件 146 | 147 | 要注册一个组件,必须这个组件中拥有 `install` 方法。有了这个方法,在其回调中的 Vue 参数中调用 `component` 方法,即可。方法如下⤵️ 148 | 149 | ``` 150 | import WIcon from './Icon'; 151 | 152 | WIcon.install = (Vue) => { 153 | Vue.component(WIcon.name, WIcon); 154 | }; 155 | 156 | export default WIcon; 157 | ``` 158 | 159 | ## 写一个图标组件的单元测试 160 | 161 | 单元测试一个图标组件,我们需要测试其属性是否真正用到了,是否与预期的一样。我们需要测试其快照的 UI 是否是我们想要的 UI 。我们不传 type 属性不显示的特殊处理是否真的生效。我们自定义前缀是否真的自定义了。 162 | 163 | 我们在一开始需要实例化组件,我们可以用 `vue-test-utils` 中的 `mount` 方法。当 DOM 更新之后, `this` 绑定到当前实例上之后( $nextTick ) 做一些事情。 164 | 165 | 具体测试代码⤵️ 166 | 167 | ``` 168 | import { mount } from 'vue-test-utils'; 169 | import Icon from './Icon'; 170 | 171 | describe('Icon.vue', () => { 172 | let wrapper = null; 173 | let wrapperNo = null; 174 | let wrapperPrefix = null; 175 | let wrapperSpin = null; 176 | 177 | // 实例化 178 | beforeEach(() => { 179 | // 传入 loading1 ,然后去检测实例化之后 type 是否是 loading1 。 180 | wrapper = mount(Icon, { 181 | propsData: { 182 | type: 'loading1', 183 | }, 184 | }); 185 | // 不向其传任何参数,去检测针对 type 为空不显示的特殊处理是否生效。 186 | wrapperNo = mount(Icon); 187 | // 传前缀 test ,测试实例化之后的前缀是否完全改变 188 | wrapperPrefix = mount(Icon, { 189 | propsData: { 190 | type: 'loading1', 191 | prefix: 'test', 192 | }, 193 | }); 194 | // 实例化之后图标是否拥有旋转动画 195 | wrapperSpin = mount(Icon, { 196 | propsData: { 197 | type: 'loading1', 198 | spin: true, 199 | }, 200 | }); 201 | }); 202 | 203 | it('验证 prop 值是否正确', (done) => { 204 | wrapper.vm.$nextTick(() => { 205 | try { 206 | expect(wrapper.props().type).toBe('loading1'); 207 | done(); 208 | } catch (err) { 209 | done.fail(err); 210 | } 211 | }); 212 | }); 213 | 214 | it('验证 class 值是否正确', (done) => { 215 | wrapper.vm.$nextTick(() => { 216 | try { 217 | expect(wrapper.is('i')).toBe(true); 218 | expect(wrapper.classes().toString()).toBe('w-font,w-loading1'); 219 | done(); 220 | } catch (err) { 221 | done.fail(err); 222 | } 223 | }); 224 | }); 225 | 226 | it('验证 prop 为空不显示', (done) => { 227 | wrapperNo.vm.$nextTick(() => { 228 | try { 229 | expect(wrapperNo.is('i')).toBe(false); 230 | done(); 231 | } catch (err) { 232 | done.fail(err); 233 | } 234 | }); 235 | }); 236 | 237 | it('验证 自定义前缀 prefix', (done) => { 238 | wrapperPrefix.vm.$nextTick(() => { 239 | try { 240 | expect(wrapperPrefix.is('i')).toBe(true); 241 | expect(wrapperPrefix.classes().toString()).toBe('test-font,test-loading1'); 242 | done(); 243 | } catch (err) { 244 | done.fail(err); 245 | } 246 | }); 247 | }); 248 | 249 | it('验证 spin 字段转动', (done) => { 250 | wrapperSpin.vm.$nextTick(() => { 251 | try { 252 | expect(wrapperSpin.is('i')).toBe(true); 253 | expect(wrapperSpin.classes().toString()).toBe('w-font,w-loading1,w-spin'); 254 | done(); 255 | } catch (err) { 256 | done.fail(err); 257 | } 258 | }); 259 | }); 260 | 261 | it('检测快照是否一样。', (done) => { 262 | wrapper.vm.$nextTick(() => { 263 | try { 264 | // 检测 UI 是否改变 265 | expect(wrapper.text()).toMatchSnapshot(); 266 | done(); 267 | } catch (err) { 268 | done.fail(err); 269 | } 270 | }); 271 | }); 272 | }); 273 | ``` 274 | 275 | ## 源码 276 | 277 | 更完整的源码,请移步 [w-icon](https://github.com/fe6/water/tree/master/water/icon) 。 278 | --------------------------------------------------------------------------------