<strike id="cy2gs"><menu id="cy2gs"></menu></strike>
  • <del id="cy2gs"><dfn id="cy2gs"></dfn></del>
  • 初學(xué)者應(yīng)該看的 Webpack 完整指南(2020)

    2020-7-19    seo達人

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

    如今,CLI工具(如create-react-app或Vue -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 的最終目標是將所有這些不同的源和模塊類型統(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的目標是在模塊中轉(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-cli和 webpack-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的最終目標有兩個:


    加載 html 文件

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

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


    <!DOCTYPE html>

    <html lang="en">

    <head>

       <meta charset="UTF-8">

       <title>Webpack tutorial</title>

    </head>

    <body>


    </body>

    </html>

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


    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 標簽,引入的是我們的 main.js。


    clipboard.png


    使用 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)配置每個加載程序組或單個加載程序。


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


    {

       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 標簽


    <!DOCTYPE html>

    <html lang="en">

    <head>

       <meta charset="UTF-8">

       <title>Webpack tutorial</title>

    </head>

    <body>

    <h1>Hello webpack!</h1>

    </body>

    </html>

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


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


    css-loader: 解析 css 代碼中的 url、@import語法像import和require一樣去處理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的頭部:


    clipboard.png


    一旦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 元素:


    <!DOCTYPE html>

    <html lang="en">

    <head>

       <meta charset="UTF-8">

       <title>Webpack tutorial</title>

    </head>

    <body>

     <h1>Hello webpack!</h1>

     <p>Hello sass!</p>

    </body>

    </html>

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


    import "./style.scss";

    console.log("Hello webpack!");

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


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

    css-loader: 解析 css 代碼中的 url、@import語法像import和require一樣去處理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的頭部看到加載的樣式表:


    clipboard.png


    打包現(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 還沒有一個代碼重用的標準機制。多年來,人們對這方面的規(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仍然是一個體積較大的庫。 有更好的選擇,如使用luxon或date-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)用戶的交互(例如單擊或鼠標移動)。 或者,可以在響應(yīng)路由更改時加載代碼的相關(guān)部分。


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


    <!DOCTYPE html>

    <html lang="en">

    <head>

       <meta charset="UTF-8">

       <title>Dynamic imports</title>

    </head>

    <body>

    <button id="btn">Load!</button>

    </body>

    </html>

    在 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)在想象一下,我們想在某人單擊按鈕后加載用戶列表。 “原生”的方法可以使用靜態(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 包:


    clipboard.png


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


    clipboard.png


    對應(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));

     });

    });

    藍藍設(shè)計www.skdbbs.com )是一家專注而深入的界面設(shè)計公司,為期望卓越的國內(nèi)外企業(yè)提供卓越的UI界面設(shè)計、BS界面設(shè)計 、 cs界面設(shè)計 、 ipad界面設(shè)計 、 包裝設(shè)計 、 圖標定制 、 用戶體驗 、交互設(shè)計、 網(wǎng)站建設(shè) 平面設(shè)計服務(wù)

    日歷

    鏈接

    個人資料

    藍藍設(shè)計的小編 http://www.skdbbs.com

    存檔

    主站蜘蛛池模板: 精品露脸国产偷人在视频| 亚洲福利精品一区二区三区| 精品日韩欧美国产| 97久久久久人妻精品专区| 欧美亚洲另类精品第一页 | 亚洲精品国产精品乱码在线观看| 欧美日激情日韩精品| 成人国产精品免费视频| 亚洲精品你懂的在线观看| 麻豆精品国产自产在线观看一区| 亚洲一二成人精品区| 国产精品无码a∨精品| 亚洲精品无码av人在线观看 | 国产精品无码无卡在线播放| 最新精品国偷自产在线| 久久91精品综合国产首页| 国产成人精品怡红院在线观看| 99精品免费视品| 久久发布国产伦子伦精品| 亚洲高清国产拍精品26U| 合区精品久久久中文字幕一区 | 精品一区二区无码AV| 粉嫩精品美女国产在线观看| 麻豆精品久久久一区二区| 99久久免费国产精品热| 精品国产第一国产综合精品| 亚洲日韩国产AV无码无码精品| 国产一在线精品一区在线观看| 91精品婷婷国产综合久久| 999久久久免费国产精品播放| 久久精品国产精品国产精品污| 国产精品高清一区二区三区不卡| 69国产成人综合久久精品| 高清在线亚洲精品国产二区| 97久久超碰国产精品旧版 | 国产精品扒开腿做爽爽爽视频 | 精品乱码一区二区三区四区| 热re99久久6国产精品免费| 久久久无码精品亚洲日韩蜜臀浪潮| 欧美精品hdvideosex4k| 国产亚洲精品精华液|