gitbook 入门教程之解决windows热加载失败问题
破鏡如何貼花黃
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 目錄
- 加載依賴插件,若沒有找到相應插件會報錯,提示運行 gitbook install 安裝插件.
- 掃描頁面和靜態資源文件
- 讀取配置文件并初始化
- 拷貝樣式資源和插件資源
- 開始生成單獨頁面,依次執行 page:before ,page 回調函數,全部頁面執行完畢后執行 finish:before 和 finish 回調函數.
- 生成搜索文件
- 啟動完畢,輸出成功信息
默認情況下服務器啟動后會占用兩個端口,一個是對外暴露的 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 filesgit-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.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 文件.
回想到版本號規范,可能 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 小姐姐了呢!
轉載于:https://www.cnblogs.com/snowdreams1006/p/10834754.html
總結
以上是生活随笔為你收集整理的gitbook 入门教程之解决windows热加载失败问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 中国银行信用卡怎么查卡号?查询方法有这些
- 下一篇: python第十九天(random、js