點燈坊

失くすものさえない今が強くなるチャンスよ

Pug 初體驗

Sam Xiao's Avatar 2021-05-11

雖然 HTML / CSS / JavaScript 為 Web 三劍客,但 Preprocessor 出現後,CSS 與 JavaScript 已經有不同寫法,如 SCSS、TypeScript,事實上 HTML 也有 Preprocessor:Pug,可寫出更精簡的 HTML。

Version

Pug 3.0.2

History

Pug 並不是什麼新技術,Pug 前身為 Jade,早在後端 render 時代,Node + Express + Jade 已為標準組合,Jade 為 template engine。

在 Vue 使用 Pug 只使用其一小部分語法,template engine 仍使用 Vue,且主要是為了 搭配 Tailwind CSS 。

Why Pug ?

Pug 除了是 template engine 外,還大幅改變了 HTML 語法:

  • 取消 HTML 需要 close tag,使 codebase 更為精簡
  • 可直接以 . 使用 CSS class,這對 Tailwind CSS 尤其方便
  • 可省略 <div> 直接使用 CSS class,使 codebase 更為精簡

簡單來說,Pug 可視為 better HTML,尤其適合搭配 Tailwind CSS。

Attribute

Abbreviation

overview000

以 Pug 使用 attribute。

<template lang='pug'>
a(href='https://www.google.com') Google
</template>

第 2 行

a(href='https://www.google.com') Google

相當於

<a href="htts://www.google.com">Google</a>
  • HTML attribute 改用 JavaScript 習慣的 () 表示, String 也改用 JavaScript 慣用的 single quote
  • 並不需要 close tag,比 HTML 更為精簡
  • tag 與 content 以 space 分開即可

Vue

pug001

以 Pug 使用 event binding。

<template lang='pug'>
button(@click='onClick') Submit
div {{ msg }}
</template>

<script setup>
ref: msg = ''
let onClick = () => msg = 'Hello World'
</script>

第 2 行

button(@click='onClick') Submit
  • () 內也可使用 Vue 的 event binding

相當於

<button @click="onClick">Submit</button>

Multi Attribute

pug002

以 Pug 同時使用多個 attribute。

<template lang='pug'>
button(@click='onClick' autofocus) Submit
div {{ msg }}
</template>

<script setup>
ref: msg = ''
let onClick = () => msg = 'Hello World'
</script>

第 2 行

button(@click='onClick' autofocus) Submit
  • 多 attribute 可使用如 HTML 以 space 隔開
button(@click='onClick', autofocus) Submit
  • 也可如同 JavaScript 以 , 隔開

相當於

<button @click='onClick' autofocus>Submit</button>

Self Closing

pug003

以 Pug 使用 self closing 的 tag。

<template lang='pug'>
input(v-model='name')/
div {{ name }}
</template>

<script setup>
ref: name = ''
</script>

第 2 行

input(v-model='name')/ 
  • 對於只有一個 tag 的 HTML,則以 / 結尾

/ 必須緊接著 ) 不可有 space

相當於

<input v-model="name">

Class

Abbreviation

pug004

以 Pug 使用 CSS class

<template lang='pug'>
a(href='https://www.google.com').text-2xl.text-red-500 Google
</template>

第 2 行

a(href='https://www.google.com').text-2xl.text-red-500 Google
  • 只要以 . 就可使用 CSS class

相當於

<a href="htts://www.google.com" class="text-2xl text-red-500">Gogle</a>

Div

pug005

以 Pug 使用 div 實現 layout。

<template lang='pug'>
.flex.justify-center.h-96
  .w-20.h-20.m-2 1
  .w-20.h-20.m-2 2
  .w-20.h-20.m-2 3
</template>

第 2 行

.flex.justify-center.h-96
  .w-20.h-20.m-2 1
  .w-20.h-20.m-2 2
  .w-20.h-20.m-2 3
  • div 都用在 layout,造成 HTML 一堆 div,然這些 div 本身必須搭配 Tailwind utility 才有效用,可省略 div 直接使用 utility

Pug 因為 Tailwind 而顯得更為實用,這也是在 Vue 使用 Pug 主因

相當於

<div class="flex justify-center h-96">
  <div class="w-20 h-20 m-2">1</div>
  <div class="w-20 h-20 m-2">2</div>
  <div class="w-20 h-20 m-2">3</div>  
</div>

Special Character

pug006

以 Pug 使用含用特出字元的 utility。

<template lang='pug'>
.flex
  div(class='w-4/12') 1
  div(class='w-4/12') 2
  div(class='w-4/12') 3
</template>

第 2 行

.flex
  div(class='w-4/12') 1
  div(class='w-4/12') 2
  div(class='w-4/12') 3
  • Tailwind CSS 有些 utility 使用特殊字元:/[]#,但可惜 . 語法並不支援特殊字元,但 (class='') 語法則可,因此若遇到使用特殊字元的 utility,則必須使用 class 語法

相當於

<div class="flex">
  <div class="w-4/12">1</div>
  <div class="w-4/12">2</div>
  <div class="w-4/12">3</div>
</div>

ID

pug000

以 Pug 使用 ID。

<template lang='pug'>
a#link(href='https://www.google.com') Google
</template>

第 2 行

a#link(href='https://www.google.com') Google
  • 與 CSS 的 id 使用 # 一樣

相當於

<a id="link" href="https://www.google.com">Google</a>

Data Binding

pug007

以 Pug 使用 data binding。

<template lang="pug">
input(type='text', v-model='name')/
.text-red-500.text-2xl {{ name }}
</template>

<script setup>
ref: name = ''
</script>

第 3 行

.text-red-500.text-2xl {{ name }}
  • 將 state 在最後 data binding
<template lang="pug">
input(type='text', v-model='name')/
.text-red-500.text-2xl. 
  {{ name }}
</template>

<script setup>
ref: name = ''
</script>

第 3 行

.text-red-500.text-2xl. 
  {{ name }}
  • 或在 class 最後加上 .,換行縮排後將 state 做 data binding
<template lang="pug">
input(type='text', v-model='name')/
.text-red-500.text-2xl
  | {{ name }}
</template>

<script setup>
ref: name = ''
</script>

第 3 行

.text-red-500.text-2xl
  | {{ name }}
  • 或者換行後縮排使用 | pipe operator 再接上 state 做 data binding

相當於

<template>
<input type='text' v-model="name">
<div class="text-red-500 text-2xl">{{ name }}</div>
</template>

<script setup>
ref: name = ''
</script>

White Space

pug008

以 Pug 實現 +3 之間的 white space。

<template lang='pug'>
button(@click='onClick') +
|  {{ count }}
</template>

<script setup>
ref: count = 0

let onClick = () => count++
</script>

第 2 行

button(@click='onClick') +
|  {{ count }}
  • | 表示同一行,本來與 之間就必須空一格,但為了多一個 white space 再多一個 space

相當於

<template>
<button @click='onClick'>+</button> {{ count }}
</template>

<script setup>
ref: count = 0
let onClick = () => count++
</script>

Conclusion

  • Pug 原本為 template engine,但在 Vue 使用 Pug 只使用其 HTML 語法,template engine 仍使用 Vue,因此只能算使用 Pug 子集而已
  • Pug 可任意組合 (). 位置,HTML 的 attribute 已經逐漸被 CSS 取代,attribute 目前多用在 component 的 v-model、event 與 prop,實務上會先使用 (),再使用 .
  • Pug 在 CSS class 無法使用特殊字元是唯一遺憾之處,在 Jade / Pug 時空背景不支援可以理解,畢竟沒人會特別使用特殊字元命名 class,但 Functional CSS 則不然,這使得 Pug 只能退而求其次使用 divclass 語法,期待 Pug 日後能加以改進
  • Pug 另外一個難點在於處理 white space,必須在 | 後面接兩個 space 才代表一個 white space,因為 | 與 data 之間本來就需要一個 space