一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

超全面的前端工程化配置指南

 風聲之家 2022-08-15 發(fā)布于江蘇

Vue中文社區(qū) 2022-08-15 08:41 發(fā)表于北京

前端工程化配置指南

本文講解如何構建一個工程化的前端庫,并結合 Github Actions,自動發(fā)布到 Github 和 NPM 的整個詳細流程。

示例

我們經(jīng)常看到像 Vue、React 這些流行的開源項目有很多配置文件,他們是干什么用的?他們的 Commit、Release 記錄都那么規(guī)范,是否基于某種約定?

廢話少說,先上圖!

圖片上圖標紅就是相關的工程化配置,有 Linter、Tests,Github Actions 等,覆蓋開發(fā)、測試、發(fā)布的整個流程。

相關配置清單

  • Eslint
  • Prettier
  • Commitlint
  • Husky
  • Jest
  • GitHub Actions
  • Semantic Release

下面我們從創(chuàng)建一個 TypeScript 項目開始,一步一步完成所有的工程化配置,并說明每個配置含義以及容易踩的坑。

初始化

為了避免兼容性問題,建議先將 node 升級到最新的長期支持版本。

首先在 Github 上創(chuàng)建一個 repo,拉下來之后通過npm init -y初始化。然后創(chuàng)建src文件夾,寫入index.ts。

package.json 生成之后,我需要添加如下配置項:

   "main": "index.js",
+  "type": "module",
   "scripts": {
     "test": "echo \"Error: no test specified\" && exit 1"
   },
+  "publishConfig": {
+    "access": "public"
+  }

我們將項目定義為ESM規(guī)范,前端社區(qū)正逐漸向ESM標準遷移,從Node v12.0.0開始,只要設置了 "type": "module", Node 會將整個項目視為ESM規(guī)范,我們就可以直接寫裸寫import/export

publishConfig.access表示當前項目發(fā)布到NPM的訪問級別,它有 restrictedpublic兩個選項,restricted表示我們發(fā)布到NPM上的是私有包(收費),訪問級別默認為restricted,因為我們是開源項目所以標記為public

配置

創(chuàng)建項目之后,我們開始安裝工程化相關的依賴,因為我們是 TypeScript 項目,所以也需要安裝 TypeScript 的依賴。

Typescript

先安裝 TypeScript,然后使用 tsc 命名生成 tsconfig.json

npm i typescript -D
npx tsc --init

然后我們需要添加修改 tsconfig.json 的配置項,如下:

{
  "compilerOptions": {
    /* Basic Options */
    "baseUrl""."// 模塊解析根路徑,默認為 tsconfig.json 位于的目錄
    "rootDir""src"// 編譯解析根路徑,默認為 tsconfig.json 位于的目錄
    "target""ESNEXT"// 指定輸出 ECMAScript 版本,默認為 es5
    "module""ESNext"// 指定輸出模塊規(guī)范,默認為 Commonjs
    "lib": ["ESNext""DOM"], // 編譯需要包含的 API,默認為 target 的默認值
    "outDir""dist"// 編譯輸出文件夾路徑,默認為源文件同級目錄
    "sourceMap"true// 啟用 sourceMap,默認為 false
    "declaration"true// 生成 .d.ts 類型文件,默認為 false
    "declarationDir""dist/types"// .d.ts 類型文件的輸出目錄,默認為 outDir 目錄
    /* Strict Type-Checking Options */
    "strict"true// 啟用所有嚴格的類型檢查選項,默認為 true
    "esModuleInterop"true// 通過為導入內(nèi)容創(chuàng)建命名空間,實現(xiàn) CommonJS 和 ES 模塊之間的互操作性,默認為 true
    "skipLibCheck"true// 跳過導入第三方 lib 聲明文件的類型檢查,默認為 true
    "forceConsistentCasingInFileNames"true// 強制在文件名中使用一致的大小寫,默認為 true
    "moduleResolution""Node"// 指定使用哪種模塊解析策略,默認為 Classic
  },
  "include": ["src"// 指定需要編譯文件,默認當前目錄下除了 exclude 之外的所有.ts, .d.ts,.tsx 文件

更多詳細配置參考:www.typescriptlang.org/tsconfig

注意的點,如果你的項目涉及到WebWorker API,需要添加到 lib 字段中

"lib": ["ESNext""DOM""WebWorker"],

然后我們將編譯后的文件路徑添加到 package.json,并在 scripts 中添加編譯命令。

-  "main": "index.js",
+  "main": "dist/index.js",
+  "types": "dist/types/index.d.ts"
   "type": "module",
-   "scripts": {
-     "test": "echo \"Error: no test specified\" && exit 1"
-   },
+   "scripts": {
+     "dev": "tsc --watch",
+     "build": "npm run clean && tsc",
+     "clean": "rm -rf dist"
+  },
   "publishConfig": {
     "access": "public"
   }

types 配置項是指定編譯生成的類型文件,如果 compilerOptions.declarationDir 指定的是dist,也就是源碼和 .d.ts 同級,那么types可以省略。

驗證配置是否生效,在 index.ts 寫入

const calc = (a: number, b: number) => {
  return a - b
}
console.log(calc(102428))

在控制臺中執(zhí)行

npm run build && node dist/index.js

會在 dist 目錄中生成 types/index.d.tsindex.js、index.js.map,并打印 996

Eslint & Prettier

代碼規(guī)范離不開各種 Linter, 之所以把這兩個放在一起講,借用 Prettier 官網(wǎng)的一句話:“使用 Prettier 解決代碼格式問題,使用 linters 解決代碼質(zhì)量問題”。雖然eslint也有格式化功能,但是prettier的格式化功能更強大。

大部分同學編輯器都裝了prettier-vscodeeslint-vscode這兩個插件,如果你項目只有其中一個的配置,因為這兩者部分格式化的功能有差異,那么就會造成一個的問題,代碼分別被兩個插件分別格式化一次,網(wǎng)上解決prettier+eslint沖突的方案五花八門,甚至還有把整個rules列表貼出來的。

那這里我們按照官方推薦,用最少的配置去解決prettiereslint的集成問題。

Eslint

首先安裝 eslint,然后利用 eslint 的命令行工具生成基本配置。

npm i eslint -D
npx eslint --init

執(zhí)行上面命令后會提示一些選項,我們依次選擇符合我們項目的配置。

注意,這里 eslint 推薦了三種社區(qū)主流的規(guī)范,Airbnb、Standard、Google,因個人愛好我選擇了不寫分號的 Standard規(guī)范。

生成的.eslintrc.cjs文件應該長這樣

module.exports = {
  env: {
    browsertrue,
    es2021true,
    nodetrue
  },
  extends: [
    'standard'
  ],
  parser'@typescript-eslint/parser',
  parserOptions: {
    ecmaVersion12,
    sourceType'module'
  },
  plugins: [
    '@typescript-eslint'
  ],
  rules: {
  }
}

有些同學可能就要問了,這里為什么生成的配置文件名稱是.eslintrc.cjs而不是.eslintrc.js?

因為我們將項目定義為ESMeslit --init會自動識別type,并生成兼容的配置文件名稱,如果我們改回.js結尾,再運行eslint將會報錯。出現(xiàn)這個問題是eslint內(nèi)部使用了require()語法讀取配置。

同樣,這個問題也適用于其他功能的配置,比如后面會講到的Prettier、Commitlint等,配置文件都不能以xx.js結尾,而要改為當前庫支持的其他配置文件格式,如:.xxrc.xxrc.json、.xxrc.yml。

驗證配置是否生效,修改index.ts

  const calc = (a: number, b: number) => {
    return a - b
  }
- console.log(calc(1024, 28))
+ // console.log(calc(1024, 28))

package.json中添加lint命令

  "scripts": {
    "dev": "tsc --watch",
    "build": "npm run clean && tsc",
+   "lint": "eslint src --ext .js,.ts --cache --fix",
    "clean": "rm -rf dist"
  },

然后在控制臺執(zhí)行 lint,eslint將會提示 1 條錯誤信息,說明校驗生效。

npm run lint
# 1:7  error  'calc' is assigned a value but never used  no-unused-vars

因為是 Typescript 項目所以我們還要添加Standard規(guī)范提供的 TypeScrip 擴展配置(其他規(guī)范同理)

安裝eslint-config-standard-with-typescript

npm i eslint-config-standard-with-typescript -D

添加修改 .eslintrc.cjs

    module.exports = {
      env: {
        browser: true,
        es2021: true,
        node: true
      },
-     extends: ['standard']
+     extends: ['standard', 'eslint-config-standard-with-typescript'],
      parser: '@typescript-eslint/parser',
      parserOptions: {
        ecmaVersion: 12,
        sourceType: 'module',
+       project: './tsconfig.json'
      },
      plugins: ['@typescript-eslint'],
      rules: {}
    }

驗證配置是否生效

在控制臺執(zhí)行lint,eslint將會提示 2 條錯誤信息,說明校驗生效。

npm run lint
# 1:7  error  'calc' is assigned a value but never used  no-unused-vars
# 1:14 error  Missing return type on function 

Prettier

現(xiàn)在我們按照官網(wǎng)的推薦方式,把 prettier 集成到 eslint 的校驗中。

安裝 prettier 并初始化配置文件

npm i prettier -D
echo {}> .prettierrc.json

然后在.prettierrc.json添加配置,這里只需要添加和你所選規(guī)范沖突的部分。

{
  "semi"false// 是否使用分號
  "singleQuote"true// 使用單引號代替雙引號
  "trailingComma""none" // 多行時盡可能使用逗號結尾
}

更多配置詳見:prettier.io/docs/en/opt…

安裝解決沖突需要用到的兩個依賴

  • eslint-config-prettier 關閉可能與 prettier 沖突的規(guī)則
  • eslint-plugin-prettier 使用 prettier 代替 eslint 格式化
npm i eslint-config-prettier eslint-plugin-prettier -D

再添加修改 .eslintrc.cjs,如下:

  module.exports = {
  env: {
    browser: true,
    es2021: true,
    node: true,
  },
- extends: ['standard', 'eslint-config-standard-with-typescript'],
+ extends: ['standard', 'eslint-config-standard-with-typescript', 'prettier'],
  parser: '@typescript-eslint/parser',
  parserOptions: {
    ecmaVersion: 12,
    sourceType: 'module',
    project: './tsconfig.json',
  },
- plugins: ['@typescript-eslint'],
+ plugins: ['@typescript-eslint', 'prettier'],
- rules: {},
+ rules: {
+   'prettier/prettier': 'error'
+ },
}

然后驗證配置是否生效,修改index.ts

-  const calc = (a: number, b: number) => {
+  const calc = (a: number, b: number): number => {
    return a - b
  }
- // console.log(calc(1024, 28))
+ console.log(calc(1024, 28))

然后在控制臺執(zhí)行lint,這里prettiereslint的行為已保持一致,如果沒有報錯,那就成功了。

npm run lint

我們現(xiàn)在已經(jīng)完成了eslintprettier的集成配置。和編輯器無關,也就是說無論你使用什么編輯器,有沒有安裝相關插件,都不會影響代碼校驗的效果。

Husky

因為一個項目通常是團隊合作,我們不能保證每個人在提交代碼之前執(zhí)行一遍lint校驗,所以需要git hooks 來自動化校驗的過程,否則禁止提交。

安裝Husky并生成.husky文件夾

npm i husky -D
npx husky install

然后我們需要在每次執(zhí)行npm install時自動啟用husky

如果你的npm版本大于等于7.1.0

npm set-script prepare "husky install"

否則手動在package.json中添加

 "scripts": {
    "dev": "tsc --watch",
    "build": "npm run clean && tsc",
    "lint": "eslint src --ext .js,.ts --cache --fix",
    "clean": "rm -rf dist",
+   "prepare": "husky install"
  },

然后添加一個lint鉤子

npx husky add .husky/pre-commit "npm run lint"

相當于手動在.husky/pre-commit文件寫入以下內(nèi)容:

#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npm run lint

測試鉤子是否生效,修改index.ts

  const calc = (a: number, b: number): number => {
    return a - b
  }
- console.log(calc(1024, 28))
+ // console.log(calc(1024, 28))

然后提交一條commit,如果配置正確將會自動執(zhí)行lint并提示 1 條錯誤信息,commit提交將會失敗。

git add .
git commit -m 'test husky'
# 1:7  error  'calc' is assigned a value but never used

Commitlint

為什么需要 Commitlint,除了在后續(xù)的生成changelog文件和語義發(fā)版中需要提取commit中的信息,也利于其他同學分析你提交的代碼,所以我們要約定commit的規(guī)范。

安裝 Commitlint

  • @commitlint/cli Commitlint 命令行工具
  • @commitlint/config-conventional 基于 Angular 的約定規(guī)范
npm i @commitlint/config-conventional @commitlint/cli -D

最后將Commitlint添加到鉤子

npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'

創(chuàng)建.commitlintrc,并寫入配置

{
  "extends": [
    "@commitlint/config-conventional"
  ]
}

注意,這里配置文件名使用的是.commitlintrc而不是默認的.commitlintrc.js,詳見 Eslint 章節(jié)

測試鉤子是否生效,修改index.ts,讓代碼正確

  const calc = (a: number, b: number): void => {
    console.log(a - b)
  }
- // calc(1024, 28)
+ calc(1024, 28)

提交一條不符合規(guī)范的commit,提交將會失敗

git add .
git commit -m 'add eslint and commitlint'

修改為正確的commit,提交成功!

git commit -m 'ci: add eslint and commitlint'

Angular 規(guī)范說明:

  • feat:新功能
  • fix:修補 BUG
  • docs:修改文檔,比如 README, CHANGELOG, CONTRIBUTE 等等
  • style:不改變代碼邏輯 (僅僅修改了空格、格式縮進、逗號等等)
  • refactor:重構(既不修復錯誤也不添加功能)
  • perf:優(yōu)化相關,比如提升性能、體驗
  • test:增加測試,包括單元測試、集成測試等
  • build:構建系統(tǒng)或外部依賴項的更改
  • ci:自動化流程配置或腳本修改
  • chore:非 src 和 test 的修改,發(fā)布版本等
  • revert:恢復先前的提交

Jest

美好生活從測試覆蓋率 100% 開始。

安裝jest,和類型聲明@types/jest,它執(zhí)行需要ts-nodets-jest

這里暫時固定了ts-node的版本為 v9.1.1,新版的ts-node@v10.0.0會導致jest報錯,等待官方修復,詳見:issues

npm i jest @types/jest ts-node@9.1.1 ts-jest -D

初始化配置文件

npx jest --init

然后修改jest.config.ts文件

   // A preset that is used as a base for Jest's configuration
-  // preset: undefined,
+  preset: 'ts-jest'

將測試命令添加到package.json中。

  "scripts": {
    "dev": "tsc --watch",
    "build": "npm run clean && tsc",
    "lint": "eslint src --ext .js,.ts --cache --fix",
    "clean": "rm -rf dist",
    "prepare": "husky install",
+   "test": "jest"
  },

創(chuàng)建測試文件夾__tests__和測試文件__tests__/calc.spec.ts

修改index.ts

  const calc = (a: number, b: number): number => {
    return a - b
  }
- // console.log(calc(1024, 28))
+ export default calc

然后在calc.spec.ts中寫入測試代碼

import calc from '../src'

test('The calculation result should be 996.', () => {
  expect(calc(102428)).toBe(996)
})

驗證配置是否生效

在控制臺執(zhí)行test,將會看到測試覆蓋率 100% 的結果。

npm run test

最后我們給__tests__目錄也加上lint校驗

修改package.json

  "scripts": {
    "dev": "tsc --watch",
    "build": "npm run clean && tsc",
-   "lint": "eslint src --ext .js,.ts --cache --fix",
+   "lint": "eslint src __tests__ --ext .js,.ts --cache --fix",
    "clean": "rm -rf dist",
    "prepare": "husky install",
    "test": "jest"
  },

這里如果我們直接執(zhí)行npm run lint將會報錯,提示__tests__文件夾沒有包含在tsconfig.jsoninclude中,當我們添加到include之后,輸出的dist中就會包含測試相關的文件,這并不是我們想要的效果。

我們使用typescript-eslint官方給出的解決方案,如下操作:

新建一個tsconfig.eslint.json文件,寫入以下內(nèi)容:

{
  "extends""./tsconfig.json",
  "include": ["**/*.ts""**/*.js"]
}

.eslintrc.cjs中修改

  parserOptions: {
    ecmaVersion: 12,
    sourceType: 'module',
-   project: './tsconfig.json'
+   project: './tsconfig.eslint.json'
  },

然后驗證配置是否生效,直接提交我們添加的測試文件,能正確提交說明配置成功。

git add .
git commit -m 'test: add unit test'

Github Actions

我們通過Github Actions實現(xiàn)代碼合并或推送到主分支,dependabot機器人升級依賴等動作,會自動觸發(fā)測試和發(fā)布版本等一系列流程。

在項目根目錄創(chuàng)建.github/workflows文件夾,然后在里面新建ci.yml文件和cd.yml文件

ci.yml文件中寫入:

name: CI

on:
  push:
    branches:
      - '**'
  pull_request:
    branches:
      - '**'
jobs:
  linter:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v2
        with:
          node-version: 16
      - run: npm ci
      - run: npm run lint
  tests:
    needs: linter
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v2
        with:
          node-version: 16
      - run: npm ci
      - run: npm run test

上面配置大概意思就是,監(jiān)聽所有分支的pushpull_request動作,自動執(zhí)行lintertests任務。

GithubActions 更多用法參考:github.com/features/ac…

然后推送代碼,驗證配置是否生效

git add .
git commit -m 'ci: use github actions'
git push

此時打開當前項目的 Github 頁面,然后點擊頂部 Actions 菜單就會看到正在進行的兩個任務,一個將會成功(測試),一個將會失?。òl(fā)布)。

上面只是實現(xiàn)了代碼自動測試流程,下面實現(xiàn)自動發(fā)布的流程。

在此之前需要到NPM網(wǎng)站上注冊一個賬號(已有可忽略),并創(chuàng)建一個package。

然后創(chuàng)建GH_TOKENNPM_TOKEN(注意,不要在代碼中包含任何的 TOKEN 信息):

  • 如何創(chuàng)建 GITHUB\_TOKEN(創(chuàng)建時勾選 repo 和 workflow 權限)
  • 如何創(chuàng)建 NPM\_TOKEN(創(chuàng)建時選中 Automation 權限)

將創(chuàng)建好的兩個TOKEN添加到項目的 Actions secrets 中:

Github 項目首頁 -> 頂部 Settings 菜單 -> 側邊欄 Secrets

然后修改package.json中的“name”,“name”就是你在NPM上創(chuàng)建的package的名稱。

cd.yml文件中寫入:

name: CD

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main
jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v2
        with:
          node-version: 16
      # https://github.com/semantic-release/git/issues/209
      - run: npm ci --ignore-scripts
      - run: npm run build
      - run: npx semantic-release
        env:
          GH_TOKEN: ${{ secrets.GH_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

由于“黑命貴”,Github 已將新項目的默認分支名稱更改為 “main”,詳見:issues, 為了方便,后面統(tǒng)一稱為 主分支

所以如果你的主分支名稱是“main”,上面的branches需要修改為:

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

然后安裝語義發(fā)版依賴,需要用到semantic-release和它的插件:

  • semantic-release:語義發(fā)版核心庫
  • @semantic-release/changelog:用于自動生成 changelog.md
  • @semantic-release/git:用于將發(fā)布時產(chǎn)生的更改提交回遠程倉庫
npm i semantic-release @semantic-release/changelog @semantic-release/git -D

在項目根目錄新建配置文件.releaserc并寫入:

{
  "branches": ["master"],
  "plugins": [
    "@semantic-release/commit-analyzer",
    "@semantic-release/release-notes-generator",
    "@semantic-release/changelog",
    "@semantic-release/github",
    "@semantic-release/npm",
    "@semantic-release/git"
  ]
}

這里同樣,如果你的主分支名稱是“main”,上面的branches需要修改為:

  "branches": ["+([0-9])?(.{+([0-9]),x}).x""main"],

最后新建分支 develop 分支并提交工作內(nèi)容。

git checkout -b develop
git add .
git commit -m 'feat: complete the CI/CD workflow'
git push --set-upstream origin develop
git push

然后將 develop 分支合并到 主分支,并提交,注意:這個提交會觸發(fā)測試并 發(fā)布版本 (自動創(chuàng)建tagchangelog)

git checkout master
git merge develop
git push

完成上面操作之后,打開 Github 項目主頁 和 NPM 項目主頁 可以看到一個 Release 的更新記錄。

最后切回到 develop 分支,創(chuàng)建一個自動更新依賴的workflow。

.github文件夾中創(chuàng)建dependabot.yml文件,并寫入內(nèi)容:

version: 2
updates:
  # Enable version updates for npm
  - package-ecosystem: 'npm'
    # Look for `package.json` and `lock` files in the `root` directory
    directory: '/'
    # Check the npm registry for updates every day (weekdays)
    schedule:
      interval: 'weekly'

提交并查看 workflows 是否全部通過,再合并到 主分支 并提交,這個提交不會觸發(fā)版本發(fā)布。

git pull origin master
git add .
git commit -m 'ci: add dependabot'
git push 

git checkout master
git merge develop
git push

觸發(fā)版本發(fā)布需要兩個條件:

  1. 只有當pushpull_request到 主分支 上才會觸發(fā)版本發(fā)布
  2. 只有commit前綴為featfix、perf才會發(fā)布,否則跳過。

更多發(fā)布規(guī)則,詳見:github.com/semantic-re…

SemanticRelease 使用方式,詳見:semantic-release.gitbook.io

如果你能正確配置上面所有步驟,并成功發(fā)布,那么恭喜你!你擁有了一個完全自動化的項目,它擁有:自動依賴更新、測試、發(fā)布,和自動生成版本信息等功能。

完整的項目示例:@resreq/event-hub

結語

本文未涉及到:組件庫、Monorepo、Jenkins CI 等配置,但能覆蓋絕大部前端項目 CI/CD 流程。

有些地方講得比較細,甚至有些啰嗦,但還是希望能幫助到大家!撒花!??????


作者:molvqingtai

https:///post/6971812117993226248


確定

  • 不看此公眾號

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    亚洲最新中文字幕一区| 日本午夜免费啪视频在线| 一级片黄色一区二区三区| 中文字幕乱码一区二区三区四区| 国产精品自拍杆香蕉视频| 国产免费操美女逼视频| 中文字幕人妻日本一区二区| 青青操视频在线播放免费| 日本高清一区免费不卡| 日本欧美一区二区三区就| 色好吊视频这里只有精| 亚洲妇女作爱一区二区三区| 九九热在线视频精品免费| 日本精品最新字幕视频播放| 麻豆亚州无矿码专区视频| 国产一区二区三区丝袜不卡| 99久久精品午夜一区二区| 免费特黄一级一区二区三区| 日韩免费午夜福利视频| 日韩黄色一级片免费收看| 午夜传媒视频免费在线观看| 日韩国产亚洲欧美激情| 欧美自拍偷自拍亚洲精品| 欧美成人免费一级特黄| 国产又粗又爽又猛又黄的| 99久久精品免费看国产高清| 欧美日韩亚洲巨色人妻| 国产超碰在线观看免费| 欧美日韩国产成人高潮| 国产大屁股喷水在线观看视频| 婷婷激情五月天丁香社区| 久久免费精品拍拍一区二区| 在线观看那种视频你懂的| 日韩中文字幕狠狠人妻| 日本女人亚洲国产性高潮视频| 麻豆91成人国产在线观看| 正在播放国产又粗又长| 我想看亚洲一级黄色录像| 日本久久精品在线观看| 中文字幕人妻av不卡| 精品国产av一区二区三区不卡蜜|