Webpack:入門

Webpack:入門

簡介

現代的前端項目已經不再是簡單的 HTML+CSS+JavaScript 了,可能會使用一些響應式框架(Vue、React),使用了 CSS 預處理(SCSS、LESS),使用許多第三方庫。如果使用舊版的技術可能需要引入大量的 <scirpt> 標標籤,甚至將會存在許多根本沒用到的代碼。到了 node、npm 出現的時代,透過 node_modules 管理第三方庫的依賴,也能夠使用 import/export 等技術管理模塊化,但是還存在許多外部資源(字體、圖片)也無法直接引入 JS 解析,就會形成大量引用散落在 html 文件中。並且如果在運行時因為原生的靜態引入方法造成客戶端網絡的瓶頸而產生加載延遲。

這時候我們就需要透過打包(bundling)的手段,將一些靜態關聯的模塊一次打包成一個完整的 JS 文件,這樣客戶端就能夠一次引入必要的部份,剩下的再透過動態加載的方式引入

在 Webpack 之前也出現過一些類似的打包工具(Grunt、Gulp、Brunch)那時稱作任務管理器(Task Runner),但是在打包的過程可能會出現"牽一髮而動全身"的問題,僅僅修改了一行代碼就必須導致整個項目重新打包。

Webpack 解決了這些問題,透過建立依賴圖(Dependency Graph),不僅能夠實現按需加載(避免不必要的代碼引用),還能夠根據依賴圖實現部分重新打包,大幅優化打包的速度。並且開放 LoaderPlugin 提供了擴展的可能性,只要編寫相應的加載器(Loader)或是插件(Plugin),能夠實現任何資源的加載。

參考

webpack官方https://webpack.docschina.org/
Getting-Startedhttps://webpack.docschina.org/guides/getting-started/

正文

本篇將會簡單介紹 Webpack 的配置結構,並且透過參考官網的起步自製的一個流程,邊做邊說明。

Overview 概述

Webpack 的核心思想就是將一個項目視作許多模塊(Module)之間的連結,透過指定入口(Entry)出口(output),並借助模塊加載器(Loader)插件(Plugin)來對不同的模塊類型做不同的預處理,最終建立依賴圖(Dependency Graph)。並且也能夠透過依據目的來區分不同的打包模式(mode)

這邊幾乎點出了 Webpack 配置文件裡面的所有配置項:

  1. Entry 入口:依賴圖的起點,通常作為源文件代碼中的項目入口模塊
  2. Output 輸出:打包後輸出的文件
  3. Loader 加載器:負責對其他模塊類型進行預處理,將其他模塊透過一些步驟處理為 JS 的語法
  4. Plugin 插件:可以說是更強大且更完整的 Loader,詳細差別下面將會提到
  5. Mode 模式:透過指定不同的打包模式,可控制打包的行為(進行打包優化、壓縮代碼等)

Configuration 配置

Webpack 配置最重要的就是要有一個配置文件(Loader 有三種配置,不過依舊推薦都寫在配置文件內),配置文件的結構如下:

// webpack.config.js
module.exports = {
  // 配置入口
  entry: Object | String,
  // 配置輸出文件
  output: {
    filename: String,
    path: String
  },
  // 配置模塊加載器 Loader
  module: {
    rules: [
      {
        test: RegExp, // 模塊名匹配規則
        use: Array<String> | String // 指定加載器
      }
    ]
  },
  // 配置插件(JS 對象)
  plugins: Array<Plugin>,
  // 配置打包模式
  mode: String
}

接下來我們就來邊做邊介紹,這邊的簡易項目參考官方的 Getting Start 流程

起步

首先我們先建立一個 npm 項目:

$ mkdir webpack-demo
$ cd webpack-demo
$ npm init -y

就會產生一個 package.json 文件:

  • package.json
{
  "name": "webpack-demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

Install 安裝

首先先安裝 Webpack 的核心模塊(webpack)以及 CLI 命令行工具(webpack-cli)

$ npm i -D webpack webpack-cli

這時候的 package.json 將會多出開發項配置,並且我們將 main 改成 private,詳情查看 npm 官方文檔:

  • package.json
{
  "name": "webpack-demo",
  "version": "1.0.0",
  "description": "",
- "main": "index.js",
+ "private": true,
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
+ "devDependencies": {
+   "webpack": "^4.43.0",
+   "webpack-cli": "^3.3.11"
+ }
}

並且建立最基礎的項目架構:

  webpack-demo
  |- package.json
+ |- /dist
+   |- index.html
+ |- /src
+   |- index.js

並再簡單佈置一下 index.htmlindex.js

  • index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Webpack-demo</title>
  </head>
  <body>
    <div id="root"></div>

    <script src="main.js"></script>
  </body>
</html>
  • index.js
function component() {
  const div = document.createElement('div')

  div.innerHTML = ['Hello', 'Webpack'].join(' ')

  return div
}

const root = document.getElementById('root')
root.appendChild(component())

這時候已經可以使用默認配置進行打包了,先用 npm 配置 webpack 指令:

  • package.json
"scripts": {
  "build": "webpack"
}

接著執行 npm run build 就能夠看到默認配置的打包結果了

Entry 入口

接下來我們將透過配置文件來配置,首先來配置入口。

先建立 webpack.config.js 文件:

  webpack-demo
  |- package.json
  |- node_modules
+ |- webpack.config.js
  |- /dist
    |- index.html
    |- main.js
  |- /src
    |- index.js

然後加上入口(Entry)配置:

  • webpack.config.js
const path = require('path')

module.exports = {
  entry: './src/index.js'
}

只有一個字符串的時候表示單入口,通常單頁面應用(SPA:Single Page Application)使用單入口就足以應付;而多頁應用就需要配置多個入口,如下配置:

module.exports = {
  entry: {
    // 入口名:入口文件路徑
    app: './src/index.js',
    print: './src/print.js'
  }
}

Output 輸出文件

有了入口還不夠,我們還需要配置輸出文件,告訴 Webpack 我們要輸出到哪,並指定輸出文件的名稱:

  • webpack.config.js
const path = require('path')

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js', // 默認配置為 main.js
    path: path.resolve(__dirname, 'dist')
  }
}

與此同時我們需要修改 index.html<script> 標籤,以及 npm script 裡面的指令:

  • index.html
-
<script src="main.js"></script>
+
<script src="bundle.js"></script>
<!-- 這邊引入的 js 文件對應 Output(輸出) 的 filename -->
  • package.json
{
  // ...
  "scripts": {
    "build": "webpack --config webpack.config.js"
  }
}

這時候再執行 npm run build 就能夠看到配置入口出口文件之後的打包情形了(可以刪掉上次打包遺留的 main.js):

  webpack-demo
  |- package.json
  |- node_modules
  |- webpack.config.js
  |- /dist
    |- index.html
+   |- bundle.js
  |- /src
    |- index.js

如此一來 webpack 就以 index.js 作為入口將相關靜態引入的依賴打包成 bundle.js 放置到 dist 目錄之下。現在在瀏覽器開啟 /dist/index.html 文件就能夠看到當前的網頁樣式了。

Loader 模塊加載器

由於 webpack 默認只能打包 .js.json 類型的文件(模塊),如果想要加載其他類型的模塊就需要透過對應的加載器(Loader)。加載器相當於對其他類型的文件進行預處理,最後轉變成 JS 文件可讀的形式(url、import 啥的)

這邊我們以加載 .css 做範例,對應的加載器為 style-loadercss-loader

Loader 存在三種使用方式:配置方式(寫在配置文件內)、內聯方式(寫在 JS 文件內)、CLI(作為命令行參數),推薦使用第一種,後面兩種就不解釋了,自己查官網

首先我們先安裝相關的加載器:

$ npm i -D style-loader css-loader

再加入要引入的 .css 文件:

  webpack-demo
  |- package.json
  |- node_modules
  |- webpack.config.js
  |- /dist
    |- index.html
    |- bundle.js
  |- /src
    |- index.js
+   |- index.css

並且填充一下內容

  • index.css
* {
  color: red;
}

然後在 index.js 中引入依賴:

  • index.js
+ import './index.css'

  function component() {
    const div = document.createElement('div')

    div.innerHTML = ['Hello', 'Webpack'].join(' ')

    return div
  }

  const root = document.getElementById('root')
  root.appendChild(component())

最後為配置文件添加 Loader 相關的配置:

  • webpack.config.js
module.exports = {
  // ...
  module: {
    rules: [
      {
        // test 表示文件名的匹配模式
        test: /\.css$/,
        // use 表示使用的 loader
        use: ['style-loader', 'css-loader']
      }
    ]
  }
}

注意!這邊的 loader 支持戀是調用

這時候再運行 npm run build 就能看到打包後的情形了:

Hash: 2d96f286fe38387953e0
Version: webpack 4.43.0
Time: 596ms
Built at: 2020-06-10 16:12:56
    Asset      Size  Chunks             Chunk Names
bundle.js  4.74 KiB       0  [emitted]  main
Entrypoint main = bundle.js
[0] ./src/index.js 230 bytes {0} [built]
[1] ./src/index.css 519 bytes {0} [built]
[3] ./node_modules/css-loader/dist/cjs.js!./src/index.css 253 bytes {0} [built]
    + 2 hidden modules

Plugin 插件

除了 Loader 之外,還有另一個更強大的功能是引入插件(plugins)。插件本身將作為一個具有 apply 方法的對象,在整個編譯週期都能訪問,傳入一個類似的配置對象,實際上將作為 compile 參數調用插件的 apply 方法,我們現在向我們的項目加入 html-webpack-plugin 插件:

  • 安裝
$ npm i -D html-webpack-plugin

然後修改目錄結構,創建 public 目錄並創建 index.html 作為網頁入口,並且先暫時將 dist 目錄下的文件清空:

  webpack-demo
  |- package.json
  |- node_modules
  |- webpack.config.js
  |- /dist
-   |- index.html
-   |- bundle.js
+ |- /public
+   |- index.html
  |- /src
    |- index.js
    |- index.css
  • index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>webpack-demo</title>
  </head>
  <body></body>
</html>

並且在配置文件中添加 html-webpack-plugin 的配置,需要往 plugins 插入一個插件對象,引用方式如下:

  • webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')

module.exports = {
  // ...
  plugins: [new HtmlWebpackPlugin({ template: './public/index.html' })]
}

最後執行 npm run build 打包項目,就能夠看到 dist 目錄下出現的 index.html 啦!內容如下:

  • index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <title>webpack-demo</title>
  </head>
  <body>
    <script src="bundle.js"></script>
  </body>
</html>

咦?你有發現嗎,除了原先 /public/index.html 的內容之外,webpack 還自動將打包後的輸出文件 bundle.js 引入到 html 中,這也是 vue-cli 或 react-react-app 創建的項目中,打包項目的時候的 html 配置來來源喔(這邊的 html 位置也是模仿腳手腳手架生成的目錄結構,其實直接放在 src 目錄之下也並無不可)

Mode 模式

最後的最後稍微介紹一下,webpack 配置文件中還有極為重要的一項,就是配置打包模式(Mode),可選值如下:

模式描述
development開發模式,開發時打包用
production生產模式,需要部署上線時使用
none不配置模式

配置模式最主要的核心就是控制 process.env.NODE_ENV 值的轉變,在 node 環境之下會影響到許多配置項和功能表現,配置方法如下:

  • webpack.config.js
const path = require('path')

module.exports = {
  mode: 'development'
  // ...
}

基於 webpack 的打包模式,因此就有人提出將不同模式的不同配置分成多個配置文件的形式,並且放如統一的 config 目錄下,形成如下結構:

  webpack-demo
  |- config
    |- webpack.base.config.js
    |- webpack.dev.config.js
    |- webpack.prod.config.js
  • webpack.base.config.js:表示基礎配置,將由 devprod 繼承
  • webpack.dev.config.js:繼承 base,作為開發模式下的配置使用
  • webpack.prod.config.js:繼承 base,作為生產模式下的配置使用

三者的簡要結構如下,這邊需要用到一個 webpack-merge 的插件,本篇不使用也將不做介紹,未來會在 webpack 專欄的其他文章中單獨介紹:

  • webpack.base.config.js
module.exports = {
  // ...
}
  • webpack.dev.config.js
const merge = reuqire('webpack-merge')
const config = require('./webpack.base.config')

module.exports = merge(config, {
  mode: 'development'
  //
})
  • webpack.prod.config.js
const merge = reuqire('webpack-merge')
const config = require('./webpack.base.config')

module.exports = merge(config, {
  mode: 'production'
  //
})

這樣就可以完成配置文件的分離和基礎配置的復用

完整項目

以上流程創建了一個使用 webpack.config.js 做配置文件,引用了 style-loadercss-loader 加載 CSS 文件,使用 html-webpack-plugin 配置 html 入口文件,作為一個小型測試 webpack 功能的項目配置和使用方法呈現給大家。以下是項目目錄結構以及各文件內容:

Directory 項目目錄結構

webpack-demo
|- package.json
|- node_modules
|- webpack.config.js
|- /dist
  |- index.html
  |- bundle.js
|- /public
  |- index.html
|- /src
  |- index.js
  |- index.css
  • package.json:由 npm init -y 命令自動生成
  • node_modules:作為 npm 包安裝的目錄
  • dist:作為編譯打包之後的目標目錄
  • webpack.config.js/src/index.js/src/index.css/public/index.html:需要手動創建並完成內容

各文件內容(需要手動創建的部分)

  • package.json
{
  "name": "webpack-demo",
  "version": "1.0.0",
  "description": "",
  "private": true,
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack --config webpack.config.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "css-loader": "^3.5.3",
    "html-webpack-plugin": "^4.3.0",
    "style-loader": "^1.2.1",
    "ts-loader": "^7.0.5",
    "webpack": "^4.43.0",
    "webpack-cli": "^3.3.11"
  }
}

  • /public/index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>webpack-demo</title>
  </head>
  <body></body>
</html>
  • /src/index.js
import './index.css'

function component() {
  const div = document.createElement('div')

  div.innerHTML = ['Hello', 'Webpack'].join(' ')

  return div
}

const root = document.getElementById('root')
root.appendChild(component())
  • /src/index.css
* {
  color: red;
}
  • webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      }
    ]
  },
  plugins: [new HtmlWebpackPlugin({ template: './public/index.html' })]
}

鏘鏘!這樣就完成最基礎的 webpack 配置與使用啦

結語

本篇簡單介紹了 webpack 的主要配置屬性和使用的範例,作者為了縮小篇幅真的簡化了很多東西,希望能夠幫助剛開始接觸 webpack 的小夥伴們一點一點的熟悉各種 Loader 以及 Plugin 的用途和用法。之後會介紹加上 babel-loader 來引入 babel 成為編譯的一環,以及透過 webpack-dev-server 來創建開發用的簡單網頁服務器等功能。

並且近年來前端工程化的議題也正在迅速發酵,webpack 作為三大框架之中 Vue、React 所使用的打包工具,或許在不遠的將來,webpack 的原理已經優化或許也將成為前端面試的重要課題之一。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值