Nuxt 3 使用 unocss 與 vuetify

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