Jekyll2023-10-05T07:15:26+00:00/feed.xmlAaronFlowerJust for fun!Browserslist 为你中意的浏览器写代码2019-01-09T00:00:00+00:002019-01-09T00:00:00+00:00/essay/Browserslist<p><img src="https://pbs.twimg.com/profile_banners/874631111854501888/1497572903/1500x500" alt="img" /></p>
<blockquote class="af-sectionDivider">
<p>tl;dr</p>
<p>Browserslist 是一个前端项目配置工具,功能是在前端工具之间共享目标环境的浏览器信息。</p>
<p><a href="https://github.com/ai/browserslist">Browserslist</a> is a config to share target browsers between different front-end tools.</p>
</blockquote>
<p class="af-sectionDivider">在现代前端项目中,我们会使用 Babel 来转换 ES6 语法、使用 AutoPrefixer, PostCSS 来转换 CSSNext 语法、使用 ESLint 来保证代码质量和规范。所以一般在前端项目中会使用下面常用的工具:</p>
<ul>
<li><strong><a href="https://github.com/postcss/autoprefixer">Autoprefixer</a></strong></li>
<li><strong><a href="https://babeljs.io/">Babel</a></strong></li>
<li><strong><a href="https://github.com/csstools/postcss-preset-env">postcss-preset-env</a></strong></li>
<li><strong><a href="https://github.com/csstools/postcss-normalize">postcss-normalize</a></strong></li>
<li><strong>ESLint 的 <a href="https://github.com/eslint/eslint">eslint-plugin-compat</a></strong></li>
<li><strong>Stylelint 的 <a href="https://github.com/ismay/stylelint-no-unsupported-browser-features">stylelint-no-unsupported-browser-features</a></strong></li>
</ul>
<p>这些工具会根据配置的目标浏览器环境来决定使用那些策略来处理你的源代码。</p>
<p>例如,如果你仅支持 Edge 15, 那么 Babel 不会对 <code class="language-plaintext highlighter-rouge">const str = `hello world`</code>进行转换,但是如果要支持 IE 10 那么 Babel 就会把其转换成 <code class="language-plaintext highlighter-rouge">var str = "hello world";</code>。</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">"babel"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"presets"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
</span><span class="p">[</span><span class="w">
</span><span class="s2">"env"</span><span class="p">,</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nl">"targets"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"browsers"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"Edge 15"</span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">]</span><span class="w">
</span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>Babel 在转换时会根据目标浏览器信息加入特殊的 Plugins 或 Polyfills,同样 <strong><a href="https://github.com/postcss/autoprefixer">Autoprefixer</a></strong> ,<strong><a href="https://github.com/csstools/postcss-preset-env">postcss-preset-env</a></strong> ,<strong><a href="https://github.com/csstools/postcss-normalize">postcss-normalize</a></strong> ,<strong>ESLint 的 <a href="https://github.com/eslint/eslint">eslint-plugin-compat</a></strong> ,<strong>Stylelint 的 <a href="https://github.com/ismay/stylelint-no-unsupported-browser-features">stylelint-no-unsupported-browser-features </a></strong> 工具也提供同样的配置。</p>
<p>但所有这样工具都有自己的配置信息,这样很可能会导致工具之间读取的配置信息是不一致的。</p>
<h3 class="af-sectionDivider" id="browserslist-是一个好注意">Browserslist 是一个好注意</h3>
<p><a href="https://github.com/ai/browserslist">Browserslist</a> 的出现就是为了解决工具之间各自为战的情况,可以提供统一的配置。即共享项目中的目标浏览器环境信息。</p>
<p><img src="/assets/imgs/2019-01-09-browserslist-query.png" alt="image-20190110114658577" /></p>
<h4 id="使用方法">使用方法</h4>
<p>Browserslists 通过向 <a href="https://caniuse.com/">caniuse</a> 传递查询字符串(queries)来获取目标环境信息,这些 queries 可写在下面两个文件中,即 Browserslists 提供两种配置方法。(其实还有其它配置方法,可参考文档)。</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">.browserslistrc</code> 文件</li>
</ul>
<p>在项目中添加一个<code class="language-plaintext highlighter-rouge">.browserlistrc</code>文件来配置, 每一行都是一个 query, <code class="language-plaintext highlighter-rouge">#</code> 用来注释。</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Browsers that we support</span>
last 1 version
<span class="o">></span> 1%
not dead
</code></pre></div></div>
<ul>
<li>通过 <code class="language-plaintext highlighter-rouge">package.json</code> 文件</li>
</ul>
<p>在项目中的 <code class="language-plaintext highlighter-rouge">package.json</code>文件中添加一个 <code class="language-plaintext highlighter-rouge">broserslist</code> 项也可以完成配置,每一个元素都是一个 query。</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
</span><span class="nl">"private"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
</span><span class="nl">"browserslist"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
</span><span class="s2">"last 1 version"</span><span class="p">,</span><span class="w">
</span><span class="s2">"> 1%"</span><span class="p">,</span><span class="w">
</span><span class="s2">"not dead"</span><span class="w">
</span><span class="p">],</span><span class="w">
</span><span class="nl">"scripts"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>上面两种配置方法效果是一样的,那么通过上面的配置后,我们的项目的目标浏览器环境是什么那?通过 <code class="language-plaintext highlighter-rouge">npx browserslist</code>可以查看:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>npx browserslist
and_chr 70
and_ff 63
and_qq 1.2
and_uc 11.8
android 67
baidu 7.12
chrome 71
chrome 70
chrome 69
edge 18
edge 17
firefox 64
firefox 63
ie 11
ie_mob 11
ios_saf 12.0-12.1
ios_saf 11.3-11.4
op_mini all
op_mob 46
opera 57
safari 12
</code></pre></div></div>
<h4 class="af-sectionDivider" id="queries">Queries</h4>
<ol>
<li>query 字符串不区分大小写。</li>
<li>如果没有 query 字符串,则会使用默认的 defaults 字符串,其代表的 queries 是:<code class="language-plaintext highlighter-rouge">> 0.5%, last 2 versions, Firefox ESR, not dead</code>.</li>
</ol>
<p>上面例子中的 queries:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="s2">"last 1 version"</span>
<span class="s2">"> 1%"</span>
<span class="s2">"not dead"</span>
</code></pre></div></div>
<p>是什么意思那?解释如下:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">last 1 version</code> : 即支持各类浏览器最近的一个版本,当然这里的 1 是可变的数字。</li>
<li><code class="language-plaintext highlighter-rouge">1%</code> : 支持市场份额大于 1% 的浏览器。</li>
<li><code class="language-plaintext highlighter-rouge">not dead</code>: 这个 query 中 <code class="language-plaintext highlighter-rouge">not</code> 是<strong>逻辑非</strong>操作符,即对 <code class="language-plaintext highlighter-rouge">dead</code>取反,而浏览器被认为是 <code class="language-plaintext highlighter-rouge">dead</code> 条件是:最新的两个版本中发现其市场份额已经低于 0.5% 并且 24 个月内没有任务官方支持和更新了。</li>
</ul>
<p><em>not</em> 也 queries 中惟一一个操作符,可以用在任何 query 前。</p>
<p>Browserslist 支持更完善的 queries 请参考<a href="https://github.com/browserslist/browserslist#full-list">文档</a>。</p>
<h4 id="最佳实践">最佳实践</h4>
<ul>
<li>直接选择支持的浏览器(如:<code class="language-plaintext highlighter-rouge">last 2 Chrome versions</code>),如果你的项目仅支持某个浏览器。之前见过公司的内部系统仅支持 Chrome 浏览器,就可以使用这个 query 啦。</li>
<li>如果要 Override 默认配置,可以通过组合 <code class="language-plaintext highlighter-rouge">last 1 version</code>, <code class="language-plaintext highlighter-rouge">not dead</code> , <code class="language-plaintext highlighter-rouge">> 0.2%</code> (or <code class="language-plaintext highlighter-rouge">> 1% in US</code>, <code class="language-plaintext highlighter-rouge">> 1% in my stats</code>). 来实现。</li>
<li>不要删除你不了解的浏览器。Opera Mini 在非洲的用户超过 10 亿比 Edge 的全球市场份额还大。QQ 浏览器在中国的份额超过 Firefox 和 Safari 的总合。</li>
</ul>
<h4 id="结论">结论</h4>
<p>当你使用 Browserslist 配置好支持的浏览器后,那么 Babel, PostCSS, ESLint 等工具就可以为你提供一致的服务了。</p>
<ul>
<li>ESLint 配置效果</li>
</ul>
<p><img src="https://raw.githubusercontent.com/amilajack/eslint-plugin-compat/master/img/eslint-plugin-compat-demo.gif" alt="ESLint 配置效果" /></p>
<ul>
<li>StyleLint 配置效果</li>
</ul>
<p><img src="https://css-tricks.com/wp-content/uploads/2017/05/stylelist-browserlist.png" alt="img" /></p>
<h4 id="参考">参考</h4>
<ol>
<li>
<p><a href="https://css-tricks.com/browserlist-good-idea/">Browserslist is a good idea</a></p>
</li>
<li>
<p><a href="https://github.com/browserslist/browserslist-example">Browserslist Example</a></p>
</li>
</ol>stdin、stdout、stderr2018-12-25T00:00:00+00:002018-12-25T00:00:00+00:00/essay/stdin-stdout-stderr<h2 id="stderr-stdout-stdin">stderr, stdout, stdin</h2>
<p>在 Unix-Like 系统中一个进程总可以访问三个文件描述符是:0,1,2;其分别代表 stdin, stdout, stderr。在我们执行一些命令的时候正确的 stdout, stderr 的信息很方便我们查看相应的信息。</p>
<h3 id="standard-errorstderr">Standard error(stderr)</h3>
<p>标准错误输出是另一种 output stream 用来输出程序的错误信息或调试信息(error messages or diagnostics)。它和标准输出流相互独立可以分别进行重定向。注意,程序的输出可以在管道中重定向,但是错误或调试信息仍然被输出到终端中。如果想抑制错误信息,需要我们对 stderr 进程重定向。</p>
<h3 id="all-about-redirection">All About Redirection</h3>
<p>测试准备,在这个测试目录 <code class="language-plaintext highlighter-rouge">foo</code> 中有一个 <code class="language-plaintext highlighter-rouge">bar.txt</code> 文件和一个空目录 <code class="language-plaintext highlighter-rouge">dir</code>。</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>foo ➜ tree
<span class="nb">.</span>
├── bar.txt
└── <span class="nb">dir
</span>1 directory, 1 file
foo ➜ <span class="nb">cat </span>bar.txt
stderr
stdout
stdin
</code></pre></div></div>
<ol>
<li><code class="language-plaintext highlighter-rouge">stdout</code> to a file</li>
</ol>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>➜ <span class="nb">ls</span> <span class="nt">-l</span> <span class="o">></span> ls-l.txt
➜ ll
total 16
<span class="nt">-rw-r--r--</span> 1 easonzhan staff 20B Dec 25 14:54 bar.txt
drwxr-xr-x 2 easonzhan staff 64B Dec 25 14:55 <span class="nb">dir</span>
<span class="nt">-rw-r--r--</span> 1 easonzhan staff 173B Dec 25 15:21 ls-l.txt
</code></pre></div></div>
<ol>
<li><code class="language-plaintext highlighter-rouge">stderr</code> to a file</li>
</ol>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>➜ <span class="nb">grep </span>std <span class="k">*</span>
bar.txt:stderr
bar.txt:stdout
bar.txt:stdin
<span class="nb">grep</span>: <span class="nb">dir</span>: Is a directory
</code></pre></div></div>
<p>这个命令的输出有两部分,一部分是 grep 正常的输出结果,而 <code class="language-plaintext highlighter-rouge">grep: dir: Is a directory</code> 是错误输出。可以对这两部分信息进行以下处理:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># a. 丢掉错误输出</span>
<span class="nb">grep </span>std <span class="k">*</span> 2> /dev/null
<span class="c"># b. 丢掉正确输出</span>
<span class="nb">grep </span>std <span class="k">*</span> 1> /dev/null
<span class="c"># c. mute 所有的输出</span>
<span class="nb">grep </span>std <span class="k">*</span> &> /dev/null
<span class="c"># d. 正确和错误输出分别输出到两个文件中。</span>
<span class="nb">grep </span>std <span class="k">*</span> 1> grep.out.txt 2> grep.err.txt
<span class="c"># e. 将正确和错误输出到同一个文件中</span>
<span class="nb">grep </span>std <span class="k">*</span> &> grep.all.txt
</code></pre></div></div>
<ol>
<li><code class="language-plaintext highlighter-rouge">stderr</code> 与 <code class="language-plaintext highlighter-rouge">stdout</code>相互转换</li>
</ol>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># stderr 转 stdout</span>
<span class="nb">grep </span>std <span class="k">*</span> 2>&1
<span class="c"># stdout 转 stderr</span>
<span class="nb">grep </span>std <span class="k">*</span> 1>&2
</code></pre></div></div>
<h3 id="nginx--v"><code class="language-plaintext highlighter-rouge">nginx -v</code></h3>
<p>注意因为 stderr 的信息是无法 <code class="language-plaintext highlighter-rouge">grep</code> 的,所以我们可以把 stderr 的信息转换到 stdout 上再 <code class="language-plaintext highlighter-rouge">grep</code>.</p>
<p><img src="/assets/imgs/2018-12-25-grep-stderr.png" alt="image-20181225153449442" /></p>
<p>这个很重要,因为有些命令的输出是到调试信息中的。如 <code class="language-plaintext highlighter-rouge">nginx -V</code>。</p>
<p><img src="/assets/imgs/2018-12-25-nginx-v.png" alt="image-20181225154312654" /></p>
<p>然后可以用下面的命令来查看, Nginx 的 module 信息。<code class="language-plaintext highlighter-rouge">nginx -V 2>&1|sed 's/--/\'$'\n--/g'</code>。</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 将 nginx 的 stderr 调试信息重向到 stdout 中,然后用 sed 进行替换。</span>
nginx <span class="nt">-V</span> 2>&1|sed <span class="s1">'s/--/\'$'</span><span class="se">\n</span><span class="s1">--/g'</span>
nginx version: nginx/1.13.10
built by clang 9.0.0 <span class="o">(</span>clang-900.0.39.2<span class="o">)</span>
built with OpenSSL 1.0.2n 7 Dec 2017 <span class="o">(</span>running with OpenSSL 1.0.2q 20 Nov 2018<span class="o">)</span>
TLS SNI support enabled
configure arguments:
<span class="nt">--prefix</span><span class="o">=</span>/usr/local/Cellar/nginx/1.13.10
<span class="nt">--sbin-path</span><span class="o">=</span>/usr/local/Cellar/nginx/1.13.10/bin/nginx
<span class="nt">--with-cc-opt</span><span class="o">=</span><span class="s1">'-I/usr/local/opt/pcre/include -I/usr/local/opt/openssl/include'</span>
<span class="nt">--with-ld-opt</span><span class="o">=</span><span class="s1">'-L/usr/local/opt/pcre/lib -L/usr/local/opt/openssl/lib'</span>
<span class="nt">--conf-path</span><span class="o">=</span>/usr/local/etc/nginx/nginx.conf
<span class="nt">--pid-path</span><span class="o">=</span>/usr/local/var/run/nginx.pid
<span class="nt">--lock-path</span><span class="o">=</span>/usr/local/var/run/nginx.lock
<span class="nt">--http-client-body-temp-path</span><span class="o">=</span>/usr/local/var/run/nginx/client_body_temp
<span class="nt">--http-proxy-temp-path</span><span class="o">=</span>/usr/local/var/run/nginx/proxy_temp
<span class="nt">--http-fastcgi-temp-path</span><span class="o">=</span>/usr/local/var/run/nginx/fastcgi_temp
<span class="nt">--http-uwsgi-temp-path</span><span class="o">=</span>/usr/local/var/run/nginx/uwsgi_temp
<span class="nt">--http-scgi-temp-path</span><span class="o">=</span>/usr/local/var/run/nginx/scgi_temp
<span class="nt">--http-log-path</span><span class="o">=</span>/usr/local/var/log/nginx/access.log
<span class="nt">--error-log-path</span><span class="o">=</span>/usr/local/var/log/nginx/error.log
<span class="nt">--with-debug</span>
<span class="nt">--with-http_addition_module</span>
<span class="nt">--with-http_auth_request_module</span>
<span class="nt">--with-http_dav_module</span>
<span class="nt">--with-http_degradation_module</span>
<span class="nt">--with-http_flv_module</span>
<span class="nt">--with-http_gunzip_module</span>
<span class="nt">--with-http_gzip_static_module</span>
<span class="nt">--with-http_mp4_module</span>
<span class="nt">--with-http_random_index_module</span>
<span class="nt">--with-http_realip_module</span>
<span class="nt">--with-http_secure_link_module</span>
<span class="nt">--with-http_slice_module</span>
<span class="nt">--with-http_ssl_module</span>
<span class="nt">--with-http_stub_status_module</span>
<span class="nt">--with-http_sub_module</span>
<span class="nt">--with-http_v2_module</span>
<span class="nt">--with-ipv6</span>
<span class="nt">--with-mail</span>
<span class="nt">--with-mail_ssl_module</span>
<span class="nt">--with-pcre</span>
<span class="nt">--with-pcre-jit</span>
<span class="nt">--with-stream</span>
<span class="nt">--with-stream_realip_module</span>
<span class="nt">--with-stream_ssl_module</span>
<span class="nt">--with-stream_ssl_preread_module</span>
</code></pre></div></div>
<p>用 <code class="language-plaintext highlighter-rouge">gsed</code> 更加方便些:<code class="language-plaintext highlighter-rouge">nginx -V 2>&1 | gsed 's/--/\n--/g'</code>.</p>
<p>mac 安装 gun-sed: <code class="language-plaintext highlighter-rouge">brew install gun-sed</code>。</p>stderr, stdout, stdinlsof 命令2018-12-15T09:12:35+00:002018-12-15T09:12:35+00:00/abc/lsof<p><code class="language-plaintext highlighter-rouge">lsof</code>, list open files.</p>
<p><img src="/assets/imgs/2018-12-15-lsof.jpg" /></p>
<p>用于查看打开的文件。一般使用该命令可以查看端口的使用进程,还可以用来查看 nginx, mysqld 相关进行正在使用的文件等。</p>
<h4 class="af-sectionDivider" id="1-查看某文件正在被那些进程使用">1. 查看某文件正在被那些进程使用?</h4>
<p>直接在命令后面加上相应的文件名就可以了。 <code class="language-plaintext highlighter-rouge">lsof /some/file</code>。</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>lsof /var/log/nginx/access.log
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nginx 54320 root 2w REG 1,4 35121 8633537136 error.log
nginx 54320 root 4w REG 1,4 35121 8633537136 error.log
nginx 54322 nobody 2w REG 1,4 35121 8633537136 error.log
nginx 54322 nobody 4w REG 1,4 35121 8633537136 error.log
<span class="nb">tail </span>64756 aaronflower 3r REG 1,4 35121 8633537136 error.log
</code></pre></div></div>
<p>可以看到是 <code class="language-plaintext highlighter-rouge">nginx, tail</code> 进程在打开该文件,还可看到相应的 <code class="language-plaintext highlighter-rouge">PID</code> : 54322, 54320, 64756。</p>
<p>命令输出的每一个域说明:</p>
<ul>
<li>COMMAND: 进程命令</li>
<li>PID : 进程号</li>
<li>USER: 启动进程的用户。</li>
<li>FD: File Description, 文件描述。
<ul>
<li>w:写</li>
<li>r:读</li>
<li>u: 读写</li>
</ul>
</li>
<li>TYPE: 与该文件相关联的节点类型。常见的有:
<ul>
<li>CHR: 字符特殊文件。</li>
<li>REG : 一个常规文件。</li>
<li>IPv4: 一个 IPv4 socket.</li>
<li>IPv6: 一个 IPv6 socket.</li>
</ul>
</li>
<li>NODE: 是一个编码,该编码可以是:
<ul>
<li>文件在本地文件系统中的节点编码 (node number)</li>
<li>文件在NFS 服务器中的节点编码(inode number)</li>
<li>协议类型,如: TCP, UDP</li>
<li>流,如:STR</li>
</ul>
</li>
</ul>
<h4 class="af-sectionDivider" id="2-查看某进程打开了那些文件">2. 查看某进程打开了那些文件?</h4>
<p>我们先找到对应的进程号。如找到 nginx 对应的进程号。然后查看其主进程打开了那些文件。</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ps aux|grep nginx
nobody 54322 0.0 0.0 4300136 1736 ?? S 4:12PM 0:00.01 nginx: worker process
root 54320 0.0 0.0 4291452 556 ?? Ss 4:12PM 0:00.00 nginx: master process nginx
</code></pre></div></div>
<p>直接使用 <code class="language-plaintext highlighter-rouge">-p</code> 选项加上对应的 PID 就可以了。 <code class="language-plaintext highlighter-rouge">lsof -p pid</code></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>lsof <span class="nt">-p</span> 54320
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nginx 54320 root txt REG 1,4 1100896 8633491812 /usr/lib/dyld
nginx 54320 root 0u CHR 3,2 0t0 308 /dev/null
nginx 54320 root 1u CHR 3,2 0t0 308 /dev/null
nginx 54320 root 2w REG 1,4 41615 8633537136 /private/tmp/logs/error.log
nginx 54320 root 3u unix 0xd147dfbe983cbcbf 0t0 ->0xd147dfbe983cdf1f
nginx 54320 root 4w REG 1,4 41615 8633537136 /private/tmp/logs/error.log
nginx 54320 root 5w REG 1,4 67959 118150373 /usr/local/var/log/nginx/access.log
nginx 54320 root 6u systm 0xd147dfbea67f2f9f 0t0 <span class="o">[</span>ctl com.apple.netsrc <span class="nb">id </span>8 unit 18]
nginx 54320 root 7u unix 0xd147dfbe983ccb97 0t0 ->0xd147dfbe983cbbf7
nginx 54320 root 8u IPv4 0xd147dfbea5d5cfff 0t0 TCP <span class="k">*</span>:8098 <span class="o">(</span>LISTEN<span class="o">)</span>
nginx 54320 root 9u IPv4 0xd147dfbeb5f8967f 0t0 TCP <span class="k">*</span>:xmltec-xmlmail <span class="o">(</span>LISTEN<span class="o">)</span>
nginx 54320 root 10u IPv4 0xd147dfbea2d6797f 0t0 TCP <span class="k">*</span>:radan-http <span class="o">(</span>LISTEN<span class="o">)</span>
nginx 54320 root 11u unix 0xd147dfbe983cdf1f 0t0 ->0xd147dfbe983cbcbf
</code></pre></div></div>
<h4 class="af-sectionDivider" id="3-该进程的-binlog-文件在那里">3. 该进程的 bin、log 文件在那里?</h4>
<p>与相应的 <code class="language-plaintext highlighter-rouge">grep</code> 命令相接合使用,可以查看对应的 bin、log 文件。</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>lsof <span class="nt">-p</span> 54320|grep bin
nginx 54320 root txt REG 1,4 1152404 8602545023 /usr/local/Cellar/nginx/1.13.10/bin/nginx
</code></pre></div></div>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>lsof <span class="nt">-p</span> 54320|grep log
nginx 54320 root 2w REG 1,4 41615 8633537136 /private/tmp/logs/error.log
nginx 54320 root 4w REG 1,4 41615 8633537136 /private/tmp/logs/error.log
nginx 54320 root 5w REG 1,4 67959 118150373 /usr/local/var/log/nginx/access.log
</code></pre></div></div>
<h4 class="af-sectionDivider" id="4-查看某用户打开了那些文件">4. 查看某用户打开了那些文件?</h4>
<p>查看用户打开了那些文件。<code class="language-plaintext highlighter-rouge">lsof -u username</code></p>
<div class="language-bash af-sectionDivider highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>lsof <span class="nt">-u</span> XXX
<span class="nb">sudo </span>lsof <span class="nt">-u</span> XXX <span class="nt">-i</span>
</code></pre></div></div>
<h4 id="5-查看端口被那个进程使用">5. 查看端口被那个进程使用?</h4>
<p>使用 <code class="language-plaintext highlighter-rouge">-i</code> 参数,可以查看 IPv4/IPv6 对应端口的使用情况。也可以指定协议。</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>lsof <span class="nt">-i</span> :80
<span class="nb">sudo </span>lsof <span class="nt">-i</span> tcp
</code></pre></div></div>
<h4 id="refs">Refs:</h4>
<ol>
<li><a href="https://www.youtube.com/watch?v=rLgRkjM7amo">8 Basic lsof Commands Every Sysadmin Needs to Know</a></li>
</ol>lsof, list open files.Mac 终端代理设置2018-12-15T09:12:35+00:002018-12-15T09:12:35+00:00/abc/mac-termical-proxy<p>Mac 系统终端和 iTerm2 在请求网络时并不使用代理。那如果我们想使用代理怎么办?</p>
<p>其实很简单,直接在终端中设置 <code class="language-plaintext highlighter-rouge">http_proxy, https_proxy</code> 两个环境变量即 OK 了。<code class="language-plaintext highlighter-rouge">http_proxy, https_proxy</code>的内容是代理服务器地址。如:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">export </span><span class="nv">http_proxy</span><span class="o">=</span>http://xx.xx.xx:8099
<span class="nb">export </span><span class="nv">http_proxy</span><span class="o">=</span>http://xx.xx.xx:8099
</code></pre></div></div>
<p class="af-sectionDivider">待って,问题来了, <code class="language-plaintext highlighter-rouge">http_proxy, https_proxy</code> 的值该填什么那?</p>
<p>假如,你已经搭建好了一个 <a href="https://github.com/shadowsocks/shadowsocks/tree/master">shadowsocks</a> 服务器,可以通过浏览器来科学上网了。那么我们知道,shadowsocks 是使用 <code class="language-plaintext highlighter-rouge">pac</code>文件来自动代理的,它的 HTTP 协议的下一层使用的是 <code class="language-plaintext highlighter-rouge">SOCKS5</code>代理服务器来转发的。该 SOCKS5 服务器一般的地址是 <code class="language-plaintext highlighter-rouge">localhost:1080</code> 或 <code class="language-plaintext highlighter-rouge">127.0.0.1:1080</code>。</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 执行 lsof 命令来查看 1080 的使用情况。</span>
<span class="nb">sudo </span>lsof <span class="nt">-i</span> :1080
</code></pre></div></div>
<p>既然,shadowsocks 使用 <code class="language-plaintext highlighter-rouge">localhost:1080</code> 来做代理,那么我们的终端的 http, https 也可以使用这个服务器作代理呀。即:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">export </span><span class="nv">http_proxy</span><span class="o">=</span>http://localhost:1080
<span class="nb">export </span><span class="nv">https_proxy</span><span class="o">=</span>http://localhost:1080
</code></pre></div></div>
<p><strong>不过,这是不行的。</strong> 因为 <code class="language-plaintext highlighter-rouge">localhost:1080</code> 是 SOCKS5 服务器,并不是 HTTP 服务器。那我们该怎么解决那?</p>
<h3 class="af-sectionDivider" id="解决方法">解决方法</h3>
<p>–> 请直接用鼠标滑到<strong>最后</strong>看解决方法。</p>
<hr />
<p>我们可以使用 <a href="http://www.privoxy.org/">Privoxy</a>来解决这个问题。因为 Privoxy 除了可以直接代理 HTTP 层外,还可以将 HTTP 转发到 SOCKS5 服务器上。原理及具体操作如下:</p>
<p><img src="/assets/imgs/2018-12-15-privoxy.jpg" /></p>
<p class="af-figCaptionBottom">Provixy</p>
<h4 id="1-安装-privoxy">1. 安装 Privoxy</h4>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>brew <span class="nb">install </span>privoxy
The formula built, but is not symlinked into /usr/local
Could not symlink sbin/privoxy
/usr/local/sbin is not writable.
You can try again using:
brew <span class="nb">link </span>privoxy
<span class="o">==></span> Caveats
To have launchd start privoxy now and restart at login:
brew services start privoxy
Or, <span class="k">if </span>you don<span class="s1">'t want/need a background service you can just run:
privoxy /usr/local/etc/privoxy/config
</span></code></pre></div></div>
<h4 id="2-编辑-usrlocaletcprivoxyconfig-文件">2. 编辑 <code class="language-plaintext highlighter-rouge">/usr/local/etc/privoxy/config</code> 文件</h4>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 在文件最后加上这一句</span>
<span class="c"># 告诉 Privoxy 我们要把 http, https 都转发到 socks5 代理服务器上去。</span>
forward-socks5 / localhost:1080 <span class="nb">.</span>
</code></pre></div></div>
<h4 id="3-设置-http_proxy-https_proxy变量">3. 设置 <code class="language-plaintext highlighter-rouge">http_proxy, https_proxy</code>变量</h4>
<p>因为, Privoxy 服务启动之后,会在本地启动一个 <code class="language-plaintext highlighter-rouge">127.0.0.1:8118</code> 的代理服务器。所以们把终端下所有的 http 请求都转发到这个代理服务器上,然后这个代理服务器会把请求都转发到 SOCKS5 服务器上。</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">export </span><span class="nv">http_proxy</span><span class="o">=</span><span class="s1">'http://localhost:8118'</span>
<span class="nb">export </span><span class="nv">https_proxy</span><span class="o">=</span><span class="s1">'http://localhost:8118'</span>
</code></pre></div></div>
<h4 id="4-启动-provixy-服务器">4. 启动 Provixy 服务器</h4>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>brew services list
<span class="nb">sudo </span>brew services start privoxy
</code></pre></div></div>
<h4 id="5-测试">5. 测试</h4>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~ ➜ curl ip.gs
Current IP / 当前 IP: xx.xx.xx.xx
lease visit https://ip.sb/ <span class="k">for </span>more information. / IP.GS 已更改为 IP.SB ,请访问 https://ip.sb/ 获取更详细 IP 信息!
Please <span class="nb">join </span>Telegram group https://t.me/sbfans <span class="k">if </span>you have any issues. / 如有问题,请加入 Telegram 群 https://t.me/sbfans
/<span class="se">\_</span>/<span class="se">\</span>
<span class="o">=(</span> °w° <span class="o">)=</span>
<span class="o">)</span> <span class="o">(</span> //
<span class="o">(</span>__ __<span class="o">)</span>//
</code></pre></div></div>
<h4 id="6-配置成命令">6. 配置成命令</h4>
<p>为了方便我们可以配置方法写在 <code class="language-plaintext highlighter-rouge">.bashrc</code> 文件中,在终端中通过命令就可以调用啦。</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># privoxy proxy</span>
proxy <span class="o">()</span> <span class="o">{</span>
<span class="nb">echo</span> <span class="s2">"start use privoxy proxy"</span>
brew services start privoxy
<span class="nb">export </span><span class="nv">no_proxy</span><span class="o">=</span>localhost,127.0.0.0,127.0.0.1,127.0.1.1,local.home
<span class="nb">export </span><span class="nv">http_proxy</span><span class="o">=</span>http://localhost:8118
<span class="nb">export </span><span class="nv">https_proxy</span><span class="o">=</span>http://localhost:8118
<span class="o">}</span>
<span class="c"># no privoxy</span>
noproxy <span class="o">()</span> <span class="o">{</span>
<span class="nb">echo</span> <span class="s2">"stop use privoxy proxy"</span>
brew services stop privoxy
<span class="nb">export </span><span class="nv">http_proxy</span><span class="o">=</span>
<span class="nb">export </span><span class="nv">https_proxy</span><span class="o">=</span>
<span class="o">}</span>
</code></pre></div></div>
<hr />
<h3 id="最后">最后</h3>
<p>解决方法是直接把代理写成 <code class="language-plaintext highlighter-rouge">socks5://localhost:1080</code> 呀!^_^ 😂</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">export </span><span class="nv">http_proxy</span><span class="o">=</span>socks5://localhost:1080
<span class="nb">export </span><span class="nv">https_proxy</span><span class="o">=</span><span class="nv">$http_proxy</span>
</code></pre></div></div>
<p>如果看到了中间部分的内容,了解下 Pvivoxy, Tor 也是可以的。不过如果使用 Docker 的话,代理还是最好设置成 http 的,而不是使用 socks5 协议。</p>
<h4 id="参考">参考</h4>
<ul>
<li><a href="https://tech.jandou.com/to-accelerate-the-terminal.html">使用 shadowsocks 加速 Mac 自带终端或iTerm 2</a></li>
<li><a href="https://blog.csdn.net/huyuyang6688/article/details/79914884">iterm通过代理访问网络</a></li>
</ul>Mac 系统终端和 iTerm2 在请求网络时并不使用代理。那如果我们想使用代理怎么办?2018 书单2018-02-17T00:00:00+00:002018-02-17T00:00:00+00:00/essays/book-list<ul>
<li>《世界美术名作二十讲》– 傅雷</li>
</ul>
<p class="af-sectionDivider">本书按时间线,先是详述了文艺复兴初期的乔托、多那太罗、波提切利,以及文艺复兴三杰达᠂ 芬奇、米开朗基罗、拉斐尔;而后又介绍了文艺复兴后的巴洛克艺术的贝尔尼尼;再者把荷兰的光影大师伦勃朗和鲁本斯做了下对比;最后介绍了浪漫风景画派的几位艺术大师。</p>
<p>文艺复兴是冲破黑暗的中世纪对古代艺术的复兴,在三杰的手中达到高峰。但当艺术到达高峰之后,后人一定会寻找另外一种艺术形式,这就是后者的巴洛克艺术。</p>
<blockquote>
<p>当一种艺术形式产生了所能产生的杰作之后,当它有了完满的发展时,这决不会长留在一种无可更易的规范中。艺术家们必得要寻找别的方式,别的出路。在米开朗基罗之后,再要产生米开朗基罗的作品,是不可能的了。有人曾经尝试过,但他们的名字早已被人遗忘了。</p>
</blockquote>
<p>一般史家认为巴洛克这种娱悦视觉的艺术是颓废的艺术。其实,这是在一个伟大文艺复兴的艺术时代以后所必不可免的现象。前人在艺术上的表现已经是登峰造极了,后来的艺术家除了别求新路外,更无依循旧法以图自显的可能。故以公正的态度说来,与其指巴洛克艺术为颓废,毋宁说它是意大利十七世纪的新艺术。</p>
<p>文艺复兴的艺术及巴洛克艺术所表现的大都是宗教主题。后来到了伦勃朗、鲁本斯大师时开始了肖像画,在到后来的风景画,直至后来浪漫主义画派,这大致是西方艺术的时间轴吧。</p>
<p>其实艺术革命有一个永远不变的公式: 『当一种艺术渐趋呆滞死板,不能再行表现时代趋向的时候,必得要回返自然,向其汲取新艺术的灵感』。</p>《世界美术名作二十讲》– 傅雷H5 History API2018-01-13T00:00:00+00:002018-01-13T00:00:00+00:00/essays/h5-history-api<p>使用 H5 History API 可以帮助我们更好的操作浏览器历史记录,尤其在 SPA 中。更进一步,可以帮我们减少带宽(bandwith)。</p>
<h3 class="af-sectionDivider" id="can-i-use"><a href="https://caniuse.com/#search=history">Can I Use</a></h3>
<p>现代浏览器都支持.</p>
<h3 class="af-sectionDivider" id="history-提供的接口"><a href="https://html.spec.whatwg.org/multipage/history.html#the-history-interface">History 提供的接口</a></h3>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">enum</span> <span class="nc">ScrollRestoration</span> <span class="o">{</span> <span class="s">"auto"</span><span class="o">,</span> <span class="s">"manual"</span> <span class="o">};</span>
<span class="o">[</span><span class="nc">Exposed</span><span class="o">=</span><span class="nc">Window</span><span class="o">]</span>
<span class="kd">interface</span> <span class="nc">History</span> <span class="o">{</span>
<span class="n">readonly</span> <span class="n">attribute</span> <span class="n">unsigned</span> <span class="kt">long</span> <span class="n">index</span><span class="o">;</span>
<span class="n">readonly</span> <span class="n">attribute</span> <span class="n">unsigned</span> <span class="kt">long</span> <span class="n">length</span><span class="o">;</span>
<span class="n">attribute</span> <span class="nc">ScrollRestoration</span> <span class="n">scrollRestoration</span><span class="o">;</span>
<span class="n">readonly</span> <span class="n">attribute</span> <span class="n">any</span> <span class="n">state</span><span class="o">;</span>
<span class="kt">void</span> <span class="nf">go</span><span class="o">(</span><span class="n">optional</span> <span class="kt">long</span> <span class="n">delta</span> <span class="o">=</span> <span class="mi">0</span><span class="o">);</span>
<span class="kt">void</span> <span class="nf">back</span><span class="o">();</span>
<span class="kt">void</span> <span class="nf">forward</span><span class="o">();</span>
<span class="kt">void</span> <span class="nf">pushState</span><span class="o">(</span><span class="n">any</span> <span class="n">data</span><span class="o">,</span> <span class="nc">DOMString</span> <span class="n">title</span><span class="o">,</span> <span class="n">optional</span> <span class="nc">USVString</span><span class="o">?</span> <span class="n">url</span> <span class="o">=</span> <span class="kc">null</span><span class="o">);</span>
<span class="kt">void</span> <span class="nf">replaceState</span><span class="o">(</span><span class="n">any</span> <span class="n">data</span><span class="o">,</span> <span class="nc">DOMString</span> <span class="n">title</span><span class="o">,</span> <span class="n">optional</span> <span class="nc">USVString</span><span class="o">?</span> <span class="n">url</span> <span class="o">=</span> <span class="kc">null</span><span class="o">);</span>
<span class="o">};</span>
</code></pre></div></div>
<h4 id="for-web-developers-non-normative-非标准">For web developers (non-normative, 非标准)</h4>
<ul>
<li>
<p>window.history.index</p>
<p>返回当前入口在会话历史记录的 index. 测试了下,主流浏览器都没有实现该属性。</p>
</li>
<li>
<p>window.history.length</p>
<p>当前会话历史记录的总数。</p>
</li>
<li>
<p>window.history.scrollRestoration[=value]</p>
<p>当前会话历史记录的的 scroll 模式,指定在来回遍历历史记录时是否恢复滚动条到指定位置。</p>
</li>
<li>
<p>window.history.state</p>
<p>当前序列化的记录状态。</p>
</li>
<li>
<p>window.history.back()</p>
<p>在历史记录中,回退一步。如果没有上一个页面,则什么也不做。</p>
</li>
<li>
<p>window.history.forward()</p>
<p>在历史记录中,向前一步。如是没有下一个页面,则什么也不做。</p>
</li>
<li>
<p>window.history.go([delta])</p>
<p><code class="language-plaintext highlighter-rouge">back,forward</code> 方法只能回退或前进一步,而 go 方法支持指定 delta 步长。正数向前,负数后退,为 0 则重新加载当前页面。 默认 delat = 0, 即重新加载当前页面,即执行 <code class="language-plaintext highlighter-rouge">location.reload()</code>。</p>
</li>
<li>
<p>window.history.pushState(data, title, [, url])</p>
<p>向会话历史中添加一条历史记录,并且把<strong>最新的 push 的这条记录更新为当前记录</strong>。</p>
<p><strong>注意</strong>,如果当前页面在历史记录中不是最后一条,那么会先把当前之后的记录全部删除掉然后再追加一条新的记录。</p>
</li>
<li>
<p>window.history.replaceState(data, title, [, url])</p>
<p>替换会话历史中的当前项的 state 对象,title 以及可以更新当前页面在 history 中的 url。仅仅是替换而已。</p>
</li>
</ul>
<p><code class="language-plaintext highlighter-rouge">pushState,replaceState</code>只是操作历史记录的变更,并不会去做导航,如果提供了第三个参数 URL, 那么会更新 URL, 但是绝对不会触发 <code class="language-plaintext highlighter-rouge">hashchange</code>事件。</p>
<h3 class="af-sectionDivider" id="popstate-事件">popstate 事件</h3>
<p>每当当前历史记录项(entry 游标)发生变化时,就会触发 window 的 <code class="language-plaintext highlighter-rouge">popstate</code>事件。如果当前历史记录项是由 <code class="language-plaintext highlighter-rouge">pushState,replaceState</code>改变的,则该事件的 <code class="language-plaintext highlighter-rouge">state</code> 会包含当前历史记录状态的对象拷贝。</p>
<p><code class="language-plaintext highlighter-rouge">popstate</code>事件只会在浏览器某些行为下触发, 比如点击后退、前进按钮(或者在JavaScript中调用<code class="language-plaintext highlighter-rouge">history.back()、history.forward()、history.go()</code>方法).</p>
<p>当网页加载时,各浏览器对<code class="language-plaintext highlighter-rouge">popstate</code>事件是否触发有不同的表现,Chrome 和 Safari会触发<code class="language-plaintext highlighter-rouge">popstate</code>事件, 而Firefox不会.</p>
<h3 class="af-sectionDivider" id="by-the-way">By The Way</h3>
<p>Vue 的路由插件 vue-router ,实现了 <code class="language-plaintext highlighter-rouge">router.push</code>、 <code class="language-plaintext highlighter-rouge">router.replace</code> 和 <code class="language-plaintext highlighter-rouge">router.go</code> 其表现和 <a href="https://developer.mozilla.org/en-US/docs/Web/API/History"><code class="language-plaintext highlighter-rouge">window.history.pushState</code>、 <code class="language-plaintext highlighter-rouge">window.history.replaceState</code> 和 <code class="language-plaintext highlighter-rouge">window.history.go</code></a>保持一致, 所以在基于 Vue 的 Spa 中,我们可以像操作 router 的 push, replace, go 方法一样来实现 window 的 history 表现功能。</p>使用 H5 History API 可以帮助我们更好的操作浏览器历史记录,尤其在 SPA 中。更进一步,可以帮我们减少带宽(bandwith)。使用 git 和 pathogen 来管理 vim 插件2018-01-11T00:00:00+00:002018-01-11T00:00:00+00:00/essays/manager-your-vim-plugins<p>使用 git 和 pathogen 来管理你的 vim 插件,无论是在跨机器同步还是记录你的 vim 配置都是一个不错的方案。该方案配置十分简单,大致可以分为以下四个步骤:</p>
<ol>
<li>初始化 vim git repo。</li>
<li>安装 pathogen 管理 vim 插件。</li>
<li>更新插件。</li>
<li>在其它机器上同步配置。</li>
</ol>
<h3 class="af-sectionDivider" id="1-初始化-git-repo">1. 初始化 git repo</h3>
<p>将默认的 vim 配置放在一个目录中用 git 来管理。vim 默认是使用 home 目录下 <code class="language-plaintext highlighter-rouge">~/.vimrc</code> 文件和 <code class="language-plaintext highlighter-rouge">.vim</code> 目录(可以还有 <code class="language-plaintext highlighter-rouge">.gvimrc</code> 文件)来读取你的个人配置。现在我们把这些文件全部都放在同一个目录,并且初始化在 git repo 用 git 来管理。</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 将配置文件放在同一个目录中。</span>
<span class="nb">cd</span> ~
<span class="nb">mv</span> .vimrc ~/.vim/vimrc
<span class="nb">mv</span> .gvimrc ~/.vim/gvimrc <span class="c"># 如果用 .gvimrc 的话。</span>
<span class="c"># 创建配置文件软链</span>
<span class="nb">ln</span> <span class="nt">-s</span> ~/.vim/vimrc ~/.vimrc
<span class="nb">ln</span> <span class="nt">-s</span> ~/.vim/gvimrc ~/.gvimrc
<span class="c"># 将 `~/.vim` 目录初始化成 git repo.</span>
<span class="nb">cd</span> ~/.vim
git init
<span class="c"># 提交配置。</span>
git add <span class="nb">.</span>
git commit <span class="nt">-m</span> <span class="s1">'Initial Commit'</span>
<span class="c"># 将配置推送到 github 上。 </span>
</code></pre></div></div>
<h3 class="af-sectionDivider" id="2-管理-vim-插件">2. 管理 vim 插件</h3>
<p>vim 插件默认的安装方式是将插件的脚本文件拷贝到相应的 <code class="language-plaintext highlighter-rouge">.vim</code> 子目录中。例如如果你想安装 <a href="https://github.com/tpope/vim-fugitive">vim-fugitive</a>, 你需要将该插件的 <a href="https://github.com/tpope/vim-fugitive/blob/master/doc/fugitive.txt">doc 文件</a> 和 <a href="https://github.com/tpope/vim-fugitive/blob/master/plugin/fugitive.vim">脚本文件</a> 分别拷贝到 <code class="language-plaintext highlighter-rouge">~/.vim/doc</code> 和 <code class="language-plaintext highlighter-rouge">~/.vim/plugin</code> 目录中。</p>
<p>这样拷贝安装的步骤还是很麻烦的,特别是当插件更新了,你更新的插件的时候还是需要重新拷贝一遍。既然vim 的插件是 git 来管理的,那么我们为什么不也用 git 来管理 vim 插件的安装那?</p>
<p><a href="https://github.com/tpope/vim-pathogen">pathogen</a> 插件可以让我们将 vim 插件当作 bundle 来安装, 而不是像默认的复制目录文件的方式来管理,当 vim 插件更新时也更方便。</p>
<h4 id="安装-pathogen">安装 pathogen.</h4>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">mkdir</span> <span class="nt">-p</span> ~/.vim/autoload ~/.vim/bundle <span class="o">&&</span> <span class="se">\</span>
curl <span class="nt">-LSso</span> ~/.vim/autoload/pathogen.vim https://tpo.pe/pathogen.vim
</code></pre></div></div>
<h4 id="开启-pathogen">开启 pathogen</h4>
<p>将下面的代码放在 <code class="language-plaintext highlighter-rouge">.vimrc</code> 的文件类型检测(filetype detection)的前面,推荐放在文件的开始。</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>call pathogen#infect<span class="o">()</span>
call pathogen#helptags<span class="o">()</span>
</code></pre></div></div>
<h4 id="安装其它-vim-插件">安装其它 vim 插件</h4>
<p>开启了 pathogen 之后我们可以将其它 vim 插件通过 git 子模块的方式来安装。以 <code class="language-plaintext highlighter-rouge">fugitive</code> 为例。</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cd</span> ~/.vim/bundle
git submodule add http://github.com/tpope/vim-fugitive.git bundle/fugitive
git add <span class="nb">.</span>
git commit <span class="nt">-m</span> <span class="s2">"Install Fugitive.vim bundle as a submodule."</span>
</code></pre></div></div>
<h4 id="删除-vim-插件">删除 vim 插件</h4>
<p>删除 vim 插件的方法,即是删除 <code class="language-plaintext highlighter-rouge">git submodule</code> 的方法。如下:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0. mv a/submodule a/submodule_tmp
1. git submodule deinit -f -- a/submodule
2. rm -rf .git/modules/a/submodule
3. git rm -f a/submodule
# Note: a/submodule (no trailing slash)
# or, if you want to leave it in your working tree and have done step 0
3. git rm --cached a/submodule
3bis mv a/submodule_tmp a/submodule
</code></pre></div></div>
<p>其它插件的安装方法类似。</p>
<h3 class="af-sectionDivider" id="3-更新插件">3. 更新插件</h3>
<p>当某个插件更新了之后,我们只需要到插件的目录用 git 更新下即可。如更新 <code class="language-plaintext highlighter-rouge">fugitive</code> :</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cd</span> ~/.vim/bundle/fugitive
git pull origin master
</code></pre></div></div>
<p>如果想一次性更新所有插件,可以使用下面的命令。</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cd</span> ~/.vim
git submodule foreach git pull origin master
</code></pre></div></div>
<h3 class="af-sectionDivider" id="4-在其它机器上同步">4. 在其它机器上同步</h3>
<p>使 git 来管理并且同步了 github 上,就可以在其它机器上同步使用你的 vim 配置。可以使用下面命令来同步:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cd</span> ~
git clone http://github.com/username/dotvim.git ~/.vim
<span class="nb">ln</span> <span class="nt">-s</span> ~/.vim/vimrc ~/.vimrc
<span class="nb">ln</span> <span class="nt">-s</span> ~/.vim/gvimrc ~/.gvimrc
<span class="nb">cd</span> ~/.vim
<span class="c"># 初始化 submodule</span>
git submodule update <span class="nt">--init</span> <span class="nt">--recursive</span>
<span class="c"># 如果的插件需要单独配置,就自行配置如 YouCompleteMe 在安装完成后,还需要执行下面的命令</span>
bundle/YouCompleteMe/install.py <span class="nt">--go-completer</span> <span class="nt">--js-completer</span> <span class="nt">--clang-completer</span>
</code></pre></div></div>
<p class="af-sectionDivider"><strong>注意</strong>:vim 8 已经支持类似 pathogen 的原生插件管理方法, 所以你也可以不用 pathogen 🙃😁。</p>
<h4 id="参考">参考</h4>
<ol>
<li><a href="http://vimcasts.org/episodes/synchronizing-plugins-with-git-submodules-and-pathogen/">Synchronizing plugins with git submodules and pathogen</a></li>
<li><a href="https://shapeshed.com/vim-packages/">Vim: So long Pathogen, hello native package loading</a></li>
</ol>使用 git 和 pathogen 来管理你的 vim 插件,无论是在跨机器同步还是记录你的 vim 配置都是一个不错的方案。该方案配置十分简单,大致可以分为以下四个步骤:Github 标准 Fork & Pull Request 流程2018-01-11T00:00:00+00:002018-01-11T00:00:00+00:00/essays/github-fork-pull-workflow<p>原文 <a href="https://gist.github.com/Chaser324/ce0505fbed06b947d962">GitHub Standard Fork & Pull Request Workflow</a></p>
<p>开源社区 save your time!当你想回报 Github 社区,或者用 Git 管理与别人合作的项目时,了解怎么正确的 fork & pull request 是非常必要的。但是,如果你不熟悉这个流程的话,则可能会出错。</p>
<p>这个简单的手册介绍一个相对来说标准的流程:创建 fork, 开发,发起 Pull Request, 以及 merge Pull Request。</p>
<h3 class="af-sectionDivider" id="创建-fork">创建 Fork</h3>
<p>很简单,到 Github 主页上单击 “fork” 按钮。然后在开发目录中执行下面的命令 clone 你 fork 的项目代码。</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Clone your fork to your local machine</span>
git clone git@github.com:USERNAME/FORKED-PROJECT.git
</code></pre></div></div>
<h3 class="af-sectionDivider" id="fork-与-upstream-保持一致">Fork 与 upstream 保持一致</h3>
<p>虽然这不是必要的一步,但是如果你想参与更多而不是仅仅做一个 quick fix, 你需要保证你的代码与远程原始代码库 (the original “upstream” repo) 保持一致。做到这一步,你仅需要设置下 remote:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Add 'upstream' repo to list of remotes</span>
git remote add upstream https://github.com/UPSTREAM-USER/ORIGINAL-PROJECT.git
<span class="c"># Verify the new remote named 'upstream'</span>
git remote <span class="nt">-v</span>
</code></pre></div></div>
<p>当你想更新远程代码到你的 fork 时,<strong>首先</strong>你需要 fetch 原始上游分支的最新提交到你的项目中:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Fetch from upstream remote</span>
git fetch upstream
<span class="c"># View all branches, including those from upstream</span>
git branch <span class="nt">-va</span>
</code></pre></div></div>
<p><strong>然后</strong>,将上游远程 master 合并到你的 master 分支上:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Checkout your master branch and merge upstream</span>
git checkout master
git merge upstream/master
</code></pre></div></div>
<p><em>注意</em>:如果与上游用非 master 分支交流,则改成相应的分支。</p>
<p>在 merge 过程中,如果没有冲突 git 会执行 fast-forward 合并。如果有冲突的话,请尊重上游的更改解决冲突。现在你的项目就与 upstream 保持一致了。</p>
<h3 class="af-sectionDivider" id="开发">开发</h3>
<h4 id="创建新的分支-branch">创建新的分支 Branch</h4>
<p>无论什么时候,你想开发一个新的 feature 或者 bugfix, 创建一个新的分支很重要。这不仅仅是正确的 git 工作流,而是这样你的开发的 feature 变化与 master 分支分隔,当每完成一个任务时就可发起 pull request.</p>
<p>创建新分支,开始工作:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Checkout the master branch - you want your new branch to come from master</span>
git checkout master
<span class="c"># Create a new branch named newfeature (give your branch its own simple informative name)</span>
git branch newfeature
<span class="c"># Switch to your new branch</span>
git checkout newfeature
</code></pre></div></div>
<p>现在,你就可以开发你的 feture 或者做 bugfix 了。</p>
<h3 class="af-sectionDivider" id="发起-pull-request">发起 Pull Request</h3>
<p>当你的功能开发完成后可以发起 Pull Request。</p>
<blockquote>
<p>开发者向团队成员通知功能开发已经完成,<code class="language-plaintext highlighter-rouge">Pull Requests</code>是最简单的用法。开发者完成功能开发后,发起一个<code class="language-plaintext highlighter-rouge">Pull Request</code>。这样让涉及这个功能的所有人知道,要去做<code class="language-plaintext highlighter-rouge">Code Review</code>和合并到<code class="language-plaintext highlighter-rouge">master</code>分支。</p>
<p><code class="language-plaintext highlighter-rouge">Pull Request</code>远不止一个简单的通知,而是为讨论提交的功能的一个专门论坛。如果变更有任何问题,团队成员反馈在<code class="language-plaintext highlighter-rouge">Pull Request</code>中,甚至<code class="language-plaintext highlighter-rouge">push</code>新的提交微调功能。所有的这些活动都直接跟踪在<code class="language-plaintext highlighter-rouge">Pull Request</code>中。</p>
</blockquote>
<h4 id="cleaning-up-your-work">Cleaning up your work</h4>
<p>在发起 Pull Request 之前,你可能需要整理下你的分支以保持尽可能的简洁。这样其它维护者可以更方便的测试,accept, merge 你的代码。</p>
<p>如有上游的 master 分支有了新的提交,你需要 rebase 你的开发分支以保证在 merge 时不会有冲突能够执行 fast-forward 。</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Fetch upstream master and merge with your repo's master branch</span>
git fetch upstream
git checkout master
git merge upstream/master
<span class="c"># If there were any new commits, rebase your development branch</span>
git checkout newfeature
git rebase master
</code></pre></div></div>
<p>再者,在开发的时候你的提交历史可能很混乱,你可以重新整理 squash 你的提交,以保持精简。你可以使用交互式 rebase:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Rebase all commits on your development branch</span>
git checkout
git rebase <span class="nt">-i</span> master
</code></pre></div></div>
<h4 id="提交-push-request">提交 push request</h4>
<p>做完上面的步骤,可以到你的 github 主页上,选择你的开发分支然后单击 pull request 按钮发起 pull request. 如果之后有新的调整,你只需要直接 push 更新的到 github 上就行了。你发起的 pull request 会跟踪的更新。</p>
<h3 class="af-sectionDivider" id="接受合并-pull-request">接受合并 Pull Request</h3>
<p>如是你仅仅是代码贡献者,自己不是该项目的管理者。那你的流程就已经结束了,因为这部分是写给上游原始代码库的 owner 的。Owner 要来处理 Pull Request.</p>
<h4 id="checking-out--testing-pull-requests">Checking out & Testing Pull Requests</h4>
<p>打开 <code class="language-plaintext highlighter-rouge">.git/config</code> 文件,在 <code class="language-plaintext highlighter-rouge">[remote "origin"]</code> 后添加一行:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>fetch <span class="o">=</span> +refs/pull/<span class="k">*</span>/head:refs/pull/origin/<span class="k">*</span>
</code></pre></div></div>
<p>现在,你可以 fetch , checkout 做任意一个 pull request ,以方便你测试它们。</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Fetch all pull request branches</span>
git fetch origin
<span class="c"># Checkout out a given pull request branch based on its number</span>
git checkout <span class="nt">-b</span> 999 pull/origin/999
</code></pre></div></div>
<p><strong>注意</strong>: 这些分支你只能测试,而不能变更后提交更新。</p>
<h4 id="自动-merge-pull-request">自动 Merge Pull Request</h4>
<p>如果 Pull Request 是一个 fast-forward 非常简单的功能,你可以直接在 Github 页面上单击 merge 来自动 merge request.</p>
<h4 id="手动-merge-pull-request">手动 Merge Pull Request</h4>
<p>做手动 Merge ,你需要 checkout 源代码库的目标分支,拉下来 fork, 进行 merge 然后 push .</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Checkout the branch you're merging to in the target repo</span>
git checkout master
<span class="c"># Pull the development branch from the fork repo where the pull request development was done.</span>
git pull https://github.com/forkuser/forkedrepo.git newfeature
<span class="c"># Merge the development branch</span>
git merge newfeature
<span class="c"># Push master with the new feature merged into it</span>
git push origin master
</code></pre></div></div>
<p>最后你就可以删除你的开发分支了, up to you。</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git branch <span class="nt">-d</span> newfeature
</code></pre></div></div>
<p class="af-sectionDivider"><strong>Additional Reading</strong></p>
<ul>
<li><a href="https://www.atlassian.com/git/tutorials/merging-vs-rebasing">Atlassian - Merging vs. Rebasing</a></li>
</ul>
<p><strong>Sources</strong></p>
<ul>
<li><a href="https://help.github.com/articles/fork-a-repo">GitHub - Fork a Repo</a></li>
<li><a href="https://help.github.com/articles/syncing-a-fork">GitHub - Syncing a Fork</a></li>
<li><a href="https://help.github.com/articles/checking-out-pull-requests-locally">GitHub - Checking Out a Pull Request</a></li>
</ul>原文 GitHub Standard Fork & Pull Request WorkflowEDM, Bolier Room List2017-12-10T00:00:00+00:002017-12-10T00:00:00+00:00/life/bolier-room-list<ul>
<li>Jamie XX</li>
<li>Chet Faker</li>
<li>Fourtet</li>
<li>Purple Disco Machine</li>
<li>Little Boots</li>
</ul>Jamie XX Chet Faker Fourtet Purple Disco Machine Little Boots又是一个程序猿节2017-10-24T11:12:35+00:002017-10-24T11:12:35+00:00/essays/festival<p class="af-textAlignCenter af-imgSizeFull"><img src="/assets/imgs/evolution-of-programmer.jpg" alt="My helpful screenshot" /></p>
<p class="af-sectionDivider">首先那,祝自己节日快乐啦!</p>
<p>然后,起身看看周围的同事都已经下班了。自己做在办公室发下呆🤔。</p>
<p>近来工作不是太忙了,难道有时间看下自己之前感兴趣的东西。但又发现自己怎么也专注不下了来,心理莫名的浮躁。也许写点东西也能让自己沉下来。</p>
<p class="af-sectionDivider">来,现在分析自己的弱点…</p>
<p>坐井观天还似乎有一种优越感,很难踏出自己的舒适区。看别的小伙伴都在新的领域,新的环境大显身手,自己好像毫无波澜。</p>
<p>我觉得这是已经走在了失败人生道路上了,因为这是一种老庄的心态。想起林语堂先生所说的,失败的人喜老庄,成功的人喜孔孟。自己现在的状态不就是那只小蜩、小学鸠吗?</p>
<blockquote>
<p>蜩与学鸠笑之曰:“我决起而飞,抢榆枋而止,时则不至,而控于地而已矣,奚以之九万里而南为?” 适莽苍者,三餐而反,腹犹果然;适百里者宿舂粮,适千里者,三月聚粮。之二虫又何知!</p>
</blockquote>
<p>是呀!在原地踏步而『又何知』那?『修身齐家』好像一事无成吧?自己感兴趣想探索的领域还没浅尝就辄止了吧?…</p>
<p class="af-sectionDivider">不行,所以要立个 Flag 🚩, 今天起,</p>
<ul>
<li>每周都要更新一篇 POST。</li>
<li>整理起自己的知识框架。</li>
<li>能够找到对象</li>
</ul>
<p>最后,Always Be Coding…</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nb">puts</span> <span class="s1">'Hello World!'</span>
</code></pre></div></div>