### Config File 設計 Config File 在寫程式時是一個必定會出現的事情,在 Javascript 的世界裏我們可以使用 JSON 檔案來儲存系統的 Config。而在使用 JSON 時又一定會使用到 Tree 的方法來儲存資料。看看以下的例子 `Config.json` : ```json { "app":{ "port":80, "db":{ "host":"db.abc.com", "port":3306, "user":"myuser", "password":"mypassword", "database":"myproject" } } } ``` 大概有 80% 的系統都會有以下的設定了,最基本的 Database 連線設定檔。 當我們要使用參數時,可以直接匯入要 JSON 檔案然後經 Object 存取資料。 ```js import Config from 'Config.json'; // connect to db const connectDB = () => { var host = Config.app.db.host || 'default host name'; var port = Config.app.db.port || 3306; var user = Config.app.db.user || 'default user'; var password = Config.app.db.password || 'default password'; var database = Config.app.db.database || 'default database'; }; ``` 以上的方法可以把資料從 Config 中讀取出來,還可以設定他們的預設值。但是有一個問題,就是如果 Config 的路徑內有其中一個環節斷掉,程式就會 throw error。例如 : ```js // config const Config = { "port":80, "db":{ "host":"db.abc.com", "port":3306, "user":"myuser", "password":"mypassword", "database":"myproject" } } // connect db const connectDB = () => { var host = Config.app.db.host || 'default host name'; var port = Config.app.db.port || 3306; var user = Config.app.db.user || 'default user'; var password = Config.app.db.password || 'default password'; var database = Config.app.db.database || 'default database'; }; ``` 因為 Config 中沒有 app 這個屬性存在,所以當運行到 assign host 那句時,就會 throw error 了 !!! ### 解決方法 要解決問題,可以加入檢查就可以了 : ```js // check every node of config path var host = (Config && Config.app && Config.app.db && Config.app.db.host? Config.app.db.host: undefined); ``` 以上方法可以確保萬無一失,不過又好像寫得太長 !! ### Configuration File 平整化 平整化就是把一個立體的 model 變成為一個單純的 array。我們可以通過 Database First Normalization Form 來達成目的。以下為例 : ```json { "app":{ "port":80, "db":{ "host":"db.abc.com", "port":3306, "user":"myuser", "password":"mypassword", "database":"myproject" } } } ``` 平整化後可以變成為 : ```json { "app":{ "port":80, "db":{ "host":"db.abc.com", "port":3306, "user":"myuser", "password":"mypassword", "database":"myproject" } }, "app.port":80, "app.db":{ "host":"db.abc.com", "port":3306, "user":"myuser", "password":"mypassword", "database":"myproject" }, "app.db.host":"db.abc.com", "app.db.port":3306, "app.db.user":"myuser", "app.db.password":"mypassword", "app.db.database":"myproject" } ``` 處理好後像 Config 的 Route 檔案,一個 KEY 可以對應到一個 VALUE。在使用上便簡單得多了。 ```js import Config from 'Config.json'; // connect to db const connectDB = () => { var host = Config['app.db.host'] || 'default host name'; var port = Config['app.db.port'] || 3306; var user = Config['app.db.user'] || 'default user'; var password = Config['app.db.password'] || 'default password'; var database = Config['app.db.database'] || 'default database'; }; ``` 這樣就算其中的一層參數繼掉了,也不會 throw error,而是回傳 `undefined`。 ### 如何實作平整化 由於 Config 是一種不轉變的資料,所以我們在 Build 時可以使用 Script 產生 Config 檔案。另一個方法是在 Runtime 是進行。而當然前者的效能會較為好,而後者就有更大的彈性。 ```js import Config from 'config'; /** * flat config */ const flatConfig = (config, path) => { // result var result = {}; // init config config = config || Config; // init path path = path || 'Config.'; // each config attribute for( var i in config ) { result[path + i] = config[i]; if( typeof config[i] === 'object' ) { result = { ...result, ...flatConfig(config[i], path + i + '.') }; } } // return return result; }; /** * read config attribute */ const readConfig = path => { // get config var config = flatConfig(); // return return config[path]; }; // get host var host = readConfig('Config.app.db.host'); ``` 上面使用了 Recursion 的方法來處理整個 tree model。大家可以使用自己的方法來實作也可以的喔 !