精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Webpack - 手把手教你寫一個 loader / plugin

開發(fā) 前端
webpack 只能理解 JavaScript 和 JSON 文件,這是 webpack 開箱可用的自帶能力。**loader **讓 webpack 能夠去處理其他類型的文件,并將它們轉換為有效模塊,以供應用程序使用,以及被添加到依賴圖中。

[[406788]]

一、Loader

1.1 loader 干啥的?

webpack 只能理解 JavaScript 和 JSON 文件,這是 webpack 開箱可用的自帶能力。**loader **讓 webpack 能夠去處理其他類型的文件,并將它們轉換為有效模塊,以供應用程序使用,以及被添加到依賴圖中。

也就是說,webpack 把任何文件都看做模塊,loader 能 import 任何類型的模塊,但是 webpack 原生不支持譬如 css 文件等的解析,這時候就需要用到我們的 loader 機制了。 我們的 loader 主要通過兩個屬性來讓我們的 webpack 進行聯(lián)動識別:

  1. test 屬性,識別出哪些文件會被轉換。
  2. use 屬性,定義出在進行轉換時,應該使用哪個 loader。

那么問題來了,大家一定想知道自己要定制一個 loader 的話需要怎么做呢?

1.2 開發(fā)準則

俗話說的好,沒有規(guī)矩不成方圓,編寫我們的 loader 時,官方也給了我們一套用法準則(Guidelines),在編寫的時候應該按照這套準則來使我們的 loader 標準化:

  • 簡單易用。
  • 使用鏈式傳遞。(由于 loader 是可以被鏈式調(diào)用的,所以請保證每一個 loader 的單一職責)
  • 模塊化的輸出。
  • 確保無狀態(tài)。(不要讓 loader 的轉化中保留之前的狀態(tài),每次運行都應該獨立于其他編譯模塊以及相同模塊之前的編譯結果)
  • 充分使用官方提供的 loader utilities。
  • 記錄 loader 的依賴。
  • 解析模塊依賴關系。

根據(jù)模塊類型,可能會有不同的模式指定依賴關系。例如在 CSS 中,使用@import 和 url(...)語句來聲明依賴。這些依賴關系應該由模塊系統(tǒng)解析。 可以通過以下兩種方式中的一種來實現(xiàn):

  • 通過把它們轉化成 require 語句。
  • 使用 this.resolve 函數(shù)解析路徑。
  • 提取通用代碼。
  • 避免絕對路徑。
  • 使用 peer dependencies。如果你的 loader 簡單包裹另外一個包,你應該把這個包作為一個 peerDependency 引入。

1.3 上手

一個 loader 就是一個 nodejs 模塊,他導出的是一個函數(shù),這個函數(shù)只有一個入?yún)ⅲ@個參數(shù)就是一個包含資源文件內(nèi)容的字符串,而函數(shù)的返回值就是處理后的內(nèi)容。也就是說,一個最簡單的 loader 長這樣:

  1. module.exports = function (content) { 
  2.  // content 就是傳入的源內(nèi)容字符串 
  3.   return content 

當一個 loader 被使用的時候,他只可以接收一個入?yún)ⅲ@個參數(shù)是一個包含包含資源文件內(nèi)容的字符串。 是的,到這里為止,一個最簡單 loader 就已經(jīng)完成了!接下來我們來看看怎么給他加上豐富的功能。

1.4 四種 loader

我們基本可以把常見的 loader 分為四種:

  • 同步 loader
  • 異步 loader
  • "Raw" Loader
  • Pitching loader

① 同步 loader 與 異步 loader

一般的 loader 轉換都是同步的,我們可以采用上面說的直接 return 結果的方式,返回我們的處理結果:

  1. module.exports = function (content) { 
  2.  // 對 content 進行一些處理 
  3.   const res = dosth(content) 
  4.   return res 

也可以直接使用 this.callback() 這個 api,然后在最后直接 **return undefined **的方式告訴 webpack 去 this.callback() 尋找他要的結果,這個 api 接受這些參數(shù):

  1. this.callback( 
  2.   err: Error | null, // 一個無法正常編譯時的 Error 或者 直接給個 null 
  3.   content: string | Buffer,// 我們處理后返回的內(nèi)容 可以是 string 或者 Buffer() 
  4.   sourceMap?: SourceMap, // 可選 可以是一個被正常解析的 source map 
  5.   meta?: any // 可選 可以是任何東西,比如一個公用的 AST 語法樹 
  6. ); 

接下來舉個例子:

[[406789]]

這里注意[this.getOptions()](https://webpack.docschina.org/api/loaders/#thisgetoptionsschema) 可以用來獲取配置的參數(shù)

從 webpack 5 開始,this.getOptions 可以獲取到 loader 上下文對象。它用來替代來自loader-utils中的 getOptions 方法。

  1. module.exports = function (content) { 
  2.   // 獲取到用戶傳給當前 loader 的參數(shù) 
  3.   const options = this.getOptions() 
  4.   const res = someSyncOperation(content, options) 
  5.   this.callback(null, res, sourceMaps); 
  6.   // 注意這里由于使用了 this.callback 直接 return 就行 
  7.   return 

這樣一個同步的 loader 就完成了!

再來說說異步: 同步與異步的區(qū)別很好理解,一般我們的轉換流程都是同步的,但是當我們遇到譬如需要網(wǎng)絡請求等場景,那么為了避免阻塞構建步驟,我們會采取異步構建的方式,對于異步 loader 我們主要需要使用 this.async() 來告知 webpack 這次構建操作是異步的,不多廢話,看代碼就懂了:

  1. module.exports = function (content) { 
  2.   var callback = this.async() 
  3.   someAsyncOperation(content, function (err, result) { 
  4.     if (err) return callback(err) 
  5.     callback(null, result, sourceMaps, meta) 
  6.   }) 

② "Raw" loader

默認情況下,資源文件會被轉化為 UTF-8 字符串,然后傳給 loader。通過設置 raw 為 true,loader 可以接收原始的 Buffer。每一個 loader 都可以用 String 或者 Buffer 的形式傳遞它的處理結果。complier 將會把它們在 loader 之間相互轉換。大家熟悉的 file-loader 就是用了這個。簡而言之:你加上 module.exports.raw = true; 傳給你的就是 Buffer 了,處理返回的類型也并非一定要是 Buffer,webpack 并沒有限制。

  1. module.exports = function (content) { 
  2.   console.log(content instanceof Buffer); // true 
  3.   return doSomeOperation(content) 
  4. // 劃重點↓ 
  5. module.exports.raw = true

③ Pitching loader

我們每一個 loader 都可以有一個 pitch 方法,大家都知道,loader 是按照從右往左的順序被調(diào)用的,但是實際上,在此之前會有一個按照從左往右執(zhí)行每一個 loader 的 pitch 方法的過程。pitch 方法共有三個參數(shù):

  • remainingRequest:loader 鏈中排在自己后面的 loader 以及資源文件的絕對路徑以!作為連接符組成的字符串。
  • precedingRequest:loader 鏈中排在自己前面的 loader 的絕對路徑以!作為連接符組成的字符串。
  • data:每個 loader 中存放在上下文中的固定字段,可用于 pitch 給 loader 傳遞數(shù)據(jù)。

在 pitch 中傳給 data 的數(shù)據(jù),在后續(xù)的調(diào)用執(zhí)行階段,是可以在 this.data 中獲取到的:

  1. module.exports = function (content) { 
  2.   return someSyncOperation(content, this.data.value);// 這里的 this.data.value === 42 
  3. }; 
  4.  
  5. module.exports.pitch = function (remainingRequest, precedingRequest, data) { 
  6.   data.value = 42; 
  7. }; 

注意! 如果某一個 loader 的 pitch 方法中返回了值,那么他會直接“往回走”,跳過后續(xù)的步驟,來舉個例子:

[[406790]]

假設我們現(xiàn)在是這樣:use: ['a-loader', 'b-loader', 'c-loader'],那么正常的調(diào)用順序是這樣:

現(xiàn)在 b-loader 的 pitch 改為了有返回值:

  1. // b-loader.js 
  2. module.exports = function (content) { 
  3.   return someSyncOperation(content); 
  4. }; 
  5.  
  6. module.exports.pitch = function (remainingRequest, precedingRequest, data) { 
  7.   return "誒,我直接返回,就是玩兒~" 
  8. }; 

那么現(xiàn)在的調(diào)用就會變成這樣,直接“回頭”,跳過了原來的其他三個步驟:

1.5 其他 API

  • this.addDependency:加入一個文件進行監(jiān)聽,一旦文件產(chǎn)生變化就會重新調(diào)用這個 loader 進行處理
  • this.cacheable:默認情況下 loader 的處理結果會有緩存效果,給這個方法傳入 false 可以關閉這個效果
  • this.clearDependencies:清除 loader 的所有依賴
  • this.context:文件所在的目錄(不包含文件名)
  • this.data:pitch 階段和正常調(diào)用階段共享的對象
  • this.getOptions(schema):用來獲取配置的 loader 參數(shù)選項
  • this.resolve:像 require 表達式一樣解析一個 request。resolve(context: string, request: string, callback: function(err, result: string))
  • this.loaders:所有 loader 組成的數(shù)組。它在 pitch 階段的時候是可以寫入的。
  • this.resource:獲取當前請求路徑,包含參數(shù):'/abc/resource.js?rrr'
  • this.resourcePath:不包含參數(shù)的路徑:'/abc/resource.js'
  • this.sourceMap:bool 類型,是否應該生成一個 sourceMap

官方還提供了很多實用 Api ,這邊只列舉一些可能常用的,更多可以戳鏈接👇更多詳見官方鏈接

1.6 來個簡單實踐

功能實現(xiàn)

接下來我們簡單實踐制作兩個 loader ,功能分別是在編譯出的代碼中加上 /** 公司@年份 */ 格式的注釋和簡單做一下去除代碼中的 console.log ,并且我們鏈式調(diào)用他們:

company-loader.js

  1. module.exports = function (source) { 
  2.   const options = this.getOptions() // 獲取 webpack 配置中傳來的 option 
  3.   this.callback(null, addSign(source, options.sign)) 
  4.   return 
  5.  
  6. function addSign(content, sign) { 
  7.   return `/** ${sign} */\n${content}` 

console-loader.js

  1. module.exports = function (content) { 
  2.   return handleConsole(content) 
  3.  
  4. function handleConsole(content) { 
  5.   return content.replace(/console.log\(['|"](.*?)['|"]\)/, ''

調(diào)用測試方式

功能就簡單的進行了一下實現(xiàn),這里我們主要說一下如何測試調(diào)用我們的本地的 loader,方式有兩種,一種是通過 Npm link 的方式進行測試,這個方式的具體使用就不細說了,大家可以簡單查閱一下。 另外一種就是直接在項目中通過路徑配置的方式,有兩種情況:

1.匹配(test)單個 loader,你可以簡單通過在 rule 對象設置 path.resolve 指向這個本地文件

webpack.config.js

  1.   test: /\.js$/ 
  2.   use: [ 
  3.     { 
  4.       loader: path.resolve('path/to/loader.js'), 
  5.       options: {/* ... */} 
  6.     } 
  7.   ] 

2.匹配(test)多個 loaders,你可以使用 resolveLoader.modules 配置,webpack 將會從這些目錄中搜索這些 loaders。例如,如果你的項目中有一個 /loaders 本地目錄:

webpack.config.js

  1. resolveLoader: { 
  2.   // 這里就是說先去找 node_modules 目錄中,如果沒有的話再去 loaders 目錄查找 
  3.   modules: [ 
  4.     'node_modules'
  5.     path.resolve(__dirname, 'loaders'
  6.   ] 

配置使用

我們這里的 webpack 配置如下所示:

  1. module: { 
  2.     rules: [ 
  3.       { 
  4.         test: /\.js$/, 
  5.         use: [ 
  6.           'console-loader'
  7.           { 
  8.             loader: 'company-loader'
  9.             options: { 
  10.               sign: 'we-doctor@2021'
  11.             }, 
  12.           }, 
  13.         ], 
  14.       }, 
  15.     ], 
  16.   }, 

項目中的 index.js:

  1. function fn() { 
  2.   console.log("this is a message"
  3.   return "1234" 

執(zhí)行編譯后的 bundle.js: 可以看到,兩個 loader 的功能都體現(xiàn)到了編譯后的文件內(nèi)。

  1. /******/ (() => { // webpackBootstrap 
  2. var __webpack_exports__ = {}; 
  3. /*!**********************!*\ 
  4.   !*** ./src/index.js ***! 
  5.   \**********************/ 
  6. /** we-doctor@2021 */ 
  7. function fn() { 
  8.    
  9.   return "1234" 
  10. /******/ })() 

二、Plugin

為什么要有 plugin

plugin 提供了很多比 loader 中更完備的功能,他使用階段式的構建回調(diào),webpack 給我們提供了非常多的 hooks 用來在構建的階段讓開發(fā)者自由的去引入自己的行為。

基本結構

  • 一個最基本的 plugin 需要包含這些部分:
  • 一個 JavaScript 類
  • 一個 apply 方法,apply 方法在 webpack 裝載這個插件的時候被調(diào)用,并且會傳入 compiler 對象。
  • 使用不同的 hooks 來指定自己需要發(fā)生的處理行為
  • 在異步調(diào)用時最后需要調(diào)用 webpack 提供給我們的 callback 或者通過 Promise 的方式(后續(xù)異步編譯部分會詳細說)

  1. class HelloPlugin{ 
  2.   apply(compiler){ 
  3.     compiler.hooks.<hookName>.tap(PluginName,(params)=>{ 
  4.       /** do some thing */ 
  5.     }) 
  6.   } 
  7. module.exports = HelloPlugin 

Compiler andCompilation

Compiler 和 Compilation 是整個編寫插件的過程中的**重!中!之!重!**因為我們幾乎所有的操作都會圍繞他們。

compiler 對象可以理解為一個和 webpack 環(huán)境整體綁定的一個對象,它包含了所有的環(huán)境配置,包括 options,loader 和 plugin,當 webpack 啟動時,這個對象會被實例化,并且他是全局唯一的,上面我們說到的 apply 方法傳入的參數(shù)就是它。

compilation 在每次構建資源的過程中都會被創(chuàng)建出來,一個 compilation 對象表現(xiàn)了當前的模塊資源、編譯生成資源、變化的文件、以及被跟蹤依賴的狀態(tài)信息。它同樣也提供了很多的 hook 。

Compiler 和 Compilation 提供了非常多的鉤子供我們使用,這些方法的組合可以讓我們在構建過程的不同時間獲取不同的內(nèi)容,具體詳情可參見官網(wǎng)直達。

上面的鏈接中我們會發(fā)現(xiàn)鉤子會有不同的類型,比如 SyncHook、SyncBailHook、AsyncParallelHook、AsyncSeriesHook ,這些不同的鉤子類型都是由 tapable 提供給我們的,關于 tapable 的詳細用法與解析可以參考我們前端構建工具系列專欄中的 tapable 專題講解。

基本的使用方式是:

  1. compiler/compilation.hooks.<hookName>.tap/tapAsync/tapPromise(pluginName,(xxx)=>{/**dosth*/}) 
  • Tip: 以前的寫法是 compiler.plugin ,但是在最新的 webpack@5 可能會引起問題,參見 webpack-4-migration-notes

同步與異步

plugin 的 hooks 是有同步和異步區(qū)分的,在同步的情況下,我們使用 .tap 的方式進行調(diào)用,而在異步 hook 內(nèi)我們可以進行一些異步操作,并且有異步操作的情況下,請使用 tapAsync 或者 tapPromise 方法來告知 webpack 這里的內(nèi)容是異步的,當然,如果內(nèi)部沒有異步操作的話,你也可以正常使用 tap 。

tapAsync

使用 tapAsync 的時候,我們需要多傳入一個 callback 回調(diào),并且在結束的時候一定要調(diào)用這個回調(diào)告知 webpack 這段異步操作結束了。👇 比如:

  1. class HelloPlugin { 
  2.   apply(compiler) { 
  3.     compiler.hooks.emit.tapAsync(HelloPlugin, (compilation, callback) => { 
  4.       setTimeout(() => { 
  5.         console.log('async'
  6.         callback() 
  7.       }, 1000) 
  8.     }) 
  9.   } 
  10. module.exports = HelloPlugin 

tapPromise

當使用 tapPromise 來處理異步的時候,我們需要返回一個 Promise 對象并且讓它在結束的時候 resolve 👇

  1. class HelloPlugin { 
  2.   apply(compiler) { 
  3.     compiler.hooks.emit.tapPromise(HelloPlugin, (compilation) => { 
  4.       return new Promise((resolve) => { 
  5.         setTimeout(() => { 
  6.           console.log('async'
  7.           resolve() 
  8.         }, 1000) 
  9.       }) 
  10.     }) 
  11.   } 
  12. module.exports = HelloPlugin 

做個實踐

接下來我們通過實際來做一個插件梳理一遍整體的流程和零散的功能點,這個插件實現(xiàn)的功能是在打包后輸出的文件夾內(nèi)多增加一個 markdown 文件,文件內(nèi)記錄打包的時間點、文件以及文件大小的輸出。

首先我們根據(jù)需求確定我們需要的 hook ,由于需要輸出文件,我們需要使用 compilation 的 emitAsset 方法。 其次由于需要對 assets 進行處理,所以我們使用 compilation.hooks.processAssets ,因為 processAssets 是負責 asset 處理的鉤子。

這樣我們插件結構就出來了👇OutLogPlugin.js

  1. class OutLogPlugin { 
  2.   constructor(options) { 
  3.     this.outFileName = options.outFileName 
  4.   } 
  5.   apply(compiler) { 
  6.     // 可以從編譯器對象訪問 webpack 模塊實例 
  7.     // 并且可以保證 webpack 版本正確 
  8.     const { webpack } = compiler 
  9.     // 獲取 Compilation 后續(xù)會用到 Compilation 提供的 stage 
  10.     const { Compilation } = webpack 
  11.     const { RawSource } = webpack.sources 
  12.     /** compiler.hooks.<hoonkName>.tap/tapAsync/tapPromise */ 
  13.     compiler.hooks.compilation.tap('OutLogPlugin', (compilation) => { 
  14.       compilation.hooks.processAssets.tap( 
  15.         { 
  16.           name'OutLogPlugin'
  17.           // 選擇適當?shù)?nbsp;stage,具體參見: 
  18.           // https://webpack.js.org/api/compilation-hooks/#list-of-asset-processing-stages 
  19.           stage: Compilation.PROCESS_ASSETS_STAGE_SUMMARIZE, 
  20.         }, 
  21.         (assets) => { 
  22.           let resOutput = `buildTime: ${new Date().toLocaleString()}\n\n` 
  23.           resOutput += `| fileName  | fileSize  |\n| --------- | --------- |\n` 
  24.           Object.entries(assets).forEach(([pathname, source]) => { 
  25.             resOutput += `| ${pathname} | ${source.size()} bytes |\n` 
  26.           }) 
  27.           compilation.emitAsset( 
  28.             `${this.outFileName}.md`, 
  29.             new RawSource(resOutput), 
  30.           ) 
  31.         }, 
  32.       ) 
  33.     }) 
  34.   } 
  35. module.exports = OutLogPlugin 

對插件進行配置:webpack.config.js

  1. const OutLogPlugin = require('./plugins/OutLogPlugin'
  2.  
  3. module.exports = { 
  4.   plugins: [ 
  5.     new OutLogPlugin({outFileName:"buildInfo"}) 
  6.   ], 

打包后的目錄結構:

  1. dist 
  2. ├─ buildInfo.md 
  3. ├─ bundle.js 
  4. └─ bundle.js.map 

buildInfo.md

可以看到按照我們希望的格式準確輸出了內(nèi)容,這樣一個簡單的功能插件就完成了!

 

責任編輯:姜華 來源: 微醫(yī)大前端技術
相關推薦

2022-05-18 08:51:44

調(diào)用模板后端并行

2023-03-27 08:28:57

spring代碼,starter

2023-11-28 07:36:41

Shell腳本部署

2019-08-26 09:25:23

RedisJavaLinux

2022-06-28 15:29:56

Python編程語言計時器

2020-12-23 09:48:37

數(shù)據(jù)工具技術

2017-07-19 13:27:44

前端Javascript模板引擎

2014-01-22 09:19:57

JavaScript引擎

2011-01-10 14:41:26

2011-05-03 15:59:00

黑盒打印機

2025-05-07 00:31:30

2021-07-14 09:00:00

JavaFX開發(fā)應用

2022-08-26 08:01:38

DashWebJavaScrip

2022-09-22 12:38:46

antd form組件代碼

2016-11-01 09:46:04

2018-05-16 15:46:06

Python網(wǎng)絡爬蟲PhantomJS

2018-05-16 13:50:30

Python網(wǎng)絡爬蟲Scrapy

2021-08-31 10:02:10

KubernetesLinux集群

2018-11-22 09:17:21

消息推送系統(tǒng)

2023-03-22 09:00:38

點贊
收藏

51CTO技術棧公眾號

亚洲h精品动漫在线观看| 国产毛片一区二区| 亚洲天堂av在线免费| 一本久道综合色婷婷五月| 天天在线视频色| 国产剧情一区在线| 日本精品久久久久久久| 三区精品视频观看| 99在线观看免费| 成人看的羞羞网站| 精品久久久精品| 91观看网站| 91传媒免费观看| 精品国产乱子伦一区二区| 在线精品观看国产| 国产一区二区三区小说| av午夜在线| av在线播放成人| 久久久久久国产精品久久| 亚洲精品国产一区黑色丝袜| 亚洲开心激情| 欧美高清hd18日本| 99久久久无码国产精品6| 草莓福利社区在线| 国产午夜精品久久| 国内精品久久久久久久果冻传媒| 亚洲中文字幕在线观看| 亚洲欧美网站| 欧美激情一区二区三区成人| 99久久99久久精品免费看小说.| 中文日产幕无线码一区二区| 亚洲视频在线一区观看| 日韩精品av一区二区三区| 日本人妻丰满熟妇久久久久久| 欧美午夜a级限制福利片| 国产亚洲美女精品久久久| 你懂的在线观看网站| 亚洲精品一二三**| 日韩一区二区精品葵司在线 | 免费看污片的网站| 欧美爱爱网站| 亚洲丁香久久久| 一级黄色大片免费看| a级网站在线播放| 欧美激情一区在线观看| 欧美不卡三区| 深夜福利视频一区| 99在线视频精品| 国产嫩草一区二区三区在线观看| 99国产精品99| 国产精品一区在线观看乱码| 91性高湖久久久久久久久_久久99| 中国女人真人一级毛片| 丝袜美腿亚洲综合| 国产精品99久久久久久久久久久久| 国精产品一区二区三区| 天堂在线精品| 亚洲女人天堂成人av在线| 白丝女仆被免费网站| 奇米777国产一区国产二区| 亚洲国产精品va在线| 毛茸茸free性熟hd| 欧洲精品一区| 亚洲天堂网站在线观看视频| 国产毛片欧美毛片久久久| 欧美特黄一级大片| 中日韩美女免费视频网站在线观看| 国产美女永久免费无遮挡| 欧美日韩激情| 啊v视频在线一区二区三区| 中文字幕在线观看2018| 一区二区三区网站| 欧美激情久久久久| 国产精品第5页| 日本aⅴ免费视频一区二区三区| 国产日产亚洲精品| 精品乱子伦一区二区| 成人黄页在线观看| 久久精品中文字幕一区二区三区| 国产小视频在线| 国产精品成人在线观看| 日韩精品一区二区在线视频| 免费福利在线观看| 国产喷白浆一区二区三区| 一区二区三区欧美在线| 欧美人与禽性xxxxx杂性| 精品久久久久久久久久久久久| 男人的天堂99| 精品国产鲁一鲁****| 精品福利在线导航| 一区二区精品免费| 欧美ab在线视频| 2019中文字幕全在线观看| 中文无码精品一区二区三区| 国产精品中文字幕欧美| 久久久一本精品99久久精品| 1024国产在线| 亚洲国产欧美一区二区三区丁香婷| 无码aⅴ精品一区二区三区浪潮| jizz欧美| 亚洲国产97在线精品一区| 久久久免费看片| 亚洲国产片色| 欧美黑人巨大精品一区二区| av大片在线免费观看| 国产在线日韩欧美| 免费观看成人在线| 深夜国产在线播放| 在线视频观看一区| 尤物网站在线观看| 午夜精品一区二区三区国产 | 日韩有码片在线观看| 国产精彩视频在线观看| 精品亚洲成a人| 欧美精品成人一区二区在线观看 | 91精品国产电影| 国产一区二区女内射| 91网站在线播放| www.九色.com| 亚洲伦理久久| 欧美日韩一二三| 国产ts在线观看| 日韩影院二区| 日韩av不卡在线| 深夜福利视频网站| 有坂深雪av一区二区精品| 国产三级国产精品国产专区50| 久久97精品| 欧美激情精品久久久久| 91av久久久| 国产精品天天摸av网| 国产肥臀一区二区福利视频| 一区二区精彩视频| 免费91在线视频| 亚洲一区二区影视| 国产精品区一区二区三区| 国产最新免费视频| 欧美wwwwww| 97精品国产aⅴ7777| 亚洲精品综合网| 一区二区不卡在线视频 午夜欧美不卡在 | 久操免费在线| 欧美日韩一级视频| 99热在线观看精品| 久久99精品一区二区三区三区| 色99中文字幕| 久久久久久一区二区三区四区别墅| 欧洲另类一二三四区| 欧美深性狂猛ⅹxxx深喉| 亚洲激情亚洲| 精品国产乱码久久久久久蜜柚| 日本一级特级毛片视频| 成人豆花视频| xvideos成人免费中文版| 亚洲综合视频在线播放| 国产精品国产三级国产a| 91制片厂毛片| 亚洲人metart人体| 成人av播放| av中文资源在线资源免费观看| 亚洲成成品网站| 黄网在线观看视频| 久久久久久久久久久电影| 亚洲精品中文字幕无码蜜桃| 欧美伦理在线视频| 91精品国产综合久久男男| 超碰免费公开在线| 亚洲成av人乱码色午夜| 久久99精品波多结衣一区| 久久久精品蜜桃| 91插插插插插插插插| 五月婷婷六月综合| 成人羞羞视频免费| 超碰aⅴ人人做人人爽欧美| 国产一区二区三区毛片| 一级黄色a视频| 亚洲午夜一区二区三区| 亚洲成av人片在线观看无| 久久亚洲色图| 免费成人深夜夜行网站视频| aiai久久| 国产精品久久久久久久久久久新郎 | 久久久久人妻精品一区三寸| 欧美日韩久久精品| 91网站在线免费观看| 嗯啊主人调教在线播放视频 | 尤物视频在线看| 天天免费综合色| 国产精品无码久久久久久| 日本欧美一区二区| 99久久免费观看| 欧美人妖在线| 91亚洲精品视频| 午夜欧美激情| 久久亚洲精品视频| 日本不卡免费播放| 91精品在线麻豆| 69堂免费视频| 韩国三级av在线免费观看| 欧美性大战久久久| 青娱乐免费在线视频| 26uuu国产电影一区二区| 国产农村妇女精品久久| 午夜在线播放视频欧美| 免费看av软件| 妖精视频一区二区三区免费观看| 亚洲最大av在线| 欧美××××黑人××性爽| 欧美mv日韩mv国产网站app| 999福利视频| 99热国产精品| 亚洲热在线视频| 日韩二区三区四区| 久久久久免费看黄a片app| 99成人在线视频| 欧美日韩在线观看一区| 成人动态视频| 91亚洲精品视频| 久久69成人| 97超碰蝌蚪网人人做人人爽| 超碰在线最新| 日韩有码在线播放| 精品无吗乱吗av国产爱色| 亚洲成人黄色网| 国产黄色片免费观看| 欧美日韩中文一区| 欧美在线视频精品| 欧美日韩中文字幕在线视频| 日韩精品成人在线| 一区二区三区四区在线免费观看| 国产精品免费在线视频| 中文字幕+乱码+中文字幕一区| 一级特黄a大片免费| 懂色av一区二区三区蜜臀| 国内av免费观看| 久久国产剧场电影| 麻豆三级在线观看| 日本不卡的三区四区五区| 农村妇女精品一二区| 亚洲激情成人| 一女被多男玩喷潮视频| 黄页网站一区| 久艹在线免费观看| 亚洲精品一二| aa视频在线播放| 亚洲毛片视频| 黄色国产一级视频| 亚洲美女毛片| 一二三四视频社区在线| 在线亚洲欧美| 农村妇女精品一二区| 老妇喷水一区二区三区| 凹凸日日摸日日碰夜夜爽1| 日韩不卡在线视频| 一二三四区精品视频| 亚洲色图欧美色| 国产精品久久毛片av大全日韩| 五月天婷婷丁香网| 国产精品成人一区二区艾草| 91香蕉视频在线播放| 亚洲精选免费视频| 久久久久久久黄色| 亚洲成人精品一区二区| www.日本精品| 欧美在线你懂的| 国产又粗又黄又爽| 精品日本一线二线三线不卡| 天堂在线视频免费| 亚洲欧美国产精品专区久久| 国产1区2区3区在线| 少妇高潮久久久久久潘金莲| 欧美成人视屏| 久久久久久中文字幕| 美女视频在线免费| 国产精品视频公开费视频| 成人国产精品久久| 国产精品一码二码三码在线| 羞羞答答一区二区| 一区二区免费电影| 在线成人www免费观看视频| 欧美日韩在线中文| 久久69国产一区二区蜜臀| 极品人妻一区二区| 久久久一区二区三区捆绑**| 亚洲欧洲综合网| 亚洲午夜久久久久久久久电影院| av大片免费观看| 欧美精选一区二区| 无码精品人妻一区二区三区影院| 中文字幕国产亚洲| 超碰91在线观看| 国产精品日韩一区| 国产精品45p| 中文字幕色一区二区| 亚洲理伦在线| 手机av在线网| 久久综合久久综合久久| 免费在线黄色网| 欧美性高潮在线| 精品人妻无码一区二区三区蜜桃一 | 久久久999国产精品| 女人高潮被爽到呻吟在线观看| 国产日本欧美一区| 欧美五码在线| 色乱码一区二区三区熟女 | 午夜精品一区二区三区在线视| 91精品影视| 国产亚洲精品自在久久| 国产精品伦理久久久久久| 欧美三级午夜理伦三级| 国产成人aaaa| 精品无码一区二区三区蜜臀| 欧美性极品xxxx做受| 亚洲欧美国产高清va在线播放| 欧美日韩和欧美的一区二区| 少妇一级淫片免费看| 欧美成人午夜剧场免费观看| 亚洲伦乱视频| 久久国产一区二区| 精品电影在线| 欧美在线观看一区| 亚洲 欧美 激情 另类| 欧美成人免费网| 国产精品毛片aⅴ一区二区三区| 日韩亚洲视频| 免费在线成人| 亚洲综合自拍网| 亚洲综合在线第一页| 国产欧美一区二区三区视频在线观看 | 日本熟妇人妻中出| 91污在线观看| 日产电影一区二区三区| 欧美成人一区二区三区片免费 | 日本久久91av| 老牛影视av一区二区在线观看| 欧美另类videosbestsex日本| 精品一区二区三区香蕉蜜桃| 亚洲色图27p| 51精品国自产在线| 免费av在线播放| 91精品久久久久| 91精品国产自产拍在线观看蜜| 亚洲国产高清av| 国产精品乱码人人做人人爱| 中文字幕人妻一区二区在线视频 | 大黄网站在线观看| av资源站久久亚洲| 欧美人成网站| 岛国av免费观看| 婷婷综合另类小说色区| 少妇人妻一区二区| 日本不卡高字幕在线2019| 色天下一区二区三区| 欧洲av无码放荡人妇网站| 久久久影视传媒| 久久久999久久久| 在线视频中文亚洲| 成人乱码手机视频| 天堂а√在线中文在线| 福利电影一区二区三区| 日韩美女一级片| 亚洲女人被黑人巨大进入| 97成人超碰| 法国空姐在线观看免费| 成人一级片网址| 亚洲精品中文字幕乱码三区91| 伊人久久久久久久久久久| 久久久久久久性潮| www.国产在线视频| 97久久久精品综合88久久| 亚洲高清视频免费观看| 久久精品在线播放| 99ri日韩精品视频| 欧洲av无码放荡人妇网站| 国产精品国产三级国产专播品爱网 | 亚洲精品88| 亚洲精品日韩成人| 国产盗摄女厕一区二区三区| 日韩av手机在线播放| 欧美日韩国产黄| 国产高清视频在线| 91情侣偷在线精品国产| 一区精品久久| 亚洲精品国产一区黑色丝袜| 欧美精品一级二级三级| 538在线视频| 天堂一区二区三区| 国产寡妇亲子伦一区二区| 日韩综合在线观看| 久热精品在线视频| 免费成人高清在线视频theav| 日本不卡一区二区在线观看| 亚洲国产aⅴ成人精品无吗| 国产裸舞福利在线视频合集| 97久久精品午夜一区二区| 久久人人超碰| 久久久久人妻一区精品色欧美| 国产一区av在线| 国产女人18毛片水真多18精品| jizz欧美性11|