.ts-loader是如何與vue單文件組件銜接作用的
首先看一下官方的starter pack
https://github.com/microsoft/TypeScript-Vue-Starter
https://www.npmjs.com/package/ts-loader
從文檔上可以看到,處理單文件組件安裝了 typescript 和 ts-loader這兩個依賴。
ts-loader是如何處理.vue單文件組件的,
在rule的配置里,ts-loader的test是以.ts文件結尾的啊,下面研究下
———————————————————————————————
首先再來回憶一下vue-loader+VueLoaderPlugin的處理過程:
vueloaderplugin在webpack初始化的階段,
vueloaderplugin擴展了開發者module.rule的配置,加入了vue-loader內部提供的pitcher-loader(即:pitcher這個rule,它的use是pitcher-loader),
(pitcher的resourceQuery是 request帶”vue”query的 (如xxx.xx?vue&xxx) )
並以下面這個順序將rules重新組合
[pitcher,…clone Rules,…vue-loader] (將vue-loader放到最后,將pitch-loader放到最開始,中間是被重寫過fakeResourcepath的clone Rules)
(pitcher-loader的匹配條件是,request中帶”vue”這個query (如xxx.xx?vue&xxx))
Step1:
當處理一個.vue文件的時候,vue-loader會判斷,如果request不帶type=vue,會生成下面這一大段js module:
這就是第一步, 這里一個.vue文件會被處理成下面的jsmodule
"import { render, staticRenderFns } from "./index.vue?vue&type=template&id=2964abc9&"
import script from "./index.vue?vue&type=script&lang=ts&"
export * from "./index.vue?vue&type=script&lang=ts&"
/* normalize component */
import normalizer from "!../node_modules/vue-loader/lib/runtime/componentNormalizer.js"
var component = normalizer(
script,
render,
staticRenderFns,
false,
null,
null,
null
)
/* hot reload */
if (module.hot) {
var api = require("/Users/huhao/Desktop/demo/node_modules/vue-hot-reload-api/dist/index.js")
api.install(require('vue'))
if (api.compatible) {
module.hot.accept()
if (!api.isRecorded('2964abc9')) {
api.createRecord('2964abc9', component.options)
} else {
…
Step2:
webpack中的acron開始對這個新生成的一坨jsmodule進行處理,依賴收集的過程中,會拿到
import { render, staticRenderFns } from "./index.vue?vue&type=template&id=2964abc9&"
import script from "./index.vue?vue&type=script&lang=ts&"
export * from "./index.vue?vue&type=script&lang=ts&"
…
這些request,然后對每個request進行resolve,創建獨立的module..
因為request帶vue這個query,所以會先被pitcher-loader處理,pitcher在runLoaders過程中操作,會第一個執行,剔除掉eslint-loader,剔除pitcher自身,根據不同的type=xxx 返回一段新的request,
..有template的..
..有style的..
..有script的..
然后我們debug會發現,這個時候處理script的生成的request,已經附帶了ts-loader了。
如下:
"/Users/huhao/Desktop/demo/node_modules/ts-loader/index.js??ref--2!/Users/huhao/Desktop/demo/node_modules/vue-loader/lib/index.js??vue-loader-options!/Users/huhao/Desktop/demo/src/index.vue?vue&type=script&lang=ts&"
問題: 為什么script block的部分生成的request。。直接就判定附帶有ts-loader了
繼續向前看,
在最后生成上面這坨request的過程前,會先經過build的過程,
在調用棧doBuild的時候,要執行runLoaders方法的時候,this.loaders包括了ts-loader了
在build之前是創建module和resolve的過程,看一下創建module的過程,
在normalModule.factory中 會使用rulest.exec({})對resouce("./index.vue?vue&type=script&lang=ts&")進行操作,根據webpack的rule規則,去和webpack的options中配置的loader進行過濾,解析出了本次構建module過程中可以使用的loader,看看為什么這里會把ts-loader也加入了進來
注意,此時是在對step2中收集依賴時收集的 import script from "./index.vue?vue&type=script&lang=ts&" 進行操作。
繼續向前debug,下面要進行exec了, 可以看到 rules是webpack處理得到的所有rules 要從里面篩選出本次構建module可用的loaders
exec里面會執行run方法, run方法會接觸到這一大坨過濾條件, 如果都滿足了,才會將這個loader加入到result中
這個方法里有一個rule.resourceQuery, 這時候會發現對/.tsx?$/結尾的這種rule的resourceQuery已經被vueLoaderPlugin改寫過了 ,
(
在vue-loader的 plugin.js的 cloneRule方法中:
會對webpack的所有配置的rules中除了,/.vue$/的rule,的resource和resourceQuery進行重寫
重寫的resourceQuery里:
加了這句話,
const fakeResourcePath = `${currentResource}.${parsed.lang}`
主要是這句話,fakeResourcePath…
fakeResourcePath的值是
所以在exec的過程中,拿webpack的rules過濾loaders的過程中,ts-loader會加入構建,因為..
所有resourcePath后面拼接了parsed.lang
)
而ts-loader的過濾條件是
以’ts’或’tsx’結尾的能通過他的條件篩選
資料:
1. ruleSet的使用機制: https://github.com/CommanderXL/Biu-blog/issues/30