Nuxt 3 使用 unocss 與 vuetify
建立 nuxt 3 專案
輸入 nuxt cli 建立專案的指令
npx nuxi init <project-name>
進入資料夾中安裝 package
code <project-name>
npm install
安裝完成後就可以開啟開發環境
npm run dev
安裝 unocss
安裝 unocss nuxt module
npm i -D @unocss/nuxt
在 nuxt 中加入 unocss
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@unocss/nuxt'],
unocss: {
uno: true,
icons: true,
attributify: true,
shortcuts: {},
rules: [],
}
})
基本設定說明
-
uno
使用預設的 @unocss/preset-uno,提供常見 framework (Tailwind CSS, Windi CSS, Bootstrap 等) 的 utilities class
-
icons
加入 @unocss/preset-icons,利用 utilities class 就能使用各種 icon。
須額外安裝 icon 套件,來源是 Iconify,可以選擇安裝所有的 icon 或是只安裝其中一種
npm i -D @iconify/json // 安裝全部 icon npm i -D @iconify-json/mdi // 安裝 material design icon
-
attributify
可以使用 attributify mode
-
shortcuts
將常用或是組件化的 style 加入 shortcuts
// object mode shortcuts: { 'btn': 'px-4 py-2 border rounded' } // array mode shortcuts: [ { 'btn': 'px-4 py-2 border rounded' } ]
-
rules
自定義規則
rules: [ ['m-1', { margin: '0.25rem' }], ]
安裝 vuetify 3
安裝 vuetify
npm install vuetify@next
在 plugins 資料夾中建立 vuetify plugin 並加入 nuxt config 中
// plugins/vuetify.ts
import { createVuetify } from 'vuetify'
import * as components from 'vuetify/components'
import * as directives from 'vuetify/directives'
export default defineNuxtPlugin(nuxtApp => {
const vuetify = createVuetify({
// 引入所有的 component 與 directives
components,
directives,
})
nuxtApp.vueApp.use(vuetify)
})
// nuxt.config.ts
export default defineNuxtConfig({
css: ['vuetify/lib/styles/main.sass'],
build: {
transpile: ['vuetify'],
}
})
設定 vuetify tree shaking 和移除 vuetify utilities class
安裝完 unocss 與 vuetify 後會發現因爲 vuetify 也有自己的 utilities class,造成同個 class 卻有兩種 style 的情況,找到的解法是移除 vuetify 的 utilities class 或是在 unocss 的設定中加入 prefix ,這邊選擇第一個方法,原因一是加入 prefix 會讓可讀性變差,二是移除 vuetify utilities class 需要透過 tree shaking ,也能同時減少 bundle size。
設定 tree shaking
在 plugin 中移除原先引入的 components 與 directives,安裝 vite-plugin-vuetify
並加入 modules 選項中,移除 css 選項中的 vuetify/lib/styles/main.sass
// plugins/vuetify.ts
import { createVuetify } from 'vuetify'
export default defineNuxtPlugin((nuxtApp) => {
const vuetify = createVuetify()
nuxtApp.vueApp.use(vuetify)
})
// nuxt.config.ts
import vuetify from 'vite-plugin-vuetify'
export default defineNuxtPlugin({
css: [],
modules: [
// ...
(options, nuxt) => {
nuxt.hooks.hook('vite:extendConfig', (config) => {
config.plugins?.push(
vuetify()
)
})
}
],
})
移除 utilities class
建立 sass 檔案去改寫 vuetify 預設的 utilities 變數,並加在 vite-plugin-vuetify
中
// assets/vuetify-setting.scss
@use 'vuetify' with (
$utilities: false
);
// nuxt.config.ts
import vuetify from 'vite-plugin-vuetify'
export default defineNuxtPlugin({
css: [],
modules: [
// ...
(options, nuxt) => {
nuxt.hooks.hook('vite:extendConfig', (config) => {
config.plugins?.push(
vuetify({
style: { configFile: 'assets/vuetify-setting.scss' }
})
)
})
}
],
})
將 $utilities 變數設為 false 的原因是在 /node_modules/vuetify/lib/styles/settings/_utilities.scss
中可以看到是透過這個變數去產生所有的 utilities class
// /node_modules/vuetify/lib/styles/settings/_utilities.scss
$utilities: () !default;
@if ($utilities != false) {
// ...
}
觀察 bundle size
設定完 treeshaking 可以觀察 bundle size 的差別,輸入 npx nuxi analyze
就可以在瀏覽器上看到打包後所包含的檔案
without treeshaking
with treeshaking
References
https://nuxt.com/docs/getting-started/installation
https://github.com/unocss/unocss
https://github.com/unocss/unocss/tree/main/packages/nuxt
https://codybontecou.com/how-to-use-vuetify-with-nuxt-3.html
https://next.vuetifyjs.com/en/features/treeshaking/
https://next.vuetifyjs.com/en/features/sass-variables/
https://medium.com/@pierremriau/how-to-replace-vuetify-utility-classes-with-tailwindcss-9a3ebaa21f4f