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

国产色产综合色产在线视频| 国产精品久久| 欧美午夜精品理论片a级按摩| 国产免费一区视频观看免费| 中文字幕求饶的少妇| 精品视频在线观看免费观看| 午夜视频在线观看一区二区| 日韩免费中文专区| 国产美女主播在线观看| 国产精品videossex久久发布| 日韩欧美一级二级三级| 1024av视频| 欧美私人网站| 成人av网址在线观看| 国产精品xxxxx| 欧美三级在线免费观看| 国产精品欧美三级在线观看| 欧美狂野另类xxxxoooo| 欧美极品欧美精品欧美| 国产原创精品视频| 久久久久久久一区| 999久久久| 欧美日韩 一区二区三区| 欧美一区二区| 在线播放日韩精品| 精品国产乱码久久久久夜深人妻| 日韩欧美一中文字暮专区| 国产欧美精品区一区二区三区 | 欧洲一区二区三区精品| 1000部国产精品成人观看| 久久99精品久久久久久秒播放器| 中文字幕免费在线看| 亚洲精品韩国| 久久综合免费视频| 神马久久久久久久久久久| 高潮按摩久久久久久av免费| 欧美精品乱人伦久久久久久| 日本老熟妇毛茸茸| 成人小电影网站| 婷婷国产在线综合| 国产人妻人伦精品| 午夜精品一区| 国产精品私房写真福利视频| 欧美极品jizzhd欧美| 深夜福利视频网站| www.日韩精品| 国产一区二区自拍| 欧美亚洲精品在线观看| 国产二区国产一区在线观看| 国产伦精品一区二区三区精品视频| 精品美女久久久久| 亚洲精品激情| 97色在线视频观看| 免费看日韩毛片| 在线视频精品| 欧美专区在线视频| 日本熟女毛茸茸| 肉色丝袜一区二区| 国产精品视频导航| 国产乡下妇女三片| 免费人成精品欧美精品| 国产精品专区h在线观看| 怡红院男人天堂| 蜜臀久久99精品久久久久宅男| 97久久精品人搡人人玩| 少妇影院在线观看| 在线日韩视频| 97久久精品国产| 日韩精品人妻中文字幕| 国产精品99免费看| 欧美激情在线狂野欧美精品| 欧美日韩三级在线观看| 欧美一区成人| 久久精品99久久久香蕉| 永久免费看片视频教学| 天天综合网91| 欧美老妇交乱视频| 精品午夜福利视频| 夜久久久久久| 日本精品免费一区二区三区| 麻豆成人免费视频| 青青草97国产精品免费观看无弹窗版| 日韩综合中文字幕| 国产三级黄色片| 禁果av一区二区三区| 亚洲人在线观看| 在线观看国产精品一区| 精品视频亚洲| 久热国产精品视频| 精品少妇久久久| 亚洲高清网站| 欧美一级片久久久久久久| 男人午夜免费视频| 日本伊人色综合网| 成人在线视频网| 国模私拍视频在线| 91麻豆免费看| 一区二区在线观看网站| 中日韩高清电影网| 亚瑟在线精品视频| 亚欧在线免费观看| 4438五月综合| 亚洲国产精久久久久久| 久久美女免费视频| 欧美日韩国产免费观看视频| 欧美xxxx18性欧美| 日韩大片免费在线观看| 天堂va蜜桃一区二区三区漫画版| 国产精品久久久久久av下载红粉| 中文字幕在线观看精品| 国产盗摄精品一区二区三区在线 | 人妻av无码专区| 欧洲一区精品| 欧美影院午夜播放| 欧美一级片在线免费观看| 天天久久夜夜| 免费不卡在线观看av| 欧美性猛交bbbbb精品| 久久99国产精品久久99| 国产视频精品网| 国产午夜精品一区理论片| 亚洲国产精品人人做人人爽| 日韩欧美在线免费观看视频| 麻豆一区在线| 亚洲一区二区久久久| 欧美日韩国产精品综合| 亚洲欧美日本国产专区一区| 99久久无色码| 天堂中文а√在线| 欧美网站在线观看| 久久发布国产伦子伦精品| 国产99亚洲| 欧美激情高清视频| 一二三四区在线| 久久综合九色欧美综合狠狠| 超碰免费在线公开| 爱情电影社保片一区| 亚洲国产成人精品久久| 日本精品在线免费观看| 久久综合伊人| 国产嫩草一区二区三区在线观看| 国产最新视频在线观看| 疯狂蹂躏欧美一区二区精品| 人妻换人妻a片爽麻豆| 在线一区电影| 91成人理论电影| 在线观看中文字幕的网站| 91精品国产黑色紧身裤美女| 日本一二三不卡视频| 国产日韩一区二区三区在线| www 成人av com| 国产成人l区| 制服.丝袜.亚洲.另类.中文 | 亚洲免费激情视频| 精品无码三级在线观看视频| 亚洲电影一二三区| 桃色一区二区| 日韩第一页在线| 久久精品欧美一区二区| 懂色中文一区二区在线播放| 成人性做爰片免费视频| 色综合久久久| 亚洲天堂成人在线| 中文字幕欧美色图| 国产精品污www在线观看| 日日碰狠狠躁久久躁婷婷| 欧美一级三级| 欧美亚洲另类制服自拍| 日本人妻熟妇久久久久久 | 五月婷婷综合色| 欧美福利在线播放| 亚洲新声在线观看| 亚洲无码精品在线播放| 国产精品久久久99| 色免费在线视频| 久久中文字幕二区| 亚洲自拍偷拍视频| 97在线视频免费观看完整版| 亚洲精品美女在线观看| 日韩在线 中文字幕| 欧美国产日韩在线观看| 久久婷五月综合| 66国产精品| 国产成人精品自拍| 国产不卡123| 亚洲色图第一页| 99热这里只有精品9| 亚洲一二三级电影| 国产黄色三级网站| 日韩中文字幕91| 亚洲精品成人久久久998| 香蕉久久一区| 久久久久久国产免费 | 三上悠亚一区二区| 日日狠狠久久偷偷四色综合免费 | av在线天堂| 欧美日韩精品免费| 1024手机在线视频| av电影一区二区| 国产又猛又黄的视频| 综合天天久久| 日韩欧美亚洲v片| 亚洲福利合集| 欧美专区中文字幕| 老司机免费在线视频| 日韩美女一区二区三区| www.欧美色| 亚洲国产精品视频| 来吧亚洲综合网| www.99精品| av中文字幕网址| 中文亚洲欧美| 亚洲最大色综合成人av| 日韩三区视频| 亚洲综合精品一区二区| 桃色av一区二区| 久久综合免费视频| 成人亚洲综合天堂| 亚洲国产精品一区二区久| 一区二区小视频| 午夜精品影院在线观看| 欧美性生给视频| www日韩大片| 无码人妻一区二区三区一| 日韩高清一区在线| 欧美精品久久久久久久自慰| 国产一区二区精品福利地址| 国产一区在线免费观看| 99精品美女视频在线观看热舞| 欧美激情久久久久久| 成年网站在线| 日韩国产激情在线| 亚洲精选一区二区三区| 欧美日韩免费一区二区三区视频 | 刘亦菲久久免费一区二区| 欧美视频一区二区三区四区| 国产午夜激情视频| 亚洲品质自拍视频网站| 伊人影院综合网| 国产日韩精品一区二区浪潮av| 特黄特黄一级片| 美女mm1313爽爽久久久蜜臀| 免费在线观看亚洲视频| 午夜久久福利| 曰韩不卡视频| 日韩中文字幕高清在线观看| 视频一区二区三区在线观看| 亚洲精品中文字幕99999| 国产精品美女久久久久av福利| 久久69成人| 日韩美女免费线视频| 日韩精品美女| 国外成人在线直播| a√中文在线观看| 97在线视频一区| 波多野结衣中文在线| 欧美激情视频一区二区三区不卡| 在线激情小视频| 中文字幕欧美精品日韩中文字幕| 涩涩视频在线观看免费| 亚洲精品永久免费| 亚洲人午夜射精精品日韩| 日韩美女一区二区三区四区| 精品人妻少妇嫩草av无码专区| 欧美日韩激情一区二区三区| 自拍偷拍色综合| 欧美午夜电影在线播放| 天天干天天干天天操| 欧美影院午夜播放| 国产精品久久久久久久成人午夜| 欧美在线制服丝袜| 在线观看国产成人| 欧美日产国产精品| 国产免费一区二区三区最新不卡| 欧美日韩国产a| 国产精品永久久久久久久久久| 欧美日韩国产一区二区三区地区| 免费在线不卡av| 欧美猛男超大videosgay| 91久久久久国产一区二区| 日韩一区二区在线看片| 亚洲三级中文字幕| 亚洲日韩第一页| 午夜在线免费观看视频| 超碰精品一区二区三区乱码| 日本aa在线| 992tv在线成人免费观看| 国产免费不卡| 国产一区私人高清影院| 精品国产三区在线| 久久av一区二区三区亚洲| 欧美日韩播放| 青春草在线视频免费观看| 亚洲日韩视频| 欧美大尺度做爰床戏| 国产精品香蕉一区二区三区| 喷水视频在线观看| 国产欧美日韩麻豆91| 永久久久久久久| 一本大道av一区二区在线播放| 69视频免费看| 日韩欧美电影一区| 日本福利片高清在线观看| 色偷偷888欧美精品久久久| 午夜成年人在线免费视频| 午夜免费在线观看精品视频| 婷婷久久免费视频| 久久草视频在线看| 久久精品高清| 免费不卡av在线| 奇米影视一区二区三区小说| 毛毛毛毛毛毛毛片123| 99在线精品视频| av黄色免费在线观看| 亚洲成人自拍一区| 性色av一区二区三区四区| 亚洲精品在线电影| 成人在线免费公开观看视频| 1769国产精品| 久久视频免费| 日韩久久精品一区二区三区| 欧美精品福利| 免费看涩涩视频| 91亚洲精品一区二区乱码| 欧美大片xxxx| 色综合 综合色| 农村少妇久久久久久久| 日韩在线资源网| 激情欧美丁香| 久久99精品久久久久久水蜜桃| 欧美日韩在线二区| 亚洲熟女乱色一区二区三区| 国产一区福利在线| 尤物在线精品| 免费一区二区三区在线观看| av一区二区三区在线| 亚洲一级生活片| 欧美精品乱人伦久久久久久| 可以免费看污视频的网站在线| www.久久久久| 欧洲av一区二区| 久久婷婷国产综合尤物精品| 亚洲经典一区| 久久精品一区二| 99久久国产综合色|国产精品| 九九热最新地址| 欧美日韩不卡在线| 日韩精品系列| 国产精品xxx视频| 久草在线成人| 91免费视频网站在线观看| 99视频一区二区| 国产无套粉嫩白浆内谢| 精品久久久久久久一区二区蜜臀| 日本三级视频在线播放| 国产精品久久久久久久久久久久久 | 天堂成人娱乐在线视频免费播放网站| 99国产在线视频| 国产精品99久久精品| 五月婷婷之婷婷| 国产精品久久久久影视| 在线观看国产一区二区三区| 亚洲最新av在线| 在线视频成人| 国产高清免费在线| 国产一区二区三区不卡在线观看| 精品一区二区三孕妇视频| 欧美在线一区二区三区| 成人在线网址| 91沈先生播放一区二区| 欧美日韩精品一本二本三本| 欧美成人精品一区二区综合免费| 国产婷婷色一区二区三区| 在线免费观看av片| 久久九九精品99国产精品| 国产精品亚洲欧美日韩一区在线 | 亚洲人和日本人hd| 日本黄网站免费| 国产精品久久三区| av一区二区三| 欧美精品在线播放| 波多野结衣一区二区三区免费视频| 免费观看中文字幕| 国产在线不卡一卡二卡三卡四卡| 免费一级全黄少妇性色生活片| 91精品国产乱码| av资源中文在线| 人偷久久久久久久偷女厕| 久久精品网址| 在线看的片片片免费| 精品国产伦理网| 欧洲亚洲两性| 成人在线观看www| av资源网一区| 中文字幕av免费观看| 欧美成人在线影院| 日本亚洲不卡| 三级a在线观看| 欧美日韩国产精品| 秋霞影院午夜丰满少妇在线视频|