typescript(如下簡稱ts) 官推是腳手架 create-react-app 的ts版本,可自行查閱。可是我沒有用它,緣由有2:javascript
- Webpack 版本是3.x,在組內用過4.x重構腳手架以後以後不想再回頭配3.x。
- 做爲學習項目以及教程,方便貫穿整個項目構建流程。
接下來將分別從一些用到的tsconfig、webpack配置展開來說解css
ts 做爲 js 的方言要編譯成 js 須要編譯器安裝(相關參考5分鐘上手TypeScript)html
npm install -g typescript
複製代碼
編譯代碼固然也就是:java
tsc 文件名.ts
複製代碼
最終默認會在當前目錄下生產一個js文件,就是編譯後的代碼了。node
既然有默認那就有自定義配置,如何作呢?react
自定義配置有兩種方式:webpack
在命令行後加相應配置參數例如你不想將如下代碼編譯成es5的函數形式(配置參考連接:compiler-options)git
const fuc = ()=>{
console.log(1);
}
fuc();
複製代碼
你能夠es6
tsc 文件名.ts --target es6
複製代碼
若是須要多個配置,繼續日後寫便可,這裏就不詳述了。github
第一種方式若是參數多了看上去很難受,這裏我推薦第二種方式:在項目跟目錄新建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 # 配置無效仍是默認配置
複製代碼
經過編譯後的幾種模塊模式來幫助理解module
和esModuleInterop
、allowSyntheticDefaultImports
配置項;
// 原始代碼
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();
});
複製代碼
原始代碼在 commonjs
和 amd
導出的數據格式實際上是這樣子的(若是不知道defineProperty
能夠查下mdn):
{
__esModule: true,
default:fuc()
}
複製代碼
當在某處遇到一行代碼引用了
import fuc from '這個地址';
console.log(fuc);
複製代碼
當咱們加上esModuleInterop
或allowSyntheticDefaultImports
它會被編譯成
"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;若是配置了esModuleInterop
或allowSyntheticDefaultImports
,若是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
他是一個資源整合工具,通過:資源->入口->loader + plugin->output這樣一個過程,進行策略整合。本小結不詳細講解配置過程,只是描述下配置思路,具體配置項可點我查看。
首先咱們給本身定一個小目標賺他一個億,別走錯片場了,咱們的項目須要:
autoprefixer
並額外導出,js我想壓縮;接下來咱們一個一個實現這些小目標:
具體過程我就不詳述了若是你想看demo就點我吧