開發必備的webpack4

正兒八經的嬌嬌發表於2019-03-04

首先webpack4建議使用node版本在8.5以上,是因為要相容新版npm下的npx,cmd中node -v檢視node版本。

1.什麼是webpack

WebPack可以看做是模組打包機:它做的事情是,分析你的專案結構,找到JavaScript模組以及其它的一些瀏覽器不能直接執行的擴充語言(Scss,TypeScript等),並將其打包為合適的格式以供瀏覽器使用。

構建就是把原始碼轉換成釋出到線上的可執行 JavaScrip、CSS、HTML 程式碼,包括如下內容。

  • 程式碼轉換:TypeScript 編譯成 JavaScript、SCSS 編譯成 CSS 等。
  • 檔案優化:壓縮 JavaScript、CSS、HTML 程式碼,壓縮合並圖片等。
  • 程式碼分割:提取多個頁面的公共程式碼、提取首屏不需要執行部分的程式碼讓其非同步載入。
  • 模組合併:在採用模組化的專案裡會有很多個模組和檔案,需要構建功能把模組分類合併成一個檔案。
  • 自動重新整理:監聽本地原始碼的變化,自動重新構建、重新整理瀏覽器。
  • 程式碼校驗:在程式碼被提交到倉庫前需要校驗程式碼是否符合規範,以及單元測試是否通過。
  • 自動釋出:更新完程式碼後,自動構建出線上釋出程式碼並傳輸給釋出系統。

構建其實是工程化、自動化思想在前端開發中的體現,把一系列流程用程式碼去實現,讓程式碼自動化地執行這一系列複雜的流程。 構建給前端開發注入了更大的活力,解放了我們的生產力。

2.初始化專案

  • 初始化package.json
npm init -y 
複製程式碼
// package.json 檔案中
"scripts": {
    "build": "webpack  --profile --progress --colors --display-error-details",
    "dev": "webpack  --display-modules --profile --progress --colors --display-error-details"
  },

複製程式碼
  • color 輸出結果帶彩色,比如:會用紅色顯示耗時較長的步驟

  • profile 輸出效能資料,可以看到每一步的耗時

  • progress 輸出當前編譯的進度,以百分比的形式呈現

  • display-modules 預設情況下 node_modules 下的模組會被隱藏,加上這個引數可以顯示這些被隱藏的模組

  • display-error-details 輸出詳細的錯誤資訊

  • 全域性安裝

npm install webpack -g
複製程式碼
  • 本地安裝
npm install webpack webpack-cli -D//-D是指開發環境需要,上線不需要,下同;
複製程式碼

一般推薦本地安裝,安裝在自己的專案中,不然版本不同會有不相容。

3. 快速上手

3.1 webpack核心概念

  • Entry:入口,Webpack 執行構建的第一步將從 Entry 開始,可抽象成輸入。
  • Module:模組,在 Webpack 裡一切皆模組,一個模組對應著一個檔案。Webpack 會從配置的 Entry 開始遞迴找出所有依賴的模組。
  • Chunk:程式碼塊,一個 Chunk 由多個模組組合而成,用於程式碼合併與分割。
  • Loader:模組轉換器,用於把模組原內容按照需求轉換成新內容。
  • Plugin:擴充套件外掛,在 Webpack 構建流程中的特定時機注入擴充套件邏輯來改變構建結果或做你想要的事情。
  • Output:輸出結果,在 Webpack 經過一系列處理並得出最終想要的程式碼後輸出結果。

3.2 配置webpack

npm install webpack webpack-cli -D
複製程式碼
  • 建立src
  • 建立dist
    • 建立index.html
  • 配置檔案webpack.config.js
    • entry:配置入口檔案的地址
    • output:配置出口檔案的地址
    • module:配置模組,主要用來配置不同檔案的載入器
    • plugins:配置外掛
    • devServer:配置開發伺服器
// 基於node的 遵循commonjs規範的
let path = require(`path`);//node的模組
module.exports = {
  entry:`./src/index.js`, // 入口
  output:{
    filename:`build.js`,
    // 這個路徑必須是絕對路徑
    path: path.resolve(`./dist`)
  }, // 出口
  devServer:{
    contentBase:`./dist`,
    port:8080,
    compress:true,// 伺服器壓縮
    open:true,// 自動開啟瀏覽器
    // hot:true//熱更新
  },// 開發伺服器
  module:{}, // 模組配置
  plugins:[], // 外掛的配置
  mode:`development`, // 可以更改模式
  resolve:{}, // 配置解析
}
// 在webpack中如何配置開發伺服器 webpack-dev-server
複製程式碼

4. 配置開發伺服器

npm i webpack-dev-server –D
複製程式碼
  • contentBase 配置開發服務執行時的檔案根目錄
  • host:開發伺服器監聽的主機地址
  • compress 開發伺服器是否啟動gzip等壓縮
  • port:開發伺服器監聽的埠
+ devServer:{
+        contentBase:path.resolve(__dirname,`dist`),
+        host:`localhost`,
+        compress:true,
+        port:8080
+ }//開發伺服器
複製程式碼
+  "scripts": {
+    "build": "webpack --mode development",
+    "dev": "webpack-dev-server --open --mode development "
+  }//開啟本地服務 npm run dev
複製程式碼

5. 入口檔案的型別

5.1單入口+單出口

這種情況很少,一般就以字串的形式出現即可,例如:

entry: `./src/index.js`,
複製程式碼

5.2 多入口陣列形式+單出口

entry:[`./src/index.js`,`./src/a.js`]
複製程式碼

5.1. 多入口+多出口

有時候我們的頁面可以不止一個HTML頁面,會有多個頁面,所以就需要多入口

entry: {
        index: `./src/index.js`,
        main:`./src/main.js`
    },
     output: {
            path: path.resolve(__dirname, `dist`),
            filename: `[name].[hash].js`,
            publicPath:PUBLIC_PATH
        },
        new HtmlWebpackPlugin({
                    minify: {
                        removeAttributeQuotes:true
                    },
                    hash: true,
                    template: `./src/index.html`,
                    chunks:[`index`],
                    filename:`index.html`
                }),
                new HtmlWebpackPlugin({
                    minify: {
                        removeAttributeQuotes:true
                    },
                    hash: true,
                    chunks:[`main`],
                    template: `./src/main.html`,
                    filename:`main.html`
                })],
複製程式碼

6. 支援載入css檔案

6.1 什麼是Loader

通過使用不同的Loader,Webpack可以要把不同的檔案都轉成JS檔案,比如CSS、ES6/7、JSX等

  • test:匹配處理檔案的副檔名的正規表示式
  • use:loader名稱,就是你要使用模組的名稱
  • include/exclude:手動指定必須處理的資料夾或遮蔽不需要處理的資料夾
  • query:為loaders提供額外的設定選項

loader三種寫法

  • use
  • loader
  • use+loader

6.2 css-loader

npm i style-loader css-loader -D
複製程式碼

配置載入器

    module: {
+        rules:[
+            {
+                test:/.css$/,
+                use:[`style-loader`,`css-loader`],//從右往左寫,webpack特性
+                include:path.join(__dirname,`./src`),
+                exclude:/node_modules/
+            }
+        ]
    },
複製程式碼

7. 支援圖片

7.1 手動新增圖片

npm i file-loader url-loader -D
複製程式碼
  • file-loader 解決CSS等檔案中的引入圖片路徑問題
  • url-loader 當圖片較小的時候會把圖片BASE64編碼,大於limit引數的時候還是使用file-loader 進行拷貝
let logo=require(`./images/logo.png`);
let img=new Image();
img.src=logo;
document.body.appendChild(img);
複製程式碼
  {
    test:/.(jpg|png|gif|svg)$/,
    use:`url-loader`,
    include:path.join(__dirname,`./src`),
    exclude:/node_modules/
  }
複製程式碼

7.2 在CSS中引入圖片

還可以在CSS檔案中引入圖片

.img-bg{
    background: url(./images/logo.png);
    width:173px;
    height:66px;
}
複製程式碼

8. 自動產出html

8.1 什麼是外掛

外掛是 wepback 的支柱功能。webpack 自身也是構建於,你在 webpack 配置中用到的相同的外掛系統之上!

  • 外掛使用
npm install 外掛名 -D
複製程式碼

因為外掛都是類,引用方式,在plugins陣列中 new 外掛名 即可使用。

8.2 我們希望自動能產出HTML檔案,並在裡面引入產出後的資源

npm i html-webpack-plugin -D
複製程式碼
  • minify 是對html檔案進行壓縮,removeAttrubuteQuotes是去掉屬性的雙引號
  • hash 引入產出資源的時候加上雜湊避免快取
  • template 模版路徑
    plugins: [
+        new HtmlWebpackPlugin({
+       minify: {
+            removeAttributeQuotes:true
+        },
+        hash: true,
+        template: `./src/index.html`,
+        filename:`index.html`
    })]
複製程式碼

9. 分離CSS

因為CSS的下載和JS可以並行,當一個HTML檔案很大的時候,我們可以把CSS單獨提取出來載入,webpack4中mini-css-extract-plugin也可以實現,但是目前bug比較多,不能分成多個css。

npm install --save-dev extract-text-webpack-plugin@next
複製程式碼
{
    test:/.css$/,
    use: ExtractTextWebpackPlugin.extract({
        use:`css-loader`
    }),
    include:path.join(__dirname,`./src`),
    exclude:/node_modules/
},

plugins: [
    new ExtractTextWebpackPlugin(`css/index.css`),
]
複製程式碼

處理圖片路徑問題

const PUBLIC_PATH=`/`;

output: {
    path: path.resolve(__dirname, `dist`),
    filename: `bundle.js`,
    publicPath:PUBLIC_PATH
},
複製程式碼

指定打包後的圖片位置

use: [
    {
     loader: `url-loader`,
     options: {
       limit: 1024,
      outputPath:`images/`
     }
    }
],
複製程式碼

在HTML中使用圖片

npm i html-withimg-loader -D
複製程式碼
<div class="img-container "><img src="./images/logo.png" alt="logo.png"></div>
複製程式碼
  {
+    test:/.(html|html)$/,
+    use:`html-withimg-loader`,
+    include:path.join(__dirname,`./src`),
+    exclude:/node_modules/
  }
複製程式碼

10. 編譯less 和 sass

npm i less less-loader -D
npm i node-saas sass-loader -D
複製程式碼
@color:orange;
.less-container{
	border:1px solid @color;
}

$color:green;
.sass-container{
	border:1px solid $color;
}
複製程式碼
const cssExtract=new ExtractTextWebpackPlugin(`css.css`);
const lessExtract=new ExtractTextWebpackPlugin(`less.css`);
const sassExtract=new ExtractTextWebpackPlugin(`sass.css`);

 {
                test:/.less$/,
                use: lessExtract.extract({
                    use:[`css-loader`,`less-loader`]
                }),
                include:path.join(__dirname,`./src`),
                exclude:/node_modules/
            },
            {
                test:/.scss$/,
                use: sassExtract.extract({
                    use:[`css-loader`,`sass-loader`]
                }),
                include:path.join(__dirname,`./src`),
                exclude:/node_modules/
            },
複製程式碼

11. 處理CSS3屬性字首

為了瀏覽器的相容性,有時候我們必須加入-webkit,-ms,-o,-moz這些字首

  • Trident核心:主要代表為IE瀏覽器, 字首為-ms
  • Gecko核心:主要代表為Firefox, 字首為-moz
  • Presto核心:主要代表為Opera, 字首為-o
  • Webkit核心:產要代表為Chrome和Safari, 字首為-webkit
npm i postcss-loader autoprefixer -D
複製程式碼

postcss-loader

postcss.config.js

module.exports={
	plugins:[require(`autoprefixer`)]
}
複製程式碼
.circle {
+    transform: translateX(100px);
複製程式碼
{
                test:/.css$/,
                use: cssExtract.extract({
+                   use:[`css-loader`,`postcss-loader`]
                }),
                include:path.join(__dirname,`./src`),
                exclude:/node_modules/
            },
複製程式碼

12. 轉義ES6/ES7/JSX

Babel其實是一個編譯JavaScript的平臺,可以把ES6/ES7,React的JSX轉義為ES5

npm i babel-core babel-loader babel-preset-env babel-preset-stage-0 babel-preset-react -D
複製程式碼
{
        test:/.jsx?$/,
        use: {
            loader: `babel-loader`,
            options: {
                presets: ["env","stage-0","react"]
            }
        },
        include:path.join(__dirname,`./src`),
        exclude:/node_modules/
        },
複製程式碼

13. 如何除錯打包後的程式碼

webapck通過配置可以自動給我們source maps檔案,map檔案是一種對應編譯檔案和原始檔的方法

  • source-map 把對映檔案生成到單獨的檔案,最完整最慢
  • cheap-module-source-map 在一個單獨的檔案中產生一個不帶列對映的Map
  • eval-source-map 使用eval打包原始檔模組,在同一個檔案中生成完整sourcemap
  • cheap-module-eval-source-map sourcemap和打包後的JS同行顯示,沒有對映列
devtool:`eval-source-map`
複製程式碼

14. 拷貝靜態檔案

有時專案中沒有引用的檔案也需要打包到目標目錄

npm i copy-webpack-plugin -D
複製程式碼
 new CopyWebpackPlugin([{
            from: path.join(__dirname,`public`),//靜態資源目錄源地址
            to:`./public` //目標地址,相對於output的path目錄
        }]),
複製程式碼

15. 打包前先清空輸出目錄

npm i  clean-webpack-plugin -D
複製程式碼
new cleanWebpaclPlugin(path.join(__dirname,`dist`))
複製程式碼

16. 壓縮CSS

webpack可以消除未使用的CSS

npm i -D purifycss-webpack purify-css glob
複製程式碼
new PurifyCSSPlugin({//purifycss根據這個路徑配置遍歷你的HTML檔案,查詢你使用的CSS
  paths:require(`glob`).sync(path.join(__dirname,`src/*.html`))
}),
複製程式碼

17. resolve解析

17.1 extensions

指定extension之後可以不用在require或是import的時候加副檔名,會依次嘗試新增副檔名進行匹配

resolve: {
    //自動補全字尾,注意第一個必須是空字串,字尾一定以點開頭
   extensions: [" ",".js",".css",".json"],
},
複製程式碼

17.2 alias

配置別名可以加快webpack查詢模組的速度

  • 每當引入jquery模組的時候,它會直接引入jqueryPath,而不需要從node_modules資料夾中按模組的查詢規則查詢
  • 不需要webpack去解析jquery.js檔案
const bootstrap=path.join(__dirname,`node_modules/bootstrap/dist/css/bootstrap.css`)
resolve: {
 +       alias: {
 +           `bootstrap`: bootstrap
 +       }
    },
複製程式碼

18. 區分環境變數

許多 library 將通過與 process.env.NODE_ENV 環境變數關聯,以決定 library 中應該引用哪些內容。例如,當不處於生產環境中時,某些 library 為了使除錯變得容易,可能會新增額外的日誌記錄(log)和測試(test)。其實,當使用 process.env.NODE_ENV === `production` 時,一些 library 可能針對具體使用者的環境進行程式碼優化,從而刪除或新增一些重要程式碼。我們可以使用 webpack 內建的 DefinePlugin 為所有的依賴定義這個變數:

npm install cross-env -D
複製程式碼
  "scripts": {
    "build": "cross-env NODE_ENV=production webpack --mode development",
     "dev": "webpack-dev-server --open --mode development "
  },
複製程式碼
 plugins: [
    new webpack.DefinePlugin({
        NODE_ENV:JSON.stringify(process.env.NODE_ENV)
}),
複製程式碼
if (process.env.NODE_ENV == `development`) {
	console.log(`這是開發環境`);
} else {
	console.log(`這是生產環境`);
}
複製程式碼

19. 抽離公共部分

optimization:{
    splitChunks:{
        cacheGroups:{
            vendor:{//抽離第三外掛
                test:/node_module/,
                chunks:`initial`,
                name: `vendor`,
                priority:10,//優先順序
            },
            commons:{//抽離公共的js
                chunks:`initial`,
                name:`commons`,
                minSize: 0//只要超出0位元組就生成新的公共的包
            }
        }
    }
},
複製程式碼
  • 從右往左,首先抽離公共部分js(比如兩個檔案共用的部分)會把第三方(比如jquery)首先打包,此時需要設定優先順序priority,第三方外掛不會打包到公共部分。

謝謝你看到了最後

相關文章