摘要:前情提要自動工具,前端打字員的自我救贖記第一次發布包經歷,是重構中的代碼是版本可以工作的代碼配置文件待導入的模塊引用模塊的文件引用模塊的方式忽略的模塊實現監聽文件的刪除和添加以上代碼主要使用了來監聽文件的變化。
前情提要
自動 Import 工具,前端打字員的自我救贖
記第一次發布npm包經歷,smart-import
GitHub:smart-import
develop是重構中的代碼
master是1.0版本可以工作的代碼
配置文件from:待導入的模塊
to:引用模塊的文件
template:引用模塊的方式
ignored:忽略的模塊
{ "from": "demo/pages/**/*.vue", "to": "demo/router/index.js", "template": "const moduleName = () => import(modulePath)", "ignored": [ "demo/pages/pageA.vue" ] }實現監聽文件的刪除和添加
#!/usr/bin/env node const path = require("path") const chokidar = require("chokidar") const config = JSON.parse(fs.readFileSync("smart-import.json")) class SmartImport { constructor({ from }) { this.from = from this.extname = path.extname(from) } watch() { chokidar .watch(this.from, { ignoreInitial: true }) .on("add", file => { console.log("add", file) }) .on("unlink", file => { console.log("unlink", file) }) } } let smartImport = new SmartImport(config) smartImport.watch()
以上代碼主要使用了chokidar來監聽文件的變化。但存在一個問題,如果刪除文件夾,而文件夾中包含匹配的模塊,不會觸發unlink事件。所以改成watch整個目錄,然后在add和unlink的回調中添加判斷文件后綴的代碼,因為我們可能只在意.vue,而不在意.js
... watch() { chokidar .watch(path.dirname(this.from), { ignoreInitial: true }) .on("add", file => { if (path.extname(file) === this.extname) { console.log("add", file) } }) .on("unlink", file => { if (path.extname(file) === this.extname) { console.log("unlink", file) } }) } ...
現在符合from的文件的變動(添加和刪除)都被監視了,但是總覺得
if (path.extname(file) === this.extname) { }
寫了兩遍,不開心
class SmartImport { constructor({ from }) { this.from = from this.extname = path.extname(from) this.checkExt = this.checkExt.bind(this) } watch() { const { from, checkExt } = this chokidar .watch(path.dirname(from), { ignoreInitial: true }) .on( "add", checkExt(file => { console.log("add", file) }) ) .on( "unlink", checkExt(file => { console.log("unlink", file) }) ) } checkExt(cb) { return file => { if (path.extname(file) === this.extname) { cb(file) } } } }
新添加了函數checkExt(),它的參數和返回值都是函數,只是添加了判斷文件后綴名的邏輯。
高階函數有木有!
函數式編程有木有!
另外就是注意通過this.checkExt = this.checkExt.bind(this),綁定this的指向。
文件的變動映射到數組中定義一個數組保存匹配的文件,另外匹配文件的變動會觸發doImport()事件
代碼就變成了這樣
class SmartImport { constructor({ from, ignored }) { this.from = from this.ignored = ignored this.extname = path.extname(from) this.modules = [] } watch() { const { from, ignored, extname, modules } = this chokidar .watch(path.dirname(from), { ignoreInitial: true, ignored }) .on( "add", this.checkExt(file => { console.log("add", file) modules.push(file) this.doImport() }) ) .on( "unlink", this.checkExt(file => { console.log("unlink", file) _.remove(modules, p => p === file) this.doImport() }) ) } checkExt(cb) { const { extname } = this return file => { if (path.extname(file) === extname) { cb(file) } } } doImport() { console.log("doImport...") console.log(this.modules) } }
注意,我又把this.checkExt = this.checkExt.bind(this)給刪了,還是直接通過this.checkExt()調用方便,雖然代碼看起來凌亂了。
另外就是把this.doImport()又寫了兩遍。嗯,思考一下。其實modules變化,就應該觸發doImport()。
發布-訂閱模式有木有
所以添加了個類ModuleEvent
class ModuleEvent { constructor() { this.modules = [] this.events = [] } on(event) { this.events.push(event) } emit(type, val) { if (type === "push") { this.modules[type](val) } else { _.remove(this.modules, p => p === val) } for (let i = 0; i < this.events.length; i++) { this.events[i].apply(this, [type, this.modules]) } } }
同時修改類SmartImport
class SmartImport { constructor({ from, ignored }) { this.from = from this.ignored = ignored this.extname = path.extname(from) this.moduleEvent = new ModuleEvent() } init() { this.moduleEvent.on((type, modules) => { this.doImport(type, modules) }) this.watch() } watch() { const { from, ignored, extname, modules } = this chokidar .watch(path.dirname(from), { ignoreInitial: true, ignored }) .on( "add", this.checkExt(file => { console.log("add", file) this.moduleEvent.emit("push", file) }) ) .on( "unlink", this.checkExt(file => { console.log("unlink", file) this.moduleEvent.emit("remove", file) }) ) } checkExt(cb) { const { extname } = this return file => { if (path.extname(file) === extname) { cb(file) } } } doImport(type, modules) { console.log(`type: ${type}`) console.log(modules) } } let smartImport = new SmartImport(config) smartImport.init()
終于理解了很多庫中on方法的原理有木有!對象中有個events,專門存這些回調函數有木有
另外我們觀察chokidar.on(eventType, cb),對比自己的moduleEvent.on(cb)。想想也是,也許我只想監聽特定的事件呢
修改ModuleEvent
class ModuleEvent { constructor({ from, ignored }) { this.modules = glob.sync(from, { ignore: ignored }) this.events = {} } on(type, cb) { if (!this.events[type]) { this.events[type] = [] } this.events[type].push(cb) } emit(type, val) { if (type === "push") { this.modules[type](val) } else { _.remove(this.modules, p => p === val) } for (let i = 0; i < this.events[type].length; i++) { this.events[type][i].apply(this, [this.modules]) } } }
后來覺得這個套路挺常見,將其抽象出來,最后形成代碼如下
#!/usr/bin/env node const fs = require("fs") const path = require("path") const glob = require("glob") const chokidar = require("chokidar") const _ = require("lodash") const config = JSON.parse(fs.readFileSync("smart-import.json")) const CustomEvent = (() => { let events = {} let on = (type, cb) => { if (!events[type]) { events[type] = [] } events[type].push(cb) } let emit = (type, data) => { for (let i = 0; i < events[type].length; i++) { events[type][i].apply(this, [data]) } } return { on, emit } })() class SmartImport { constructor({ from, ignored }) { this.from = from this.ignored = ignored this.extname = path.extname(from) this.modules = glob.sync(from, { ignore: ignored }) } init() { CustomEvent.on("push", m => { console.log("Do pushing") this.modules.push(m) }) CustomEvent.on("remove", m => { console.log("Do removing") _.remove(this.modules, p => p === m) }) this.watch() } watch() { const { from, ignored, extname, modules } = this chokidar .watch(path.dirname(from), { ignoreInitial: true, ignored }) .on( "add", this.checkExt(file => { CustomEvent.emit("push", file) }) ) .on( "unlink", this.checkExt(file => { CustomEvent.emit("remove", file) }) ) } checkExt(cb) { const { extname } = this return file => { if (path.extname(file) === extname) { cb(file) } } } } let smartImport = new SmartImport(config) smartImport.init()未完待續
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/92502.html
摘要:故事背景前情提要自動工具,前端打字員的自我救贖的功能根據配置文件,在目標文件中自動導入規定目錄下自定義模塊,并監聽規定目錄下文件的變動,自動更新尚在測試中的使用安裝工具編寫配置文件需要自動導入的模塊的后綴名自動導入的模塊的來源目 故事背景 前情提要:自動 Import 工具,前端打字員的自我救贖 github: smart-import smart-import 的功能 根據配置文件...
摘要:無論如何,單元測試一直是一中非常重要卻常常被忽視的技能。在實踐中,重構的要求是很高的它需要有足夠詳盡的單元測試,需要有持續集成的環境,需要隨時隨地在小步伐地永遠讓代碼處于可工作狀態下去進行改善。 showImg(https://segmentfault.com/img/bVbttWF?w=1000&h=528); 五月初的時候朋友和我說《重構》出第 2 版了,我才興沖沖地下單,花了一個...
摘要:難以通過重構手法完成設計的改動先想像重構的情況。何時不該重構現有代碼根本不能正常運作。現在,我可以修改這個子類而不必承擔午一中影響另一處的風險。 重構:對軟件內部結構的一種調整,目的是再不改變軟件的可觀察行為的前提下,提高其可理解性,降低其修改成本。 兩頂帽子 添加新功能 添加新功能時不應該修改既有代碼,只管添加新功能,通過測試重構 重構時你就不能再添加功能,只管改進程序結構,此時...
摘要:改進代碼設計的一個重要原則就是消除重復代碼使軟件更容易被理解優秀的代碼能夠讓接收你代碼的付出更少的學習成本。重構更容易找到重構能加深對代碼的理解。可以重構的情況添加功能時可以重構。說明你沒有發現代碼的錯誤。需要重構復審代碼時可以重構。 為何重構 重構不是銀彈,但是幫助你達到以下幾個目的 改進軟件設計 不良的程序需要更多的代碼。而代碼越多,正確的修改就越困難。改進代碼設計的一個重要原則就...
摘要:重構改善既有代碼設計動詞使用一系列重構手法,在不改變軟件可觀察行為的前提下,調整其結構。修補錯誤時重構代碼時重構怎么重構關于代碼的重構技巧參考重構改善既有代碼設計讀書筆記代碼篇個人博客 重構定義 名詞 對軟件內部結構的一種調整,目的是在不改變軟件可觀察行為的前提下,提高其可理解性,降低其修改成本。——《重構-改善既有代碼設計》 動詞 使用一系列重構手法,在不改變軟件可觀察行為的前提下,...
閱讀 3025·2021-11-24 10:21
閱讀 1596·2021-10-11 10:57
閱讀 2811·2021-09-22 15:24
閱讀 2666·2021-09-22 14:58
閱讀 2334·2019-08-30 13:16
閱讀 3483·2019-08-29 13:05
閱讀 3417·2019-08-29 12:14
閱讀 3451·2019-08-27 10:55