蒋小昆的博客
做一个安静的小开发

windows 安装 jekyll

|

缘起

原项目在Mac上创建,Mac上 jekyll 环境搭建比较容易,花了个把小时即可运行一个基础的jekyll server。而windows的开发预览环境的搭建,着实费了一番功夫,从官网上不建议使用windows就可以看出坑的深度,所以记录一下

写在前面

本教程具有高度的唯一性,意思就是严格保证环境和配置一样,才有可能运行成功,如果遇到问题,请检查版本是否与本文有细微差别。如严格一致仍遇到问题,请依照错误信息自行Google,依然解决不了的可以评论区留言,大家一起研究研究。

亲身实践,用最新版Ruby配置遇到的问题Google好多没答案,如果只是为了运行成功的话就按部就班吧,同时期待windows大牛的更好的配置方式

  • 操作系统 win7 64位
  • Ruby version:ruby 2.3.3p222 (2016-11-21 revision 56859) [x64-mingw32]
  • gem version: 2.5.2

资源文件

  1. 下载Ruby2.3.3:https://dl.bintray.com/oneclick/rubyinstaller/rubyinstaller-2.3.3-x64.exe

    备用:https://pan.baidu.com/s/1wTDoHy6Klq52rpx86SaMXg 密码:plex

  2. 下载DevKit: https://dl.bintray.com/oneclick/rubyinstaller/DevKit-mingw64-64-4.7.2-20130224-1432-sfx.exe

    备用:https://pan.baidu.com/s/1d4H0J2Wi9Ojs6b5_o2Yc7w 密码:ecs1

安装

安装 Ruby2.3.3

双击安装,在Installation Destination and Optional Tasks这一步,路径不要包含Program Files这类系统路径,这个路径等会也会用到,将三个选项都勾上,一直往下安装完成

安装DevKit(其实就是解压)

新建一个文件夹 devkit(我为了方便管理就放在Ruby文件夹下面了,这个不影响),选中这个文件夹路径后点击 Extract 等待完成即可

将Ruby 和 DevKit 关联起来

进入到 devkit 目录下

  1. 执行 ruby dk.rb init
    Initialization complete! Please review and modify the auto-generated
    'config.yml' file to ensure it contains the root directories to all
    of the installed Rubies you want enhanced by the DevKit.
    

    请修改自动生成的 config.yml 文件, 这里我们在config.yml添加第一步安装 Ruby 的路径,注意如果是反斜杆需要两个,这里使用正斜杆路径

---
- E:/Temp/Ruby23-x64
  1. 执行 ruby dk.rb install, 看到以下信息表示DevKit安装完成
    [INFO] Updating convenience notice gem override for 'E:/Temp/Ruby23-x64'
    [INFO] Installing 'E:/Temp/Ruby23-x64/lib/ruby/site_ruby/devkit.rb'
    

配置 ruby-china 源(因为众所周知的原因)

gem sources,查看目前 gem 的源,如果已经是 http://gems.ruby-china.com,则可以跳过本步骤

  1. gem sources -a http://gems.ruby-china.com,使用https需要额外配置证书,这里为了省事直接使用http地址了
  2. gem sources --remove https://rubygems.org

安装 jekyll

  1. gem install jekyll
  2. jekyll new test,切换到 test 目录下,执行 jekyll serve
    E:/Temp/Ruby23-x64/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require': cannot load such file -- bundler (LoadError)
    
  3. 执行 bundle install,发现卡在 Fetching source index from https://rubygems.org/,创建出的模板默认使用 https://rubygems.org
  4. 修改 Gemfile第一行,改成 source 'http://gems.ruby-china.com',再次执行 bundle install
  5. bundler update,然后执行 jekyll serve, 如遇 loadError,gem install XX 即可

    在我的电脑上,缺失的有jekyll-feed,jekyll-seo-tag,tzinfo-data,wdm 等等,依次安装即可

  6. 大功告成 ``` Configuration file: E:/KuGou/test/_config.yml Source: E:/KuGou/test Destination: E:/KuGou/test/_site Incremental build: disabled. Enable with –incremental Generating… Jekyll Feed: Generating feed for posts done in 0.605 seconds. Auto-regeneration: enabled for ‘E:/KuGou/test’ Server address: http://127.0.0.1:4000/ Server running… press ctrl-c to stop.

``` 打开浏览器输入:http://127.0.0.1:4000 即可预览效果

Windows和Mac协同开发

windows因为坑太深,所以版本什么的以Windows为基础,Mac做相应调整

Windows

  1. 修改Gemfile 的source
  2. 修改Gemfile.lock ,解决版本冲突

    Mac

  3. 使用rbenv降级 Bundler 版本:rbenv install 2.3.3
  4. 应用安装的Ruby版本:rbenv local 2.3.3
  5. 安装jekyll: gem install jekyll
  6. gem install bundler
  7. bundler update
  8. jekyll serve

总结

终于理解某些公司为什么直接给所有员工配 Mac 了 本文只提供一个例子,同时提供了一些搭建环境中遇到问题的解决方案,具体操作起来可能遇到更多奇奇怪怪的问题,可能是环境变量未设置正确、机器安装多个版本未能正确引用等等问题,查看错误信息,截取关键部分,Google上很多人也会遇到类似的问题,如果Google仍未解决,可以在下面留言一起讨论。

参考

Mac下Jekyll安装

在Windows上搭建Jekyll运行环境

Git bash 中使用 cmd 命令 乱码的探究

|

缘起

安装 Ruby 的时候需要选择 32位还是64位 的安装包,原来都是现查,就想着整理记录一下,方便以后查阅。

  1. 自己最常用的:[控制面板] > [系统和安全] > [系统],可以看到系统类型64位操作系统,基于64位处理器
  2. win10下:点击操作系统最下角的[开始]田字标识,然后点[设置]齿轮标识 > [系统] > [ 关于 ]
  3. 命令行:systeminfo在Git Bash 中执行时出现了乱码

Why

  1. Git Bash 本质上是只一个壳(Shell),Core 依然是系统自带的指令,只是部分命令进行了包装

    所以:Git Bash 中可以运行 cmd 中的一些命令: 包括 systeminfo, ipconfig

  2. 默认的 cmd 的活动代码页(active codepage)是 936 代表的GBK编码,在 CMD 中执行 chcp 即可查看
  3. git bash 默认的编码是 utf8,安装的时候的初始设置

    所以:在 git bash 中执行 cmd 中的命令,例如 systeminfo,会出现乱码问题

How

因为 cmd 是操作系统的基础工具,如果贸然改动其编码会遇到不可知问题,所以正确的做法是修改 Git Bash 展示中文时的编码

在 Git Bash 中右键选中 options,在左侧栏目中点击Text,在右侧最下方,点击 Locale 选中 zh_CN, Charactor set 选中 GBK (chinese) , 点击 Apply

悲惨的消息

Git Bash 默认 utf8 的时候已经解决了诸如 文件夹为中文 等问题;而将其改成 GBK 时,本机用户名,和中文路径都出问题了。。。

缘灭

本文实际意义不大,主要是探寻的过程。知其所以然,才能在遇到问题时不再手足无措。既然没法直接解决,那就绕过去,这也是一种解决方案。 经过测试之后也明确的知道了: Git Bash 不是一个很好的 CMD 的替代者,不要因为TA 可以执行 CMD 中的指令,就认为TA是万能的,

  • 如果你想找的是一个 CMD 的替代者:Babun, cmder或者 PowerShell 是你不错的选择
  • 如果你遇到的是 Git 使用时的乱码问题,可以跳转到扩展阅读

扩展阅读

解决 Git 在Windows上的中文乱码问题

参考

windows git-bash 设置

隐藏字符引发的血案

|

前因

使用 GitHubjekyll 搭建博客,公司的电脑是Mac,家里的电脑是windows,前面遇到了 git clone 下来文件所有文件都提示已更改的问题,对文件字符出现乱码的本质原因没有仔细探究。作为一个留了坑,心里会记很久的人,最有效的方法当然是探寻问题的本质,找到根本解决之法咯(没办法,我也是被迫的)

问题表现

  1. 因为文件名乱码导致 git clone 失败,git check failed,所有文件被标识为modified状态
  2. 文章在 windows 电脑上展示效果,不忍直视

尝试解决

  1. 首先怀疑是编码的问题,一个GBK, 一个utf-8的老问题,不能忽视,查看最终生成的HTML文件,meta 没有问题
  2. 打开浏览器控制台,瞄一眼Elements没什么问题呀(不够仔细,与问题擦肩而过),再看 font-family 和 woff2 字体文件的下载,也没发现什么问题

    既然出问题了,肯定有原因的,回来查看windows的源markdown文件 发现也乱码了, 所以暂时能排除是 jekyll 转换 HTML 出的问题。难道是Git的锅?在windows上 Git clone下来之后除了能改换行符,还能改其他字符?这太不科学了,得换个思路。

从更小的粒度分析

  1. 既然产生乱码了,看看到底是哪些个字符乱码了,如果实在没法定位哪个字符,至少知道是哪一段字符出现了问题

    结果发现:Mac 中正常的字符,在即使乱码中的文件和windows网页上,都能展示正常,这里证明是多了一些乱码字符,而不是字符转码或者解析出问题了

  2. 那多出来的字符是什么呢?我们再回到控制台,这次不再粗略地看一眼Document,而是找到错误的区域,点击 Edit as Html,可以看到原来乱码的地方出现了类似 · 这样的字符,这样的字符在 Mac 的电脑上被浏览器忽略了,而在 windows 上却被渲染出来了,从而出现了我们看到的乱码。那这多余的字符到底是如何产生的呢,输入法,VSCode,Markdown还是其他?

查资料

  • Google Mac 隐藏字符,原来是 VScode 的锅(底层是chromium的锅),在开启 Markdown 实时预览模式的时候,退格键删除输入的文字,竟然会留下一个退格符,真的是神坑

  • 开启VScode显示隐藏字符的设置:"editor.renderControlCharacters": true

    可以看到确实出现了小小的类似bs这样的特殊字符,罪魁祸首找到了!

  • 那如何避免呢?遗憾的是这是内核底层的BUG,所以没有完美的解决方案

  • 暂时规避的办法:写md不开preview预览;开启显示隐藏字符的设置,出现back space等特殊字符时手动删除。

参考

Mac 上的 VSCode 编写 Markdown 总是出现隐藏字符?

由git clone之后 all files modified 引发的思考

|

缘起

原项目在Mac上开发,在 Windows 电脑执行 git clone 时,全部文件状态变为 modified.

!!! 如果只想看文件Git status异常的问题的结果,请点击 剧情反转

初始情况

  • 源文件换行符为 LF
  • windows 上的配置按照惯例已经将 自动转换关闭,即 autocrlf 为 false

遍寻资料之后找到可能的解决方案

  1. git config –global core.autocrlf true
  2. git config –global core.autocrlf input
  3. git config core.filemode false
  4. git config core.safecrlf true/false/warn
  5. 添加 .gitattributes 配置文件

分析可行性,并扫除知识盲区

  1. git config --global core.autocrlf true

    工作原理是windows上,在执行 git clone的时候,会把文件的格式都转为 CRLF, 在提交的时候 再转回 LF. 在最开始学习 Git 的时候我们就知道,这种自动转换很容易因为编辑器创建文件或者引入文件出现CRLF和LF文件共存的问题,这里即使解决了,也不是我们想要的方案。

  • 新增一个 CRLF 文件,或者原来为LF已经被转成CRLF的文件,在进行push之后,最终的文件确实转回了 LF,至少证明这个配置不是一无是处

需要注意的是:

git config settings can be overridden by .gitattributes settings.

项目中已经存在的LF文件,变成了历史遗留问题,只有当其发生变化再 add 的时候才有可能发现,而 Git 并不会帮你转换,只是 报个错给你看fatal: LF would be replaced by CRLF in demo/t.html就没有然后了,典型的耍流氓

如果你在 windows上创建了一个 LF 文件的格式,在要 git add 的时候也会报错 fatal: LF would be replaced by CRLF in demo/t.html,蠢哭了,啥也不能干,只会报错

  • 个人理解就是:项目最开始不能有遗留问题(实践发现不可能避免,且 git clone 时总有个别奇怪的文件CNAME和README.md没有被转成CRLF);多人开发时,需保证每个人的配置都应该是 core.autocrlf true (或者项目配有后面将提到的 .gitattributes)
  1. git config --global core.autocrlf input

    按照说明:会在Windows系统上的签出文件中保留CRLF,会在Mac和Linux系统上,包括仓库中保留LF, 根本听不懂有木有? 那就实际操作一波!创建一个CRLF 文件,分别执行 git add 和 git commit,文件纹丝不动,擦泪,什么情况? 再琢磨一下上面的说明,吓出一身冷汗,windows上和Mac上两套换行符(不就是两套代码吗,太可怕了!)。但是既然有这个配置,肯定是有用的,拜读了大佬的解释之后才算理解了三分,大佬的解释:

How autocrlf works:

core.autocrlf=true:      core.autocrlf=input:     core.autocrlf=false:

        repo                     repo                     repo
      ^      V                 ^      V                 ^      V
     /        \               /        \               /        \
crlf->lf    lf->crl      crlf->lf       \             /          \
   /            \           /            \           /            \

并给出了建议

never use core.autocrlf = input unless you have a good reason to (eg if you're using unix utilities under windows or if you run into makefiles issues)

简单来说就是,不懂怎么用就别瞎用,当这个配置不存在就好了

  1. core.safecrlf XXX
    • 这货也是一个 validate,只是做校验用的,不会帮你做转换
    • core.safecrlf true: 拒绝提交包含混合换行符的文件
    • core.safecrlf false: 允许提交包含混合换行符的文件
    • core.safecrlf warn: 提交包含混合换行符的文件时给出警告
  2. core.filemode false: 参考 Git文档, The default is true.

    因为NTFS没有Linux下丰富的权限,所以Git clone 下来的文件的权限很可能会发生变化,从而导致所有文件发生改变

  • 虽然有文章表示:只有可执行文件才会受影响,但是本着死马当活马医的态度,还是将其置为false,表示忽略权限变更引起的文件变更,依然没有解决。
  1. .gitattributes 阅读gitattributes的用法之后发现主要四个配置:
    • text 控制行尾的规范性
    • eol 设置行末字符
    • diff 设置Git对特殊文件生成差异的方式。 eg. .doc 文件发生更改时,执行 git diff.

      常规使用可以看 Git的gitattributes简介,或者文末的官方文档。配置.gitattributes 依然是解决换行符相关的问题。只是多了更针对性的配置,但本质没变,经过尝试之后依然 all files modified,只能暂时搁置

个人理解的Git最佳实践

  1. 配置 core.autocrlf false, 在 .gitattributes 或 命令行全局配置
  2. 编辑器默认创建的文件 设置为 LF

    即使不小心混入了个别CRLF文件,不会影响其他的文件,且很容易被控制在一个小范围并被找到和改回来

研究过程中的小小收获

  1. 配置 VScode,默认创建出来的文件即是LF,一劳永逸

    点击顶部菜单:文件>设置>首选项,搜索框输入: files:eol, 将默认行尾字符改为 \n (LF)

  2. 使用 vim 打开文件:vim README.md README.md [unix] (01:34 14/11/2018)

    查看换行符为 unix 风格的,即为 LF

  3. 使用 vim 打开文件之后,输入 :set list 进入 listmode, 可以看到以“$”表示的换行符和以“^I”表示的制表符

剧情反转

  • 由于最开始的目的不是为了快速解决问题,而是探寻问题的本质,所以竟然趁着这个机会把Git又学习了一遍。但是再对Git了解更深后依然没有头绪。直到今天用公司的 windows 电脑再clone下来之后,在同事的提醒下发现了

  • 出现 all files modified 的原因原来是Clone succeeded, but checkout failed
  • 而出现 checkout failed 的原因是一个乱码的文件夹,这个乱码文件夹是在Markdown引入图片资源的时候,jekyll创建的,找到了出问题的原因,解决起来就方便多了,只需要把乱码的文件夹改掉就好了
  • 由于文件 checkout failed,不敢直接改了上线,怕将错误的文件上传,覆盖了原本正常的文件,最后选择了直接GitHub上修改文件的方式。至此,总算是将这个困扰许久的问题初步解决了
  • 那为什么会出现这个乱码的文件夹呢,难道是 jekyll 的锅?还有md文件也存在乱码,这两个问题很可能是同一个问题,乱码的解决过程,请看 隐藏字符引发的血案

反思

传说软件开发有三个层次:看山是山(即能看到问题,也知道问题,却也只停留在问题层面),看山不是山(能看到问题,也能看到问题的前因后果,开发语言也好技巧也罢,都是为了需求而生,你看到的是一堆纷繁的技术,他看到的是一堆实现目标的工具),看山还是山(每一门技术有他的适用面也有它的局限性,没有最好只有最适合,JS还是那个JS,只是少年不再是那个少年)

  • 也许是对技术过于敬畏,当很多触碰到底层,触碰到源码的时候,就会产生一种惧怕感,迫切希望外界能提供协助,比如Google或者Stack Overflow,业务需求是一方面,最关键还是变懒了,很多问题浅尝辄止,总是拿产品需求紧来当挡箭牌

  • 其实静下心来,仔细看看报错信息,兴许问题就已经解决大半了,(这次的问题就是忽略了日志这一关键信息);多打印点日志,很快就能定位到问题的区域;定位问题之后确认是库或者框架的问题,专门查看相关API文档兴许就已经解决了(好的API文档比Google更精确)

  • 阅读特定部分的源码实现:(最优的是直接发现合理的方案,次优的是找到替代方案,再次的是至少知道了为什么会出问题,下次能够避免,最次的是给框架做了测试,可以提Issue或者PR帮助框架的改进)

意外收获

antony-hatchkins大神关于 core.autocrlf 的详解

一堆有用的.gitattributes

如何删除已经push到远端repo仓库的文件

  • 最优的方案应该是:
git rm -r --cached .idea  #--cached不会把本地的.idea删除
git commit -m 'delete .idea dir'
git push -u origin master
  • 由于 git clone下来的所有文件都是 modified,且存在乱码( 下一篇博客会讲解如何解决乱码问题),所以不敢在 windows电脑上处理好之后再push,最终选择的是网页github 操作,即 零点小筑 的回答

参考

避免NTFS文件权限变更引起的修改

Git的gitattributes简介

gitattributes官方文档

也谈 JS 中的深浅拷贝(一)

|

缘起

在JS中,值类型和引用类型的处理是特别容易出问题的地方

知识储备

  • JS中基础数据类型有7种,其中原始数据类型:String,Number,Boolean,Null,Undefined,Symbol(ES6新增),和 Object

    声明: new String() 和 typeof Null === ‘object’ 等特殊表现不在讨论范围之内

  • 按照在内存中的位置可以分为值类型引用类型,其中值类型存放在栈(Stack)内存中,而引用类型存放在堆(Heap)内存中

JS 中能够实现 copy 功能的

  1. Array 中的 slice, concat, …运算符,Array.from, 还有 .map 等
  2. Object 中的 JSON.parse(JSON.stringify()), Object.assign 等

当数组中的项均为 原始数据类型 的时候,都能复制出一个表现一样的数组 当对象中的 value 均为 原始数据类型 的时候,都能复制出一个表现一样的对象 本文中着重讨论当数组或者对象中的项 非原始数据类型 的时候,各种 copy 的 差别

基础例子

```
var o1 = {
    name: 'test1',
    desc: '这是一个最基础的对象'
};
var o2 = {
    name: 'test2',
    desc: '这是一个最基础的对象'
};
var o3 = {
    name: 'test3',
    desc: '这是一个最基础的对象'
};
var objArr = [
    o1, o2, o3
];
```

slice/concat/…/Array.from/.map

    var t_slice = objArr.slice();
    var t_concat = objArr.concat();
    var t_spread = [...objArr];
    var t_arrayfrom = Array.from(objArr);
    var t_map = objArr.map((item) => {
        return item;
    });
    var t_assign = Object.assign({}, objArr);
    var t_stringify = JSON.parse(JSON.stringify(objArr));
    objArr[0].name = 'new name';
    objArr[0] = null;
    console.log(t_slice[0].name);// output: new name
    console.log(t_concat[0].name);// output: new name
    console.log(t_spread[0].name);// output: new name
    console.log(t_arrayfrom[0].name);// output: new name
    console.log(t_map[0].name);// output: new name
    console.log(t_assign[0].name);// output: new name
    console.log(t_stringify[0].name);// output: test1

本例中只以数组为例,因为数组也是 Object,通过数组的表现很容易推到出 单纯的 Object 的表现

当数组中的项为对象的时候,objArr = [0x1111, 0x1112, 0x1113], 而 slice/concat 等相当于 将 地址 进行了copy

值得注意的是执行了 objArr[0] = null; 对最终的结果没有影响,因为置 null只是把指针打断了,对内存中的对象实体没有影响

总结

  • slice/concat/…/Array.from/.map/Object.assign等复制方法,本质上都是浅拷贝,即只拷贝了引用地址(而不是实际的对象)
  • JSON.parse(JSON.stringify()),能实现 JSON格式 数据的深拷贝,但也有其弊端:
    • 无法处理循环引用
    • function 或者 RegExp 等类型无法进行深拷贝(而且会直接丢失相应的值)
    • 在处理 null/undefined/NaN 等特殊类型时会有异常表现
        var old = {
        k1: null,
        k2: undefined,
        k3: {
            arr: []
        },
        k4: {
            arr: [null, undefined, NaN]
        },
        k5: NaN
        };
      

      经过处理之后: Object.keys结果发生了改变,原来的 undefined/NaN 等被转成了 null ```javascript var new = JSON.parse(JSON.stringify(old)); /* { k1: null, k3: { arr: [] } k4: { arr: [null, null, null] } } */

    ```

    • 对象的 constructor 也会丢失,无论原来的构造函数(类)是什么,均变成 Object,执行 instanceof 原构造函数 会返回 false
  1. 如果是用 Angular,可以使用 angular.copy
  2. 如果是用 jQuery,可以使用 $.extend(true, {}, source);
  3. 如果是用 lodash,可以使用 _.cloneDeep()

分享一个目前在用相对健壮的深copy,能应对绝大部分情况

const clone = (obj) => {
    // Handle the 3 simple types, and null or undefined
    if (obj === null || typeof obj !== 'object') return obj;
    // Handle Date
    if (obj instanceof Date) {
        const copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }
    // Handle Array
    if (obj instanceof Array) {
        const copy = [];
        const len = obj.length;
        for (let i = 0; i < len; ++i) {
            copy[i] = clone(obj[i]);
        }
        return copy;
    }
    // Handle Object
    const copy = {};
    for (const attr in obj) {
        if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]);
    }
    return copy;
};

下一节将深入介绍:

  1. 如何处理循环引用, CircularJSON
  2. 如何处理 RegExp/Function/Null/Undefined/NaN 等类型的拷贝
  3. 如何实现一个类(含有构造方法和原型)的拷贝
  4. 经过 defineProperty 重新定义了对象, 能否进行深拷贝
  5. 如果由浅入深,从零开始写一个深拷贝的方法