国产秋霞理论久久久电影-婷婷色九月综合激情丁香-欧美在线观看乱妇视频-精品国avA久久久久久久-国产乱码精品一区二区三区亚洲人-欧美熟妇一区二区三区蜜桃视频

可能是最詳細的React組件庫搭建總結(jié)

共 29329字,需瀏覽 59分鐘

 ·

2020-06-05 23:31

Table of Contents generated with DocToc

概覽

本文包含以下內(nèi)容:

  • prepare: 組件庫前期開發(fā)準備工作。eslint/commit lint/typescript等等;

  • dev: 使用docz進行開發(fā)調(diào)試以及文檔編寫;

  • build:`umd`/cjs/esm、types、polyfill 以及按需加載;

  • test: 組件測試;

  • release: 組件庫發(fā)布流程;

  • deploy: 使用now部署文檔站點,待補充;

  • other: 使用plop.js快速創(chuàng)建組件模板。

如果本文幫助到了你請給倉庫 一顆 ??。

如果有錯誤煩請在評論區(qū)指正交流,謝謝。

倉庫地址

準備工作

初始化項目

新建一個happy-ui文件夾,并初始化。

mkdir?happy-ui

cd?happy-ui

npm?init?--y

mkdir?components?&&?cd?components?&&?touch?index.ts?#?新建源碼文件夾以及入口文件

代碼規(guī)范

此處直接使用@umijs/fabric的配置。

yarn?add?@umijs/fabric?--dev

yarn?add?prettier?--dev?#?因為@umijs/fabric沒有將prettier作為依賴?所以我們需要手動安裝

.eslintrc.js

module.exports?=?{
??extends:?[require.resolve('@umijs/fabric/dist/eslint')],
};

.prettierrc.js

const?fabric?=?require('@umijs/fabric');

module.exports?=?{
??...fabric.prettier,
};

.stylelintrc.js

module.exports?=?{
??extends:?[require.resolve('@umijs/fabric/dist/stylelint')],
};

想自行配置的同學可以參考以下文章:

  • Linting Your React+Typescript Project with ESLint and Prettier!

  • 使用 ESLint+Prettier 規(guī)范 React+Typescript 項目

Commit Lint

進行pre-commit代碼規(guī)范檢測。

yarn?add?husky?lint-staged?--dev

package.json

"lint-staged":?{
??"components/**/*.ts?(x)":?[
????"prettier?--write",
????"eslint?--fix",
????"git?add"
??],
??"components/**/*.less":?[
????"stylelint?--syntax?less?--fix",
????"git?add"
??]
},
"husky":?{
??"hooks":?{
????"pre-commit":?"lint-staged"
??}
}

進行 Commit Message 檢測。

yarn?add?@commitlint/cli?@commitlint/config-conventional?commitizen?cz-conventional-changelog?--dev

新增.commitlintrc.js寫入以下內(nèi)容

module.exports?=?{?extends:?['@commitlint/config-conventional']?};

package.json 寫入以下內(nèi)容:

//?...
"scripts":?{
??"commit":?"git-cz",
}
//?...
"husky":?{
??"hooks":?{
????"commit-msg":?"commitlint?-E?HUSKY_GIT_PARAMS",
????"pre-commit":?"lint-staged"
??}
},
"config":?{
??"commitizen":?{
????"path":?"cz-conventional-changelog"
??}
}

后續(xù)使用 yarn commit 替代 git commit生成規(guī)范的 Commit Message,當然為了效率你可以選擇手寫,但是要符合規(guī)范。

TypeScript

yarn?add?typescript?--dev

新建tsconfig.json并寫入以下內(nèi)容

{
??"compilerOptions":?{
????"baseUrl":?"./",
????"target":?"esnext",
????"module":?"commonjs",
????"jsx":?"react",
????"declaration":?true,
????"declarationDir":?"lib",
????"strict":?true,
????"moduleResolution":?"node",
????"allowSyntheticDefaultImports":?true,
????"esModuleInterop":?true,
????"resolveJsonModule":?true
??},
??"include":?["components",?"global.d.ts"],
??"exclude":?["node_modules"]
}

測試

components文件夾下新建alert文件夾,目錄結(jié)構(gòu)如下:

alert
????├──?alert.tsx???????????#?源文件
????├──?index.ts????????????#?入口文件
????├──?interface.ts????????#?類型聲明文件
????└──?style
????????├──?index.less??????#?樣式文件
????????└──?index.ts????????#?樣式文件里為什么存在一個index.ts?-?按需加載樣式?管理樣式依賴?后面章節(jié)會提到

安裝React相關(guān)依賴:

yarn?add?react?react-dom?@types/react?@types/react-dom?--dev?#?開發(fā)時依賴,宿主環(huán)境一定存在

yarn?add?prop-types????????????#?運行時依賴,宿主環(huán)境可能不存在?安裝本組件庫時一起安裝

此處依舊安裝了prop-types這個庫,因為無法保證宿主環(huán)境也使用typescript,從而能夠進行靜態(tài)檢查,故使用prop-types保證javascript用戶也能得到友好的運行時報錯信息。

components/alert/interface.ts

export?type?Kind?=?'info'?|?'positive'?|?'negative'?|?'warning';
export?type?KindMap?=?Record;

export?interface?AlertProps?{
??/**
???*?Set?this?to?change?alert?kind
???*?@default?info
???*/

??kind?:?'info'?|?'positive'?|?'negative'?|?'warning';
}

components/alert/alter.tsx

import?React?from?'react';
import?t?from?'prop-types';

import?{?AlertProps,?KindMap?}?from?'./interface';

const?prefixCls?=?'happy-alert';

const?kinds:?KindMap?=?{
??info:?'#5352ED',
??positive:?'#2ED573',
??negative:?'#FF4757',
??warning:?'#FFA502',
};

const?Alert:?React.FC?=?({?children,?kind?=?'info',?...rest?})?=>?(
??<div
????className={prefixCls}
????style={{
??????background:?kinds[kind],
????}}
????{...rest}
??>

????{children}
??div>

);

Alert.propTypes?=?{
??kind:?t.oneOf(['info',?'positive',?'negative',?'warning']),
};

export?default?Alert;

components/alert/index.ts

import?Alert?from?'./alert';

export?default?Alert;

export?*?from?'./interface';

components/alert/style/index.less

@popupPrefix:?happy-alert;

.@{popupPrefix}?{
??padding:?20px;
??background:?white;
??border-radius:?3px;
??color:?white;
}

components/alert/style/index.ts

import?'./index.less';

components/index.ts

export?{?default?as?Alert?}?from?'./alert';

此處組件參考的docz項目typescript以及less示例。

git 一把梭,可以看到控制臺已經(jīng)進行鉤子檢測了。

git?add?.

yarn?commit??#?或?git?commit?-m'feat:?chapter-1?準備工作'

git?push

準備工作完成。代碼可以在倉庫的chapter-1分支獲取,若存在與本文內(nèi)容不符的地方,以master分支以及文章為準。

開發(fā)與調(diào)試

本節(jié)解決開發(fā)組件時的預覽以及調(diào)試問題,順路解決文檔編寫。

此處選擇docz來輔助預覽調(diào)試。

docz基于MDX(Markdown + JSX),可以在 Markdown 中引入 React 組件,使得一邊編寫文檔,一邊預覽調(diào)試成為了可能。而且得益于 React 組件生態(tài),我們可以像編寫應(yīng)用一般編寫文檔,不僅僅是枯燥的文字。docz 也內(nèi)置了一些組件,比如。

安裝 docz 以及自定義配置

yarn?add?docz?--dev

yarn?add?rimraf?--dev?#?清空目錄的一個輔助庫

增加 npm scriptspackage.json。

"scripts":?{
??"dev":?"docz?dev",?//?啟動本地開發(fā)環(huán)境
??"start":?"npm?run?dev",?//?dev命令別名
??"build:doc":?"rimraf?doc-site?&&?docz?build",?//?后續(xù)會配置打包出來的文件目錄名為doc-site,故每次build前刪除
??"preview:doc":?"docz?serve"?//?預覽文檔站點
},

注意:本節(jié)所有操作都是針對站點應(yīng)用。打包指代文檔站點打包,而非組件庫。

新建doczrc.js配置文件,并寫入以下內(nèi)容:

doczrc.js

export?default?{
??files:?'./components/**/*.{md,markdown,mdx}',?//?識別的文件后綴
??dest:?'doc-site',?//?打包出來的文件目錄名
??title:?'happy-ui',?//?站點標題
??typescript:?true,?//?組件源文件是通過typescript開發(fā),需要打開此選項
};

由于使用了less作為樣式預處理器,故需要安裝 less 插件。

yarn?add?less?gatsby-plugin-less?--dev

新建gatsby-config.js,并寫入以下內(nèi)容:

gatsby-config.js

module.exports?=?{
??plugins:?['gatsby-theme-docz',?'gatsby-plugin-less'],
};

編寫文檔

新建components/alert/index.mdx,并寫入以下內(nèi)容:

---
name:?Alert?警告提示
route:?/Alert
menu:?組件
---


import?{?Playground?}?from?'docz';?import?Alert?from?'./alert';?//?引入組件?import?'./style';?//?引入組件樣式

#?Alert?警告提示

警告提示,展現(xiàn)需要關(guān)注的信息。

##?代碼演示

###?基本用法

<Playground>
??<Alert?kind="warning">這是一條警告提示Alert>
Playground>

##?API

|?屬性?|?說明?????|?類型?????????????????????????????????????????|?默認值?|
|?----?|?--------?|?--------------------------------------------?|?------?|
|?kind?|?警告類型?|?'info'/'positive'/'negative'/'warning'非必填?|?'info'?|

執(zhí)行腳本命令:

yarn?start?#?or?yarn?dev

可以在localhost:3000看到如下頁面 :

81df3ee31efcd32124672d6d3236ef99.webp文檔站點

現(xiàn)在可以在index.mdx中愉快地進行文檔編寫和調(diào)試了!

倘若本文到了這里就結(jié)束(其實也可以結(jié)束了(_^▽^_)),那我只是官方文檔的翻譯復讀機罷了,有興趣的同學可以繼續(xù)向下看。

優(yōu)化文檔編寫

如果代碼演示部分的demo較多(比如基本用法、高級用法以及各種用法等等),在組件復雜的情況下(畢竟著實太簡單了),會導致文檔很長難以維護,你到底是在寫文檔呢還是在寫代碼呢?

那就抽離吧。

components/alert/文件夾下新建demo文件夾,存放我們在編寫文檔時需要引用的 demo

components/alert/demo/1-demo-basic.tsx

import?React?from?'react';
import?Alert?from?'../alert';
import?'../style';

export?default?()?=>?<Alert?kind="warning">Alert>;

components/alert/index.mdx

-?import?Alert?from?'./alert';?//?引入組件
-?import?'./style';?//?引入組件樣式
+?import?BasicDemo?from?'./demo/1-demo-basic';

...


-?這是一條警告提示
+?

這樣我們就將 demo 與文檔進行了分隔。預覽如下:

d3aecb8bc08e6ae34e974e9605bca020.webp文檔重構(gòu)

等等,下面顯示的是,而非demo源碼。

組件暫時無法支持上述形式的展示:自定義下方展示的代碼,而非內(nèi)部的代碼。相關(guān)討論如下:

  • Allow to hide the LiveError overlay #907

  • Allow to override the playground's editor's code #906

其實第一條 PR 已經(jīng)解決了問題,但是被關(guān)閉了,無奈。

不過既然都能引入 React 組件了,在MDX的環(huán)境下自定義一個Playground組件又有何難呢,無非就是渲染組件(MDX 自帶)和展示源碼,簡單開放的東西大家都是喜聞樂見的,就叫HappyBox吧。

優(yōu)化代碼展示

編寫 ``組件

安裝依賴:

yarn?add?react-use?react-tooltip?react-feather?react-simple-code-editor?prismjs?react-copy-to-clipboard?raw-loader?styled-components?--dev
  • react-use - 2020 年了,當然要用hooks

  • react-simple-code-editor - 代碼展示區(qū)域

  • prismjs - 代碼高亮

  • raw-loader - 將源碼轉(zhuǎn)成字符串

  • react-copy-to-clipboard - 讓用戶爸爸們能夠 copy demo 代碼

  • react-tooltip/react-feather 輔助組件

  • styled-components 方便在文檔示例中讓用戶看到樣式,也用作文檔組件的樣式處理

這些依賴都是服務(wù)于文檔站點應(yīng)用,和組件庫自身毫無關(guān)聯(lián)。

最終效果如下:

7051d7912f5b89e0558f70d46c22f503.webp最終效果

根目錄下新建doc-comps文件夾,存放文檔中使用的一些工具組件,比如。

doc-comps

├──?happy-box
│???├──?style.ts
│???└──?index.tsx
└──?index.ts

components/doc-comps/happy-box/index.tsx

import?React?from?'react';
import?Editor?from?'react-simple-code-editor';
import?CopyToClipboard?from?'react-copy-to-clipboard';
import?{?useToggle?}?from?'react-use';
import?ReactTooltip?from?'react-tooltip';
import?IconCopy?from?'react-feather/dist/icons/clipboard';
import?IconCode?from?'react-feather/dist/icons/code';
import?{?highlight,?languages?}?from?'prismjs/components/prism-core';
import?{?StyledContainer,?StyledIconWrapper?}?from?'./style';

import?'prismjs/components/prism-clike';
import?'prismjs/components/prism-javascript';
import?'prismjs/components/prism-markup';

require('prismjs/components/prism-jsx');

interface?Props?{
??code:?string;
??title?:?React.ReactNode;
??desc?:?React.ReactNode;
}

export?const?HappyBox:?React.FC?=?({?code,?title,?desc,?children?})?=>?{
??const?[isEditVisible,?toggleEditVisible]?=?useToggle(false);

??return?(
????
???????{children}
??????
????????
??????????{title?||?'示例'}
????????

????????
??????????

{desc?||?'暫無描述'}


????????

????????
????????
???????????alert('復制成功')}>
????????????
??????????

??????????
????????????
??????????
????????

??????
??????{renderEditor()}
??????
????
??);

??function?renderEditor()?{
????if?(!isEditVisible)?return?null;
????return?(
??????
??????????????????readOnly
??????????value={code}
??????????onValueChange={()?=>?{}}
??????????highlight={code?=>?highlight(code,?languages.jsx)}
??????????padding={10}
??????????className="container__editor"
??????????style={{
????????????fontFamily:?'"Fira?code",?"Fira?Mono",?monospace',
????????????fontSize:?14,
??????????}}
????????/>
??????

????);
??}
};

export?default?HappyBox;

相關(guān)配置變更

新建gatsby-node.js,寫入以下內(nèi)容以開啟alias

const?path?=?require('path');

exports.onCreateWebpackConfig?=?args?=>?{
??args.actions.setWebpackConfig({
????resolve:?{
??????modules:?[path.resolve(__dirname,?'../src'),?'node_modules'],
??????alias:?{
????????'happy-ui/lib':?path.resolve(__dirname,?'../components/'),
????????'happy-ui/esm':?path.resolve(__dirname,?'../components/'),
????????'happy-ui':?path.resolve(__dirname,?'../components/'),
??????},
????},
??});
};

tsconfig.json 打包時需要忽略demo,避免組件庫打包生成types時包含其中,同時增加paths屬性用于 vscode 自動提示:

tsconfig.json

{
??"compilerOptions":?{
????"baseUrl":?"./",
+???"paths":?{
+?????"happy-ui":?["components/index.ts"],
+?????"happy-ui/esm/*":?["components/*"],
+?????"happy-ui/lib/*":?["components/*"]
+????},
????"target":?"esnext",
????"module":?"commonjs",
????"jsx":?"react",
????"declaration":?true,
????"declarationDir":?"lib",
????"strict":?true,
????"moduleResolution":?"node",
????"allowSyntheticDefaultImports":?true,
????"esModuleInterop":?true,
????"resolveJsonModule":?true
??},
??"include":?["components",?"global.d.ts"],
-?"exclude":?["node_modules"]
+?"exclude":?["node_modules",??"**/demo/**"]
}

新的問題出現(xiàn)了,vscode 的 alias 提示依賴 tsconfig.json,忽略 demo 文件夾后,demo 內(nèi)的文件模塊類型找不到聲明(paths 失效),所以不能將 demo 在 tsconfig.json 中移除:

{
-?"exclude":?["node_modules",??"**/demo/**"]
+?"exclude":?["node_modules"]
}

新建一個 tsconfig.build.json 文件:

tsconfig.build.json

{
??"extends":?"./tsconfig.json",
??"exclude":?["**/demo/**",?"node_modules"]
}

后續(xù)使用 tsc 生成類型聲明文件指定tsconfig.build.json即可。

改造相關(guān)文件

components/alert/demo/1-demo-basic.tsx

-?import?Alert?from?'../alert';
+?import?Alert?from?'happy-ui/lib/alert';

-?import?'../style';
+?import?'happy-ui/lib/alert/style';

components/alert/index.mdx

-?import?{?Playground?}?from?'docz';
+?import?{?HappyBox?}?from?'../../doc-comps';

+?import?BasicDemoCode?from?'!raw-loader!./demo/1-demo-basic.tsx';

...

-?
-???
-?

+?
+??
+?

yarn start卡住時嘗試刪除根目錄.docz文件夾,而后重新執(zhí)行命令。

現(xiàn)在可以愉快地開發(fā)組件了。代碼可以在倉庫的chapter-2分支獲取,若存在與本文內(nèi)容不符的地方,以master分支以及文章為準。

組件庫打包

宿主環(huán)境各不相同,需要將源碼進行相關(guān)處理后發(fā)布至 npm。

明確以下目標:

  1. 導出類型聲明文件

  2. 導出 umd/Commonjs module/ES module 等 3 種形式供使用者引入

  3. 支持樣式文件 css 引入,而非只有less

  4. 支持按需加載

導出類型聲明文件

既然是使用typescript編寫的組件庫,那么使用者應(yīng)當享受到類型系統(tǒng)的好處。

我們可以生成類型聲明文件,并在package.json中定義入口,如下:

package.json

{
??"typings":?"lib/index.d.ts",?//?定義類型入口文件
??"scripts":?{
????"build:types":?"tsc?-p?tsconfig.build.json?&&?cpr?lib?esm"?//?執(zhí)行tsc命令生成類型聲明文件
??}
}

值得注意的是:此處使用cprlib的聲明文件拷貝了一份,重命名為esm。用于后面存放 ES module 形式的組件。這樣做主要是為了用戶手動按需引入組件時依舊可以有自動提示。

最開始使用的將聲明文件單獨打包成一個types文件夾,這樣只通過'happy-ui'引入才可以有自動提示,但是'happy-ui/esm/xxx'和'happy-ui/lib/xxx'就無法提示。

tsconfig.build.json

{
??"extends":?"./tsconfig.json",
??"compilerOptions":?{?"emitDeclarationOnly":?true?},?//?只生成聲明文件
??"exclude":?["**/__tests__/**",?"**/demo/**",?"node_modules",?"lib",?"esm"]?//?排除示例、測試以及打包好的文件夾
}

執(zhí)行yarn build:types,可以發(fā)現(xiàn)根目錄下已經(jīng)生成了lib文件夾(tsconfig.json中定義的declarationDir字段),目錄結(jié)構(gòu)與components文件夾保持一致,如下:

types

├──?alert
│???├──?alert.d.ts
│???├──?index.d.ts
│???├──?interface.d.ts
│???└──?style
│???????└──?index.d.ts
└──?index.d.ts

這樣使用者引入npm 包時,便能得到自動提示,也能夠復用相關(guān)組件的類型定義。

接下來將ts(x)等文件處理成js文件。

需要注意的是,我們需要輸出Commonjs module以及ES module兩種模塊類型的文件(暫不考慮umd),以下使用cjs指代Commonjs module,esm指代ES module。
對此有疑問的同學推薦閱讀:import、require、export、module.exports 混合詳解

導出 Commonjs 模塊

其實完全可以使用babeltsc命令行工具進行代碼編譯處理(實際上很多工具庫就是這樣做的),但考慮到還要處理樣式及其按需加載,我們借助 gulp 來串起這個流程。

babel 配置

首先安裝babel及其相關(guān)依賴

yarn?add?@babel/core?@babel/preset-env?@babel/preset-react?@babel/preset-typescript?@babel/plugin-proposal-class-properties??@babel/plugin-transform-runtime?--dev
yarn?add?@babel/runtime-corejs3

新建.babelrc.js文件,寫入以下內(nèi)容:

.babelrc.js

module.exports?=?{
??presets:?['@babel/env',?'@babel/typescript',?'@babel/react'],
??plugins:?[
????'@babel/proposal-class-properties',
????[
??????'@babel/plugin-transform-runtime',
??????{
????????corejs:?3,
????????helpers:?true,
??????},
????],
??],
};

關(guān)于@babel/plugin-transform-runtime@babel/runtime-corejs3

更多參見官方文檔-@babel/plugin-transform-runtime

配置目標環(huán)境

為了避免轉(zhuǎn)譯瀏覽器原生支持的語法,新建.browserslistrc文件,根據(jù)適配需求,寫入支持瀏覽器范圍,作用于@babel/preset-env

.browserslistrc

>0.2%
not?dead
not?op_mini?all

很遺憾的是,@babel/runtime-corejs3無法在按需引入的基礎(chǔ)上根據(jù)目標瀏覽器支持程度再次減少polyfill的引入,參見@babel/runtime for target environment 。

這意味著@babel/runtime-corejs3 甚至會在針對現(xiàn)代引擎的情況下注入所有可能的 polyfill:不必要地增加了最終捆綁包的大小。

對于組件庫(代碼量可能很大),個人建議將polyfill的選擇權(quán)交還給使用者,在宿主環(huán)境進行polyfill。若使用者具有兼容性要求,自然會使用@babel/preset-env + core-js + .browserslistrc進行全局polyfill,這套組合拳引入了最低目標瀏覽器不支持API的全部 polyfill。

業(yè)務(wù)開發(fā)中,將@babel/preset-envuseBuiltIns選項值設(shè)置為 usage,同時把node_modulesbabel-loaderexclude掉的同學可能想要這個特性:"useBuiltIns: usage" for node_modules without transpiling #9419,在未支持該issue提到的內(nèi)容之前,還是乖乖地將useBuiltIns設(shè)置為entry,或者不要把node_modulesbabel-loaderexclude。

所以組件庫不用畫蛇添足,引入多余的polyfill,寫好文檔說明,比什么都重要(就像zent和antd這樣)。

現(xiàn)在@babel/runtime-corejs3更換為@babel/runtime,只進行helper函數(shù)抽離。

yarn?remove?@babel/runtime-corejs3

yarn?add?@babel/runtime

.babelrc.js

module.exports?=?{
??presets:?['@babel/env',?'@babel/typescript',?'@babel/react'],
??plugins:?['@babel/plugin-transform-runtime',?'@babel/proposal-class-properties'],
};

@babel/transform-runtimehelper選項默認為true

gulp 配置

再來安裝gulp相關(guān)依賴

yarn?add?gulp?gulp-babel?--dev

新建gulpfile.js,寫入以下內(nèi)容:

gulpfile.js

const?gulp?=?require('gulp');
const?babel?=?require('gulp-babel');

const?paths?=?{
??dest:?{
????lib:?'lib',?//?commonjs?文件存放的目錄名?-?本塊關(guān)注
????esm:?'esm',?//?ES?module?文件存放的目錄名?-?暫時不關(guān)心
????dist:?'dist',?//?umd文件存放的目錄名?-?暫時不關(guān)心
??},
??styles:?'components/**/*.less',?//?樣式文件路徑?-?暫時不關(guān)心
??scripts:?['components/**/*.{ts,tsx}',?'!components/**/demo/*.{ts,tsx}'],?//?腳本文件路徑
};

function?compileCJS()?{
??const?{?dest,?scripts?}?=?paths;
??return?gulp
????.src(scripts)
????.pipe(babel())?//?使用gulp-babel處理
????.pipe(gulp.dest(dest.lib));
}

//?并行任務(wù)?后續(xù)加入樣式處理?可以并行處理
const?build?=?gulp.parallel(compileCJS);

exports.build?=?build;

exports.default?=?build;

修改package.json

package.json

{
-?"main":?"index.js",
+?"main":?"lib/index.js",
??"scripts":?{
????...
+???"clean":?"rimraf?lib?esm?dist",
+???"build":?"npm?run?clean?&&?npm?run?build:types?&&?gulp",
????...
??},
}

執(zhí)行yarn build,得到如下內(nèi)容:

lib

├──?alert
│???├──?alert.js
│???├──?index.js
│???├──?interface.js
│???└──?style
│???????└──?index.js
└──?index.js

觀察編譯后的源碼,可以發(fā)現(xiàn):諸多helper方法已被抽離至@babel/runtime中,模塊導入導出形式也是commonjs規(guī)范。

lib/alert/alert.js

665cbce5d702033885d7c4fa934f9ef2.webplib/alert/alert.js

導出 ES module

生成ES module可以更好地進行tree shaking,基于上一步的babel配置,更新以下內(nèi)容:

  1. 配置@babel/preset-envmodules選項為false,關(guān)閉模塊轉(zhuǎn)換;

  2. 配置@babel/plugin-transform-runtimeuseESModules選項為true,使用ES module形式引入helper函數(shù)。

.babelrc.js

module.exports?=?{
??presets:?[
????[
??????'@babel/env',
??????{
????????modules:?false,?//?關(guān)閉模塊轉(zhuǎn)換
??????},
????],
????'@babel/typescript',
????'@babel/react',
??],
??plugins:?[
????'@babel/proposal-class-properties',
????[
??????'@babel/plugin-transform-runtime',
??????{
????????useESModules:?true,?//?使用esm形式的helper
??????},
????],
??],
};

目標達成,我們再使用環(huán)境變量區(qū)分esmcjs(執(zhí)行任務(wù)時設(shè)置對應(yīng)的環(huán)境變量即可),最終babel配置如下:

.babelrc.js

module.exports?=?{
??presets:?['@babel/env',?'@babel/typescript',?'@babel/react'],
??plugins:?['@babel/plugin-transform-runtime',?'@babel/proposal-class-properties'],
??env:?{
????esm:?{
??????presets:?[
????????[
??????????'@babel/env',
??????????{
????????????modules:?false,
??????????},
????????],
??????],
??????plugins:?[
????????[
??????????'@babel/plugin-transform-runtime',
??????????{
????????????useESModules:?true,
??????????},
????????],
??????],
????},
??},
};

接下來修改gulp相關(guān)配置,抽離compileScripts任務(wù),增加compileESM任務(wù)。

gulpfile.js

//?...

/**
?*?編譯腳本文件
?*?@param?{string}?babelEnv?babel環(huán)境變量
?*?@param?{string}?destDir?目標目錄
?*/

function?compileScripts(babelEnv,?destDir)?{
??const?{?scripts?}?=?paths;
??//?設(shè)置環(huán)境變量
??process.env.BABEL_ENV?=?babelEnv;
??return?gulp
????.src(scripts)
????.pipe(babel())?//?使用gulp-babel處理
????.pipe(gulp.dest(destDir));
}

/**
?*?編譯cjs
?*/

function?compileCJS()?{
??const?{?dest?}?=?paths;
??return?compileScripts('cjs',?dest.lib);
}

/**
?*?編譯esm
?*/

function?compileESM()?{
??const?{?dest?}?=?paths;
??return?compileScripts('esm',?dest.esm);
}

//?串行執(zhí)行編譯腳本任務(wù)(cjs,esm)?避免環(huán)境變量影響
const?buildScripts?=?gulp.series(compileCJS,?compileESM);

//?整體并行執(zhí)行任務(wù)
const?build?=?gulp.parallel(buildScripts);

//?...

執(zhí)行yarn build,可以發(fā)現(xiàn)生成了lib/esm三個文件夾,觀察esm目錄,結(jié)構(gòu)同lib一致,js 文件都是以ES module模塊形式導入導出。

esm/alert/alert.js

d156c5f2e63b801ba9e430b680b4bcf7.webpesm/alert/alert.js

別忘了給package.json增加相關(guān)入口。

package.json

{
+?"module":?"esm/index.js"
}

處理樣式文件

拷貝 less 文件

我們會將less文件包含在npm包中,用戶可以通過happy-ui/lib/alert/style/index.js的形式按需引入less文件,此處可以直接將 less 文件拷貝至目標文件夾。

gulpfile.js中新建copyLess任務(wù)。

gulpfile.js

//?...

/**
?*?拷貝less文件
?*/

function?copyLess()?{
??return?gulp
????.src(paths.styles)
????.pipe(gulp.dest(paths.dest.lib))
????.pipe(gulp.dest(paths.dest.esm));
}

const?build?=?gulp.parallel(buildScripts,?copyLess);

//?...

觀察lib目錄,可以發(fā)現(xiàn) less 文件已被拷貝至alert/style目錄下。

lib

├──?alert
│???├──?alert.js
│???├──?index.js
│???├──?interface.js
│???└──?style
│???????├──?index.js
│???????└──?index.less?#?less文件
└──?index.js

可能有些同學已經(jīng)發(fā)現(xiàn)問題:若使用者沒有使用less預處理器,使用的是sass方案甚至原生css方案,那現(xiàn)有方案就搞不定了。經(jīng)分析,有以下 3 種預選方案:

  1. 告知用戶增加less-loader;

  2. 打包出一份完整的 css 文件,進行全量引入;

  3. 單獨提供一份style/css.js文件,引入的是組件 css樣式文件依賴,而非 less 依賴,組件庫底層抹平差異;

  4. 使用css in js方案。

方案 1 會導致業(yè)務(wù)方使用成本增加。

方案 2 無法進行按需引入。

方案 4 需要詳細聊聊。

css in js除了賦予樣式編寫更多的可能性之外,在編寫第三方組件庫時更是利器。

如果我們寫一個react-use這種hooks工具庫,不涉及到樣式,只需要在package.json中設(shè)置sideEffectsfalse,業(yè)務(wù)方使用 webpack 進行打包時,只會打包被使用到的 hooks(優(yōu)先使用 ES module)。

入口文件index.js中導出的但未被使用的其他 hooks 會被tree shaking,第一次使用這個庫的時候我很好奇,為什么沒有按需引入的使用方式,結(jié)果打包分析時我傻了,原來人家天生支持按需引入。

可能常用的antd以及lodash都要配一配,導致產(chǎn)生了慣性思維。

回到正題。如果將樣式使用javascript來編寫,在某種維度上講,組件庫和工具庫一致了,配好sideEffects,自動按需引入,美滋滋。

而且每個組件都與自己的樣式綁定,不需要業(yè)務(wù)方或組件開發(fā)者去維護樣式依賴,什么是樣式依賴,后面會講到。

缺點:

  1. 樣式無法單獨緩存;

  2. styled-components 自身體積較大;

  3. 復寫組件樣式需要使用屬性選擇器或者使用styled-components,麻煩了點。

需要看取舍了,偷偷說一句styled-components做主題定制也極其方便。

方案 3 是antd使用的這種方案。

在搭建組件庫的過程中,有一個問題困擾了我很久:為什么需要alert/style/index.js引入less文件或alert/style/css.js引入css文件?

答案是管理樣式依賴。

因為我們的組件是沒有引入樣式文件的,需要用戶去手動引入。

假設(shè)存在以下場景:引入

推薦
點贊
評論
收藏
分享

手機掃一掃分享

分享
舉報

感谢您访问我们的网站,您可能还对以下资源感兴趣:

国产秋霞理论久久久电影-婷婷色九月综合激情丁香-欧美在线观看乱妇视频-精品国avA久久久久久久-国产乱码精品一区二区三区亚洲人-欧美熟妇一区二区三区蜜桃视频 最近日韩中文字幕中文翻译歌词| 久久久久一区二区三区| 亚洲免费视频在线播放| 91精品久久久久久久久久| jzzijzzij亚洲成熟少妇在线观看 九色蝌蚪9l视频蝌蚪9l视频成人熟妇 | 成人在线视频播放| 91人妻人人| 亚洲无码精品专区| 天天色天天撸| 在线观看av中文字幕| 操操操操操| 国产视频入口| 国产成人久久精品麻豆二区| 大香蕉伊人影视| 无码av无码AV| 搡BBB,搡BBBB,搡BBBB| A片小视频| 四虎精品一区二区| 黄色国产免费| 无码伦理| 五月乱伦| av福利电影在线| 韩国久久久| 久久毛片视频| 大香蕉在线网站| 翔田千里无码免费播放| 乱码少妇| 久久久性爱视频| 日本特级片| 国产永久精品| 黄片大全在线免费观看| 亚洲区一区二| 久久综合加勒比| 五月激情综合| 欧美成人免费网站| 91久久久久国产一区二区| 丁香五月天av| 最新中文字幕av| 无套内射无码| 狠狠干2025| 人人妻日日摸狠狠躁视频| 男女AV在线免费观看| 欧美性大香蕉| 成人视频免费| 欧美黄色成人网站| 天天摸天天干| 中文字幕精品一区| 欧美国产在线观看| 日本三级AAA三级AAAA97| 日本不卡视频| 欧美日韩A片| 97人妻无码一区二区| 成人无码区免费| 不卡不在线中文| 久久中文娱乐网| 影音先锋成人在线视频| 一级a一级a爰片免费免免中国A片 一级一级a免一级a做免费线看内裤 | 骚逼中文字幕| 丝袜诱惑AV| 免费中文字幕日韩欧美| 日韩一级黄色视频| 女人毛片| 91av| 国产精品久久久久久久久久两年半 | 一区二区三区网站| 久草国产在线视频| 影音先锋无码专区| 蜜臂AV| 国产在线观看欧美| 欧美黄片免费看| 波多野结衣不卡| 亚洲综合电影| 亚洲高清无码一区| 国产欧美综合视频| 丁香在线视频| 欧美成人精品激情在线视频| 天天日天天日天天干| 五月天综合视频| 日韩,变态,另类,中文,人妻| 国产无码影视| 精品欧美成人片在线| 久久一级A片| 亚洲日韩中文无码| 亚洲va综合va国产va中文| 日本少妇午夜福利| 亚洲欧美综合| 三级片国产| 人人看人人干| 波多野结衣无码视频| 一级欧美一级日韩| 天天操天天干天天日| 人妻无码免费视频| 久久草草热国产精品| 午夜无码在线| www.国产视频| 欧美一级婬片A片免费软件| 国产淫语| 国产高清自拍视频| AV资源在线播放| 日韩一级高清| 亚洲第五页| 国产精品成人99一区无码| 99热青青草| 欧美一区二区三区精品| 热99re69精品8在线播放| 丰满人妻一区二区| 91成人精品一区二区| 天天操天天撸| 日韩小电影免费观看高清完整版在线观| 免费超碰在线| 日韩a视频| 亚洲综合国产| 在线观看黄色AV| 午夜无码在线| 亚洲有码在线观看| 欧美一卡二卡三卡| 欧美激情综合| 美女毛片视频| 国产日逼视频| 操逼不卡视频| 嫩BBB槡BBBB槡BBB小号| 五月天AV网站| 成人视频毛片| 国产中文字幕在线免费观看| 亚洲天天在线| 亚洲自拍中文字幕| 艹逼视频在线观看| 色色一区二区| 最近中文字幕在线| 操逼电影网| 天天摸夜夜操| 影音先锋成人av| 日本无码电影| 一区精品| 色人阁人妻中文字幕| 韩国三级中文字幕HD久久精品| 午夜老司机福利| 日本色情视频网站| 日韩操逼av| 九色丨蝌蚪丨老版熟女| 69成人在线| 精品码产区一区二亚洲国产| 91视频在| 中文无码播放| 婷婷五月天无码| 九九热精品视频在线观看| 国产AV一级片| 五月丁香六月| 国产欧美综合视频| 日本成人A| 老太色HD色老太HD.| 高清无码直接看| 搡bbbb| 国产丝袜自拍| 中文字幕亚洲欧美| 草逼视频网| 青青青视频在线| 18XXX亚洲HD护士JD| 亚洲欧美在线视频| 五月六月丁香激情视频| 国产又黄又大又粗的视频| 欧美一级片网站| 亚洲性爱小说网址| 豆花视频久久| www.狠狠爱| www国产精品| 先锋影音资源av| 午夜免费视频| 日韩大片免费观看| 狼友视频免费| 婷婷无码成人精品俺来俺去| 99日韩精品| 天堂俺去俺来也www久久婷婷| 性爱视频无码| 亚洲无码高清视频在线观看| 亚洲精品无码在线观看| 亚洲欧美国产另类| 欧美插插| 婷婷国产精品视频| 无码区一区二区三区| 毛片视频网站| 婷婷五月丁香六月| 18SAV| 国产婬片一级A片AAA毛片AⅤ| 亚洲免费观看高清完| 久久公开视频| 亚洲日韩成人电影| 亚洲国产高清无码| 亚洲高清无码视频| 亚洲视频1区| 成人丁香五月天| AAA成人| Chinese搡老女人| 亚洲天堂无码在线观看| 国产日韩欧美在线| 久射精品| 亚洲黄色Av| 国产视频第一页| 亚洲午夜无码| 日韩免费| 久久日韩视频| 狠狠噜噜| 亚洲成人无码在线播放| 亚洲综合免费观看高清完整版 | 人人上人人摸| 国产又爽又黄免费网站在线看| 波多野结衣无码AV专区| 免费无码毛片一区二区A片| 亚洲AV网址| 日韩a片| 无码视频在线播放| 西西444WWW无码视频软件功能介绍| 伊人成人免费视频| 一区久久| 成人免费无码婬片在线观看免费 | 苏妲己一级婬片A片| 一级a免一级a做免费线看内裤| 日本成人网址| 另类罕见稀奇videos| 甘肃WBBBB搡wBBBB| 亚洲无码伊人| 日本白浆| 国产成人无码在线| 亚洲在线中文字幕| 精品免费黄色视频| 亚洲av大全| 成人激情在线视频| 男女av| 日韩91在线视频| 亚洲午夜成人精品一区二区| 黄网免费观看| 人妻视频网站| 亚洲人成免费网站| 久久久久黄片| 亚洲成人久久久| 18XXX亚洲HD护士JD| 午夜午夜福利理论片在线播放| 九九久久久久| 国产三级AV在线| 狠狠久| 蜜桃成人AV| ThePorn精品无码| 天堂中文资源库| 无码国产精品一区二区免费96 | 日韩无码高清免费| 18岁成人毛片| 日本免费一区二区三区| 国产久久视频在线观看| 狠狠狠狠狠狠狠狠| 国产成人免费观看| 91久久| 婷婷成人综合网| 一区二区三区免费在线观看| 黄色无码网站| 婷婷成人小说| 竹菊av一区二区三区四区五区| 久久久久一区| 色哟哟精品| 亚洲美女网站在线观看| 91污视频在线观看| 久久污| 欧美成人久久| 东京亚洲无码| 国产骚女| www.sese| 国产寡妇亲子伦一区二区三区四区| 豆花视频在线看| 亚洲欧美日韩一区二区| 最近中文字幕2022在线观看A| 日韩精品无码一区二区三区| 热99re69精品8在线播放| 一区二区三区久久久| 台湾AV在线| 中文字幕精品人妻| 亚洲综合色网| aⅴ免费观看| 操操操av| 激情综合婷婷| 成人在线观看无码| 麻豆视频一区二区三区| 六月激情婷婷| 超碰护士| 丝袜一区二区三区| 成人免费大香蕉| 大香蕉伊人免费| 国产精品免费观看久久久久久久久| 少妇特黄A一区二区三区| 一级片黄色免费| 九九韩剧网最新电视剧免费观看 | 欧美天堂在线观看| 吴梦梦md0069| 免费黄色片子| 青草青草| 欧美一级无码| 伊人影院久久| 青草免费视频| 一区二区免费在线观看| 在线观看99| 肏少妇女情人大骚逼直播一区二区 | 欧美VA视频| 欧美色图88| 欧美色图在线观看视频| 国产精品1区| 亚洲免费精品视频| 五月丁香视频在线观看| 欧美日韩小视频| 久久久无码AV| av天堂中文在线| 日本AI高清无码在线观看网址 | 日韩毛片中文字幕| 欧美日韩群交| 成人黄色电影在线| 东京热这里只有精品| 免费AV网站在线| 国产福利91| 国产又粗又长又硬黄色一级片 | 色就是色欧美| 狠狠成人| 首页-91n| aⅴ免费观看| 欧美特黄AAAAAAAAA片| 中文字幕免费AV| 在线观看国产小视频| 中文字幕视频在线| 一本道精品在线| 久久综合中文| 大香蕉在线视频75| 日韩免费成人| 操你啦日韩| 日韩免费小视频| 四虎久久| 53岁露大奶熟女偷情贴吧| 色二区| 国产成人免费观看视频| 91在线免费视频观看| 欧美footjob| 视色视频在线观看18| 波多野结衣黄色| 尤物网站在线观看| 色女人天堂| 一卡二卡三卡无码| 无码视频网| gogogo免费高清在线偷拍| 久久丝袜视频| 丝袜足交视频在线观看| 日本女人牲交视频| 日韩精品成人专区无码| 99久久精品国产一区二区三区| 东方成人AV| 被黑人操| a视频在线免费观看| 国产一级黄色大片| 国产精品A片守望| 亚洲免费视频在线看| 国产午夜福利在线| 青草成人在线| 欧美淫乱视频| 中文字幕无码精品| 亚洲国产成人电影| 国产一区视频在线| 成人精品毛片| 久久成人一区| 日无码视频| 麻豆AV96熟妇人妻| 日韩99在线| 九九热精品| 无码草逼| 久久久久国产一区二区三区四区| 69久久久| 性满足BBwBBWBBw| 国产成人精| A级片免费看| 无码人妻一区二区一牛影视| 一级二级三级毛片| 天天日夜夜| 99er在线观看视频| 欧美日韩逼| av在线资源观看| 黄色一级在线| 精品视频日韩| 九九热精品在线| www.日逼| 啪啪啪免费网站| 国产精品乱子伦| 亚洲国产高清在线观看视频| 亚洲另类天堂| 中文无码精品欧美日韩| 亚洲秘无码一区二区三区蜜桃中文| 中文字幕66页| 337P人体美鮑高清| 亚洲人内射片又| 久久综合伊人777777| 好吊一区二区| 俺也去啦WWW色官网| 日本少妇中文字幕| 尤物视频网| 少妇厨房愉情理伦BD在线观| 操逼免费网站| www.97av| 欧美视频操逼| 激情五月婷婷五月| 国产综合亚洲精品一区二| 免费看黄片的网站| 午夜狠狠操| 天天色天天干天天日| 91亚洲国产成人久久精品网站| 免费观看毛片| 影音先锋国产av| 91麻豆免费看| 日日骚av一区二区三区| 日本操鸡小视频| 欧美成人天堂| 国产精品乱码一区二区三区| 中韩无码| 日韩在线观看av| 无码视频在线| 天堂一区二区三区18| 黄色一级在线| 色老板最新地址| 美女性爱3P视频| 成人h在线观看| 国产精品卡一| 三级视频在线观看| 视频在线一区| 91av导航| 欲色AV| 久草国产视频| 人人色网站| 日韩无码影院| 一二区免费视频| 久久99精品久久久久| 日本色色视频| 亚洲黄色电影网| 五月天婷婷在线观看| 影音先锋成人在线视频| 免费在线观看黄片| 亚洲精品资源在线| 超碰在线播| 蜜臀久久99精品久久久老牛影视 | 中文字幕在线永久| 99re在线| 亚洲中文免费视频| 水多多成人免费A片| 五月丁香色婷婷| 色视频免费在线观看| 国产99热| 国产福利免费| 欧美XX888做受| 中文无码av| 亚洲成人综合网站| 日韩无码黄色电影| 超碰麻豆| 99久久精品国产一区二区成人| 青草成人在线| 江苏妇搡BBB搡BBBB| 亚洲色婷婷久久精品AV蜜桃| 日本www色| 91精品在线免费观看| 天天干狠狠| 超碰中文字幕| av网站免费观看| 91久久久久久久久久久久18 | 亚洲国产精品成人久久蜜臀| 91一起草高清资源| 欧美亚洲色色网视频| 一区二区视频在线观看| 国产噜噜噜噜久久久久久久久| 思思热这里只有精品| 久久高清无码视频| 青青视频网| 最近中文字幕中文翻译歌词| 胖老板办公室沙发无套爆秘书| 3344gc在线观看入口| 777色色色| 91久久精品国产91久久公交车 | 久久精品视| 18禁网站免费观看| 免费看AV大片| 亚洲艹逼| 亚洲A片V一区二区三区| 亚洲av资源在线观看| 亚洲天堂AB| 五月天av在线| 欧美一级欧美三级在线观看| 国产熟妇搡BBBB搡BBBB搡| 亚洲色婷婷| 国产成人无码免费看片| 美日韩精品| 色色色免费视频| 亚洲AV在线观看| 欧美黑人操逼| 精品人妻一区二区三区阅读全文| 亚洲不卡在线| 1插菊花综合网| 极品人妻疯狂3p超刺激| 亚洲AV成人网| 国产乱子伦一区二区三区视频| 大香蕉婷婷| 91人妻无码精品一区二区| 97AV人妻无码视频二区| 成人高清在线| 亚洲天堂天天| 国产乱轮视频| 97色色超碰| 国产人妻一区二区精选| 欧洲黄色片| 午夜操一操| 日本91视频| 日韩欧美精品| 色五月婷婷婷| 欧美96| wwwav| 中文字幕精品在线观看| www.黄色com| 欧美韩日一区二区| 成人123区| 欧美性爱一区二区| 欧美在线视频免费观看| 欧美3p视频| 先锋AV资源在线| 欧洲肥胖BBBBBBBBBB| 亚洲人BBwBBwBBWBBw| 黄色视频在线观看国产| 日本内射在线播放| 精品无人区无码乱码毛片国产 | 欧美日韩狠狠操在线观看视频| 欧美一级一级| 亚洲精品色图| 人妻无码久久精品| 久久伊人在| 91色视频在线观看| 蜜桃视频一区二区三区四区av| 日韩人妻视频| 探花无码| 影音先锋男人你懂的| 国产日韩欧美成人| 日韩肏屄视频在线观看| 狠狠的日| 91探花在线观看| 人人看人人摸人人搞| 日韩欧美成人片| 日韩AⅤ视频| 午夜成人亚洲| 亚洲婷婷五月| 先锋影音AV资源网| 欧美一区二区在线视频| 无码人妻在线播放| 亚洲天堂一区在线观看| 一本色道久久88综合无码| 欧美一区| 俺去日| 好吊视频一区二区| 无码av一区| 九九九九九九精品| 91人人妻人人爽| 苍井空中文字幕在线观看| 欧美在线不卡综合| 91精品久久人妻一区二区夜夜夜 | 亚洲日韩中文字幕| 精品在线免费观看| 欧美污网站| 蜜臀精品一区二区三区| 成人午夜精品无码区| 欧美成人手机在线观看| 18成人在线观看| 啊啊嗯嗯视频| 99热免费| 东京热综合网| 污网站免费在线观看| 欧美性猛交XXXX乱大交| 男人的天堂免费视频| 国产成人无码精品一区秘二区 | 久草中文在线视频| 久久久XXX| 黄网站在线观看| 欧美成人精品AAA| 亚洲日韩在线观看视频| 欧美性猛交XXXX乱大交| 亚洲天堂高清| 天天综合在线观看| 97干在线| 神马午夜影院| 广西少妇BBwBBwBBw| 中文字幕一区二区蜜桃| 中文字幕不卡| 麻豆中文字幕| 亚州毛片| 亚洲小说区图片区| 欧美精产国品一区二区区别| 豆花AV在线| 又黄又爽的视频| 91蝌蚪91九色| 无码在线专区| 在线观看一级片| 成人免费无码A片免费| 色色色成人视频| 大香蕉现在视频中心一| 91成人免费视频| www国产亚洲精品久久网站| 中文字幕在线不卡| 韩日无码视频| 国产熟妇毛多久久久久一区| 色婷婷一区二区三区久久| www.五月丁香| AV黄色在线| 中文字幕在线观看有码| 成人一区二区在线观看| 日韩在线免费看| 国产噜噜噜噜噜久久久久久久久| 69AV视频网站| 内射学生妹视频| 北条麻妃无码一区三区| 中文字幕在线观看完整av| 综合久久99| 亚洲无码免费看| 无码久久| 成人免费毛片AAAAAA片| 精品久久久久久久久久| 人人人人人操| 无码高清一区| 成人无码动漫A片| 蜜桃视频网站18| 一区二区三区无码免费| 亚洲香蕉在线视频| 青草青在线视频| 亚洲第一黄片| 亚洲网站免费| 日韩一级二级三级| 中文字幕aV在线| 河南乱子伦视频国产| 欧美日韩在线视频免费观看| 亚洲三级电影在线观看| 欧美亚洲成人在线观看| 色播av| 大色AV| 国产精品免费网站| 激情三区| 欧美性猛交ⅩXXX无码视频| 亚洲第一成年人网站| 国产精品国产三级囯产普通话2| 91豆花在线| 无码专区在线播放| 日本一级片免费看| www.色色网| 99高清国产| 久热人妻| 久草视频在线免费看| 大香蕉做爱视频| 国产欧美日韩在线播放| 青娱乐精品在线视频| www黄色com| 男女av免费观看| 中文字幕av久久爽爽| 成人在线一区二区三区| 亚洲网站免费观看| 天天天天天天天干| 日产电影一区二区三区| 亚洲天堂精品在线| a级网站| 97精品视频在线观看| www.午夜| 国产精品国产三级国产专业不| 国产亚洲激情| 三级成人无码| 一区二区三区高清无码| 九九九亚洲| 欧美性爱中文字幕| 日日AV| 亚洲黄色AV| 国产一区二区做爱| 2025毛片| 国产精品秘精东影业| 苍井空中文字幕在线观看| 五月丁香无码| 青青草视频免费观看| 久久久123| 国产精品久久久久久无人区| 国內精品久久久久久久| 青青草无码在线| 欧美激情在线观看| 丁香五月综合网| 日韩午夜成人电影| 国产精品91视频| 色色五月婷婷| www.bbbb| 日韩无码第一页| 久久欧洲成人精品无码区| www日本高清| 黄色视频在线| 亚洲射射| 欧美日韩在线观看中文字幕| 香蕉综合在线| 国产精品99视频| 爱爱视频天天干| 成人动漫一区二区| 老熟女-ThePorn| 无码一二三区| 69精品视频| 海滩AV黑人| 婷婷国产成人精品| 欧美日韩一区二区三区四区五区六区 | 丁香五月婷婷综合网| 伊人成人网视频| 日韩国产传媒| 午夜激情久久| 中国国产乱子伦| 日韩黄色视频网站| 豆花视频成人精品视频| 日韩欧美色图| www.天天干| 98在线++传媒麻豆的视频| 亚洲AV无码成人精品区东京热 | 最近中文字幕在线中文字幕7| 五月丁香免费视频| 高清无码一区二区三区四区| jizz在线观看视频| 麻豆传媒在线观看| 日韩乱伦毛片| 小小拗女BBw搡BBBB搡| 456成人| 日韩激情在线观看| 男女啪啪免费视频| 影音先锋成人资源网| 在线观看的av| 超碰自拍| 亚洲va综合va国产va中文| 欧美操大逼| 狠狠噜噜| 日本中文字幕亚洲| 免费观看黄色电影| 久久久国产91桃色一区二区三区| 亚洲黄色成人网站| 超碰超爽| 全部在线A片免费播放| 丁香五月天激情网| 中文字幕第9页| 夜夜操网站| 臭小子啊轻点灬太粗太长了的视频| 成人网在线视频| 2019中文字幕在线| 黄片网址在线观看| 人人干人人操人人| 日韩精品免费无码视频| 91女人18片女毛片60分钟| 自拍偷拍亚洲| 国产美女自拍| 国产第八页| 亚洲AV毛片成人精品网站| 日本免费无码| 伊人小视频| 五月天婷婷在线观看| 99热免费| 在线免费高清无码| 经典三级在线视频| 久久久精品午夜人成欧洲亚洲韩国 | 蜜桃视频com.www| 成人电影无码| 婷婷色综合| 丁香五月在线观看| 两根茎一起进去好爽A片在线观看| 99热在线观看者| 亚洲无码AV一区二区| 97色色超碰| 河南少妇搡BBBB搡BBBB| 欧美成人视频大全| 无码草| 亚洲观看黄色网| 97精品人人妻人人| 久久亚洲天堂| 人人操碰成人网| 成人中文字幕在线视频| 免费国产在线视频| 操片| 丁香五月在线视频| 日韩图片区小说视频区日| 一本色道久久综合亚洲怎么玩| 天天无码视频| 国产在线观看无码免费视频| 色综合色| 大香蕉伊人丁香五月| xxx一区二区| 麻豆精品在线观看| 四虎成人视频| 色男人天堂| 热久久视频| 怡春院院成人免费视频| 国产AV三级| 18XXX亚洲HD护士JD| 欧美日韩不卡在线| 在线色综合| 国产精品三级视频| 俺也去av| 日本乱伦电影中文字幕| 二级黄色毛片| 欧美色视频一区二区三区在线观看| 国产在线一区二区三区| 大香蕉电影网| 欧美日韩综合| 国产麻豆精品成人免费视频| 神马午夜精品| 伊人午夜| 无码天天| 成人毛片AV无码| 色天天综合网| www.日韩| 啪啪成人视频| 黄色视频导航| 中文字幕在线观看AV| 色欲影视插综合一区二区三区 | 特黄特色免费视频| 日韩视频中文| 成人内射视频| 在线亚洲福利| 无码熟妇人妻无码AV在线天堂| 高潮AV在线观看| 黄色片网站在线观看| 777欧美| 制服丝袜在线视频| 日韩免费观看视频| 樱桃AV| 日韩AV网站在线观看| 欧美人妻中文字幕| 亚洲精品视频无码| 成人欧美一区二区三区白人| 亚洲欧美v在线视频| www.91国产| 国产亚洲AV| 动漫人物插画动漫人物的视频软件 | 水果派av解说| 日韩99热| 中文一线二线视频| 国产精品a片| 日韩精品一区二区三区四区蜜桃视频 | 麻豆视频在线观看| 久久成人一区| 天天日,天天干,天天操| 精品一区二区视频| 日韩黄色电影在线免费观看| 国产三级片91| 亚洲中文娱乐| 天天澡天天爽日日AV| 精品国产AV无码一区二区三区| 亚洲爱| 桃色AV| 蜜乳av红桃嫩久久| 精品无码三级在线观看视频| 亚洲三级片在线播放| 91国产视频网站| 亚洲精选中文字幕| 午夜激情视频在线观看| 97色在线视频| 久操免费观看| A级无码| 91人妻一区二区三区无不码超满 | 2014天堂网| 成人电影三区| 激情爱爱网| 黄色特级片| 四虎在线观看视频| 国产成人自拍视频在线观看| 伊人久艹| 亚洲日韩欧美国产| 欧一美一婬一伦一区二区三区自慰, | 中文无码一区二区三区四区| 一道本av| 就去色色五月丁香婷婷久久久| 欧美午夜性爱视频| 精品视频国产| 最新中文字幕观看| 一级免费片| 四虎成人网站| 亚洲性爱一区二区三区| 秋霞久久| 亚洲一级Av无码毛片久久精品| 国产99久久久精品| 开心五月激情婷婷| 成人三级视频| 少妇一级婬片内射视频| 好色婷婷| 日韩在线观看网站| 人妻啪啪视频| 黄片aaa| 色色在线观看| 久久久久久久大香蕉| 大鸡吧在线| 操b视频在线免费观看| ThePorn日本无码| 国产免费一区二区三区免费视频| 久热免费视频在线观看| 无码视频一区| 成人影片在线观看18| 高清无码二区| 91免费在线视频| 成人影视在线免费观看| 爱爱黄色视频| 成人在线伊人| 97天天干| 亚洲视频免费观看| 岛国电影av| 午夜在线观看视频18|