自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

從JavaScript到TypeScript - 模塊化和構(gòu)建

開(kāi)發(fā) 前端
TypeScript 帶來(lái)的最大好處就是靜態(tài)類型檢查,所以在從 JavaScript 轉(zhuǎn)向 TypeScript 之前,一定要認(rèn)識(shí)到添加類型定義會(huì)帶來(lái)額外的工作量,這是必要的代價(jià)。不過(guò),相對(duì)于靜態(tài)類型檢查帶來(lái)的好處,這些代價(jià)是值得的。當(dāng)然,TypeScript 允許不定義類型或者將所有類型定義為 any,但如果這樣做,TypeScript 帶來(lái)的大部分靜態(tài)檢查功能都會(huì)失去作用。

[[188004]]

TypeScript 帶來(lái)的***好處就是靜態(tài)類型檢查,所以在從 JavaScript 轉(zhuǎn)向 TypeScript 之前,一定要認(rèn)識(shí)到添加類型定義會(huì)帶來(lái)額外的工作量,這是必要的代價(jià)。不過(guò),相對(duì)于靜態(tài)類型檢查帶來(lái)的好處,這些代價(jià)是值得的。當(dāng)然,TypeScript 允許不定義類型或者將所有類型定義為 any,但如果這樣做,TypeScript 帶來(lái)的大部分靜態(tài)檢查功能都會(huì)失去作用,換言之,也就沒(méi)必要使用 TypeScript 了。

模塊化

在轉(zhuǎn)換之前還要注意的一個(gè)問(wèn)題就是模塊化。早期的 JavaScript 代碼基本上是每個(gè) HTML 頁(yè)面對(duì)應(yīng)一個(gè)或幾個(gè) JavaScript 腳本,那時(shí)候的 JavaScript 代碼中很少有模塊化的概念。不過(guò)隨著 Web 2.0 的興起,大量的工作從后端移到前端,JavaScript 程序變得越來(lái)越復(fù)雜,模塊化成為剛需,大量的模塊化框架隨之而來(lái),其中比較有名的有 RequestJS 及其帶來(lái)的 AMD 標(biāo)準(zhǔn),還有 SeaJS 帶來(lái)的 CMD 標(biāo)準(zhǔn)。而隨著 Node.js 的興起以及 JavaScript 的全棧化,又有了 CommonJS 標(biāo)準(zhǔn)。之后又出現(xiàn)了廣為使用的 SystemJS。當(dāng)然少不了 ES6 的模塊化標(biāo)準(zhǔn),雖然到目前為止 Node.js 和大部分瀏覽器都還不支持它。

TypeScript 本身支持兩種模塊化方式,一種是對(duì) ES6 的模塊的微小擴(kuò)展,另一種是在 ES6 發(fā)布之前本身模仿 C# 的命名空間。大部分使用命令空間的場(chǎng)景都可以使用 ES6 模塊化標(biāo)準(zhǔn)來(lái)代替。我們先來(lái)看一看兩種模塊化方式區(qū)別。

命名空間

使用命令空間寫(xiě)的 TS 腳本在轉(zhuǎn)譯成 JS 后,可以不使用任何模塊加載框架,直接在頁(yè)面中加載即可使用。不過(guò)很遺憾,這種方式轉(zhuǎn)義出來(lái)的 JS 程序不能直接在 Node.js 中使用。因?yàn)?tsc 不為會(huì)命名空間形式的模塊生成 modules.exports 對(duì)象以及 require 語(yǔ)句。

有一種情況例外。將所有 .ts 文件轉(zhuǎn)譯成一個(gè) .js,假設(shè)叫 all.js,那么它可以通過(guò) node all 來(lái)運(yùn)行。這種情況下不需要任何模塊的導(dǎo)入導(dǎo)出。

不過(guò)在瀏覽器環(huán)境中,嚴(yán)格的按照依賴順序引入生成的 .js 文件是可行的。早期沒(méi)有使用模塊化的 JS 文件就可以使用“命名空間”形式的模塊化寫(xiě)法,甚至可以將原來(lái)成百上千行的大型 JS 源文件,拆分成若干小的 TS 文件,再通過(guò) tsc --outfile 輸出單一 JS 文件來(lái)使用,這樣既能實(shí)現(xiàn)模塊化重構(gòu),又能不改變?cè)械?HTML(或其它動(dòng)態(tài)頁(yè)面文件)的代碼。

還有一點(diǎn)需要注意的是,在指定生成單一輸出文件的情況下,TypeScript 不會(huì)通過(guò)代碼邏輯去檢查模塊間的依賴關(guān)系。默認(rèn)情況下它會(huì)按文件名的字母序逐個(gè)轉(zhuǎn)譯 .ts 文件,除非源文件中通過(guò) /// <reference path="..." /> 明確指定了依賴項(xiàng)。

ES6 模塊

在 TypeScript 使用 ES6 模塊語(yǔ)法來(lái)實(shí)現(xiàn)模塊化的情況下,tsc 允許通過(guò) module 參數(shù)來(lái)指定生成的 .js 會(huì)應(yīng)用于何種模塊化框架,默認(rèn)的是 commonjs,其它比較常用的還有 amd、system 等。

顯然,如果原來(lái)的 JS 程序使用了 AMD 框架,在轉(zhuǎn)換成 TS 的時(shí)候,就可以使用 ES6 模塊寫(xiě)法,并通過(guò) tsc --module amd 來(lái)輸出對(duì)應(yīng)的 JS 文件,同樣不需要修改原來(lái)的頁(yè)面文件。

但是,如果原來(lái)的 JS 文件沒(méi)有使用任何模塊框架的情況下,轉(zhuǎn)換為采用 ES6 模塊寫(xiě)法的 TS 代碼,在構(gòu)建的時(shí)候就會(huì)麻煩一點(diǎn)。這種情況下即使構(gòu)建成單一輸出文件,仍然會(huì)需要模塊化框架的支持,比如需要 AMD 的 define 和 require,或者需要 System 的 API 支持。

為了避免引入模塊化框架,可以考慮以 commonjs 標(biāo)準(zhǔn)輸出 JS,然后通過(guò) Webpack 來(lái)把所有生成的 JS 打包成單一文件。這里既然用到了 Webpack,構(gòu)建配置就可以更靈活了,因?yàn)?Webpack 可以指定多個(gè) entry,可以有多個(gè)輸出,它會(huì)通過(guò) import ... 轉(zhuǎn)譯成的 require(...) 自動(dòng)檢查依賴項(xiàng)。而且 Webpack 還可以使用 ts-loader 直接處理 .ts 文件而不需要先使用 tsc 來(lái)進(jìn)行轉(zhuǎn)譯。如果在 TS 中用到了高版本 ECMAScript 語(yǔ)法,比如 async/await,還可以通過(guò) babel-loader 來(lái)增加一層處理……非常靈活。

但這里往往會(huì)有一個(gè)問(wèn)題,生成的 .js 中所有定義都不在全局范圍,那么腳本引入網(wǎng)頁(yè)之后,如何使用其中定義的內(nèi)容?這需要借助全局對(duì)象 window——這里不需要考慮 Node.js 的全局對(duì)象 global,因?yàn)樵?Node.js 下一般是采用模塊化的方式引入,不需要向全局對(duì)象注入什么東西。

向 window 注入對(duì)象(或函數(shù)、值等)的方法也很簡(jiǎn)單,分兩步:申明、賦值,比如:

  1. import MyApi from "./myapi"
  2.  
  3. declare global { 
  4.     interface Window { 
  5.         mime: MyApi; 
  6.     } 
  7.  
  8. window.mime = new MyApi();  

常用的構(gòu)建配置

我們?cè)缙陧?xiàng)目中使用 TypeScript 的命名空間,不過(guò)最近幾乎都重構(gòu)成 ES6 模塊方式了。由于會(huì)用到 async 函數(shù),所以一般會(huì)配置 TypeScript 輸出 ES2017 代碼,再通過(guò) Babel 轉(zhuǎn)譯成 ES5 代碼,***由 Webpack 打包輸出。

tsconfig.json

  1.     "compilerOptions": { 
  2.         "module""commonjs"
  3.         "target""es2017"
  4.         "lib": [ 
  5.             "dom"
  6.             "es6"
  7.             "dom.iterable"
  8.             "scripthost"
  9.             "es2017" 
  10.         ], 
  11.         "noImplicitAny"false
  12.         "sourceMap"false 
  13.     } 
  14.  

在 target 為 es5 或 es6 的時(shí)候,TypeScript 會(huì)有默認(rèn)的 lib 列表,這在官方文檔中有詳細(xì)說(shuō)明。target 定義為 es2017 是為了支持 async 函數(shù),但這個(gè)配置沒(méi)有默認(rèn) lib 列表,所以參考官方文檔對(duì) --target es6 使用的 lib 列表,補(bǔ)充 es2017 類型庫(kù)即可。

webpack.config.js

這里使用了 Webpack2 的配置格式。

  1. module.exports = { 
  2.     entry: { 
  3.         index"./js/index" 
  4.     }, 
  5.     output: { 
  6.         filename: "[name].js" 
  7.     }, 
  8.     devtool: "source-map"
  9.     resolve: { 
  10.         extensions: [".ts"
  11.     }, 
  12.     module: { 
  13.         rules: [ 
  14.             { 
  15.                 test: /\.ts$/, 
  16.                 use: [ 
  17.                     { 
  18.                         loader: "babel-loader"
  19.                         options: { 
  20.                             presets: ["es2015""stage-3"
  21.                         } 
  22.                     }, 
  23.                     "ts-loader" 
  24.                 ], 
  25.                 exclude: /node_modules/ 
  26.             } 
  27.         ] 
  28.     } 
  29. };  

gulp task

如果還使用 gulp,任務(wù)是這樣寫(xiě)的

  1. const gulp = require("gulp"); 
  2. const gutil = require("gulp-util"); 
  3.  
  4. // 轉(zhuǎn)譯JavaScript 
  5. gulp.task("webpack", () => { 
  6.     const webpack = require("webpack-stream"); 
  7.     const config = require("./webpack.config.js"); 
  8.     return gulp.src("./js/**/*.ts"
  9.         .pipe(webpack(config, require("webpack"))) 
  10.         .on("error"function(err) { 
  11.             gutil.log(err); 
  12.             this.emit("end"); 
  13.         }) 
  14.         .pipe(gulp.dest("../www/js")); 
  15. });  

這里需要注意的是 webpack-stream 默認(rèn)使用的是 webpack1,而我們的配置需要 webpack2,所以為它指定第二個(gè)參數(shù),一個(gè)特定版本的 webpack 實(shí)例 (由 require("webpack") 導(dǎo)入的)。

需要的 Node 模塊

從上面的構(gòu)建配置中不難總結(jié)出構(gòu)建過(guò)程需要安裝的 Node 模塊,有這樣一些

  • gulp
  • gulp-util
  • webpack-stream
  • webpack
  • ts-loader
  • typescript
  • babel-loader
  • babel-core
  • babel-preset-es2015
  • babel-preset-stage-3

在 Node.js 環(huán)境直接運(yùn)行 .ts

在 Node.js 中可以通過(guò) ts-node 包來(lái)直接運(yùn)行 TypeScript 代碼。需要做的只是在入口代碼文件(當(dāng)然是個(gè) .js 代碼)中添加一句

  1. require('ts-node').register({ /* options */ }) 

或者

  1. require('ts-node/register'

因?yàn)?Node.js 7.6 開(kāi)始已經(jīng)直接支持 async 函數(shù)語(yǔ)法,所以即使用到了這個(gè)語(yǔ)法,也不用擔(dān)心 ts-node 在內(nèi)存的轉(zhuǎn)譯結(jié)果不能運(yùn)行。

入口文件仍然必須是 .js 文件,這是個(gè)小小的遺憾,不過(guò)對(duì)于使用 Node.js 寫(xiě)構(gòu)建腳本的用戶來(lái)說(shuō),有兩個(gè)好消息:gulp 和 webpack 都直接支持 .ts 入口(或配置)文件。比如以 gulp 為例,可以定義 gulpfile.ts (注意擴(kuò)展名是 .ts) 如下

  1. import * as gulp from "gulp"
  2.  
  3. gulp.task("hello", () => { 
  4.     console.log("hello gulp"); 
  5. });  

不過(guò) gulp 也是通過(guò) ts-node 模塊來(lái)實(shí)現(xiàn)使用 TypeScript 的,而 ts-node 的功能依賴于 typescript,所以別忘了安裝這兩個(gè)模塊。 

責(zé)任編輯:龐桂玉 來(lái)源: segmentfault
相關(guān)推薦

2019-08-28 16:18:39

JavaScriptJS前端

2020-05-12 08:39:50

JavaScript工具技術(shù)

2015-11-23 09:50:15

JavaScript模塊化SeaJs

2017-02-13 18:46:38

Android模塊化組件化

2013-08-20 18:39:34

JavaScript模requireJS

2017-07-11 11:02:03

APP模塊化架構(gòu)

2010-08-02 08:54:53

Flex模塊化

2013-08-20 18:18:55

CSS模塊化Normalize.c

2013-08-20 15:31:18

前端模塊化

2017-05-18 10:23:55

模塊化開(kāi)發(fā)RequireJsJavascript

2020-09-17 10:30:21

前端模塊化組件

2015-10-10 11:29:45

Java模塊化系統(tǒng)初探

2020-09-18 09:02:32

前端模塊化

2022-03-11 13:01:27

前端模塊

2019-05-07 11:24:07

ReactJavascriptTypescript

2011-12-21 16:08:43

2021-06-10 18:40:32

ES 標(biāo)準(zhǔn)模塊化

2021-12-24 07:10:36

架構(gòu)分層模塊化

2021-12-02 05:57:04

模塊化UPS電源

2015-12-11 15:51:36

華為模塊化數(shù)據(jù)中心
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)