[Vue.js] 從0開始一個Vue.js + TypeScript + Webpack專案

從0開始一個Vue.js + TypeScript + Webpack專案

最後一次寫前端的時間是AngularJs正火紅的時候,大約有四年之久...

近期因為新專案的需要,想找一個前端框架來學習

經過評估後,則是選擇用vue.js以及搭配TypeScript做開發

筆記一下整個歷程,也許不是正確的、也許漏了一些細節

但是他是work的🤣


開發環境

vue.js 2.6.11

typescript 3.8.3

Asp.Net Core 3.1(MVC)


在開始之前,記得先準備好前端的套件管理工具 npm,前端的許多步驟都會透過他來處理

https://www.npmjs.com/


1.建立一個新專案,初始化npm來建立package.json

npm init

2.install幾個package,分別是vue、webpack、webpack-cli

  • i = install
  • -d = --save-dev
npm i -d vue webpack webpack-cli

3.為webpack建立config,webpack.config.js(若沒有建立,會跑預設的設定,但現在我想要額外指定他的打包路徑)

//webpack.config.js
const path = require("path");

module.exports = {
    entry: './WebClient/index.js',
    output:{
        filename:"bundle.js",
        path:path.resolve(__dirname,"wwwroot")
    },
    mode:"development",
    devtool:"source-map",
}

4.準備一點簡單的代碼做測試,路徑需要跟設定的entry相同(這邊用的是cshtml,因為原本只是想用.Net Core MVC搭配vue)

//index.js
alert("Hello world");
<!--index.cshtml-->
<div id="app" class="text-center">
    <h1 class="display-4">Welcome</h1>
    <hello index="12"></hello>
</div>
<script src="~/bundle.js"></script>

5.為了之後方便些,也調整一下package.json,在scripts裡面加上自定義的指令,build和watch

  • build相當於 npx webpack,打包內容
  • watch相當於 npx webpack --watch,監控檔案有變化時自動打包內容
  "scripts": {
    "build": "webpack",
    "watch": "webpack --watch",
    "test": "echo \"Error: no test specified\" && exit 1"
  },

6.這時候執行npm run build,會在根目錄的wwwroot資料夾底下建立一個bundle.js,這就是webpack打包出來的檔案,可以注意到上面的html也是引入了bundle.js進去,執行網頁則會直接跳出alert("Hello world")

7.接著把vue.js加進來,調整一下index.js和index.cshtml,加上了一點點功能

//index.js
import Vue from "vue"

new Vue({
    el: "#app",
    data: {
        message: "hello world.",
        name:"name"
    },
    methods: {
        Hello: function () {
            alert("hello");
        }
    },
    mounted : function(){
        console.log('Hello Webpack and Vue !');
    }
})
<!--index.cshtml-->
<div id="app" class="text-center">
    <h1 class="display-4">Welcome</h1>
    <p>{{message}}</p>
    <p>{{name}}</p>
    <button v-on:click="Hello()">Button</button>
    <input v-model="name" type="text">
</div>
<script src="~/bundle.js"></script>

8.開啟Web,會發現完全沒有畫面,接著調整一下webpack.config.js,設置模板編譯,打包並重整後就可以正常看到畫面了

//webpack.config.js
resolve: {
        alias: {
            'vue': 'vue/dist/vue.js'
        }
    },

9.這時候有了vue.js也有了webpack幫我們做打包,已經可以開始做基本的開發了,不過還沒結束,還有一個TypeScript還沒加上

10.透過npm再install幾個package,分別是 ts-loader 和 typescript

  • typescript:就是typescript,沒什麼要特別說明的
  • ts-loader:讓webpack可以解析typescript的內容
npm i ts-loader typescript

11.接者初始化typescript,這邊可以執行指令,也可以手動建立tsconfig.json,透過指令產生的內容會包含大多數的設定(幾乎都是註解的,可以再依照個人需求調整)

tsc --init

12.把index.js改名為index.ts,內容這次先不調整

13.調整webpack.config.js,

  • 把emtry改成index.ts
  • 加上module,遇到.ts的副檔名就用 ts-loader 解析
//webpack.config.js
const path = require("path");

module.exports = {
    entry: './WebClient/index.ts',
    output: {
        filename: "bundle.js",
        path: path.resolve(__dirname, "wwwroot")
    },
    mode: "development",
    devtool: "source-map",
    resolve: {
        alias: {
            'vue': 'vue/dist/vue.js'
        }
    },
    module: {
        rules: [
            {
                test: /\.ts$/,
                loader: "ts-loader",
                include: /WebClient/,
            }
        ]
    }
}

14.再次打包並開啟網頁,理應上會跟原本一模一樣,只是背後改成了typescript

15.接著為了讓vue.js更能享受typescript的功能,逐步調整index.ts,先將它調整為Single File Components

  • vue 2對typescript的支持相當差,據說在vue 3有大幅度的支持

16.透過npm install package

npm i vue-loader vue-template-compiler

17.調整幾個檔案的內容,以及新增一個 Hello.vue(component),下面列出在webpack.confg.js的改變

  • 加入 const VueLoaderPlugin = require("vue-loader/lib/plugin")
  • 加入針對 .vue 副檔名的rule
  • 調整針對 .ts 的rule,也對 .vue 副檔名的做處理
  • 加入 plugins:[ new VueLoaderPlugin() ]
<!--index.cshtml-->
<div id="app" class="text-center">
    <h1 class="display-4">Welcome</h1>
    <hello index="12"></hello>
</div>
<script src="~/bundle.js"></script>
//index.ts
import Vue from "vue"
import Hello from "./Components/Hello.vue"

new Vue({
    el:"#app",
    components:{
        Hello
    }
})
//webpack.config.js
const Path = require("path");
const VueLoaderPlugin = require("vue-loader/lib/plugin")

module.exports = {
    entry: './WebClient/index.ts',
    output: {
        filename: "bundle.js",
        path: Path.resolve(__dirname, "wwwroot")
    },
    mode: "development",
    devtool: "source-map",
    resolve: {
        alias: {
            'vue': 'vue/dist/vue.js'
        }
    },
    module: {
        rules: [
            {
                test: /\.ts$/,
                loader: "ts-loader",
                include: /WebClient/,
                options:{
                    appendTsSuffixTo:[/\.vue/]
                }
            },
            {
                test: /\.vue$/,
                loader: "vue-loader",
                include: /WebClient/,
            },
        ]
    },
    plugins:[
        new VueLoaderPlugin()
    ]
}
//Hello.vue
<template>
    <div>
        <h1>{{Title}}</h1>
        <h2>{{Name}}</h2>
        <label>
            Input
            <input v-model="Name" type="text">
        </label>
        
        <button v-on:click="Hello">Button</button>
        <p>{{Total}}</p>
    </div>
</template>

<script lang="ts">
    import Vue from "vue"

    export default Vue.extend({
        props: ["Index"],

        data() {
            return {
                Name: "Test",
                Title: "Title",
                Index: this.Index,
            }
        },

        methods: {
            Hello() {
                alert("hello");
            }
        },

        computed: {
            Total(): number {
                return this.Index + 1;
            }
        }
    })
</script>

18.接著再新增一個檔案,vue-shims.d.ts,讓ts也能識別 .vue 的檔案

declare module "*.vue" {
    import Vue from "vue";
    export default Vue;
}

19.這部分完成了,執行的web應該要可以正常動作的

20.目前的 .vue 看起來稍微好維護多的,但是仍然沒辦法享受typesript型別檢查的優點,接著繼續調整

21.接著要改用 vue-property-decorator 讓我們開發 .vue

npm i -d vue-property-decorator

22.因為會用到decorators,所以在tsconfig.ts把 experimentalDecorators 改為 true

"experimentalDecorators": true

23.調整 Hello.vue

<template>
    <div>
        <h1>{{Title}}</h1>
        <h2>{{Name}}</h2>
        <label>
            Input
            <input v-model="Name" type="text">
        </label>

        <button v-on:click="Hello">Button</button>
        <p>{{Total}}</p>
    </div>
</template>

<script lang="ts">
    import Component from "vue-class-component"
    import {Vue, Prop} from "vue-property-decorator";

    @Component
    export default class Hello extends Vue {
        @Prop({default: 0}) Index!: number

        private Name: string = "Test";
        private Title: string = "Title";
        private IndexCount: number = this.Index;

        Hello() {
            alert("hello");
        }

        get Total(): number {
            return this.IndexCount + 1;
        }
    }
</script>

24.這時候的程式碼功能跟原本是一致的,寫法有很大的不同,而且也能開心的使用typescript的型別檢查了


如果不想從0開始設定,可以直接使用 vue-cli 直接幫你產生完整的範本專案 (https://cli.vuejs.org/zh/)

若不看其他library或是webpack,vue是很好上手的前端語言,好懂好讀又可以簡單的導入專案,不過目前vue 2 對typescript的支援度不高

所以筆者還是決定先跳回angular去了......

不過相信 vue 的未來發展是可以讓人期待的

希望這篇可以幫到任何想開始學習vue+typescript的朋友們


上面提到的所有東西都會列在下面給有興趣的朋友深入了解

npm https://www.npmjs.com/

vue.js https://cn.vuejs.org/

vue-cli https://cli.vuejs.org/zh/

vue-router https://router.vuejs.org/zh/ (上面沒有提到,不過也挺重要的)

vue-loader https://vue-loader.vuejs.org/zh/

vue-class-component https://class-component.vuejs.org/

vue-typescript-start https://github.com/Microsoft/TypeScript-Vue-Starter (由微軟提供的範例,如何在vue導入typescript)

vue-property-decorator https://github.com/kaorun343/vue-property-decorator

webpack http://webpack.docschina.org/

typescript https://www.tslang.cn/index.html


Sample Code https://github.com/ianChen806/VueJsSample