<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          初學(xué)者應(yīng)該看的 Webpack 完整指南(2020)

          共 11989字,需瀏覽 24分鐘

           ·

          2020-08-18 20:36


          我們應(yīng)該學(xué)習(xí) webpack 嗎 ?

          如今,CLI工具(如create-react-appVue -cli)已經(jīng)為我們抽象了大部分配置,并提供了合理的默認設(shè)置。

          即使那樣,了解幕后工作原理還是有好處的,因為我們遲早需要對默認值進行一些調(diào)整。

          在本文中中,我們會知道 webpack可以做什么,以及如何配置它以滿足我們的日常需求。

          什么是 webpack?

          作為前端開發(fā)人員,我們應(yīng)該熟悉 module 概念。你可能聽說過 AMD模塊,UMD,Common JS還有ES模塊

          webpack是一個模塊綁定器,它對模塊有一個更廣泛的定義,對于webpack來說,模塊是:

          • Common JS modules
          • AMD modules
          • CSS import
          • Images url
          • ES modules

          webpack 還可以從這些模塊中獲取依賴關(guān)系

          webpack 的最終目標(biāo)是將所有這些不同的源和模塊類型統(tǒng)一起來,從而將所有內(nèi)容導(dǎo)入JavaScript代碼,并最生成可以運行的代碼。

          entry

          Webpack的 **entry(入口點)**是收集前端項目的所有依賴項的起點。實際上,這是一個簡單的 JavaScript 文件。

          這些依賴關(guān)系形成一個依賴關(guān)系圖

          Webpack 的默認入口點(從版本4開始)是src/index.js,它是可配置的。webpack 可以有多個入口點。

          Output

          output是生成的JavaScript和靜態(tài)文件的地方。

          Loaders

          Loaders 是第三方擴展程序,可幫助webpack處理各種文件擴展名。例如,CSS,圖像或txt文件。

          Loaders的目標(biāo)是在模塊中轉(zhuǎn)換文件(JavaScript以外的文件)。文件成為模塊后,webpack可以將其用作項目中的依賴項。

          Plugins

          插件是第三方擴展,可以更改webpack的工作方式。例如,有一些用于提取HTML,CSS或設(shè)置環(huán)境變量的插件。

          Mode

          webpack 有兩種操作模式:開發(fā)(development)生產(chǎn)(production)。它們之間的主要區(qū)別是生產(chǎn)模式自動生成一些優(yōu)化后的代碼。

          Code splitting

          代碼拆分延遲加載是一種避免生成較大包的優(yōu)化技術(shù)。

          通過代碼拆分,開發(fā)人員可以決定僅在響應(yīng)某些用戶交互時加載整個JavaScript塊,比如單擊或路由更改(或其他條件)。

          被拆分的一段代碼稱為 chunk。

          Webpack入門

          開始使用webpack時,先創(chuàng)建一個新文件夾,然后進入該文件中,初始化一個NPM項目,如下所示:

          mkdir?webpack-tutorial?&&?cd?$_

          npm?init?-y

          接著安裝 webpack,webpack-cliwebpack-dev-server

          npm?i?webpack?webpack-cli?webpack-dev-server?--save-dev

          要運行 webpack,只需要在 package.json 配置如下命令即可:

          ??"scripts":?{
          ????"dev":?"webpack?--mode?development"
          ??},

          通過這個腳本,我們指導(dǎo)webpack在開發(fā)模式下工作,方便在本地工作。

          Webpack 的第一步

          在開發(fā)模式下運行 webpack:

          npm?run?dev

          運行完后會看到如下錯誤:

          ERROR?in?Entry?module?not?found:?Error:?Can't?resolve?'./src'

          webpack 在這里尋找默認入口點src/index.js,所以我們需要手動創(chuàng)建一下,并輸入一些內(nèi)容:

          mkdir?src

          echo?'console.log("Hello?webpack!")'?>?src/index.js

          現(xiàn)在再次運行npm run dev,錯誤就沒有了。運行的結(jié)果生成了一個名為dist/的新文件夾,其中包含一個名為main.js的 JS 文件:

          dist
          └──?main.js

          這是我們的第一個webpack包,也稱為output。

          配置 Webpack

          對于簡單的任務(wù),webpack無需配置即可工作,但是很快我們就會遇到問題,一些文件如果沒有指定的 loader 是沒法打包的。所以,我們需要對 webpack進行配置,對于 webpack 的配置是在 webpack.config.js 進行的,所以我們需要創(chuàng)建該文件:

          touch?webpack.config.js

          Webpack 用 JavaScript 編寫,并在無頭 JS 環(huán)境(例如Node.js)上運行。在此文件中,至少需要一個module.exports,這是的 Common JS 導(dǎo)出方式:

          module.exports?=?{
          ??//
          };

          webpack.config.js中,我們可以通過添加或修改來改變webpack的行為方式

          • entry point
          • output
          • loaders
          • plugins
          • code splitting

          例如,要更改入口路徑,我們可以這樣做

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

          module.exports?=?{
          ??entry:?{?index:?path.resolve(__dirname,?"source",?"index.js")?}
          };

          現(xiàn)在,webpack 將在source/index.js中查找要加載的第一個文件。要更改包的輸出路徑,我們可以這樣做:

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

          module.exports?=?{
          ??output:?{
          ????path:?path.resolve(__dirname,?"build")
          ??}
          }

          這樣,webpack將把最終生成包放在build中,而不是dist.(為了簡單起見,在本文中,我們使用默認配置)。

          打包 HTML

          沒有HTML頁面的Web應(yīng)用程序幾乎沒有用。要在webpack中使用 HTML,我們需要安裝一個插件html-webpack-plugin

          npm?i?html-webpack-plugin?--save-dev

          一旦插件安裝好,我們就可以對其進行配置:

          const?HtmlWebpackPlugin?=?require("html-webpack-plugin");
          const?path?=?require("path");

          module.exports?=?{
          ??plugins:?[
          ????new?HtmlWebpackPlugin({
          ??????template:?path.resolve(__dirname,?"src",?"index.html")
          ????})
          ??]
          };

          這里的意思是讓 webpack,從 src/index.html 加載 HTML 模板。

          html-webpack-plugin的最終目標(biāo)有兩個:

          • 加載 html 文件

          • 它將bundle注入到同一個文件中

          接著,我們需要在 src/index.html 中創(chuàng)建一個簡單的 HTML 文件:


          "en">

          ????"UTF-8">
          ????Webpack?tutorial





          稍后,我們會運行這個程序。

          webpack development server

          在本文第一部分中,我們安裝了webpack-dev-server。如果你忘記安裝了,現(xiàn)在可以運行下面命令安裝一下:

          npm?i?webpack-dev-server?--save-dev

          webpack-dev-server 可以讓開發(fā)更方便,不需要改動了文件就去手動刷新文件。配置完成后,我們可以啟動本地服務(wù)器來提供文件。

          要配置webpack-dev-server,請打開package.json并添加一個 “start” 命令:

          "scripts":?{
          ??"dev":?"webpack?--mode?development",
          ??"start":?"webpack-dev-server?--mode?development?--open",
          },

          有了 start 命令,我們來跑一下:

          npm?start

          運行后,默認瀏覽器應(yīng)打開。在瀏覽器的控制臺中,還應(yīng)該看到一個 script 標(biāo)簽,引入的是我們的 main.js。

          使用 webpack loader

          Loader是第三方擴展程序,可幫助webpack處理各種文件擴展名。例如,有用于 CSS,圖像或 txt 文件的加載程序。

          下面是一些 loader 配置介紹:

          module.exports?=?{
          ??module:?{
          ????rules:?[
          ??????{
          ????????test:?/\.filename$/,
          ????????use:?["loader-b",?"loader-a"]
          ??????}
          ????]
          ??},
          ??//
          };

          相關(guān)配置以module 關(guān)鍵字開始。在module內(nèi),我們在rules內(nèi)配置每個加載程序組或單個加載程序。

          對于我們想要作為模塊處理的每個文件,我們用testuse配置一個對象

          {
          ????test:?/\.filename$/,
          ????use:?["loader-b",?"loader-a"]
          }

          test 告訴 webpack “嘿,將此文件名視為一個模塊”。use 定義將哪些 loaders 應(yīng)用于些打包的文件。

          打包 CSS

          要 在webpack 中打包CSS,我們需要至少安裝兩個 loader。Loader 對于幫助 webpack 了解如何處理.css文件是必不可少的。

          要在 webpack 中測試 CSS,我們需要在 src 下創(chuàng)建一個style.css文件:

          h1?{
          ????color:?orange;
          }

          另外在 src/index.html 添加 h1 標(biāo)簽


          "en">

          ????"UTF-8">
          ????Webpack?tutorial


          Hello?webpack!




          最后,在src/index.js 中加載 CSS:

          在測試之前,我們需要安裝兩個 loader:

          • css-loader:解析 css 代碼中的 url、@import語法像importrequire一樣去處理css里面引入的模塊

          • style-loader:幫我們直接將css-loader解析后的內(nèi)容掛載到html頁面當(dāng)中

          安裝 loader:

          npm?i?css-loader?style-loader?--save-dev

          然后在webpack.config.js中配置它們

          const?HtmlWebpackPlugin?=?require("html-webpack-plugin");
          const?path?=?require("path");

          module.exports?=?{
          ??module:?{
          ????rules:?[
          ??????{
          ????????test:?/\.css$/,
          ????????use:?["style-loader",?"css-loader"]
          ??????}
          ????]
          ??},
          ??plugins:?[
          ????new?HtmlWebpackPlugin({
          ??????template:?path.resolve(__dirname,?"src",?"index.html")
          ????})
          ??]
          };

          現(xiàn)在,如果你運行npm start,會看到樣式表加載在HTML的頭部:

          一旦CSS Loader 就位,我們還可以使用MiniCssExtractPlugin提取CSS文件

          Webpack Loader 順序很重要!

          在webpack中,Loader 在配置中出現(xiàn)的順序非常重要。以下配置無效:

          //

          module.exports?=?{
          ??module:?{
          ????rules:?[
          ??????{
          ????????test:?/\.css$/,
          ????????use:?["css-loader",?"style-loader"]
          ??????}
          ????]
          ??},
          ??//
          };

          此處,“style-loader”出現(xiàn)在 “css-loader” 之前。但是style-loader用于在頁面中注入樣式,而不是用于加載實際的CSS文件。

          相反,以下配置有效:

          module.exports?=?{
          ??module:?{
          ????rules:?[
          ??????{
          ????????test:?/\.css$/,
          ????????use:?["style-loader",?"css-loader"]
          ??????}
          ????]
          ??},
          ??//
          };

          webpack loaders 是從右到左執(zhí)行的。

          打包 sass

          要在 webpack 中測試sass,同樣,我們需要在 src 目錄下創(chuàng)建一個 style.scss 文件:

          @import?url("https://fonts.googleapis.com/css?family=Karla:weight@400;700&display=swap");

          $font:?"Karla",?sans-serif;
          $primary-color:?#3e6f9e;

          body?{
          ??font-family:?$font;
          ??color:?$primary-color;
          }

          另外,在src/index.html中添加一些 Dom 元素:


          "en">

          ????"UTF-8">
          ????Webpack?tutorial


          ??

          Hello?webpack!


          ??

          Hello?sass!




          最后,將 sass 文件加載到src/index.js中:

          import?"./style.scss";
          console.log("Hello?webpack!");

          在測試之前,我們需要安裝幾個 loader:

          • sass-loader:加載 SASS / SCSS 文件并將其編譯為 CSS

          • css-loader:解析 css 代碼中的 url、@import語法像importrequire一樣去處理css里面引入的模塊

          • style-loader:幫我們直接將css-loader解析后的內(nèi)容掛載到html頁面當(dāng)中

          安裝 loader:

          npm?i?css-loader?style-loader?sass-loader?sass?--save-dev

          然后在webpack.config.js中配置它們:

          const?HtmlWebpackPlugin?=?require("html-webpack-plugin");
          const?path?=?require("path");

          module.exports?=?{
          ??module:?{
          ????rules:?[
          ??????{
          ????????test:?/\.scss$/,
          ????????use:?["style-loader",?"css-loader",?"sass-loader"]
          ??????}
          ????]
          ??},
          ??plugins:?[
          ????new?HtmlWebpackPlugin({
          ??????template:?path.resolve(__dirname,?"src",?"index.html")
          ????})
          ??]
          };

          注意loader的出現(xiàn)順序:首先是sass-loader,然后是css-loader,最后是style-loader

          現(xiàn)在,運行npm start,你應(yīng)該會在HTML的頭部看到加載的樣式表:

          打包現(xiàn)代 JavaScrip

          webpack 本身并不知道如何轉(zhuǎn)換JavaScript代碼。 該任務(wù)已外包給babel的第三方 loader,特別是babel-loader。

          babel是一個JavaScript編譯器和“編譯器”。babel 可以將現(xiàn)代JS(es6, es7...)轉(zhuǎn)換為可以在(幾乎)任何瀏覽器中運行的兼容代碼。

          同樣,要使用它,我們需要安裝一些 Loader:

          • babel-core :把 js 代碼分析成 ast ,方便各個插件分析語法進行相應(yīng)的處理

          • babel-preset-env:將現(xiàn)代 JS 編譯為ES5

          • **babel-loader **:用于 webpack

          引入依賴關(guān)系

          npm?i?@babel/core?babel-loader?@babel/preset-env?--save-dev

          接著,創(chuàng)建一個新文件babel.config.json配置babel,內(nèi)容如下:

          {
          ??"presets":?[
          ????"@babel/preset-env"
          ??]
          }

          最后在配置一下 webpack :

          const?HtmlWebpackPlugin?=?require("html-webpack-plugin");
          const?path?=?require("path");

          module.exports?=?{
          ??module:?{
          ????rules:?[
          ??????{
          ????????test:?/\.scss$/,
          ????????use:?["style-loader",?"css-loader",?"sass-loader"]
          ??????},
          ??????{
          ????????test:?/\.js$/,
          ????????exclude:?/node_modules/,
          ????????use:?["babel-loader"]
          ??????}
          ????]
          ??},
          ??plugins:?[
          ????new?HtmlWebpackPlugin({
          ??????template:?path.resolve(__dirname,?"src",?"index.html")
          ????})
          ??]
          };

          要測試轉(zhuǎn)換,可以在 src/index.js中編寫一些現(xiàn)代語法:

          import?"./style.scss";
          console.log("Hello?webpack!");

          const?fancyFunc?=?()?=>?{
          ??return?[1,?2];
          };

          const?[a,?b]?=?fancyFunc();

          現(xiàn)在運行npm run dev來查看dist中轉(zhuǎn)換后的代碼。打開 dist/main.js并搜索“fancyFunc”:

          \n\nvar?fancyFunc?=?function?fancyFunc()?{\n??return?[1,?2];\n};\n\nvar?_fancyFunc?=?fancyFunc(),\n????_fancyFunc2?=?_slicedToArray(_fancyFunc,?2),\n????a?=?_fancyFunc2[0],\n????b?=?_fancyFunc2[1];\n\n//#?sourceURL=webpack:///./src/index.js?"

          沒有babel,代碼將不會被轉(zhuǎn)譯:

          \n\nconsole.log(\"Hello?webpack!\");\n\nconst?fancyFunc?=?()?=>?{\n??return?[1,?2];\n};\n\nconst?[a,?b]?=?fancyFunc();\n\n\n//#?sourceURL=webpack:///./src/index.js?");?

          **注意:**即使沒有babel,webpack也可以正常工作。僅在執(zhí)行 ES5 代碼時才需要進行代碼轉(zhuǎn)換過程。

          在 Webpack 中使用 JS 的模塊

          webpack 將整個文件視為模塊。但是,請不要忘記它的主要目的:加載ES模塊。

          ECMAScript模塊(簡稱ES模塊)是一種JavaScript代碼重用的機制,于2015年推出,一經(jīng)推出就受到前端開發(fā)者的喜愛。在2015之年,JavaScript 還沒有一個代碼重用的標(biāo)準(zhǔn)機制。多年來,人們對這方面的規(guī)范進行了很多嘗試,導(dǎo)致現(xiàn)在有多種模塊化的方式。

          你可能聽說過AMD模塊,UMD,或CommonJS,這些沒有孰優(yōu)孰劣。最后,在ECMAScript 2015中,ES 模塊出現(xiàn)了。

          我們現(xiàn)在有了一個“正式的”模塊系統(tǒng)。

          要在 webpack 使用 ES module ,首先創(chuàng)建 src/common/usersAPI.js 文件:

          const?ENDPOINT?=?"https://jsonplaceholder.typicode.com/users/";

          export?function?getUsers()?{
          ??return?fetch(ENDPOINT)
          ????.then(response?=>?{
          ??????if?(!response.ok)?throw?Error(response.statusText);
          ??????return?response.json();
          ????})
          ????.then(json?=>?json);
          }

          src/index.js中,引入上面的模塊:

          import?{?getUsers?}?from?"./common/usersAPI";
          import?"./style.scss";
          console.log("Hello?webpack!");

          getUsers().then(json?=>?console.log(json));

          生產(chǎn)方式

          如前所述,webpack有兩種操作模式:開發(fā)(development )和(production)。到目前為止,我們僅在開發(fā)模式下工作。

          在開發(fā)模式中,為了便于代碼調(diào)試方便我們快速定位錯誤,不會壓縮混淆源代碼。相反,在生產(chǎn)模式下,webpac k進行了許多優(yōu)化:

          • 使用 TerserWebpackPlugin 進行縮小以減小 bundle 的大小
          • 使用ModuleConcatenationPlugin提升作用域

          在生產(chǎn)模式下配 置webpack,請打開 package.json 并添加一個“ build” 命令:

          現(xiàn)在運行 npm run build,webpack 會生成一個壓縮的包。

          Code splitting

          **代碼拆分(Code splitting)**是指針對以下方面的優(yōu)化技術(shù):

          • 避免出現(xiàn)一個很大的 bundle
          • 避免重復(fù)的依賴關(guān)系

          webpack 社區(qū)考慮到應(yīng)用程序的初始 bundle 的最大大小有一個限制:200KB。

          在 webpack 中有三種激活 code splitting ?的主要方法:

          • 有多個入口點

          • 使用 optimization.splitChunks 選項

          • 動態(tài)導(dǎo)入

          第一種基于多個入口點的技術(shù)適用于較小的項目,但是從長遠來看它是不可擴展的。這里我們只關(guān)注第二和第三種方式。

          Code splitting 與 optimization.splitChunks

          考慮一個使用Moment.js 的 JS 應(yīng)用程序,Moment.js是流行的時間和日期JS庫。

          在項目文件夾中安裝該庫:

          npm?i?moment

          現(xiàn)在清除src/index.js的內(nèi)容,并引入 moment 庫:

          import?moment?from?"moment";

          運行 npm run build 并查看控制的輸出內(nèi)容:

          ?main.js????350?KiB???????0??[emitted]??[big]??main

          整個 moment 庫都綁定到了 main.js 中這樣是不好的。借助optimization.splitChunks,我們可以從主包中移出moment.js。

          要使用它,需要在 ?webpack.config.js 添加 optimization ?選項:

          const?HtmlWebpackPlugin?=?require("html-webpack-plugin");
          const?path?=?require("path");

          module.exports?=?{
          ??module:?{
          ??//?...
          ??},
          ??optimization:?{
          ????splitChunks:?{?chunks:?"all"?}
          ??},
          ??//?...
          };

          運行npm run build 并查看運行結(jié)果:

          ????????main.js???5.05?KiB???????0??[emitted]?????????main
          vendors~main.js????346?KiB???????1??[emitted]??[big]??vendors~main

          現(xiàn)在,我們有了一個帶有moment.js 的vendors?main.js,而主入口點的大小更合理。

          注意:即使進行代碼拆分,moment.js仍然是一個體積較大的庫。有更好的選擇,如使用luxondate-fns。

          ## Code splitting 與 動態(tài)導(dǎo)入

          Code splitting的一種更強大的技術(shù)使用動態(tài)導(dǎo)入來有條件地加載代碼。在ECMAScript 2020中提供此功能之前,webpack 提供了動態(tài)導(dǎo)入。

          這種方法在 Vue 和 React 之類的現(xiàn)代前端庫中得到了廣泛使用(React有其自己的方式,但是概念是相同的)。

          Code splitting 可用于:

          • 模塊級別
          • 路由級別

          例如,你可以有條件地加載一些 JavaScript 模塊,以響應(yīng)用戶的交互(例如單擊或鼠標(biāo)移動)。或者,可以在響應(yīng)路由更改時加載代碼的相關(guān)部分。

          要使用動態(tài)導(dǎo)入,我們先清除src/index.html,并寫入下面的內(nèi)容:


          "en">

          ????"UTF-8">
          ????Dynamic?imports


          "btn">Load!


          src/common/usersAPI.js中:

          const?ENDPOINT?=?"https://jsonplaceholder.typicode.com/users/";

          export?function?getUsers()?{
          ??return?fetch(ENDPOINT)
          ????.then(response?=>?{
          ??????if?(!response.ok)?throw?Error(response.statusText);
          ??????return?response.json();
          ????})
          ????.then(json?=>?json);
          }

          src/index.js

          const?btn?=?document.getElementById("btn");

          btn.addEventListener("click",?()?=>?{
          ??//
          });

          如果運行npm run start查看并單擊界面中的按鈕,什么也不會發(fā)生。

          現(xiàn)在想象一下,我們想在某人單擊按鈕后加載用戶列表?!霸钡姆椒梢允褂渺o態(tài)導(dǎo)入從src/common /usersAPI.js加載函數(shù):

          import?{?getUsers?}?from?"./common/usersAPI";

          const?btn?=?document.getElementById("btn");

          btn.addEventListener("click",?()?=>?{
          ??getUsers().then(json?=>?console.log(json));
          });

          問題在于ES模塊是靜態(tài)的,這意味著我們無法在運行時更改導(dǎo)入的內(nèi)容。

          通過動態(tài)導(dǎo)入,我們可以選擇何時加載代碼

          const?getUserModule?=?()?=>?import("./common/usersAPI");

          const?btn?=?document.getElementById("btn");

          btn.addEventListener("click",?()?=>?{
          ??getUserModule().then(({?getUsers?})?=>?{
          ????getUsers().then(json?=>?console.log(json));
          ??});
          });

          這里我們創(chuàng)建一個函數(shù)來動態(tài)加載模塊

          const?getUserModule?=?()?=>?import("./common/usersAPI");

          現(xiàn)在,當(dāng)你第一次使用npm run start加載頁面時,會看到控制臺中已加載 js 包:

          現(xiàn)在,僅在單擊按鈕時才加載/common/usersAPI

          對應(yīng)的 chunk 是 0.js

          通過在導(dǎo)入路徑前面加上魔法注釋/ * webpackChunkName:“ name_here” * /,可以更改塊名稱:

          const?getUserModule?=?()?=>
          ??import(/*?webpackChunkName:?"usersAPI"?*/?"./common/usersAPI");

          const?btn?=?document.getElementById("btn");

          btn.addEventListener("click",?()?=>?{
          ??getUserModule().then(({?getUsers?})?=>?{
          ????getUsers().then(json?=>?console.log(json));
          ??});
          });


          最后



          如果你覺得這篇內(nèi)容對你挺有啟發(fā),我想邀請你幫我三個小忙:

          1. 點個「在看」,讓更多的人也能看到這篇內(nèi)容(喜歡不點在看,都是耍流氓 -_-)

          2. 歡迎加我微信「qianyu443033099」拉你進技術(shù)群,長期交流學(xué)習(xí)...

          3. 關(guān)注公眾號「前端下午茶」,持續(xù)為你推送精選好文,也可以加我為好友,隨時聊騷。


          點個在看支持我吧,轉(zhuǎn)發(fā)就更好了


          瀏覽 35
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  中文字幕在线视频网站国产免费 | 操逼视频大片 | 翔田千里性爱视频 | 亚洲免费观看 | 国产探花视频网站 |