99re热这里只有精品视频,7777色鬼xxxx欧美色妇,国产成人精品一区二三区在线观看,内射爽无广熟女亚洲,精品人妻av一区二区三区

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

2018-08-28 20:34 更新

TypeScript 帶來(lái)的最大好處就是靜態(tài)類(lèi)型檢查,所以在從 JavaScript 轉(zhuǎn)向 TypeScript 之前,一定要認(rèn)識(shí)到添加類(lèi)型定義會(huì)帶來(lái)額外的工作量,這是必要的代價(jià)。不過(guò),相對(duì)于靜態(tài)類(lèi)型檢查帶來(lái)的好處,這些代價(jià)是值得的。當(dāng)然,TypeScript 允許不定義類(lèi)型或者將所有類(lèi)型定義為 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)格的按照依賴(lài)順序引入生成的 .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ò)代碼邏輯去檢查模塊間的依賴(lài)關(guān)系。默認(rèn)情況下它會(huì)按文件名的字母序逐個(gè)轉(zhuǎn)譯 .ts 文件,除非源文件中通過(guò) /// <reference path="..." /> 明確指定了依賴(lài)項(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 的 definerequire,或者需要 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)檢查依賴(lài)項(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)單,分兩步:申明、賦值,比如:

import MyApi from "./myapi";


declare global {
    interface Window {
        mime: MyApi;
    }
}


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

{
    "compilerOptions": {
        "module": "commonjs",
        "target": "es2017",
        "lib": [
            "dom",
            "es6",
            "dom.iterable",
            "scripthost",
            "es2017"
        ],
        "noImplicitAny": false,
        "sourceMap": false
    }
}

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

webpack.config.js

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

module.exports = {
    entry: {
        index: "./js/index"
    },
    output: {
        filename: "[name].js"
    },
    devtool: "source-map",
    resolve: {
        extensions: [".ts"]
    },
    module: {
        rules: [
            {
                test: /\.ts$/,
                use: [
                    {
                        loader: "babel-loader",
                        options: {
                            presets: ["es2015", "stage-3"]
                        }
                    },
                    "ts-loader"
                ],
                exclude: /node_modules/
            }
        ]
    }
};

gulp task

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

const gulp = require("gulp");
const gutil = require("gulp-util");


// 轉(zhuǎn)譯JavaScript
gulp.task("webpack", () => {
    const webpack = require("webpack-stream");
    const config = require("./webpack.config.js");
    return gulp.src("./js/**/*.ts")
        .pipe(webpack(config, require("webpack")))
        .on("error", function(err) {
            gutil.log(err);
            this.emit("end");
        })
        .pipe(gulp.dest("../www/js"));
});

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

需要的 Node 模塊

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

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

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

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

或者

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)建腳本的用戶(hù)來(lái)說(shuō),有兩個(gè)好消息:gulp 和 webpack 都直接支持 .ts 入口(或配置)文件。比如以 gulp 為例,可以定義 gulpfile.ts (注意擴(kuò)展名是 .ts) 如下

import * as gulp from "gulp";


gulp.task("hello", () => {
    console.log("hello gulp");
});

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

擴(kuò)展閱讀

此文首發(fā)于 SegmentFault

敬請(qǐng) 掃碼 關(guān)注〔邊城〕的公眾號(hào):邊城客棧

公眾號(hào)“邊城客?!? /></p></div>
				          <div style=

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)