2022年7月25日 星期一

Vue3.2 <script setup> 實作 TodoMVC


Vue3.2開始將 <script setup> 移除experimental status,和setup()區別在有許多 option API 有了替代方案,props, emit 也可以寫在 setup`,variable 或 function 也不需要透過 return 才能讓 <template> 使用,哇!寫法怎麼好像有點既是感呢

下面會利用 TodoMVC 的練習,比較與統整 <script setup>setup() 常用的方法的差異。

TodoMVC 完整程式碼上傳至 Github (連結)。

data

setup
<script>
import { ref } from 'vue';

export default {
    setup() {
        const newTodo = ref(undefined);

        return {
            newTodo,
        };
    },
}
</script>
<script setup>
宣告 ref 沒有差異,差在需不需要 return
<script setup>
import { ref } from 'vue';

const newTodo = ref(undefined);
</script>


component

<template>
    <TodoListEditor />
</template>
setup
<script>
import TodoListEditor from 'components/TodoListEditor.vue';

export default {
    components: {
        TodoListEditor,
    },
}
</script>
<script setup>
import 之後就可以直接在 <template> 使用
<script setup>
import TodoListEditor from 'components/TodoListEditor.vue';
</script>


props

setup
<script>
export default {
    props: {
        todoList: {
            required: true,
            type: Array,
        },
    },
}
</script>
<script setup>
defineProps 裡面內容與之前 props 相同
<script setup>
const props = defineProps({
    todoList: {
        required: true,
        type: Array,
    },
});
</script>


emit

setup
<script>
export default {
    emits: ['remove:todo', 'update:todo'],
    setupt(props, {emit}) {
        function removeTodoItem(id){
            emit('remove:todo', id);
        }
    },
}
</script>
<script setup>
defineEmits 裡面內容與之前 emits 相同
<script setup>
const emit = defineEmits(['remove:todo', 'update:todo']);

function removeTodoItem(id){
    emit('remove:todo', id);
}
</script>


directive

directive是所有寫法中我最不適應的,底下是頁面載入時可以有 autofocus 的效果,可以根據不同 lifecyle 定義,利如 mouted
<input
    v-model="newTodo"
    v-focus>
setup
<script>
const focus = {
    mounted: el => el.focus(),
};

export default {
    directives: {
        focus,
    },
}
</script>
<script setup>
<script setup>
const vFocus = {
    mounted: el => el.focus(),
};
</script>


lifecycle

基本上沒有什麼區別
setup
<script>
import {onMounted} from 'vue';

export default {
    setup() {
        onMounted(() => {
            // to something
        });
    },
}
</script>
<script setup>
<script setup>
import {onMounted} from 'vue';

onMounted(() => {
    // to something
});
</script>


2022年7月24日 星期日

mocha + webpack 的 Vue3 元件單元測試

先說結論,我認為不適合用 mocha 進行 vue3 單元測試(@vue/test-utils),反覆查了很久的資料,相關的套件支援度不足等有重重的障礙,根據 @vue/test-utils 目前提供的測試範例,選擇 Vitest 會更適合。

完整程式碼上傳至 Github (連結)。

一、安裝

首先,第一個問題就是 vue 的版本不能太新,目前只支援 3.0.7,因此對應安裝了相同版本的 @vue/server-renderer

npm install --save-dev @vue/server-renderer@3.0.7

再來請安裝 webpck 和 mocha,mochapack,mochapack 是用來讀取 webpack 設定將元件 render 出來的套件,可支援 webpack5 和 mocha 9

npm install --save-dev webpack mocha mochapack

其他有兩個類似的套件:

mochapack 是由 mocha-webpack 延伸而來的,三者用法都非常接近,但上述兩個對 webpack 和 mocha 版本的支援度都比 mochapack 差


再來請安裝 vue3 官方的元件測試套件 @vue/test-utils

npm install --save-dev @vue/test-utils

mocha 不像是 jest 已經內建支援 jsdom、assertion ,所以要另外安裝

npm install --save-dev webpack-node-externals jsdom-global
npm install --save-dev expect


二、設定

新增測試專用的 webpack 設定檔 webpack.config-test.js

// webpack.config-test.js

const nodeExternals = require('webpack-node-externals');
const { VueLoaderPlugin } = require('vue-loader');

module.exports = {
    mode: 'development',
    target: 'node',  // webpack should compile node compatible code
    externals: [nodeExternals()], // in order to ignore all modules in node_modules folder
    devtool: 'inline-cheap-module-source-map',
    module: {
        rules: [
            {
                test: /\.vue$/,
                loader: 'vue-loader',
            },
            {
                test: /\.css$/i,
                use: ['style-loader', 'css-loader'],
            },
        ],
    },
    plugins: [
        new VueLoaderPlugin(),
    ],
};

設定 jsdom 設定檔 src/tests/setup.js

// src/tests/setup.js

require('jsdom-global')();

最後,請到 package.json 設定 script 指令

Usage: mochapack [options] [<file|directory|glob> ...]

Options
 --webpack-config  path to webpack-config file
 --require, -r     require the given module
{
  "scripts": {
    "test": "npx mochapack --webpack-config webpack.config-test.js --require src/tests/setup.js src/tests/**/*.spec.js",
  }
}


三、執行
新增測試(範例請參考 Counter.spec.js)後,執行指令即可
npm run test


四、限制

1. 無法支援目前 vue 最新版本 3.2.37,發現底下錯誤訊息:

ReferenceError: SVGElement is not defined

2. 無法支援 SFC ,發現底下警告訊息:

[Vue warn]: Component is missing template or render function.


參考文件: