gitbook 入门教程之解决windows热加载失败问题
破鏡如何貼花黃
gitbook 在 Windows 系統(tǒng)無法熱加載,總是報錯!
gitbook 是一款文檔編寫利器,可以方便地 markdown 輸出成美觀優(yōu)雅的 html ,gitbook serve 啟動服務(wù)器后,原來相貌平平的 markdown 丑小鴨搖身一變就成了傾國傾城的 html 絕色佳人.
如果源文件發(fā)生更改,Windows 卻無法按照預(yù)期那樣重啟服務(wù)器,直接拋出一個異常,立即終止了 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'對鏡貼花黃
現(xiàn)在看一下 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根據(jù)上述輸出日志,我們可以分析出 gitbook 的基本運行流程.
- 加載 readme 和 summary 文件,若存在 glossary 文件也會加載,并刪除 _book 目錄
- 加載依賴插件,若沒有找到相應(yīng)插件會報錯,提示運行 gitbook install 安裝插件.
- 掃描頁面和靜態(tài)資源文件
- 讀取配置文件并初始化
- 拷貝樣式資源和插件資源
- 開始生成單獨頁面,依次執(zhí)行 page:before ,page 回調(diào)函數(shù),全部頁面執(zhí)行完畢后執(zhí)行 finish:before 和 finish 回調(diào)函數(shù).
- 生成搜索文件
- 啟動完畢,輸出成功信息
默認情況下服務(wù)器啟動后會占用兩個端口,一個是對外暴露的 4000 端口,用于瀏覽器訪問項目.
另外一個是 35729 端口,用于監(jiān)聽本地文件變化,重啟服務(wù)器進而實現(xiàn)熱加載功能.
本地服務(wù)器啟動后我們就可以訪問 http://localhost:4000 預(yù)覽靜態(tài)網(wǎng)站效果,markdown 源文件華麗演變成 html 富文本文件.
破鏡怎化妝
不幸的是,Windows 熱加載可能會有問題,也就是說如果啟動服務(wù)器后,本地文件發(fā)生改變,此時會觸發(fā)熱加載功能而報錯 Error: EPERM: operation not permitted ,這樣一來瀏覽器又無法訪問了.
剛剛變身的 markdown 瞬間又被打回原形,無法欣賞化妝后的容顏了,這樣的體驗相當(dāng)不好!
邊化妝邊照鏡子才是做到心中有譜,隨時調(diào)整,如果不照鏡子而直接化妝,那不是一般人能做到的.
gitbook 啟動本地服務(wù)器給我們提供了鏡子,但熱加載失敗又把鏡子摔碎了,還怎么愉快的化妝?
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)尋醫(yī)問診修破鏡
現(xiàn)在問題已經(jīng)復(fù)現(xiàn),接下來就要開始尋醫(yī)問診,試圖讓破鏡重圓,好讓 markdown 灰姑娘變成人見人愛的 html 小姐姐.
根據(jù)報錯信息描述,定位到刪除 _book 目錄再次創(chuàng)建該目錄時,提示 EPERM: operation not permitted ,即無權(quán)操作.
柯南附體
既然說是操作權(quán)限的問題,那我們看一下 _book 目錄現(xiàn)在是怎樣狀態(tài)吧!
$ ls gitbook-errorforwindows-preview.png README.md SUMMARY.md當(dāng)前項目已經(jīng)沒有 _book 目錄,證明發(fā)生報錯時確實已經(jīng)刪除了 _book 目錄,但是某種原因無權(quán)再次創(chuàng)建該文件夾而重啟失敗.
然而,這只是表現(xiàn)現(xiàn)象,老師告訴我們,要透過現(xiàn)象看本質(zhì),即使現(xiàn)在沒有 _book 文件再次啟動服務(wù)器還是會啟動成功并創(chuàng)建 _book 文件的,所以真想只有一個!
那就是,gitbook 控制臺在說謊!
雖然排除了 gitbook 無權(quán)創(chuàng)建 _book 目錄的嫌疑,那又怎么解釋重啟服務(wù)器卻沒能創(chuàng)建 _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 .
分析發(fā)現(xiàn): FSWatcher._handleError 是私有方法,作用是處理異常信息,和這起事故關(guān)聯(lián)不大.
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)}; }遺憾的是,仍然沒有找到具體問題,那就繼續(xù)看一下一條線索.
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 filesgit-bash 命令行正常沒有 tree 命令,如需擴展參考我另外一篇文章.
經(jīng)過肉眼驗證,發(fā)現(xiàn) events.js 根本就沒有 174 行文件,所以這兩個文件大都不是目標文件.
既然命令行中無法找到目標文件,那就請專業(yè)的搜索工具全系統(tǒng)查找這兩個文件吧,這里使用的是 Everything 搜索工具.
然并卵,依然沒有找到目標文件.
畢竟不是柯南,沒有發(fā)現(xiàn)真相
求助官方
gitbook 可是開源產(chǎn)品,出現(xiàn)問題的應(yīng)該不止我一個,所以去 github 看看有沒有遇到和我一樣的問題.
雖然找到了志同道合的小伙伴,但是并沒有提供解決方案,連官方都放棄了,那我還有什么可留戀的?
點擊查看 gitbook serve livereload error
自己動手
最害怕的不是 bug,而是發(fā)現(xiàn)了 bug 卻無法定位,雖然控制臺有報錯信息但是沒有找到真正的文件!
首先確認下當(dāng)前系統(tǒng)版本,然后采取版本切換方式測試其他版本是否存在該問題.
$ gitbook --version CLI version: 2.3.2 GitBook version: 3.2.3- 升級到最新版
gitbook ls 是列出當(dāng)前已安裝的版本,而 gitbook ls-remote 則是列出遠程服務(wù)器版本.
# 列出本地已安裝版本 $ 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目前最新發(fā)布版本是 3.2.3 ,而我們本地已安裝的版本正是該版本,所以現(xiàn)在應(yīng)該測試 4.0.0-alpha.6 版.
看到 4.0.0-alpha.6 心里有些忐忑,根據(jù)版本管理約定,版本號一般有三部分組成,第一部分代表不兼容的重大升級,第二部分代表主干兼容的功能升級,第三部分是小版本修復(fù).
由 3.2.3 直接跨度到 4.0.0-alpha.6 意味著 gitbook 發(fā)生了重大重構(gòu)!
算了,先下載試試看!
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.# 列出當(dāng)前正在使用版本 $ gitbook current GitBook version is 3.2.3gitbook 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 文件.
回想到版本號規(guī)范,可能 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'此路不通,再換一條,既然向上無法處理,那向下回退會不會有結(jié)果呢?
- 回退版本
當(dāng)前系統(tǒng)版本是 3.2.3,最新測試版本是 4.0.0-alpha.6 ,然而最近一次提交的版本卻是 2.6.9 ?
為什么 gitbook-ci 管理的 gitbook 版本號會突然跳水,會不會有什么貓膩,難不成修復(fù)了什么 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重回現(xiàn)場
現(xiàn)在把目光再次聚焦到最初的案發(fā)現(xiàn)場,這一次只能背水一戰(zhàn)了,自己動手要么豐衣足食要么餓死凍死!
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)關(guān)于上述錯誤描述中,在真相只有一個章節(jié)中已經(jīng)探討過,當(dāng)時得出的結(jié)論是 gitbook 是刪除 _book 文件夾再新建 _book 文件夾時發(fā)生了意外.
如果這個行為不是由 gitbook 發(fā)生而是由我們手動干預(yù)的話,也就是說,當(dāng)成功啟動本地服務(wù)器后并在即將發(fā)生熱加載之前,此時人為刪除 _book 文件夾,會發(fā)生什么?
我的猜想是:
因為 gitbook 的熱加載機制是監(jiān)聽本地文件目錄系統(tǒng)發(fā)生改變,進而停止服務(wù)器再重新啟動服務(wù)器.
當(dāng)我們手動刪除了 _book 文件夾,對于 gitbook 來說,再觸發(fā)重啟服務(wù)器的那一刻來說,突然發(fā)現(xiàn)沒有 _book 文件夾,此時就不會刪除也不會新建時發(fā)生異常,相當(dāng)于直接新建 _book 文件夾,變相把熱加載弄成了初始啟動模式!
希望蒼天不負我,如若不行,只能看源碼邏輯找 bug 了!
你猜猜會怎么樣? it works !
在實驗中,gitbook serve --log=debug 啟動本地服務(wù)器后,如果本地文件發(fā)生修改會重啟失敗!
但是,如果在啟動本地服務(wù)器后立即刪除 _book 目錄,當(dāng)本地文件發(fā)生修改時重啟服務(wù)就能成功了.
到此為止,總算找到一個解決方案,那就是啟動服務(wù)后立即刪除 _book 目錄.
不算完美的總結(jié)
windows 系統(tǒng)上啟動 gitbook 服務(wù)后,如果本地文件發(fā)生更改,熱加會失敗.
如果啟動服務(wù)器后立即刪除 _book 目錄,那么之后再怎么修改本地文件都能順利重啟.
目前還沒有找到問題的根源,下一次將深入源碼繼續(xù)探討到底是哪里出問題導(dǎo)致 Windows 系統(tǒng)無法重啟.
雖然及時刪除 _book 目錄并不算是很好的解決方案,但至少 markdown 灰姑娘又能化妝成 html 小姐姐了呢!
轉(zhuǎn)載于:https://www.cnblogs.com/snowdreams1006/p/10834754.html
總結(jié)
以上是生活随笔為你收集整理的gitbook 入门教程之解决windows热加载失败问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 中国银行信用卡怎么查卡号?查询方法有这些
- 下一篇: 面试官: 用css实现android系统