1. 程式人生 > >一篇就讓你學會webpack4

一篇就讓你學會webpack4

webpack 是一個現代 JavaScript 應用程式的靜態模組打包器,目前最流行的打包神器,接下來聊一下webpack4

首先webpack4要求node版本在8.5以上,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
  1. 配置開發伺服器

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
  1. 入口檔案的型別 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'
                })],
  1. 支援載入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/
+            }
+        ]
    },
  1. 支援圖片 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;
}
  1. 自動產出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'
    })]
  1. 分離CSS

因為CSS的下載和JS可以並行,當一個HTML檔案很大的時候,我們可以把CSS單獨提取出來載入

npm install --save-dev [email protected]

{
                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

logo.png
  {
+    test:/\.(html|html)$/,
+    use:'html-withimg-loader',
+    include:path.join(__dirname,'./src'),
+    exclude:/node_modules/
  }
  1. 編譯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:/.lessKaTeX parse error: Expected group after '_' at position 154: …lude:path.join(_̲_dirname,'./src…/, use: sassExtract.extract({ use:[‘css-loader’,‘sass-loader’] }), include:path.join(__dirname,’./src’), exclude:/node_modules/ },

  2. 處理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/
            },
  1. 轉義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/
        },
  1. 如何除錯打包後的程式碼

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’

  1. 拷貝靜態檔案

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

npm i copy-webpack-plugin -D

 new CopyWebpackPlugin([{
            from: path.join(__dirname,'public'),//靜態資源目錄源地址
            to:'./public' //目標地址,相對於output的path目錄
        }]),
  1. 打包前先清空輸出目錄

npm i clean-webpack-plugin -D

new cleanWebpaclPlugin(path.join(__dirname,‘dist’))

  1. 壓縮CSS

webpack可以消除未使用的CSS,比如bootstrap中那些未使用的樣式

npm i -D purifycss-webpack purify-css
npm i bootstrap -S

{
                test:/\.css$/,
                use: cssExtract.extract({
                    use: [{
                         loader: 'css-loader',
                        options:{minimize:true}
                    },'postcss-loader']
                }),
            },

+ new PurifyCSSPlugin({
+             //purifycss根據這個路徑配置遍歷你的HTML檔案,查詢你使用的CSS
+            paths:glob.sync(path.join(__dirname,'src/*.html'))
+ }),
  1. 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
 +       }
    },
  1. 區分環境變數

許多 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('這是生產環境');
}