摘要:第一個完全使用重構的純項目已經上線并穩定運行了。測試用例的改造前邊的改為大多數原因是因為強迫癥所致。但是測試用例的改造則是一個能極大提高效率的操作。
最近的一段時間一直在搞TypeScript,一個巨硬出品、賦予JavaScript語言靜態類型和編譯的語言。
第一個完全使用TypeScript重構的純Node.js項目已經上線并穩定運行了。
第二個前后端的項目目前也在重構中,關于前端基于webpack的TypeScript套路之前也有提到過:TypeScript在react項目中的實踐。
但是這些做完以后也總感覺缺了點兒什么 _(沒有盡興)_:
是的,依然有五分之一的JavaScript代碼存在于項目中,作為一個TypeScript的示例項目,表現的很不純粹。
所以有沒有可能將這些JavaScript代碼也換成TypeScript呢?
答案肯定是有的,首先需要分析這些代碼都是什么:
Webpack打包時的配置文件
一些簡單的測試用例(使用的mocha和chai)
知道了是哪些地方還在使用JavaScript,這件事兒就變得很好解決了,從構建工具(Webpack)開始,逐個擊破,將這些全部替換為TypeScript。
Webpack 的 TypeScript 實現版本在這8102年,很幸福,Webpack官方已經支持了TypeScript編寫配置文件,文檔地址。
除了TypeScript以外還支持JSX和CoffeeScript的解釋器,在這就忽略它們的存在了
首先是要安裝TypeScript相關的一套各種依賴,包括解釋器及該語言的核心模塊:
npm install -D typescript ts-node
typescript為這個語言的核心模塊,ts-node用于直接執行.ts文件,而不需要像tsc那樣會編譯輸出.js文件。
ts-node helloworld.ts
因為要在TypeScript環境下使用Webpack相關的東東,所以要安裝對應的types。
也就是Webpack所對應的那些*.d.ts,用來告訴TypeScript這是個什么對象,提供什么方法。
npm i -D @types/webpack
一些常用的pLugin都會有對應的@types文件,可以簡單的通過npm info @types/XXX來檢查是否存在
如果是一些小眾的plugin,則可能需要自己創建對應的d.ts文件,例如我們一直在用的qiniu-webpack-plugin,這個就沒有對應的@types包的,所以就自己創建一個空文件來告訴TypeScript這是個啥:
declare module "qiniu-webpack-plugin" // 就一個簡單的定義即可 // 如果還有其他的包,直接放到同一個文件就行了 // 文件名也沒有要求,保證是 d.ts 結尾即可
放置的位置沒有什么限制,隨便丟,一般建議放到types文件夾下
最后就是.ts文件在執行時的一些配置文件設置。
用來執行Webpack的.ts文件對tsconfig.json有一些小小的要求。
compilerOptions下的target選項必須是es5,這個代表著輸出的格式。
以及module要求選擇commonjs。
{ "compilerOptions": { "module": "commonjs", "target": "es5", "esModuleInterop": true } }
但一般來講,執行Webpack的同級目錄都已經存在了tsconfig.json,用于實際的前端代碼編譯,很可能兩個配置文件的參數并不一樣。
如果因為要使用Webpack去修改真正的代碼配置參數肯定是不可取的。
所以我們就會用到這么一個包,用來改變ts-node執行時所依賴的配置文件:tsconfig-paths
在Readme中發現了這樣的說法:If process.env.TS_NODE_PROJECT is set it will be used to resolved tsconfig.json。
在Webpack的文檔中同樣也提到了這句,所以這是一個兼容的方法,在命令運行時指定一個路徑,在不影響原有配置的情況下創建一個供Webpack打包時使用的配置。
將上述的配置文件改名為其它名稱,Webpack文檔示例中為tsconfig-for-webpack-config.json,這里就直接沿用了
然后添加npm script如下
{ "scripts": { "build": "TS_NODE_PROJECT=tsconfig-for-webpack-config.json webpack --config configs.ts" } }文件的編寫
關于配置文件,從JavaScript切換到TypeScript實際上并不會有太大的改動,因為Webpack的配置文件大多都是寫死的文本/常量。
很多類型都是自動生成的,基本可以不用手動指定,一個簡單的示例:
import { Configuration } from "webpack" const config: Configuration = { mode: process.env.NODE_ENV === "production" ? "production" : "development", } export default config
Configuration是一個Webpack定義的接口(interface),用來規范一個對象的行為。
在VS Code下按住Command + 單擊可以直接跳轉到具體的webpack.d.ts定義文件那里,可以看到詳細的定義信息。
各種常用的規則都寫在了這里,使用TypeScript的一個好處就是,當要實現一個功能時你不再需要去網站上查詢應該要配置什么,可以直接翻看d.ts的定義。
如果注釋寫得足夠完善,基本可以當成文檔來用了,而且在VS Code編輯器中還有動態的提示,以及一些錯誤的糾正,比如上述的NODE_ENV的獲取,如果直接寫process.env.NODE_ENV || "development"是會拋出一個異常的,因為從d.ts中可以看到,關于mode只有三個有效值production、developemnt和none,而process.env.NODE_ENV顯然只是一個字符串類型的變量。
所以我們需要使用三元運算符保證傳入的參數一定是我們想要的。
以及在編寫的過程中,如果有一些自定義的plugin之類的,可能在使用的過程中會拋異常提示說某個對象不是有效的Plugin對象,一個很簡單的方法,在對應的plugin后邊添加一個as webpack.Plugin即可。
在這里TypeScript所做的只是靜態的檢查,并不會對實際的代碼執行造成任何影響,就算類型因為強行as而改變,也只是編譯期的修改,在實際執行的JavaScript代碼中還是弱類型的
在完成了上述的操作后,再執行npm run XXX就可以直接運行TypeScript版本的Webpack配置咯。
探索期間的一件趣事因為我的項目根目錄已經安裝了ts-node,而前端項目是作為其中的一個文件夾存在的,所以就沒有再次進行安裝。
這就帶來了一個令人吐血的問題。
首先全部流程走完以后,我直接在命令行中輸入TS_NODE_PROJECT=XXX.json NODE_ENV=dev webpack --config ./webpack/dev.ts
完美運行,然后將這行命令放到了npm scripts中:
{ "scripts": { "start": "TS_NODE_PROJECT=XXX.json NODE_ENV=dev webpack --config ./webpack/dev.ts" } }
再次運行npm start,發現竟然出錯了-.-,提示我說import語法不能被識別,這個很顯然就是沒有應用我們在ts_NODE_PROJECT中指定的config文件。
剛開始并不知道問題出在哪,因為這個在命令行中直接執行并沒有任何問題。
期間曾經懷疑是否是環境變量沒有被正確設置,還使用了cross-env這個插件,甚至將命令寫到了一個sh文件中進行執行。
然而問題依然存在,后來在一個群中跟小伙伴們聊起了這個問題,有人提出,__你是不是全局安裝了ts-node__。
檢查以后發現,果然是的,在命令行執行時使用的是全局的ts-node,但是在npm scripts中使用的是本地的ts-node。
在命令行環境執行時還以為是會自動尋找父文件夾node_modules下邊的依賴,其實是使用的全局包。
乖乖的在client-src文件夾下也安裝了ts-node就解決了這個問題。
全局依賴害人。。
前邊的Webpack改為TypeScript大多數原因是因為強迫癥所致。
但是測試用例的TypeScript改造則是一個能極大提高效率的操作。
測試用例使用chai來編寫,_(之前的Postman也是用的chai的語法)_
chai提供了一系列的語義化鏈式調用來實現斷言。
在之前的分享中也提到過,這么多的命令你并不需要完全記住,只知道一個expect(XXX).to.equal(true)就夠了。
但是這樣的通篇to.equal(true)是巨丑無比的,而如果使用那些語義化的鏈式調用,在不熟練的情況下很容易就會得到:
Error: XXX.XXX is not a function
因為這確實有一個門檻問題,必須要寫很多才能記住調用規則,各種not、includes的操作。
但是接入了TypeScript以后,這些問題都迎刃而解了。
也是前邊提到的,所有的TypeScript模塊都有其對應的.d.ts文件,用來告訴我們這個模塊是做什么的,提供了什么可以使用。
也就是說在測試用例編寫時,我們可以通過動態提示來快速的書寫斷言,而不需要結合著文檔去進行“翻譯”。
如果是之前有寫過mocha和chai的童鞋,基本上修改文件后綴+安裝對應的@types即可。
可以直接跳到這里來:開始編寫測試腳本
但是如果對測試用例感興趣,但是并沒有使用過的童鞋,可以看下邊的一個基本步驟。
TypeScript相關的安裝,npm i -D typescript ts-node
Mocha、chai相關的安裝,npm i -D mocha chai @types/mocha @types/chai
如果需要涉及到一些API的請求,可以額外安裝chai-http,npm i -D chai-http @types/chai-http
環境的依賴就已經完成了,如果額外的使用一些其他的插件,記得安裝對應的@types文件即可。
如果有使用ESLint之類的插件,可能會提示modules必須存在于dependencies而非devDependencies
這是ESLint的import/no-extraneous-dependencies規則導致的,針對這個,我們目前的方案是添加一些例外:
import/no-extraneous-dependencies: - 2 - devDependencies: - "**/*.test.js" - "**/*.spec.js" - "**/webpack*" - "**/webpack/*"
針對這些目錄下的文件/文件夾不進行校驗。_是的,webpack的使用也會遇到這個問題_
開始編寫測試腳本如果是對原有的測試腳本進行修改,無外乎修改后綴、添加一些必要的類型聲明,不會對邏輯造成任何修改。
一個簡單的示例// number-comma.ts export default (num: number | string) => String(num).replace(/B(?=(d{3})+$)/g, ",") // number-comma.spec.ts import chai from "chai" import numberComma from "./number-comma" const { expect } = chai // 測試項 describe("number-comma", () => { // 子項目1 it("`1234567` should transform to `1,234,567`", done => { expect(numberComma(1234567)).to.equal("1,234,567") done() }) // 子項目2 it("`123` should never transform", done => { const num = 123 expect(numberComma(num)).to.equal(String(num)) done() }) })
如果全局沒有安裝mocha,記得將命令寫到npm script中,或者通過下述方式執行
./node_modules/mocha/bin/mocha -r ts-node/register test/number-comma.spec.ts # 如果直接這樣寫,會拋出異常提示 mocha 不是命令 mocha -r ts-node/register test/number-comma.spec.ts
mocha有一點兒比較好的是提供了-r命令來讓你手動指定執行測試用例腳本所使用的解釋器,這里直接設置為ts-node的路徑ts-node/register,然后就可以在后邊直接跟一個文件名(或者是一些通配符)。
目前我們在項目中批量執行測試用例的命令如下:
{ "scripts": { "test": "mocha -r ts-node/register test/**/*.spec.ts" } }
npm test可以直接調用,而不需要添加run命令符,類似的還有start、build等等
一鍵執行以后就可以得到我們想要的結果了,再也不用擔心一些代碼的改動會影響到其他模塊的邏輯了 (前提是認真寫測試用例)
小結做完上邊兩步的操作以后,我們的項目就實現了100%的TypeScript化,在任何地方享受靜態編譯語法所帶來的好處。
附上更新后的代碼含量截圖:
最近針對TypeScript做了很多事情,從Node.js、React以及這次的Webpack與Mocha+Chai。
TypeScript因為其存在一個編譯的過程,極大的降低了代碼出bug的可能性,提高程序的穩定度。
全面切換到TypeScript更是能夠降低在兩種語法之間互相切換時所帶來的不必要的消耗,祝大家搬磚愉快。
TypeScript在node項目中的實踐
TypeScript在react項目中的實踐
一個完整的 TypeScript 示例typescript-example
歡迎各位來討論關于TypeScript使用上的一些問題,針對穩重的感覺不足之處也歡迎指出。
參考資料ts-node
configuration-languages | webpack
mochajs
chaijs
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/97309.html
摘要:斯坦福宣布使用作為計算機課程的首選語言近日,某位有年教學經驗的斯坦福教授決定放棄,而使用作為計算機入門課程的教學語言。斯坦福官方站點將它們新的課程描述為是最流行的構建交互式的開發語言,本課程會用講解中的實例。 前端每周清單第 11 期:Angular 4.1支持TypeScript 2.3,Vue 2.3優化服務端渲染,優秀React界面框架合集 為InfoQ中文站特供稿件,首發地址為...
摘要:前端每周清單專注前端領域內容,以對外文資料的搜集為主,幫助開發者了解一周前端熱點分為新聞熱點開發教程工程實踐深度閱讀開源項目巔峰人生等欄目。背后的故事本文是對于年之間世界發生的大事件的詳細介紹,闡述了從提出到角力到流產的前世今生。 前端每周清單專注前端領域內容,以對外文資料的搜集為主,幫助開發者了解一周前端熱點;分為新聞熱點、開發教程、工程實踐、深度閱讀、開源項目、巔峰人生等欄目。歡迎...
摘要:背景需要包寫起來爽,然而如果遇到沒有現成的化的工具函數,就需要自己想辦法弄出一份類型聲明文件了。最為重要的是,這種遷移方面我們可以隨意自定義化中所需要的工具函數,遷移粒度都可以由自己控制。 1、背景 1.1、需要 TS 包 TypeScript 寫起來爽,然而如果遇到沒有現成的 TS 化的工具函數,就需要自己想辦法弄出一份類型聲明文件了。 前兩天要寫的小工具庫(Typescript 語...
摘要:承接前一篇做一個合格的前端,自動化構建工具入門教程故而整理了如下插件資源大全。接下來我會逐一開源觀點網開發過程中的前后端技術,如全文索引自定義富文本編輯器圖片上傳壓縮水印等等。 承接前一篇《做一個合格的前端,gulp自動化構建工具入門教程》故而整理了如下gulp插件資源大全。**【我的新作觀點網:http://www.guandn.com (觀點網是一個獵獲新奇、收獲知識、重在獨立思考...
摘要:運行時用來創建實例渲染并處理虛擬等的代碼。基本上就是除去編譯器的其它一切。版本可以通過標簽直接用在瀏覽器中。為這些打包工具提供的默認文件是只有運行時的構建。為瀏覽器提供的用于在現代瀏覽器中通過直接導入。 Vue版本:2.6.9 源碼結構圖 ├─ .circleci // 包含CircleCI持續集成/持續部署工具的配置文件 ├─ .github ...
閱讀 2344·2021-11-23 09:51
閱讀 1999·2021-10-14 09:43
閱讀 2760·2021-09-27 13:35
閱讀 1144·2021-09-22 15:54
閱讀 2495·2021-09-13 10:36
閱讀 3785·2019-08-30 15:56
閱讀 3404·2019-08-30 14:09
閱讀 1711·2019-08-30 12:57