typescript + react 項目開發體驗之起手式

目錄

前言

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

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

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

ts配置

編譯器安裝

ts 做爲 js 的方言要編譯成 js 須要編譯器安裝(相關參考5分鐘上手TypeScripthtml

npm install -g typescript
複製代碼

編譯代碼固然也就是:java

tsc 文件名.ts
複製代碼

最終默認會在當前目錄下生產一個js文件,就是編譯後的代碼了。node

既然有默認那就有自定義配置,如何作呢?react

Ts自定義配置

自定義配置有兩種方式:webpack

  1. 在命令行後加相應配置參數例如你不想將如下代碼編譯成es5的函數形式(配置參考連接:compiler-optionsgit

    const fuc = ()=>{
      console.log(1);
    }
    fuc();
    複製代碼

    你能夠es6

    tsc 文件名.ts --target es6
    複製代碼

    若是須要多個配置,繼續日後寫便可,這裏就不詳述了。github

  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();
// amd
define(["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 x
export const a = 1;
export const b = 1;
export const c = 1;
export const d = 1;
export default 10;
// module import module x
import * 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就點我吧

相關文章
相關標籤/搜索