gitbook 入門教程之解決windows熱載入失敗問題
破鏡如何貼花黃
gitbook
在Windows
系統無法熱載入,總是報錯!
gitbook
是一款文件編寫利器,可以方便地 markdown
輸出成美觀優雅的 html
,gitbook serve
啟動伺服器後,原來相貌平平的 markdown
醜小鴨搖身一變就成了傾國傾城的 html
絕色佳人.
如果原始檔發生更改,Windows
卻無法按照預期那樣重啟伺服器,直接丟擲一個異常,立即終止了 markdown
的化妝.
Restart after change in file README.md Stopping server events.js:183 throw 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.md
Stopping server
debug: readme found at README.md
debug: summary file found at SUMMARY.md
debug: cleanup folder "G:\sublime\gitbook-test\_book"
events.js:174
throw 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:174
throw 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.js
11 directories, 2 files
Administrator@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.3
Run "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.1
Tags:
latest : 2.6.9
pre : 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
[email protected] C:\Users\SNOWDR~1\AppData\Local\Temp\tmp-8912hSrxNvTCrFEH\node_modules\gitbook
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
└── [email protected] ([email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected])
GitBook 4.0.0-alpha.6 has been installed
先看一下本地安裝 gitbook
版本,確保待會執行時使用最新的 4.0.0-alpha.6
版本.
# 列出本地已安裝版本
$ gitbook ls
GitBook Versions Installed:
* 4.0.0-alpha.6
3.2.3
Run "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.1
Tags:
latest : 2.6.9
pre : 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:174
throw 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
小姐姐了