精品欧美一区二区三区在线观看 _久久久久国色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技術棧公眾號

91国偷自产一区二区三区的观看方式| 精品国产老师黑色丝袜高跟鞋| 国产欧美一区二区三区视频 | 日本在线观看视频网站| 国产精品欧美大片| 在线国产亚洲欧美| 久久人妻无码一区二区| 天堂中文在线官网| 轻轻草成人在线| 欧美激情在线有限公司| 谁有免费的黄色网址| 精品久久免费| 色噜噜夜夜夜综合网| 裸体裸乳免费看| 欧美成熟毛茸茸| 国产精品一区一区| 国产精品99一区| 久久久精品国产sm调教网站| 奇米狠狠一区二区三区| 欧美不卡在线视频| 亚洲欧美偷拍另类| 国产乱码午夜在线视频| 中文字幕中文字幕一区| 久久久久网址| 亚洲国产剧情在线观看| 捆绑变态av一区二区三区| 69视频在线免费观看| 日韩成人毛片视频| 欧美综合一区| 精品亚洲国产视频| 久久久久亚洲AV成人网人人小说| 午夜精品久久久久久毛片| 色综合久久综合网97色综合 | jizz日本免费| 一区二区三区在线免费看| 欧美日韩综合一区| 欧美黄色一级片视频| 国产拍在线视频| 亚洲午夜影视影院在线观看| 天天操天天干天天玩| 欧美69xxxx| 中文字幕巨乱亚洲| 免费久久久一本精品久久区| 亚洲欧美色视频| 国产在线精品一区二区三区不卡| 国产欧美精品日韩| 欧美成人精品网站| 日韩二区在线观看| 国产精品成人久久久久| 久久久久久久久久一级| 日韩电影免费在线看| 国产999精品久久久| 久久久免费高清视频| 黑丝一区二区| 国内免费精品永久在线视频| 精品无码人妻一区二区三区品| 久久久久久久久久久久久久| 久久精品一本久久99精品| 欧美色图17p| 国产精品精品| 成人97在线观看视频| 999精品视频在线观看播放| 99久久精品费精品国产| 精品国产一区二区三区在线观看| 美女福利视频网| 亚洲天堂免费| 久久久久九九九九| 国产微拍精品一区| 久久久综合网| 国产区精品视频| 精品黑人一区二区三区国语馆| 国产经典欧美精品| 激情伦成人综合小说| 蜜桃视频在线观看视频| 国产女人aaa级久久久级| 亚洲图片都市激情| 污污网站在线看| 欧美视频一区二区三区…| 少妇人妻互换不带套| 久草综合在线| 日韩免费观看高清完整版| 日韩精品一区二区三区高清免费| 亚洲宅男一区| 久久久国产一区二区| 国产精品成人免费一区二区视频| 国产精品丝袜xxxxxxx| 国产精品色婷婷视频| 国产富婆一级全黄大片| 99久久婷婷国产综合精品 | 欧美二区视频| 欧美在线视频播放| 91亚洲国产成人精品一区| 成人午夜在线免费| 日韩欧美亚洲精品| 欧美野外wwwxxx| 日本道在线观看一区二区| aaaaaaaa毛片| 精品99久久| 欧美激情成人在线视频| 懂色av蜜臀av粉嫩av喷吹 | 欧美特级黄色录像| 伊人成综合网| 欧美在线视频在线播放完整版免费观看| 中文字幕在线观看第二页| 懂色一区二区三区免费观看| 亚洲精品wwwww| 丁香激情五月少妇| 尤物在线精品| 成人欧美一区二区三区黑人孕妇| 色网站免费观看| 日韩一区中文字幕| 男女视频一区二区三区| 成人av动漫| 久久香蕉国产线看观看av| 亚洲图片欧美日韩| 成人av电影在线观看| 中文字幕av导航| 玛雅亚洲电影| 日韩精品福利网站| 老湿机69福利| 蜜臀久久久久久久| 欧美日韩一区二区视频在线| av在线不卡免费| 91精品在线麻豆| 手机av在线不卡| 亚洲一区成人| 精品视频一区在线| 黄页在线观看免费| 91精品国产综合久久福利 | 欧美日一区二区| 国产91精品久| 午夜在线视频免费| 亚洲国产精品麻豆| 激情小说欧美色图| 亚洲欧美亚洲| 亚洲最大的av网站| 精品欧美色视频网站在线观看| 欧美影视一区在线| 国产免费无遮挡吸奶头视频| 亚洲综合二区| 久久国产精品高清| 天堂在线中文网官网| 亚洲精品wwwww| 国产精品久久久免费视频| 成人黄色小视频在线观看| 欧美狂野激情性xxxx在线观| 亚洲电影一区| 国内精品久久久久伊人av| 国模无码一区二区三区| 亚洲伊人伊色伊影伊综合网| 精品久久久久久无码人妻| 欧美日韩hd| 国产富婆一区二区三区 | 国产精品成av人在线视午夜片| 日本福利午夜视频在线| 欧美性生交xxxxx久久久| 麻豆国产精品一区| 视频一区二区国产| 亚洲午夜精品久久久久久浪潮| 91p九色成人| 精品国产美女在线| 性一交一乱一乱一视频| 亚洲国产精品人人做人人爽| 国产高潮视频在线观看| 亚洲一区二区三区高清不卡| 免费看成人片| 日韩综合久久| 免费99精品国产自在在线| 亚洲精品综合网| 精品国产91久久久| 国产男男chinese网站| 日韩二区三区四区| 蜜臀在线免费观看| 精品视频高潮| 国产精品99一区| 1stkiss在线漫画| 亚洲国产小视频| 91porny九色| 亚洲欧美二区三区| 好吊一区二区三区视频| 日本不卡视频一二三区| 视色,视色影院,视色影库,视色网 日韩精品福利片午夜免费观看 | 天天综合网在线观看| 91久久国产综合久久| 日韩av手机在线免费观看| www.欧美亚洲| 亚洲视频一二三四| 亚洲激情精品| 亚洲一区3d动漫同人无遮挡| 大型av综合网站| 国产精品国产亚洲伊人久久| 欧洲在线视频| 色偷偷91综合久久噜噜| 蜜臀久久99精品久久久| 欧美亚洲一区二区在线| 国产大片中文字幕| 国产精品美女久久久久高潮| 艳妇乳肉豪妇荡乳xxx| 日韩av中文字幕一区二区| 成人av在线播放观看| 欧美精选视频在线观看| 国产一区二区三区四区hd| 久久久久久一区二区三区四区别墅| 欧美激情精品久久久久久| 福利视频在线看| 亚洲第一男人av| 国产精品国产一区二区三区四区| 精品久久久久久亚洲国产300| 人妻互换一区二区激情偷拍| bt7086福利一区国产| 中文字幕免费高清在线| 久热国产精品| 无码专区aaaaaa免费视频| 亚洲精品tv久久久久久久久久| 鲁丝一区二区三区免费| 亚洲精品在线播放| 成人性生交xxxxx网站| 欧美成人免费电影| 午夜精品免费视频| 青春草在线免费视频| 日韩在线视频二区| 国产在线视频资源| 日韩经典中文字幕| 婷婷色在线观看| 日韩免费一区二区三区在线播放| 97人妻精品一区二区三区动漫| 色播五月激情综合网| 黄色片视频网站| 亚洲一区av在线| 亚洲成人生活片| 国产精品成人免费| 中文字幕第69页| 欧美国产一区视频在线观看| 精品无码人妻一区| 91免费看视频| 五级黄高潮片90分钟视频| 不卡的av网站| xfplay5566色资源网站| 高清成人在线观看| 免费观看污网站| 懂色av中文一区二区三区 | 成人香蕉社区| 精品国产福利| 亚洲精品亚洲人成在线| 久久久久久久久一区| 亚洲成在人线免费观看| 欧美成人综合一区| 国产欧美一区二区精品久久久| 久久久99爱| 久久爱www成人| 欧美一区二区三区成人久久片| 中国av一区| 日韩欧美一区二区三区四区| 成人精品天堂一区二区三区| 亚州欧美一区三区三区在线| 久9久9色综合| 亚洲午夜精品一区二区三区| 99精品视频精品精品视频| 亚洲av首页在线| 国产精品大片| 欧美s码亚洲码精品m码| 久久久久国产精品一区二区| 中文字幕欧美人妻精品一区| 美女网站色91| 欧美一级免费在线| 成人性色生活片| 天堂久久精品忘忧草| 国产精品成人一区二区艾草 | 欧美人与禽性xxxxx杂性| 久久免费视频这里只有精品| 亚洲天堂手机| 国产欧美欧洲在线观看| 嫩呦国产一区二区三区av| 国产66精品久久久久999小说| 日韩中文av| 亚洲制服欧美久久| 国产一区清纯| av无码精品一区二区三区| 激情小说亚洲一区| 国产草草浮力影院| 国产精品素人一区二区| 在线免费日韩av| 欧美性xxxx在线播放| 国产精品久久久久久免费播放| 精品电影一区二区三区| 国产中文字幕在线视频| 免费成人高清视频| 三上悠亚一区二区| 99精品国产高清一区二区| 蜜乳av综合| 成人污网站在线观看| 久久久久久网| 国产成人精品一区二区在线小狼| 久久久久久久av麻豆果冻| 黑人巨大精品一区二区在线| 色综合视频一区二区三区高清| 精品久久无码中文字幕| 国产亚洲欧美日韩一区二区| 日本精品600av| 国产精品入口免费视| www国产精品| 亚洲在线不卡| 天堂资源在线中文精品| 国产艳妇疯狂做爰视频| 国产精品成人网| 人人妻人人爽人人澡人人精品| 精品欧美乱码久久久久久| 一本一道波多野毛片中文在线 | 一区二区三区福利视频| 91精品国产综合久久香蕉麻豆| 水中色av综合| 欧美精品成人在线| 国产日韩欧美中文在线| 欧美一区1区三区3区公司| 激情欧美一区| 秋霞午夜鲁丝一区二区| 国产精品私房写真福利视频| www.毛片.com| 亚洲国产精品电影在线观看| 91小视频xxxx网站在线| av网站大全在线观看| 欧美日韩综合视频网址| 国产女人18毛片水18精| 国产小视频国产精品| 福利网站在线观看| 91精品视频免费| 日韩a一区二区| 欧美牲交a欧美牲交aⅴ免费下载| 国产白丝网站精品污在线入口| 欧美成人另类视频| 色综合一区二区三区| 天堂在线观看av| 欧美激情在线狂野欧美精品| 日本在线成人| 一本色道久久88亚洲精品综合| 麻豆精品一区二区| 亚洲欧美日韩第一页| 欧美视频一区二区在线观看| 噜噜噜噜噜在线视频| 欧美专区日韩视频| 亚洲+变态+欧美+另类+精品| 黄页免费在线观看视频| 成人高清视频在线| 国产第一页在线播放| 精品国产乱码久久久久久久久| 主播国产精品| 国产高清在线一区二区| 精品1区2区3区4区| 国产chinese中国hdxxxx| 亚洲高清中文字幕| 神马久久久久久久久久| 午夜精品国产精品大乳美女| 国产色噜噜噜91在线精品| 丁香六月激情婷婷| 99久久亚洲一区二区三区青草| 日韩大片免费在线观看| 亚洲级视频在线观看免费1级| 岛国av在线播放| 欧美精品久久久| 麻豆精品视频在线| 动漫性做爰视频| 亚洲国产精品人久久电影| 是的av在线| 视频一区不卡| 国内精品国产成人| 国产亚洲成人av| 日韩精品欧美激情| 成人在线黄色| 久久观看最新视频| 97aⅴ精品视频一二三区| 日本中文字幕在线观看视频| 日韩在线播放视频| 国产精品视屏| 成人性做爰aaa片免费看不忠| 中文字幕一区二区在线观看| 亚洲av无码国产综合专区| 欧美一级大片视频| 日韩欧美高清在线播放| 图片区偷拍区小说区| 在线精品视频小说1| 在线看女人毛片| 欧美成人一区二区在线| 国产一区二区三区精品视频| 日产精品久久久久久久| 色一区av在线| 国产精品男女| 天天摸天天舔天天操| 午夜免费久久看| 亚洲s色大片| 精品欧美国产| 国内成+人亚洲+欧美+综合在线| 黄色激情视频在线观看| 影音先锋日韩有码| 国产精品中文字幕制服诱惑| 成人黄色一区二区| 五月综合激情婷婷六月色窝| 婷婷免费在线视频| 麻豆精品蜜桃一区二区三区| 国产在线观看一区二区| 亚洲天堂视频网站|