typescript + react 專案開發體驗之起手式

li2568261發表於2019-01-19

目錄

前言

typescript(以下簡稱ts) 官推是腳手架 create-react-appts版本,可自行查閱。但是我沒有用它,原因有2:

  1. Webpack 版本是3.x,在組內用過4.x重構腳手架之後之後不想再回頭配3.x。
  2. 作為學習專案以及教程,方便貫穿整個專案構建流程。

接下來將分別從一些用到的tsconfig、webpack配置展開來講解

ts配置

編譯器安裝

ts 作為 js 的方言要編譯成 js 需要編譯器安裝(相關參考5分鐘上手TypeScript

npm install -g typescript複製程式碼

編譯程式碼當然也就是:

tsc 檔名.ts複製程式碼

最終預設會在當前目錄下生產一個js檔案,就是編譯後的程式碼了。

既然有預設那就有自定義配置,如何做呢?

Ts自定義配置

自定義配置有兩種方式:

  1. 在命令列後加相應配置引數例如你不想將以下程式碼編譯成es5的函式形式(配置參考連結:compiler-options

    const fuc = ()=>
    {
    console.log(1);

    }fuc();
    複製程式碼

    你可以

    tsc 檔名.ts --target es6複製程式碼

    如果需要多個配置,繼續往後寫即可,這裡就不詳述了。

  2. 第一種方式如果引數多了看上去很難受,這裡我推薦第二種方式:在專案跟目錄新建tsconfig.json檔案,我推薦在方法1文件上找到一個配置引數**–init**初始化tsconfig.json(參考連結:tsconfig.json)。

    tsc --init複製程式碼

    這裡我列舉幾個用到的屬性

    { 
    "compilerOptions": {
    "target": "es5", // 你最終編譯成js模型 "lib":[ "es2017", "dom" ],// 你使用的一些庫,你可以理解成ts的一些polyfill "module": "ESNext", // 你編譯後的程式碼的模式,amd umd esmodule...等等下面詳述 "jsx": "react", // jsx 語法糖用哪個 "allowJs": true, // 是否允許引入js "checkJs": true, // 是否檢測js檔案型別 "paths": {
    "@components/*": ["./src/components/*"], "@utils/*": ["./src/utils/*"], "@view/*": ["./src/view/*"], "@styles/*": ["./src/styles/*"], "@api/*": ["./src/api/*"], "@store/*": ["./src/store/*"], "@decorators/*": ["./src/decorators/*"], "@assets/*": ["./src/assets/*"],
    },// 別名 "strict": true, //嚴格模式 "moduleResolution": "node", // 直接看這個吧https://www.tslang.cn/docs/handbook/module-resolution.html "baseUrl": ".", // 配合paths,當符合 paths 規則的檔案引入,會採用baseUrl+相應陣列列表下查詢的方式去找相應檔案 // "esModuleInterop": true, // 作用是讓commonjs/esmodule兩種模組模式正常通訊(具體看下一節),作用同下,如果使用了es7相關polyfill不可用會報錯(不確定,個人經驗)。 "allowSyntheticDefaultImports": true, // 往下看模組機制 "experimentalDecorators": true, // 使用裝飾器 "rootDir": "./src", // 執行tsc命令時去編譯哪個目錄下的檔案配合webpack可以不設定 "outDir": "./dist" // 同樣,其實這個也可以不設定,但是如果不設定你要給js檔案寫d.ts(後文會講到)這裡會報一個overWrite的錯,作為強迫症就設定一下吧。
    }, "include": [ "src/**/*" ], // tsc 會編譯在->
    rootDir<
    -內哪些檔案 "exclude": [ "node_modules", "dist", "build" ] // tsc 不會編譯->
    rootDir<
    -內的哪些檔案
    }複製程式碼

    Ps:檔案新建好了之後如果要編譯當前子資料夾,配置是無效的:

    tsc ./sub/檔名.ts # 配置無效還是預設配置複製程式碼

模組轉化

通過編譯後的幾種模組模式來幫助理解moduleesModuleInteropallowSyntheticDefaultImports配置項;

// 原始程式碼const fuc = ()=>
{
console.log(1);

}export default fuc();
// commonjs"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var fuc = function () {
console.log(1);

};
exports.default = fuc();
// amddefine(["require", "exports"], function (require, exports) { "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var fuc = function () {
console.log(1);

};
exports.default = fuc();

});
複製程式碼

原始程式碼在 commonjsamd 匯出的資料格式其實是這樣子的(如果不知道defineProperty可以查下mdn):

{ 
__esModule: true, default:fuc()
}複製程式碼

當在某處遇到一行程式碼引用了

import fuc from '這個地址';
console.log(fuc);
複製程式碼

當我們加上esModuleInteropallowSyntheticDefaultImports它會被編譯成

"use strict";
var __importDefault = (this &
&
this.__importDefault) || function (mod) {
return (mod &
&
mod.__esModule) ? mod : {
"default": mod
};

};
Object.defineProperty(exports, "__esModule", {
value: true
});
var complie_1 = __importDefault(require("./complie"));
console.log(complie_1.default);
複製程式碼

require("./complie") 這玩意兒就是上面說的那個物件

然後來分析 __importDefault,首先會識別__esModule變數,如果為true,直接把當前模組作為匯出,否則匯出一個物件,物件的default是匯出的模組。

當我們不加上面那兩個選項的時候編譯成

"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var complie_1 = require("./complie");
console.log(complie_1.default);
複製程式碼

小結一下:import variable from 'xx' variable 會被轉成 variable.default;如果配置了esModuleInteropallowSyntheticDefaultImports,如果import的是esmodule直接採用當前模組,否則把當前模組放到一個含default的物件中去,default的值就是當前模組。

OK,接下來我們來解釋這兩個屬性的意義,引入@types/react/index.d.ts一段程式碼(d.ts是啥之後再探討)

export = React;
export as namespace React;
複製程式碼

我們發現沒有預設值匯出值,但是我們想import React from 'react'這種操作就會報錯,OK結論就是這兩句話,但是過程。。很曲折。

再看下另外一種引入和匯出方式會如何轉換

// module xexport const a = 1;
export const b = 1;
export const c = 1;
export const d = 1;
export default 10;
// module import module ximport * as all from 'x';
console.log(all)// 轉化過後"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.a = 1;
exports.b = 1;
exports.c = 1;
exports.d = 1;
exports.default = 10;
//----------------------------------var __importStar = (this &
&
this.__importStar) || function (mod) {
if (mod &
&
mod.__esModule) return mod;
var result = {
};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;

};
var all = __importStar(require("x"));
console.log(all);
複製程式碼

同樣esModule原樣匯出,否則取當前物件上的屬性匯出(剔除原型鏈上的屬性);
這裡引入的變數不會被處理成all.default;

webpack配置

我眼中的webpack他是一個資源整合工具,經過:資源->
入口->
loader + plugin->
output這樣一個過程,進行策略整合。本小結不詳細講解配置過程,只是描述下配置思路,具體配置項可點我檢視。

首先我們給自己定一個小目標賺他一個億,別走錯片場了,我們的專案需要:

  1. 能解析 ts|tsx 檔案;
  2. 能用scss/less檔案;
  3. 能跟根據不同命令,打包/執行不同執行環境下的程式碼;
  4. 能熱更新;
  5. 移動端線真機除錯需要vconsole,但也受命令控制是否引入;
  6. import(‘xx’)實現模組切割,非同步載入模組;
  7. 公用庫的只想構建一次;
  8. 構建後的程式碼,樣式我想autoprefixer並額外匯出,js我想壓縮;
  9. 我想引入antd-mobile並能按需引入模組;

接下來我們一個一個實現這些小目標:

  1. 官推兩個loader:ts-loader/aweasome-typescript-loader,他們都會根據你專案根目錄下的tsconfig.json進行解析。
  2. 配置scss-loader/less-loader
  3. 在package.json中的scripts項分別新增相應引數的命令,可以通過yargs這個庫去拿相應的引數通過DefinePlugin去修改方法體上的程式碼。
  4. 那就是配置devServer配置項嘛,當然別忘了加入入HotModuleWebpackPlugin。react的熱更新需要react-hot-loader除了基礎配置以外還需要一個ForkTsCheckerWebpackPlugin外掛。
  5. vconsole-webpack-plugin
  6. 啥也不用幹,ts已經處理好了
  7. dll??我要更簡單一點,用AutoDllPlugin。
  8. postcss 配下這個外掛
  9. ts-import-plugin

具體過程我就不詳述瞭如果你想看demo就點我吧

來源:https://juejin.im/post/5c42c6b76fb9a049fc03d392

相關文章