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

2025/09/15

Container vs VM

Container 是類似 docker 這樣建構在某個 OS 的虛擬機器,VM 是類似 Hypervisor VMWare 建立的虛擬機器。

VM

優點:

  • 從硬體開始就虛擬化,機器獨立

  • 可在不同 VM 安裝不同的 OS

  • 不同應用程式內的相關套件耦合,不會互相影響

  • 適合比較大型,需要很多不同的整合服務的應用

缺點:

  • 耗用的硬碟空間較多,使用的硬體資源比較高

  • 啟動服務需要比較長的時間

Container

優點:

  • 檔案比較小

  • 啟動速度快

  • 耗用系統資源比較少

  • 容易更新

  • 通常以應用程式為單位

缺點:

  • 主要依賴 Host OS的操作,無法同時安裝不同的 OS

  • container 之間的元件部署比較複雜

2025/09/08

Open Street Map Local Server

Switch2OSM

https://switch2osm.org/

因為 Open Street Map 的免費公用特性,所以我們可以複製這些地圖資料到自己的地圖 server,Switch2OSM 是一個推廣 OSM 的專案,我們可以透過這個專案,建置自己的 Map Server

PBF format

.pbf空間數據詳解

PBF 就是 Protocolbuffer Binary Format 這是基於 ProtoBuffer 的一種 binary data format,這是一種比 XML, GeoJSON 等等地圖格式還要精簡的檔案格式。

在 OSM 通常是以 *.osm.pbf 這個 file extension 代表 OSM PBF file

Open Street Map 在 PBF Format - OpenStreetMap Wiki 有說明該檔案格式的定義。

Taiwan OSM

Geofabrik Download Server Taiwan 這個網站,有固定更新從 Open Street Map 下載的 Taiwan 離線地圖,我們可以到這個網站下載 taiwan-latest.osm.pbf

取得 osm PBF 檔案以後,就可以匯入 switch2osm local map server

docker

參考 Using a Docker container – Switch2OSM 的說明,最簡單的方式就是透過 container 建置 switch2osm

以下以 Redhat 系列的 podman 進行測試

匯入 osm.pbf 檔案

podman volume create osm-data

podman run  --name osmtile-import -v /root/download/osm/taiwan-latest.osm.pbf:/data/region.osm.pbf  -v osm-data:/data/database/  overv/openstreetmap-tile-server  import

tile server

podman volume create osm-tiles
# 啟動 tile server
podman run --name osmtile -p 8081:80 -v osm-data:/data/database/ -v osm-tiles:/data/tiles -d overv/openstreetmap-tile-server run

啟動後就可以在 http://localhost:8081/tile/ 看到透過 Leaflet 取得的 OSM 地圖