破鏡如何貼花黃
gitbook
在Windows
系統無法熱加載,總是報錯!
gitbook
是一款文檔編寫利器,可以方便地 markdown
輸出成美觀優雅的 html
,gitbook serve
啟動服務器后,原來相貌平平的 markdown
丑小鴨搖身一變就成了傾國傾城的 html
絕色佳人.
如果源文件發生更改,Windows
卻無法按照預期那樣重啟服務器,直接拋出一個異常,立即終止了 markdown
的化妝.
Restart after change in file README.mdStopping server
events.js:183throw er; // Unhandled 'error' event^Error: EPERM: operation not permitted, lstat 'F:\workspace\private-cloud-backup\gitbook-test\_book'
對鏡貼花黃
現在看一下 markdown
灰姑娘變身 html
小姐姐的神奇過程吧!
$ gitbook serve --log=debug
Live reload server started on port: 35729
Press CTRL+C to quit ...debug: readme found at README.md
debug: summary file found at SUMMARY.md
debug: cleanup folder "G:\sublime\gitbook-test\_book"
info: 7 plugins are installed
info: loading plugin "livereload"... OK
...
info: loading plugin "theme-default"... OK
info: found 1 pages
info: found 0 asset files
debug: calling hook "config"
debug: calling hook "init"
debug: copy assets from theme C:\Users\snowdreams1006\.gitbook\versions\3.2.3\node_modules\gitbook-plugin-theme-default\_assets\website
...
debug: copy resources from plugin C:\Users\snowdreams1006\.gitbook\versions\3.2.3\node_modules\gitbook-plugin-livereload\book
debug: generate page "README.md"
debug: calling hook "page:before"
debug: calling hook "page"
debug: index page README.md
debug: calling hook "finish:before"
debug: calling hook "finish"
debug: write search index
info: >> generation finished with success in 1.5s !Starting server ...
Serving book on http://localhost:4000
根據上述輸出日志,我們可以分析出 gitbook
的基本運行流程.
- 加載
readme
和summary
文件,若存在glossary
文件也會加載,并刪除_book
目錄
debug: readme found at README.md
debug: summary file found at SUMMARY.md
debug: cleanup folder "G:\sublime\gitbook-test\_book"
- 加載依賴插件,若沒有找到相應插件會報錯,提示運行
gitbook install
安裝插件.
info: 7 plugins are installed
info: loading plugin "livereload"... OK
info: loading plugin "highlight"... OK
info: loading plugin "search"... OK
info: loading plugin "lunr"... OK
info: loading plugin "sharing"... OK
info: loading plugin "fontsettings"... OK
info: loading plugin "theme-default"... OK
- 掃描頁面和靜態資源文件
info: found 1 pages
info: found 0 asset files
- 讀取配置文件并初始化
debug: calling hook "config"
debug: calling hook "init"
- 拷貝樣式資源和插件資源
debug: copy assets from theme C:\Users\snowdreams1006\.gitbook\versions\3.2.3\node_modules\gitbook-plugin-theme-default\_assets\website
debug: copy resources from plugin C:\Users\snowdreams1006\.gitbook\versions\3.2.3\node_modules\gitbook-plugin-fontsettings\assets
debug: copy resources from plugin C:\Users\snowdreams1006\.gitbook\versions\3.2.3\node_modules\gitbook-plugin-sharing\assets
debug: copy resources from plugin C:\Users\snowdreams1006\.gitbook\versions\3.2.3\node_modules\gitbook-plugin-lunr\assets
debug: copy resources from plugin C:\Users\snowdreams1006\.gitbook\versions\3.2.3\node_modules\gitbook-plugin-search\assets
debug: copy resources from plugin C:\Users\snowdreams1006\.gitbook\versions\3.2.3\node_modules\gitbook-plugin-highlight\css
debug: copy resources from plugin C:\Users\snowdreams1006\.gitbook\versions\3.2.3\node_modules\gitbook-plugin-livereload\book
- 開始生成單獨頁面,依次執行
page:before
,page
回調函數,全部頁面執行完畢后執行finish:before
和finish
回調函數.
debug: generate page "README.md"
debug: calling hook "page:before"
debug: calling hook "page"
debug: index page README.md
debug: calling hook "finish:before"
debug: calling hook "finish"
- 生成搜索文件
debug: write search index
- 啟動完畢,輸出成功信息
Starting server ...
Serving book on http://localhost:4000
默認情況下服務器啟動后會占用兩個端口,一個是對外暴露的 4000
端口,用于瀏覽器訪問項目.
另外一個是 35729
端口,用于監聽本地文件變化,重啟服務器進而實現熱加載功能.
本地服務器啟動后我們就可以訪問 http://localhost:4000
預覽靜態網站效果,markdown
源文件華麗演變成 html
富文本文件.
破鏡怎化妝
不幸的是,Windows
熱加載可能會有問題,也就是說如果啟動服務器后,本地文件發生改變,此時會觸發熱加載功能而報錯 Error: EPERM: operation not permitted
,這樣一來瀏覽器又無法訪問了.
剛剛變身的 markdown
瞬間又被打回原形,無法欣賞化妝后的容顏了,這樣的體驗相當不好!
邊化妝邊照鏡子才是做到心中有譜,隨時調整,如果不照鏡子而直接化妝,那不是一般人能做到的.
gitbook
啟動本地服務器給我們提供了鏡子,但熱加載失敗又把鏡子摔碎了,還怎么愉快的化妝?
Restart after change in file README.mdStopping server
debug: readme found at README.md
debug: summary file found at SUMMARY.md
debug: cleanup folder "G:\sublime\gitbook-test\_book"
events.js:174throw er; // Unhandled 'error' event^Error: EPERM: operation not permitted, lstat 'G:\sublime\gitbook-test\_book'
Emitted 'error' event at:at FSWatcher._handleError (C:\Users\snowdreams1006\.gitbook\versions\3.2.3\node_modules\chokidar\index.js:236:10)at ReaddirpReadable.emit (events.js:189:13)at Immediate.<anonymous> (C:\Users\snowdreams1006\.gitbook\versions\3.2.3\node_modules\chokidar\node_modules\readdirp\stream-api.js:82:32)at runCallback (timers.js:705:18)at tryOnImmediate (timers.js:676:5)at processImmediate (timers.js:658:5)
尋醫問診修破鏡
現在問題已經復現,接下來就要開始尋醫問診,試圖讓破鏡重圓,好讓 markdown
灰姑娘變成人見人愛的 html
小姐姐.
根據報錯信息描述,定位到刪除 _book
目錄再次創建該目錄時,提示 EPERM: operation not permitted
,即無權操作.
柯南附體
既然說是操作權限的問題,那我們看一下 _book
目錄現在是怎樣狀態吧!
$ ls
gitbook-errorforwindows-preview.png README.md SUMMARY.md
當前項目已經沒有 _book
目錄,證明發生報錯時確實已經刪除了 _book
目錄,但是某種原因無權再次創建該文件夾而重啟失敗.
然而,這只是表現現象,老師告訴我們,要透過現象看本質,即使現在沒有 _book
文件再次啟動服務器還是會啟動成功并創建 _book
文件的,所以真想只有一個!
那就是,gitbook
控制臺在說謊!
雖然排除了 gitbook
無權創建 _book
目錄的嫌疑,那又怎么解釋重啟服務器卻沒能創建 _book
目錄這件事呢?
debug: cleanup folder "G:\sublime\gitbook-test\_book"
events.js:174throw er; // Unhandled 'error' event^Error: EPERM: operation not permitted, lstat 'G:\sublime\gitbook-test\_book'
Emitted 'error' event at:at FSWatcher._handleError (C:\Users\snowdreams1006\.gitbook\versions\3.2.3\node_modules\chokidar\index.js:236:10)at ReaddirpReadable.emit (events.js:189:13)at Immediate.<anonymous> (C:\Users\snowdreams1006\.gitbook\versions\3.2.3\node_modules\chokidar\node_modules\readdirp\stream-api.js:82:32)at runCallback (timers.js:705:18)at tryOnImmediate (timers.js:676:5)at processImmediate (timers.js:658:5)
先看一下 FSWatcher._handleError
異常信息: sed -n "223,239p" ~/.gitbook/versions/3.2.3/node_modules/chokidar/index.js
.
分析發現: FSWatcher._handleError
是私有方法,作用是處理異常信息,和這起事故關聯不大.
Administrator@snowdreams1006 MINGW64 /f/workspace/private-cloud-backup/gitbook-test (master)
$ sed -n "223,239p" ~/.gitbook/versions/3.2.3/node_modules/chokidar/index.js
// Private method: Common handler for errors
//
// * error - object, Error instance
//
// Returns the error if defined, otherwise the value of the
// FSWatcher instance's `closed` flag
FSWatcher.prototype._handleError = function(error) {var code = error && error.code;var ipe = this.options.ignorePermissionErrors;if (error &&code !== 'ENOENT' &&code !== 'ENOTDIR' &&(!ipe || (code !== 'EPERM' && code !== 'EACCES'))) this.emit('error', error);return error || this.closed;
};
我們接著往下找,再看一下 ReaddirpReadable.emit (events.js:189:13)
,這里沒有給出文件的具體路徑,所以暫時無法定位.
那我們再看下一個 Immediate.<anonymous>
: sed -n "78,96p" ~/.gitbook/versions/3.2.3/node_modules/chokidar/node_modules/readdirp/stream-api.js
Administrator@snowdreams1006 MINGW64 /f/workspace/private-cloud-backup/gitbook-test (master)
$ sed -n "78,96p" ~/.gitbook/versions/3.2.3/node_modules/chokidar/node_modules/readdirp/stream-api.js
proto._handleFatalError = function (err) {var self = this;setImmediate(function () {if (self._paused) return self._errors.push(err);if (!self._destroyed) self.emit('error', err);});
}function createStreamAPI () {var stream = new ReaddirpReadable();return {stream : stream, processEntry : stream._processEntry.bind(stream), done : stream._done.bind(stream), handleError : stream._handleError.bind(stream), handleFatalError : stream._handleFatalError.bind(stream)};
}
遺憾的是,仍然沒有找到具體問題,那就繼續看一下一條線索.
timers.js:705:18
和 events.js:189:13
都沒有顯示具體的文件位置,如果也在 chokidar
模塊的話就好了.
Administrator@snowdreams1006 MINGW64 /f/workspace/private-cloud-backup/gitbook-test (master)
$ tree -P "events.js" --prune ~/.gitbook/versions/3.2.3/
/c/Users/Administrator/.gitbook/versions/3.2.3/
└── node_modules├── cheerio│?? └── node_modules│?? └── jsdom│?? └── lib│?? └── jsdom│?? └── level2│?? └── events.js└── gitbook-plugin-theme-default└── src└── js└── core└── events.js11 directories, 2 filesAdministrator@snowdreams1006 MINGW64 /f/workspace/private-cloud-backup/gitbook-test (master)
$ tree -P "timers.js" --prune ~/.gitbook/versions/3.2.3/
/c/Users/Administrator/.gitbook/versions/3.2.3/
0 directories, 0 files
git-bash
命令行正常沒有tree
命令,如需擴展參考我另外一篇文章.
經過肉眼驗證,發現 events.js
根本就沒有 174
行文件,所以這兩個文件大都不是目標文件.
既然命令行中無法找到目標文件,那就請專業的搜索工具全系統查找這兩個文件吧,這里使用的是 Everything
搜索工具.
然并卵,依然沒有找到目標文件.
畢竟不是柯南,沒有發現真相
求助官方
gitbook
可是開源產品,出現問題的應該不止我一個,所以去 github
看看有沒有遇到和我一樣的問題.
雖然找到了志同道合的小伙伴,但是并沒有提供解決方案,連官方都放棄了,那我還有什么可留戀的?
點擊查看 gitbook serve livereload error
自己動手
最害怕的不是 bug
,而是發現了 bug
卻無法定位,雖然控制臺有報錯信息但是沒有找到真正的文件!
首先確認下當前系統版本,然后采取版本切換方式測試其他版本是否存在該問題.
$ gitbook --version
CLI version: 2.3.2
GitBook version: 3.2.3
- 升級到最新版
gitbook ls
是列出當前已安裝的版本,而 gitbook ls-remote
則是列出遠程服務器版本.
# 列出本地已安裝版本
$ gitbook ls
GitBook Versions Installed:* 3.2.3Run "gitbook update" to update to the latest version.# 列出遠程可用版本
$ gitbook ls-remote
Available GitBook Versions:4.0.0-alpha.6, 4.0.0-alpha.5, 4.0.0-alpha.4, 4.0.0-alpha.3, 4.0.0-alpha.2, 4.0.0-alpha.1, 3.2.3, 3.2.2, 3.2.1, 3.2.0, 3.2.0-pre.1, 3.2.0-pre.0, 3.1.1, 3.1.0, 3.0.3, 3.0.2, 3.0.1, 3.0.0, 3.0.0-pre.15, 3.0.0-pre.14, 3.0.0-pre.13, 3.0.0-pre.12, 3.0.0-pre.11, 3.0.0-pre.10, 3.0.0-pre.9, 3.0.0-pre.8, 3.0.0-pre.7, 3.0.0-pre.6, 3.0.0-pre.5, 3.0.0-pre.4, 3.0.0-pre.3, 3.0.0-pre.2, 3.0.0-pre.1, 2.6.9, 2.6.8, 2.6.7, 2.6.6, 2.6.5, 2.6.4, 2.6.3, 2.6.2, 2.6.1, 2.6.0, 2.5.2, 2.5.1, 2.5.0, 2.5.0-beta.7, 2.5.0-beta.6, 2.5.0-beta.5, 2.5.0-beta.4, 2.5.0-beta.3, 2.5.0-beta.2, 2.5.0-beta.1, 2.4.3, 2.4.2, 2.4.1, 2.4.0, 2.3.3, 2.3.2, 2.3.1, 2.3.0, 2.2.0, 2.1.0, 2.0.4, 2.0.3, 2.0.2, 2.0.1, 2.0.0, 2.0.0-beta.5, 2.0.0-beta.4, 2.0.0-beta.3, 2.0.0-beta.2, 2.0.0-beta.1, 2.0.0-alpha.9, 2.0.0-alpha.8, 2.0.0-alpha.7, 2.0.0-alpha.6, 2.0.0-alpha.5, 2.0.0-alpha.4, 2.0.0-alpha.3, 2.0.0-alpha.2, 2.0.0-alpha.1Tags:latest : 2.6.9pre : 4.0.0-alpha.6
目前最新發布版本是 3.2.3
,而我們本地已安裝的版本正是該版本,所以現在應該測試 4.0.0-alpha.6
版.
看到 4.0.0-alpha.6
心里有些忐忑,根據版本管理約定,版本號一般有三部分組成,第一部分代表不兼容的重大升級,第二部分代表主干兼容的功能升級,第三部分是小版本修復.
由 3.2.3
直接跨度到 4.0.0-alpha.6
意味著 gitbook
發生了重大重構!
算了,先下載試試看!
gitbook fetch
下載 和gitbook update
升級,兩種方式都可以體驗最新版本,這里選擇下載方式方便進行不同版本的切換.
# 下載 `4.0.0-alpha.6` 版本
$ gitbook fetch 4.0.0-alpha.6
Installing GitBook 4.0.0-alpha.6
gitbook@4.0.0-alpha.6 C:\Users\SNOWDR~1\AppData\Local\Temp\tmp-8912hSrxNvTCrFEH\node_modules\gitbook
├── escape-html@1.0.3
├── escape-string-regexp@1.0.5
├── destroy@1.0.4
├── ignore@3.1.2
└── ied@2.3.6 (lodash.memoize@4.1.2, lodash.frompairs@4.0.1, force-symlink@0.0.2, semver@5.7.0, minimist@1.2.0, node-uuid@1.4.8, npm-package-arg@4.2.1, source-map-support@0.4.18, ora@0.2.3, easy-table@1.1.1, rimraf@2.6.3, tar-fs@1.16.3, gunzip-maybe@1.4.1, init-package-json@1.10.3, rxjs@5.0.0-rc.1, needle@1.0.0, node-pre-gyp@0.6.39, node-gyp@3.8.0)GitBook 4.0.0-alpha.6 has been installed
先看一下本地安裝 gitbook
版本,確保待會運行時使用最新的 4.0.0-alpha.6
版本.
# 列出本地已安裝版本
$ gitbook ls
GitBook Versions Installed:* 4.0.0-alpha.63.2.3Run "gitbook update" to update to the latest version.# 列出當前正在使用版本
$ gitbook current
GitBook version is 3.2.3
gitbook serve --gitbook=4.0.0-alpha.6 --log=debug
運行 4.0.0-alpha.6
版本并打印 debug
級別日志.
意外的是,竟然沒有連啟動都沒啟動成功,提示無法打開 ~\.gitbook\versions\4.0.0-alpha.6\node_modules\gitbook-plugin-livereload\_assets\plugin.js
文件.
回想到版本號規范,可能 v3
到 v4
更改比較大,版本不兼容吧,重新初始化項目試試看!
# 初始化項目并指定 `gitbook` 運行版本
$ gitbook init --gitbook=4.0.0-alpha.6
Warning: Accessing PropTypes via the main React package is deprecated, and will be removed in React v16.0. Use the latest available v15.* prop-types package from npm instead. For info on usage, compatibility, migration and more, see https://fb.me/prop-types-docs
info: create SUMMARY.md
info: initialization is finished
然而,仍然還是同樣的報錯,依舊無法啟動.
$ gitbook serve --gitbook=4.0.0-alpha.6 --log=debug Warning: Accessing PropTypes via the main React package is deprecated, and will be removed in React v16.0. Use the latest available v15.* prop-types package from npm instead. For info on usage, compatibility, migration and more, see https://fb.me/prop-types-docs
Live reload server started on port: 35729
Press CTRL+C to quit ......Error: ENOENT: no such file or directory, open 'C:\Users\snowdreams1006\.gitbook\versions\4.0.0-alpha.6\node_modules\gitbook-plugin-livereload\_assets\plugin.js'
此路不通,再換一條,既然向上無法處理,那向下回退會不會有結果呢?
- 回退版本
當前系統版本是 3.2.3
,最新測試版本是 4.0.0-alpha.6
,然而最近一次提交的版本卻是 2.6.9
?
為什么 gitbook-ci
管理的 gitbook
版本號會突然跳水,會不會有什么貓膩,難不成修復了什么 bug
?
$ gitbook ls-remote
Available GitBook Versions:4.0.0-alpha.6, 4.0.0-alpha.5, 4.0.0-alpha.4, 4.0.0-alpha.3, 4.0.0-alpha.2, 4.0.0-alpha.1, 3.2.3, 3.2.2, 3.2.1, 3.2.0, 3.2.0-pre.1, 3.2.0-pre.0, 3.1.1, 3.1.0, 3.0.3, 3.0.2, 3.0.1, 3.0.0, 3.0.0-pre.15, 3.0.0-pre.14, 3.0.0-pre.13, 3.0.0-pre.12, 3.0.0-pre.11, 3.0.0-pre.10, 3.0.0-pre.9, 3.0.0-pre.8, 3.0.0-pre.7, 3.0.0-pre.6, 3.0.0-pre.5, 3.0.0-pre.4, 3.0.0-pre.3, 3.0.0-pre.2, 3.0.0-pre.1, 2.6.9, 2.6.8, 2.6.7, 2.6.6, 2.6.5, 2.6.4, 2.6.3, 2.6.2, 2.6.1, 2.6.0, 2.5.2, 2.5.1, 2.5.0, 2.5.0-beta.7, 2.5.0-beta.6, 2.5.0-beta.5, 2.5.0-beta.4, 2.5.0-beta.3, 2.5.0-beta.2, 2.5.0-beta.1, 2.4.3, 2.4.2, 2.4.1, 2.4.0, 2.3.3, 2.3.2, 2.3.1, 2.3.0, 2.2.0, 2.1.0, 2.0.4, 2.0.3, 2.0.2, 2.0.1, 2.0.0, 2.0.0-beta.5, 2.0.0-beta.4, 2.0.0-beta.3, 2.0.0-beta.2, 2.0.0-beta.1, 2.0.0-alpha.9, 2.0.0-alpha.8, 2.0.0-alpha.7, 2.0.0-alpha.6, 2.0.0-alpha.5, 2.0.0-alpha.4, 2.0.0-alpha.3, 2.0.0-alpha.2, 2.0.0-alpha.1Tags:latest : 2.6.9pre : 4.0.0-alpha.6
帶著這些疑問,不妨下載 2.6.9
版本試試,看一下能否熱加載?
gitbook serve --log=debug --gitbook=2.6.9
指定gitbook
版本,依舊失敗!
$ gitbook serve --log=debug --gitbook=2.6.9
Error loading version latest: Error: Cannot find module 'q'at Function.Module._resolveFilename (internal/modules/cjs/loader.js:582:15)at Function.Module._load (internal/modules/cjs/loader.js:508:25)at Module.require (internal/modules/cjs/loader.js:637:17)at require (internal/modules/cjs/helpers.js:22:18)at Object.<anonymous> (C:\Users\myHome\.gitbook\versions\2.6.9\lib\index.js:3:9)at Module._compile (internal/modules/cjs/loader.js:701:30)at Object.Module._extensions..js (internal/modules/cjs/loader.js:712:10)at Module.load (internal/modules/cjs/loader.js:600:32)at tryModuleLoad (internal/modules/cjs/loader.js:539:12)at Function.Module._load (internal/modules/cjs/loader.js:531:3)TypeError: Cannot read property 'commands' of null
重回現場
現在把目光再次聚焦到最初的案發現場,這一次只能背水一戰了,自己動手要么豐衣足食要么餓死凍死!
Stopping server
debug: readme found at README.md
debug: summary file found at SUMMARY.md
debug: cleanup folder "G:\sublime\private-cloud-backup\gitbook-test\_book"
events.js:174throw er; // Unhandled 'error' event^Error: EPERM: operation not permitted, lstat 'G:\sublime\private-cloud-backup\gitbook-test\_book'
Emitted 'error' event at:at FSWatcher._handleError (C:\Users\myHome\.gitbook\versions\3.2.3\node_modules\chokidar\index.js:236:10)at ReaddirpReadable.emit (events.js:189:13)at Immediate.<anonymous> (C:\Users\myHome\.gitbook\versions\3.2.3\node_modules\chokidar\node_modules\readdirp\stream-api.js:82:32)at runCallback (timers.js:705:18)at tryOnImmediate (timers.js:676:5)at processImmediate (timers.js:658:5)
關于上述錯誤描述中,在真相只有一個章節中已經探討過,當時得出的結論是 gitbook
是刪除 _book
文件夾再新建 _book
文件夾時發生了意外.
如果這個行為不是由 gitbook
發生而是由我們手動干預的話,也就是說,當成功啟動本地服務器后并在即將發生熱加載之前,此時人為刪除 _book
文件夾,會發生什么?
我的猜想是:
因為 gitbook
的熱加載機制是監聽本地文件目錄系統發生改變,進而停止服務器再重新啟動服務器.
當我們手動刪除了 _book
文件夾,對于 gitbook
來說,再觸發重啟服務器的那一刻來說,突然發現沒有 _book
文件夾,此時就不會刪除也不會新建時發生異常,相當于直接新建 _book
文件夾,變相把熱加載弄成了初始啟動模式!
希望蒼天不負我,如若不行,只能看源碼邏輯找 bug
了!
你猜猜會怎么樣? it works
!
在實驗中,
gitbook serve --log=debug
啟動本地服務器后,如果本地文件發生修改會重啟失敗!但是,如果在啟動本地服務器后立即刪除
_book
目錄,當本地文件發生修改時重啟服務就能成功了.
到此為止,總算找到一個解決方案,那就是啟動服務后立即刪除 _book
目錄.
不算完美的總結
windows
系統上啟動 gitbook
服務后,如果本地文件發生更改,熱加會失敗.
如果啟動服務器后立即刪除 _book
目錄,那么之后再怎么修改本地文件都能順利重啟.
目前還沒有找到問題的根源,下一次將深入源碼繼續探討到底是哪里出問題導致 Windows
系統無法重啟.
雖然及時刪除 _book
目錄并不算是很好的解決方案,但至少 markdown
灰姑娘又能化妝成 html
小姐姐了呢!