2025/09/22

vue3 runtime

如果要使用 vue3 runtime,也就是 vue.runtime.esm-browser.js,而不使用 vue.esm-browser.js。這兩個版本的差異是使用後者,有支援 template,可直接將 template 字串寫在 component 裡面,但如果使用 runtime library,因為這個檔案大小比較小,缺少了動態編譯 template 的功能,必須改寫為使用 render function。

實例

以下是可以直接在 browser 執行的範例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <title></title>
</head>
<body>
<div id="app"></div>

<script type="importmap">
    {
        "imports": {
            "vue": "https://unpkg.com/vue@3.5.13/dist/vue.runtime.esm-browser.js",
            "vue-i18n": "https://unpkg.com/vue-i18n@11.1.1/dist/vue-i18n.runtime.esm-browser.js"
        }
    }
</script>

<script type="module">
    import { createApp, h } from 'vue';
    import { createI18n, useI18n } from 'vue-i18n';

    const messages = {
        en: { greeting: 'Hello!' },
        zh: { greeting: '你好!' }
    };

    const i18n = createI18n({
        legacy: false,
        locale: 'en',
        messages
    });

    const App = {
        setup() {
            const { t, locale } = useI18n(); // 正確取得 t() 函數

            const toggleLang = () => {
                locale.value = locale.value === 'en' ? 'zh' : 'en';
            };

            return () =>
                h('div', [
                    h('h1', t('greeting')),
                    h('button', { onClick: toggleLang }, '🌐 Switch Language')
                ]);
        }
    };

    createApp(App).use(i18n).mount('#app');
</script>
</body>
</html>

compiler-dom

vue3 官方提供了一個 compiler-dom,可以將 template 字串轉換為 render function。

安裝首先要安裝 compiler-dom

npm i @vue/compiler-dom

撰寫一個 convert.js

// https://www.npmjs.com/package/@vue/compiler-dom
// npm i @vue/compiler-dom

const fs = require('fs');
const path = require('path');
const { compile } = require('@vue/compiler-dom');

const file = process.argv[2];

if (!file || !file.endsWith('.template.html')) {
  console.error('請提供一個 .template html 檔案,例如:node convert.js MyComponent.html');
  process.exit(1);
}

const filePath = path.resolve(process.cwd(), file);

const template = fs.readFileSync(filePath, 'utf-8');

// 編譯 template 成 render 函數
const { code } = compile(template, {
  mode: 'module',
  prefixIdentifiers: true, // 避免 with()
  filename: file
});

// 產出 JS 檔案名稱
const baseName = path.basename(file, '.template.html');
const outputFile = `${baseName}.template.render.js`;

// // 包裝為可匯入的模組
const outputContent = `
${code}
`;
// 寫入檔案
fs.writeFileSync(outputFile, outputContent.trim());

console.log(`Render function 已輸出為:${outputFile}`);

使用方法

把 template 的部分,改為獨立的 test.template.html 檔案

<div>
    <h1> {{ t("greeting") }} </h1>
    <button @click="toggleLang()">🌐 Switch Language</button>
</div>

透過 nodejs 將 template 轉換為 render function

import { toDisplayString as _toDisplayString, createElementVNode as _createElementVNode, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"

export function render(_ctx, _cache) {
  return (_openBlock(), _createElementBlock("div", null, [
    _createElementVNode("h1", null, _toDisplayString(_ctx.$t("greeting")), 1 /* TEXT */),
    _createElementVNode("button", {
      onClick: $event => (_ctx.toggleLang())
    }, "🌐 Switch Language", 8 /* PROPS */, ["onClick"])
  ]))
}

改寫原本的測試網頁

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <title></title>
</head>
<body>
<div id="app"></div>

<script type="importmap">
    {
        "imports": {
            "vue": "https://unpkg.com/vue@3.5.13/dist/vue.runtime.esm-browser.js",
            "vue-i18n": "https://unpkg.com/vue-i18n@11.1.1/dist/vue-i18n.runtime.esm-browser.js",

            "render": "./test.template.render.js"
        }
    }
</script>

<script type="module">
    import { createApp, h } from 'vue';
    import { createI18n, useI18n } from 'vue-i18n';
    import {render} from 'render';

    const renderFn = render;

    const i18n = createI18n({
        legacy: false,
        locale: 'en',
        fallbackLocale: "en",
        messageCompiler: null,
        messages: {
            "en": {
                "greeting": 'Hello!'
            },
            "zh": {
                "greeting": '你好!'
            },
        },
    });

    const App = {
        setup() {
            const { t, locale } = useI18n();

            const toggleLang = () => {
                locale.value = locale.value === 'en' ? 'zh' : 'en';
            };

            return {
                t, locale, toggleLang
            };
        },
        render: renderFn,
        methods: {
        }
    };

    createApp(App).use(i18n).mount('#app');
</script>
</body>
</html>

note

點擊切換語言時,網頁 console 會出現這樣的警告訊息

[intlify] the message that is resolve with key 'greeting' is not supported for jit compilation

不影響網頁操作,但還不知道為什麼會出現這個 warning

沒有留言:

張貼留言