# Vue.js 和 Webpack
使得 Pagekit 吸引開發者的一個重要的方面就是,Pagekit 的界面是用 Vue.js 框架構建的。
在瀏覽例子時,你可能會困惑于Vue.js、Webpack、javascript 模塊以及用于起步的一般文件結構的理念。本文旨在為你厘清這些東西。
## 術語
**Vue.js** 是一個創建交互式 web 界面的 javascript 框架。它負責將 javascript 對象(model)和呈現的模板(view)二者同步。在 Vue.js 文檔中可以找到詳盡的介紹文章。閱讀此框架的[起步指南](http://vuejs.org/guide/) 和更多的[高級概念](http://blog.evanyou.me/2015/10/25/vuejs-re-introduction/) 。
**Vue 組件** 是代碼的邏輯實體,它包含定義良好的功能,并且通常包括一個視圖模板+一個用來定義組件內部交互的腳本。在 Pagekit 中,可以添加到系統的許多實體都是以 Vue 組件的形式創建并注冊到 Pagekit 系統的。包括小工具、儀表盤小工具和鏈接類型等。在代碼級上,它們都在 `*.vue` 文件中結合了 javascript 代碼和 HTML 模板。可以使用 Webpack 將 `*.vue` 文件編譯成為純`*.js`文件。你還可以在 `*.js` 文件中創建 Vue 組件,組件使用的模板在不同的文件定義,或者只是一個簡單的字符串,這種情況下就不必使用 Webpack了。
**Webpack** 是一款模塊打包工具,它會獲取你的開發資源(比如 Vue 組件和原生 javascript 文件)并將它們結合到所謂的包(bundle)。這不同于簡單地鏈接和壓縮 javascript文件。簡言之,在當前頁面被加載時模塊才會用到相關的 webpack 包(with webpack bundles only the modules required on the current page are loaded)。了解更多,查閱[Webpack 背后的動機](http://webpack.github.io/docs/motivation.html)。
**Note** 一個常見的誤解是,在開發 Pagekit 擴展時必須使用 Webpack。并非如此。如果簡單地創建和引入單個 javascript 文件對你來說更容易起步。你可以選擇稍后在遷移到 Webpack.
## 不使用 Webpack 時的文件結構
如果你打算在沒有 Webpack 的情況下使用 Vue.js,這里有一個例子 [todo extension](https://github.com/pagekit/example-todo).
1. 創建 JavaScript 文件, i.e. `js/todo.js`.
2. 在模板中加載 JavaScript 文件。確保 `vue` 在你的腳本之前加載。`<?php $view->script('todo', 'todo:js/todo.js', 'vue') ?>`
## 為何使用 Webpack ?
沒有 Webpack,位于名為 `example.js` 文件中的關于一個簡單的 Vue 組件的例子大概是這樣:
```
new Vue({
el: '<div>{{ message }}</div>',
data: {
message: 'Hello Pagekit!'
}
})
```
如果你不喜歡使用 Webpack,這個解決方案非常好。使用 Webpack 來編譯 `*.vue` 模板可以為你的文件形成更好的組織結構。可以在 `example.vue` 文件中以可讀的方式定義標簽和 javascript 代碼。
```
<template>
<div>
{{ message }}
</div>
</template>
<script>
module.exports = {
data: {
message: 'Hello Pagekit!'
}
}
</script>
```
如你所見,不必再用笨拙的字符串來定義模板了。Webpack 將可讀的 `*.vue` 轉換并編譯成為 `*.js` 文件,模板標簽則轉換成為行內字符串。
Webpack 是在終端運行的工具,可以將 `*.vue` 文件編譯成為 `*.js` 文件。Pagekit 的根目錄有一個默認的 `webpack.config.js`。在 Pagekit 根目錄運行 `webpack` 或 `webpack --watch`,它會在 `packages` 子目錄中遍歷所有主題和擴展。
你的包(package)還需要它自己的 `webpack.config.js`,例如 `packages/pagekit/example/webpack.config.js`。此文件定義哪些 `*.vue` 文件應當被編譯成什么輸出文件。
下面的例子假設你的 `*.vue` 文件位于 `packages/pagekit/example/app/components` 包的子目錄,并且它們應當在編譯后輸出到 `packages/pagekit/example/app/bundle`目錄。
```
module.exports = [
{
entry: {
"example" : "./app/components/example.vue",
"example-2": "./app/components/example-2.vue",
"example-3": "./app/components/example-3.vue"
},
output: {
filename: "./app/bundle/[name].js"
},
module: {
loaders: [
{ test: /\.vue$/, loader: "vue" }
]
}
}
];
```
現在打開終端,前往 Pagekit 根目錄并運行 `webpack` 或 `webpack --watch` 使用你剛剛添加的配置來運行 Webpack。你會在包的 `app/bundle` 目錄中看到 `*.js` 文件。例如 `example.vue` 會被編譯成名為`example.js` 的包(bundle)文件。
**Note** 在使用 Git 管理代碼時,建議添加 `app/bundle` 目錄到 `.gitignore` 文件中,因為它只包含 `*.vue` 組件被編譯后的版本。
要加載和使用已編譯的 Vue 組件,從視圖模板中加載已編譯的包文件,例如來自 `views/example.php` 的文件。你還需要將 `vue` 作為第三個參數,這樣你的組件只會在 Vue 本身的腳本文件被加載后再進行加載。
```
<?php $view->script('example', 'hello:app/bundle/example', 'vue') ?>
```
## 摘要:Webpack 下的文件結構
對于包含 webpack 配置文件的設置,查看 [hello extension](https://github.com/pagekit/extension-hello)。
1. 在你的擴展中創建 Vue 組件。例如 `*.vue` 文件: [link.vue](https://github.com/pagekit/extension-hello/blob/master/app/components/link.vue).
2. 為你的擴展程序創建 `webpack.config.js`。Webpack 配置定義了你的擴展提供的哪些 javascript 模塊應當被編譯成為什么樣的最終文件。一個例子: [webpack.config.js](https://github.com/pagekit/extension-hello/blob/master/webpack.config.js)
3. 在 Pagekit 的根目錄中運行 `webpack` 或 `webpack --watch`。Pagekit 的 webpack 會遍歷所有的包,并讀取它們的 webpack 配置。
4. 在視圖文件中引入生成的包 `<?php $view->script('settings', 'hello:app/bundle/settings.js', ['vue', 'jquery']) ?>`
## 創建和注冊 Vue 組件
使用目前的文件結構設置,你現在可以創建自己的腳本和 Vue 組件。默認情況下,上面提到資源都包含在你自己的視圖文件中。然而在某些情況下,你創建了一個 Vue 組件,并希望將它注冊到 Pagekit 系統,使之可以顯示在 Pagekit 管理界面的相應位置。你可以如此處理以下這些元素:
* 儀表盤小工具
* 網站小工具
* 鏈接類型
* 站點樹設置,在編輯單個頁面時以選項卡的形式顯示
* 針對擴展設置的模態彈出
這基本上發生在四個步驟:
1. 編寫一個 Vue 組件,i.e. `app/components/link.vue`. [Source example](https://github.com/pagekit/extension-hello/blob/master/app/components/link.vue)
2. 通過 javascript 注冊這個 Vue 組件, i.e. `window.Links.components['hello'] = module.exports;`. [Source example](https://github.com/pagekit/extension-hello/blob/master/app/components/link.vue#L39)
3. 將這個 Vue 組件添加到 webpack 包中,i.e. `"link": "./app/components/link.vue"`. [Source example](https://github.com/pagekit/extension-hello/blob/master/webpack.config.js#L6)
4. 確保組件的包文件在后臺已經通過 PHP 被加載了, i.e. `$scripts->register('hello-link', 'hello:app/bundle/link.js', '~panel-link');` [Source example](https://github.com/pagekit/extension-hello/blob/master/index.php)
**Note** 這些就是使用 Webpack 的必要步驟。沒有 Webpack 同樣也能實現。只需跳過第三步。你可以在一個原生的 `*.js` 文件中創建 Vue 組件以及以文本字符串作為 `template`屬性的值的模板。記得在第四步使用該 javascript 文件的路徑。