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

如何在 Npm 上發布二進制文件?

開發 前端
作為一個cli工具,我們的f_cli需要發配給團隊伙伴使用。此時就會出現一個問題,團隊伙伴的開發環境(處理器架構/操作系統)可能和我們本機不一樣,所以我們需要將Rust編譯成適配不同的處理器架構和操作系統。

??????號外,號外。我們的f_cli現在有了npm版本了。有兩種主流的方式來訪問。

  1. 全局安裝

npm i -g f_cli_f

f_cli_f create 你的項目名稱

  1. npx 操作
  2. npx f_cli_f create 你的項目名稱

隨意選中任意一個方式,不出意外的話,就在指定的文件路徑下,生成了一個功能完備的前端項目。

前言

我們主要的精力放在如何配置一個「功能全備」的前端項目。

然后,有些同學說,既然cli都有了,但是下載二進制文件很麻煩。最好是將f_cli發布到npm上。畢竟,在前端開發中,npm大家都熟悉。

所以,今天我們就來講講「如何將二進制文件發布到npm」。

好了,天不早了,干點正事哇。

我們能所學到的知識點

  1. Rust項目交叉編譯
  2. 構建&發布目標npm項目
  3. 構建&發布主包
  4. 本地應用

1. Rust項目交叉編譯

要將源代碼編譯到與本地平臺不同的平臺上,需要指定一個目標(target)。這將告訴編譯器應該為哪個平臺編譯代碼。

確定target

作為一個cli工具,我們的f_cli需要發配給團隊伙伴使用。此時就會出現一個問題,團隊伙伴的開發環境(處理器架構/操作系統)可能和我們本機不一樣,所以我們需要將Rust編譯成適配不同的處理器架構和操作系統。

以下是我們工作中比較常見的開發環境。

  • Darwin(arm)
  • Darwin(arm64)
  • Darwin(x64)
  • Linux (arm)
  • Windows (i686)
  • Windows (x64)

針對f_cli我們只兼容比較場景的開發環境。(后期有需要會兼容更多版本)

  • Darwin(arm64) - MacOS的M1版本
  • Darwin(x64) - MacOS的Intel版本
  • Windows (x64) - Windows

安裝指定target

我們要想將Rust項目編譯成指定的目標二進制,我們可以在cargo build時,使用--target xxx參數來指定目標環境。

還記得rustup嗎?我們在Rust環境配置和入門指南中有過介紹。

rustup的命令行工具來完成Rust的下載和安裝,這個工具被用來管理不同的Rust發行版本及其附帶工具鏈。

其實rustup除了安裝和更新Rust,它還可以查看rust在交叉編譯[1]時,能夠轉換的目標環境。

我們可以通過rustup target list來查看這些信息。

圖片圖片

上圖是我本機已經安裝的target。(我多加了一個參數--installed)

  • aarch64-apple-darwin -支持Mac Arm
  • x86_64-apple-darwin - 支持Mac Intel(也是我本機環境)
  • x86_64-pc-windows-gnu - 支持Windows環境

其中wasm32-unknown-unknown是我們處理Rust轉WebAssembly時,才用到。關于這點,可以參考我們之前的文章Rust 編譯為WebAssembly 在前端項目中使用。

既然,目標環境已經確定,那我們就需要將目標環境加入到Rust環境中。

rustup target add xxxx

通過上述命令,我們就將xxxx的環境加入到Rust中。除了像上面使用rustup target list --installed來查看已經安裝的目標環境。

我們也可以使用rustup show來查看本機的工具環境。

圖片圖片

執行編譯

其實這步也沒啥可說的。要想Rust編譯成目標環境我們僅需在cargo build時,新增target參數即可。

cargo build --release ----target = xxxx

在執行完build后,會在Rust項目中target目錄下生成對應的編譯結果。

圖片圖片

由于我本機屬于x86_64-apple-darwin,所以在build時可以不加target參數。

然后我們可以在目標目錄中的release中找到f_cli二進制文件。

圖片圖片

針對Windows環境的特殊處理

在MacOS中將Rust編譯為可以在Windows環境下執行的二進制時,需要做額外的處理。

圖片圖片

更多詳情可以參考如何在 Mac 上為 Windows 編譯 Rust 程序[2]

2. 構建&發布目標npm項目

我們的目標是- 將build后的二進制文件放置到npm包中,然后通過node進行下載安裝。

如果將所有平臺的二進制放到一個npm是極其耗費流量的。所以,我們采用的是「按需下載」的方式。

所以,我們就把上一節中交叉編譯的三個二進制文件「分別發布」成一個npm包。

  • f_cli_darwin_arm64
  • f_cli_darwin_x64
  • f_cli_windows_x64

對于快速構建一個npm目錄我們可以使用npm init然后一路回車。但是,我們不這樣做,我們這里采用手動構建package.json。然后配置一些參數即可。關于package.json中各個字段的含義,可以參考package.json的字段信息[3]

子包的目錄結構

由于我們子包的作用就是存儲二進制文件,所以我們采用最簡單的目錄結構

由于子包的處理邏輯很類似,我們下文中除了要特殊說明,都是按照一個子包的處理方式來講解

"f_cli_darwin_arm64"/"f_cli_darwin_x64"
 ├── package.json
 └── bin/
     └── f_cli

"f_cli_windows_x64"
 ├── package.json
 └── bin/
     └── f_cli.exe

bin文件夾中就是存放我們二進制源文件的,這里沒啥可說的。我們來簡單聊聊package.json

package.json

下面的package.json的內容是f_cli_darwin_arm64的。其他兩個子包的信息也是大差不差的。

{
  "name": "f_cli_darwin_arm64",
  "version": "1.0.0",
  "description": "f_cli適配MACOS_ARM64架構",
  "keywords": [
    "f_cli",
    "MACOS_ARM64"
  ],
  "author": "",
  "license": "ISC",
  "os": ["darwin"],
  "cpu": ["arm64"]
}

其中有幾個屬性我們需要額外說明一下:

  1. name該字段是我們發布npm包時,最主要的字段,你可以將起認為是數據庫中的主鍵,我們平時通過npm install xxx安裝包時,xxx就是此處的name的值

在發布包之前,我們可以為其指定具有特殊含義的名稱,同時該名稱需要在npm倉庫中唯一,不然在npm publish時就會發生錯誤

同時該名稱的格式也有要求,它需要符合^(?:(?:@(?:[a-z0-9-*~][a-z0-9-*._~]*)?/[a-z0-9-._~])|[a-z0-9-~])[a-z0-9-._~]*$正則規則

  1. os:指定模塊將在哪些操作系統上運行
  • 該值由node中的process.platform[4]決定,用于獲取操作系統平臺信息。
  • 值為aix, android, darwin, freebsd, linux, openbsd, sunprocess, win32
  1. cpu:指定代碼只能在某些 CPU 架構上運行
  • 該值由node中的process.arch[5]決定,用于獲取操作系統平臺信息。
  • 值為x32, x64, arm, arm64, s390, s390x, mipsel, ia32, mips, ppc, ppc64.

我們后期會有關于package.json各個字段的介紹文章

發布子包到npm

其實這步特別簡單就是兩個命令

  • npm login
  • npm publish

對于如何發布一個npm包,這里我們就不再贅述。后期如果有需求可以單寫一篇。

通過上述的操作,我們就把三個二進制文件發布到npm上了。

圖片圖片

上面還有一個f_cli_f,別著急,我們馬上會講到。

3. 構建&發布主包

上面我們通過各自上傳子包到npm,實現了資源的分離處理。下面我們就需要通過一些方式讓主包在被安裝時,能夠自動識別出工作平臺所需要目標并且執行對應的下載和安裝任務。

簡而言之,我們需要在主包被安裝時,實現按需下載

npm 按需下載原理

在package.json中有兩種方式可以下載特定于平臺的二進制文件,而無需下載所有二進制文件。

optionalDependencies

所有常用的 JavaScript 包管理器都支持 package.json 中的 optionalDependencies[6] 字段。包管理器通常會安裝 optionalDependencies 中列出的所有軟件包,但他們可能會根據某些條件選擇不安裝。

其中一個標準就是依賴項 package.json 文件中的 os 和 cpu 字段。(我們在處理子包時就已經把這些值賦值了)

「只有當這些字段的值與當前系統的操作系統和架構相匹配時,才會安裝依賴包」。這意味著我們可以發布單獨的軟件包,每個軟件包只包含一個特定于平臺的二進制文件,但其中的os和cpu字段指明了這些軟件包適用的體系結構,軟件包管理器將自動安裝正確的軟件包。

postinstall 腳本

如果在 package.json 中包含一個名為 postinstall 的腳本,則該腳本將在包安裝后「立即執行」,即使它是作為安裝包安裝的一種依賴。(在前端項目里都有啥?,我們講過prepare,其實他們的作用是類似的)

我們可以使用 postinstall 腳本下載當前平臺的二進制文件并將其存儲在系統上的某個位置。其實我們可以把這個包的位置存放到任何你信得過的地方,此處我們為了方便將二進制文件都放置到了npm倉庫了。

最優解

這兩種方法都有缺點,可能不適用于所有設置。

  • 如果禁用optionalDependencies可能會遇到問題(例如,通過yarn的--ignore-optional標志)。
  • postinstall 腳本也可以被禁用,并且可能會出現更多問題,因為通常建議禁用它們,因為它們容易受到攻擊。

為了最大限度地提高成功的可能性,我們將兩種方式都融合進主包中。

目錄結構

其實主包的目錄結構也很簡單。和子包類似,有package.json/bin/二進制源文件

f_cli
 ├── install.js
 ├── package.json
 └── bin/
     └── f_cli

那么下面我們就依次解釋上面文件的含義。

package.json

{
  "name": "f_cli_f",
  "version": "1.0.3",
  "description": "針對f_cli的npm 包",
  "scripts": {
    "postinstall": "node ./install.js"
  },
  "bin": {
    "f_cli_f": "bin/cli"
  },
  "optionalDependencies": {
    "f_cli_darwin": "1.0.0",
    "f_cli_linux": "1.0.0",
    "f_cli_win32": "1.0.0"
  }
}

上面出現的scripts.postinstall和optionalDependencies我們在本節剛開始就解釋了。這里就不再啰嗦。

在這里我們來講講bin字段。

bin

bin 字段允許將包中的特定文件鏈接到全局的可執行路徑,使其成為全局命令,方便用戶在命令行中直接調用。

bin 是 package.json 文件中的一個字段,用于定義「將包安裝為全局命令時的可執行文件」。

bin 字段是一個對象,其中鍵是要創建的全局命令的名稱,值是要執行的本地文件的路徑。

當用戶全局安裝該包時,bin 字段允許將指定的本地文件鏈接到全局的可執行路徑,使用戶可以在命令行中直接運行該文件。

像上文中bin 字段為 { "f_cli_f": "bin/cli" },那么在全局安裝該包后,用戶可以直接在命令行中運行 f_cli_f,實際上會執行 bin/cli 文件。

# 方式1: 全局按照
$ npm i -g f_cli_f
$ f_cli_f create xxx

# 方式2:包管理器
$ npx f_cli_f

install.js

// 引入必要的Node.js模塊
const fs = require('fs'); // 文件系統模塊
const path = require('path'); // 路徑模塊
const zlib = require('zlib'); // 壓縮模塊
const https = require('https'); // HTTPS模塊


// 所有平臺和二進制分發包的查找表
const BINARY_DISTRIBUTION_PACKAGES = {
  'darwin-x64': 'f_cli_darwin_x64',
  'darwin-arm64': 'f_cli_darwin_arm64',
  'win32-x64': 'f_cli_windows_x64',
}

// 調整你想要安裝的版本。也可以將其設置為動態的。
const BINARY_DISTRIBUTION_VERSION = '1.0.0';

// Windows平臺的二進制文件以.exe結尾,因此需要特殊處理。
const binaryName = process.platform === 'win32' ? 'f_cli.exe' : 'f_cli';

// 確定當前平臺的包名
const platformSpecificPackageName =
  BINARY_DISTRIBUTION_PACKAGES[`${process.platform}-${process.arch}`];

// 計算我們要生成的備用二進制文件的路徑
const fallbackBinaryPath = path.join(__dirname, binaryName);

// 創建HTTP請求的Promise函數
function makeRequest(url) {
  return new Promise((resolve, reject) => {
    https
      .get(url, (response) => {
        if (response.statusCode >= 200 && response.statusCode < 300) {
          const chunks = [];
          response.on('data', (chunk) => chunks.push(chunk));
          response.on('end', () => {
            resolve(Buffer.concat(chunks));
          });
        } else if (
          response.statusCode >= 300 &&
          response.statusCode < 400 &&
          response.headers.location
        ) {
          // 跟隨重定向
          makeRequest(response.headers.location).then(resolve, reject);
        } else {
          reject(
            new Error(
              `npm在下載包時返回狀態碼 ${response.statusCode}!`
            )
          );
        }
      })
      .on('error', (error) => {
        reject(error);
      });
  });
}

// 從tarball中提取文件的函數
function extractFileFromTarball(tarballBuffer, filepath) {
  let offset = 0
  while (offset < tarballBuffer.length) {
    const header = tarballBuffer.subarray(offset, offset + 512)
    offset += 512

    const fileName = header.toString('utf-8', 0, 100).replace(/\0.*/g, '')
    const fileSize = parseInt(header.toString('utf-8', 124, 136).replace(/\0.*/g, ''), 8)

    if (fileName === filepath) {
      return tarballBuffer.subarray(offset, offset + fileSize)
    }

    // 將offset固定到512的上限倍數
    offset = (offset + fileSize + 511) & ~511
  }
}

// 從Npm下載二進制文件的異步函數
async function downloadBinaryFromNpm() {
  // 下載正確二進制分發包的tarball
  const tarballDownloadBuffer = await makeRequest(
    `https://registry.npmjs.org/${platformSpecificPackageName}/-/${platformSpecificPackageName}-${BINARY_DISTRIBUTION_VERSION}.tgz`
  )

  const tarballBuffer = zlib.unzipSync(tarballDownloadBuffer)

  // 從軟件包中提取二進制文件并寫入磁盤
  fs.writeFileSync(
    fallbackBinaryPath,
    extractFileFromTarball(tarballBuffer, `package/bin/${binaryName}`),
    { mode: 0o755 } // 使二進制文件可執行
  )
}

// 檢查是否已安裝平臺特定的軟件包
function isPlatformSpecificPackageInstalled() {
  try {
    // 如果optionalDependency未安裝,解析將失敗
    require.resolve(`${platformSpecificPackageName}/bin/${binaryName}`)
    return true
  } catch (e) {
    return false
  }
}

// 如果不支持當前平臺,拋出錯誤
if (!platformSpecificPackageName) {
  throw new Error('不支持的平臺!')
}

// 如果通過optionalDependencies已安裝二進制文件,則跳過下載
if (!isPlatformSpecificPackageInstalled()) {
  console.log('未找到平臺特定的軟件包。將手動下載二進制文件。')
  downloadBinaryFromNpm()
} else {
  console.log(
    '平臺特定的軟件包已安裝。將回退到手動下載二進制文件。'
  )
}

?

這段代碼的作用是根據當前的操作系統和架構,從 Npm 下載特定平臺的二進制文件,并將其寫入磁盤。

?

大部分的代碼都有注釋,具體的功能也一目了然,這里就不再過多解釋。我們挑幾個比較重要的點來說明一下。

  • BINARY_DISTRIBUTION_PACKAGES: 用于存儲所有平臺和二進制包的信息
  • 使用process.platform和process.arch用于確定符合當前工作環境的二進制包名稱
  • isPlatformSpecificPackageInstalled方法用于判斷是否根據optionalDependency安裝了指定的包,如果因為特殊原因沒安裝成功,我們就需要執行手動下載操作(downloadBinaryFromNpm)

如果上述操作一切順利的話,我們就會在主包的根目錄下,按照了我們的二進制文件。

bin/cli

#!/usr/bin/env node

const path = require("path");
const childProcess = require("child_process");

// 存儲所有平臺和二進制分發包的查找表
const BINARY_DISTRIBUTION_PACKAGES = {
  'darwin-x64': 'f_cli_darwin_x64',
  'darwin-arm64': 'f_cli_darwin_arm64',
  'win32-x64': 'f_cli_windows_x64',
};

// Windows平臺的二進制文件以.exe結尾,因此需要特殊處理
const binaryName = process.platform === "win32" ? "f_cli.exe" : "f_cli";

// 確定此平臺的軟件包名稱
const platformSpecificPackageName =
  BINARY_DISTRIBUTION_PACKAGES[`${process.platform}-${process.arch}`]

function getBinaryPath() {
  try {
    // 如果optionalDependency未安裝,解析將失敗
    return require.resolve(`${platformSpecificPackageName}/bin/${binaryName}`);
  } catch (e) {
    // 如果未安裝,返回二進制文件的路徑
    return path.join(__dirname, "..", binaryName);
  }
}

// 使用child_process模塊執行二進制文件并傳遞命令行參數
childProcess.execFileSync(getBinaryPath(), process.argv.slice(2), {
  stdio: "inherit",
});

上面的具體邏輯和我們install.js是類似的,都是基于process.platform和process.arch確定當前工作環境匹配的二進制源文件,并且執行下載操作。

就像上面說的一樣,bin/cli這個方式是可以在命令行直接執行的。npx f_cli_f create xxx。

有一個點還是忍不住的想介紹一下

  1. #!/usr/bin/env node 是一個稱為"shebang"的特殊注釋,通常出現在Unix或類Unix系統中的腳本文件的開頭。

這行代碼告訴操作系統使用/usr/bin/env來查找node命令,并使用它來解釋和執行該腳本文件。這樣做的好處是,它允許腳本在不同的系統上找到正確的node解釋器,而不需要硬編碼node的路徑。

注意點

像使用bin/cli這種方式在命令行執行命令時,有一點需要額外的注意。如果你當前工作環境中只有一個Node環境,因為我們cli中存在文件的寫入操作,此時在執行命令時,會有一個寫入操作權限的錯誤警告。

其實這是一類錯誤,也就是npm在執行時候需要sudo的操作權限。

圖片圖片

在stackoverflow中有很多關于npmthrowing error without sudo的解決方案[7]

其中一個高贊回答就是讓我們使用nvm等node版本管理工具。在之前我們寫過文章如何更優雅的使用node版本管理工具 - fnm 高階版的nvm。

發布主包到npm

其實這步特別簡單就是兩個命令

  • npm login
  • npm publish

這樣我們所有的資源都上傳到npm了。然后,我們就可以通過我們熟悉的包管理器yarn/npm來安裝了。

額外說明

在上面的處理邏輯中我們只依據process.platfrom和process.arch做了最簡單的環境適配,其實這里還可以有很多的分支處理。

如果大家看過oxlint-npm的源碼[8]的話,它就對環境有很多的處理。

4. 本地應用

在npm中我們已經看到我們的cli已經上傳成功了。

接下來,我們就可以利用yarn/npm等執行下載操作了。

全局安裝

npm i -g f_cli_f

在控制臺中執行上述操作,然后我們就將f_cli_f安裝到npm全局環境了。

我們可以通過npm list -g來查看是否在全局按照成功。

然后我們就可以下面的命令在本地使用我們的cli創建項目了。

f_cli_f create project

npx

除了全局安裝,我們也可以使用npx f_cli_f create project進行項目的初始化。

責任編輯:武曉燕 來源: 前端柒八九
相關推薦

2022-10-31 08:02:42

二進制計算乘法

2009-08-12 18:06:53

C#讀取二進制文件

2020-05-06 09:51:37

二進制Linux命令行工具

2009-12-16 10:49:42

Ruby操作二進制文件

2009-12-10 09:24:50

PHP函數fwrite

2023-09-18 23:50:25

二進制文件裁剪Layout

2022-11-18 10:17:01

2022-08-14 08:29:21

npmNode

2013-04-28 15:37:35

JBoss

2021-11-10 09:15:00

CPU01 二進制Linux

2009-11-02 11:27:42

VB.NET二進制文件

2018-10-22 14:37:16

二進制數據存儲

2009-02-27 09:37:33

Google二進制代碼

2020-05-22 18:00:26

Go二進制文件編程語言

2023-12-26 15:10:00

處理二進制文件

2010-06-09 13:02:29

MySQL啟用二進制日

2010-10-13 15:45:23

MySQL二進制日志

2023-03-20 08:24:31

工具GoReleaser

2022-07-26 13:00:01

安全符號源代碼

2017-04-11 10:48:53

JS二進制
點贊
收藏

51CTO技術棧公眾號

欧美在线观看一区二区三区| 国产精品毛片久久久久久久| 欧美激情久久久久久| 爱豆国产剧免费观看大全剧苏畅| h视频网站在线观看| 中国女人久久久| 亚洲欧美综合图区| 依人在线免费视频| 青青草原国产在线| 成人综合在线观看| 国内外成人免费激情在线视频网站 | 四虎在线视频| 日韩伦理av| www.av精品| 国产一区视频在线播放| 国产一级二级毛片| 精品国产不卡| 日韩欧美aaaaaa| 久久婷婷国产91天堂综合精品| 影音先锋男人在线资源| 国产三级精品三级| 国产一区二区高清不卡| 亚洲一区 中文字幕| 国产一区91| 久久99精品久久久久久青青91| 亚欧洲乱码视频| 日本一区二区三区视频在线看| 在线视频你懂得一区二区三区| 国产在线xxxx| 成a人片在线观看| 国产亚洲欧美中文| 久久av一区二区三区漫画| 国产人妻精品一区二区三| 久久精品一区二区国产| 久久全球大尺度高清视频| 成人免费毛片xxx| av伊人久久| 亚洲欧美日本另类| 久久精品综合视频| 国产一区福利| 欧美精品一区二区三区在线 | 精品中文字幕一区二区三区四区| 欧美在线影院一区二区| 中文字幕无码精品亚洲35| 污污网站在线观看| 亚洲精品亚洲人成人网| 一区在线电影| 麻豆网站在线免费观看| 国产精品久久久久7777按摩| 日韩在线三级| 国产三级在线免费| 久久精品夜色噜噜亚洲a∨ | 欧美好骚综合网| 一区二区三区视频免费| 乐播av一区二区三区| 久操成人av| 亚洲人成网站777色婷婷| 国产精品一区二区入口九绯色| 国产精品17p| 亚洲精品久久久久久久久久久久| 国产性生活毛片| 麻豆精品av| 精品亚洲国产视频| 日韩av在线看免费观看| 欧美伦理在线视频| 一本色道久久88综合亚洲精品ⅰ| 久久久久久久久久久久久久久| 黑人操亚洲人| 日韩在线观看精品| 亚洲最大的黄色网址| 国产一区激情| 欧美在线激情视频| 亚洲精品毛片一区二区三区| 男人的j进女人的j一区| 国产欧美日韩91| 国产熟女一区二区三区四区| 粉嫩在线一区二区三区视频| 精品福利影视| 粉嫩av在线播放| 亚洲欧洲精品一区二区精品久久久| 潘金莲一级淫片aaaaa免费看| 日本在线视频www鲁啊鲁| 亚洲成人av一区二区三区| 日本网站免费在线观看| 日本一区免费网站| 7777精品久久久大香线蕉| 国偷自产av一区二区三区麻豆| 99亚洲乱人伦aⅴ精品| 亚洲激情国产精品| 国产精品酒店视频| 午夜国产精品视频免费体验区| 欧美黑人又粗大| 亚洲国产精品无码久久久| 激情综合色播激情啊| 成人情视频高清免费观看电影| 外国精品视频在线观看 | 91首页免费视频| 五月天婷亚洲天综合网鲁鲁鲁| 黄色在线观看网站| 午夜精品成人在线视频| www.cao超碰| 麻豆精品av| 久久视频国产精品免费视频在线| 日韩高清免费av| 精品一区二区在线看| 国产在线一区二| 日本成a人片在线观看| 同产精品九九九| 亚洲理论中文字幕| 免费av一区二区三区四区| 麻豆成人在线看| 免费的毛片视频| 国产成人免费视频网站| 涩涩涩999| h片在线观看视频免费免费| 欧美日韩在线播放三区| 精品中文字幕在线播放| 午夜av一区| 国产精品99导航| 五月婷婷在线播放| 亚洲欧洲综合另类在线| 成人黄色一区二区| 奇米影视777在线欧美电影观看| 菠萝蜜影院一区二区免费| 久久99国产综合精品免费| 国产不卡视频在线观看| 中文字幕久久综合| 欧亚一区二区| 亚洲欧美一区二区三区情侣bbw| 久草视频手机在线观看| 国内外成人在线视频| 亚洲成人一区二区三区| **在线精品| 亚洲欧洲av一区二区| 男女视频免费看| 成人动漫一区二区| 男女私大尺度视频| 亚洲一区二区三区四区电影| 欧美成人国产va精品日本一级| 一级爱爱免费视频| 中文字幕精品在线不卡| 在线观看免费成人av| 亚洲+变态+欧美+另类+精品| 久久人人爽人人| 蜜臀久久精品久久久久| 亚洲一区二区三区四区五区黄| 久久久久久国产精品日本| 亚洲欧美综合久久久| 成人在线观看视频网站| 免费在线观看av| 欧美精品1区2区3区| 欧美另类videoxo高潮| 精品亚洲aⅴ乱码一区二区三区| 亚洲一区二区在线看| 欧美一级做a| 日韩在线视频中文字幕| 国产乱码精品一区二三区蜜臂 | 日韩一区二区三区精品视频第3页| 久久久国产一区二区三区| 国产精品久久婷婷| 亚洲精品v日韩精品| avtt中文字幕| 国产欧美日韩一级| 欧美精品久久久| 日本精品网站| 久久色在线播放| 成人免费视频国产免费麻豆| 性感美女极品91精品| 一本加勒比北条麻妃| 日韩va欧美va亚洲va久久| 亚洲一区尤物| 911亚洲精品| 日本欧美一级片| 亚洲xxxxxx| 日韩视频免费直播| 亚洲欧美在线观看视频| 国产日韩视频一区二区三区| 五月天激情播播| 激情综合激情| 日本高清一区| 国产精品亚洲一区二区在线观看| 午夜剧场成人观在线视频免费观看| 成年人av电影| 成人激情免费网站| 最近免费中文字幕中文高清百度| 日韩欧美一区免费| 99在线观看视频| 蜜臀国产一区| 欧美成人午夜视频| 日韩在线免费看| 欧美疯狂性受xxxxx喷水图片| 国产一级一片免费播放| 久久久久久久久99精品| 亚洲国产综合av| 老司机精品导航| a级片一区二区| 欧洲专线二区三区| 粉嫩av免费一区二区三区| 欧美xx视频| 久久久久免费精品国产| 在线观看h片| 亚洲第一中文字幕| 亚洲在线精品视频| 午夜a成v人精品| 最新一区二区三区| 国产亚洲成年网址在线观看| 极品人妻一区二区| 麻豆精品视频在线观看免费| 欧美精品自拍视频| 一区二区三区午夜视频| 欧美性大战久久久久| 99国产精品免费网站| 国产色综合天天综合网| 超级碰碰久久| 久久久久久久久久久av| 欧美成年黄网站色视频| 亚洲欧美在线x视频| www国产在线| 欧美精品日韩精品| 国产一卡二卡三卡| 精品久久久视频| 久久视频免费看| 亚洲人成在线播放网站岛国 | 亚洲欧美日韩在线| 快灬快灬一下爽蜜桃在线观看| 97超碰欧美中文字幕| jjzz黄色片| 国产激情一区二区三区桃花岛亚洲| 亚洲色图久久久| 蜜桃久久av| 91国视频在线| 亚洲深夜影院| 免费av手机在线观看| 国产真实久久| 8x8ⅹ国产精品一区二区二区| 久久精品影视| 久久免费视频2| 我不卡影院28| 男女激烈动态图| 久久精品一区二区不卡| a级黄色片网站| 亚洲色图欧美| 18视频在线观看娇喘| 国产精品黑丝在线播放| 国产精品无码乱伦| 91精品99| 激情成人开心网| 亚洲天堂黄色| 日本a在线免费观看| 亚洲国产精品一区| 日韩日韩日韩日韩日韩| 99riav国产精品| 99re在线视频免费观看| 石原莉奈在线亚洲三区| 精品久久久久久久无码| 日本成人中文字幕在线视频| 9l视频白拍9色9l视频| 久久精品国产在热久久| 91热视频在线观看| 国产成a人亚洲| 菠萝菠萝蜜网站| 国产视频一区不卡| 99成人在线观看| 亚洲一区二区视频在线| 91午夜视频在线观看| 色婷婷激情综合| 亚洲综合免费视频| 日韩小视频在线观看专区| 丰满肥臀噗嗤啊x99av| 精品无人区太爽高潮在线播放 | 亚洲免费一级片| 国产丝袜一区二区| 日韩伦理在线观看| 欧美高清无遮挡| 涩涩视频在线| 国产欧美一区二区三区在线看| 日韩综合一区二区三区| 久久综合色一本| 97国产精品| 久久综合久久网| 日韩电影免费在线| 91丨porny丨九色| 91丝袜高跟美女视频| 林心如三级全黄裸体| 亚洲国产一二三| 国产又粗又猛又黄视频| 91精品国产91热久久久做人人| 色香蕉在线视频| 中文字幕精品av| 成人免费观看在线观看| 国产精品午夜国产小视频| 亚洲视频一起| 亚洲人成网站在线观看播放| 欧美a级在线| 亚洲视频在线观看一区二区三区| 理论片日本一区| www.日本高清| 亚洲天堂久久久久久久| 蜜臀精品一区二区三区| 91精品国产黑色紧身裤美女| 精品一二三区视频| 欧美精品激情在线| 精品久久毛片| 裸模一区二区三区免费| 中文字幕免费一区二区三区| 欧美韩国日本在线| 国产成人av影院| 懂色av蜜臀av粉嫩av永久| 精品国产精品自拍| 国产丰满美女做爰| 在线视频欧美日韩精品| 中文字幕人成乱码在线观看 | 九九在线精品| 日韩xxxx视频| 国产精品一区久久久久| 亚洲一级片在线播放| 欧美日韩中文在线| 亚洲成人一级片| 久久伊人精品一区二区三区| 黄色精品视频| 蜜桃麻豆www久久国产精品| 国产综合激情| 亚洲av午夜精品一区二区三区| 国产精品国产三级国产| 成年人视频免费| 亚洲欧美日韩精品久久亚洲区| gogo久久| 国产欧美一区二区视频| 中文字幕av亚洲精品一部二部| av污在线观看| 国产精品欧美久久久久无广告 | 亚洲精品丝袜日韩| 91九色美女在线视频| 国产精品区一区二区三含羞草| 欧美激情视频一区二区三区在线播放 | 精品sm捆绑视频| 新版中文在线官网| 成人片在线免费看| 黄色成人在线网址| 男人网站在线观看| 亚洲国产日韩在线一区模特| 亚洲精品国产片| 欧美精品久久久久久久免费观看| 视频国产精品| 国产在线视频在线| av高清久久久| 成人免费看片98欧美| 亚洲欧美国产精品| 国产不卡网站| 性欧美videosex高清少妇| 免费观看日韩av| 亚洲综合视频网站| 精品美女在线播放| 蜜桃视频在线网站| 日韩av电影免费观看| 青青国产91久久久久久| 精品一区二区在线观看视频| 欧美精品 日韩| 黄色在线观看视频网站| 黄色一区三区| 日韩精品亚洲一区二区三区免费| 调教驯服丰满美艳麻麻在线视频| 欧美私人免费视频| 91香蕉在线观看| 精品九九九九| 日本aⅴ精品一区二区三区| 日本黄色录像视频| 欧美不卡一区二区三区四区| 国产伦久视频在线观看| 欧洲一区二区在线| 黑人精品欧美一区二区蜜桃| 久久精品www| 亚洲人成网站999久久久综合| 日韩欧乱色一区二区三区在线| 国产成人在线小视频| 久久新电视剧免费观看| ,亚洲人成毛片在线播放| 欧美放荡办公室videos4k| 午夜精品福利影院| 黄大色黄女片18第一次| 亚洲午夜精品17c| 国产三级在线免费| 成人做爰66片免费看网站| 久久精品导航| 久热这里有精品| 亚洲天堂2020| 日本一区二区三区视频在线看 | 青青草成人av| 色偷偷88888欧美精品久久久| youjizz欧美| 国产精品区在线| 欧美日韩国产一区二区三区| 日本在线观看视频| 久久综合给合久久狠狠色| 国产一区欧美二区| 人人草在线观看| 欧美精品激情在线| 99成人超碰| 欧洲女同同性吃奶| 精品国产一区二区三区忘忧草|