Aurelia 2 從零開始之建構專案
Tags: aurelia
Published: 2023-06-17 14:10:19

Aurelia 是一套前端框架，類似於 Svelte、Vue、React，與三天王最大的差異就是知名度低、台灣沒人用、沒有豐富的元件庫可以用，大多只能自幹，幸好它還是處於有人維護的狀況。

Aurelia 的特色是不使用 virtual DOM，而使用 [shadow DOM](https://developer.mozilla.org/zh-CN/docs/Web/Web_Components/Using_shadow_DOM)，以及同樣是 HTML 標準的 [custom element](https://developer.mozilla.org/zh-CN/docs/Web/Web_Components/Using_custom_elements) 來實現網頁元件化。

[Aurelia 2](https://docs.aurelia.io/) 則是 Aurelia 的第二代，目前還在開發階段，只適合拿來當玩具，還不適合拿來做產品。本文所用的版本是 Aurelia v2.0.0-beta.7，主要的參考文件來自 https://docs.aurelia.io/。

附註一下 Aurelia 1 與 Aurelia 2 的文件庫各自的位址：

- Aurelia 1: https://aurelia.io/docs/
- Aurelia 2: https://docs.aurelia.io/

---

我用的環境是 Elementary OS 7 Hera，相當於 Ubuntu 22.04 LTS。

## 前置作業

這部份講 Git、Node.js、Visual Studio Code 等，都有的可跳過。

### 安裝 Git

```sh
$ sudo apt install git
```

### 安裝 Node.js 與 NPM

一般來說只要安裝 Node.js 也會一併安裝 NPM。Node.js 安裝的管道包括下列幾種：

- OS 預帶的軟體庫內的版本
- Node.js 提供的 deb 軟體庫
- Node.js 提供的 snap 軟體庫
- 透過 nvm 安裝的 Node.js

OS 預帶的軟體庫過舊直接排除，其它三個都是可行的選項，對初學者我來說是用 Node.js 提供的 deb 軟體庫來做安裝，具體的操作細節可以參考這份文件：[NodeSource Node.js Binary Distributions](https://github.com/nodesource/distributions)。

在這裡裝的版本是 Node.js 18 LTS。

```sh
# Using Ubuntu
$ curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
$ sudo apt-get install -y nodejs
```

### 安裝 Visual Studio Code

去 https://code.visualstudio.com/ 抓 deb 包回來裝。

最前面提到 Aurelia 的特色，社群小，加上 Aurelia 2 又是在早期開發階段，因此 VSC 是沒有相關的延伸模組可以使用的，請自幹吧。雖然如此，Git、JavaScript、TypeScript、HTML、CSS 相關的延伸模組還是很豐富，可以善加利用。

## 建構 Aurelia 2 專案

下面這行起手式指令會以問答的方式逐步帶領我們建立專案目錄與檔案：

```sh
$ npx makes aurelia
```

這行指令會下載 Aurelia 套件與相關的依賴套件，然後執行 Aurelia 套件內預先定義好的問答程序，這系列問答決定了要專案的雛型與 scaffold（有人翻譯成腳手架）要如何搭建，下面是本人的選擇：

```
         #
      ######   xxx
     ########  xxxx   ####         _                  _ _         ____
   x   ########    ########       / \  _   _ _ __ ___| (_) __ _  |___ \
     x  ######  #############    / _ \| | | | '__/ _ \ | |/ _` |   __) |
  xxxxx  ##  ###############    / ___ \ |_| | | |  __/ | | (_| |  / __/
   xxxxx  ###############      /_/   \_\__,_|_|  \___|_|_|\__,_| |_____|
    x ###############  xxx
    ##############  #   xx
 ##############  ######          https://aurelia.io
  ########## x  ########         https://github.com/aurelia
    #####  xxxx   ########       https://twitter.com/aureliaeffect
     #   x  x      ######
                     #

✔ Please name this new project: › my-app
✔ Would you like to use the default setup or customize your choices? › Custom Aurelia 2 Project
✔ What kind of Aurelia 2 project? › Application
✔ What Aurelia 2 release would you like to use? › Latest
✔ Which bundler would you like to use? › Dumber
✔ What transpiler would you like to use? › TypeScript
✔ Do you want to use Shadow DOM or CSS Module? › Use Shadow DOM
✔ What CSS preprocessor to use? › Sass (.scss)
✔ What unit testing framework to use? › Jest
✔ Do you want to setup e2e test? › Yes (Playwright)
✔ What kind of sample code do you want in this project? › With direct routing
[makes] Project my-app has been created.
✔ Do you want to install npm dependencies now? › Yes, use npm
```

問答程序結束後，應該會多出一個 my-app 資料夾。

## 執行專案

雖然目前是空的專案，但前面的設定程序有幫我們做了一個簡單的 Hello World! 頁面，把專案跑起來看看：

```sh
$ npm start
```

應該會輸出這些訊息：

```
> my-app@0.1.0 start
> gulp

[dumber] Starting dumber bundler v2.1.1 https://dumber.js.org
[16:32:42] Using gulpfile ~/Projects/my-app/gulpfile.js
[16:32:42] Starting 'default'...
[16:32:42] Starting 'clean'...
[16:32:42] Finished 'clean' after 37 ms
[16:32:42] Starting 'build'...
[dumber] 2.0.0-beta.7 @aurelia/router
[dumber] 2.0.0-beta.7 @aurelia/runtime-html
[dumber] 2.0.0-beta.7 aurelia
[dumber] 2.5.3      tslib
[dumber] 2.0.0-beta.7 @aurelia/fetch-client
[dumber] 2.0.0-beta.7 @aurelia/kernel
[dumber] 2.0.0-beta.7 @aurelia/metadata
[dumber] 2.0.0-beta.7 @aurelia/platform
[dumber] 2.0.0-beta.7 @aurelia/platform-browser
[dumber] 2.0.0-beta.7 @aurelia/route-recognizer
[dumber] 2.0.0-beta.7 @aurelia/runtime
Update index.html with entry.bundle.js
[16:32:52] Write app-bundle.js
[16:32:52] Write entry.bundle.js
[16:32:53] Finished 'build' after 11 s
[16:32:53] Starting 'startServer'...

Dev server is started at: http://localhost:9000

[16:32:53] Finished 'startServer' after 11 ms
[16:32:53] Starting 'watch'...
```

由 Gulp 調度工作，Dumber 負責整合打包用到的套件，啟動伺服器並打開瀏覽器開啟 http://localhost:9000/，應該會在瀏覽器看到陽春的 Welcome 頁。

![Welcome to Aurelia 2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2e8cvuf6dgh505l2cf2w.png)

用 Inspector 看一下，確實是有 custom element 與 shadow DOM。

## 編譯專案

在 package.json 與 gulpfile.js 裡面同時也幫我們準備好了編譯的指令。

package.json 裡面的 build 會先執行 gulp clean 再執行 gulp build：

```json
"scripts": {
  "start": "gulp",
  "build": "gulp clean && cross-env NODE_ENV=production gulp build",
  "clear-cache": "gulp clear-cache"
}
```

gulpfile.js 的 `clean()` 很簡單，只是把 dist 資料夾砍掉而已；`build()` 則負責把所有用到的 js / html / css 檔案都包起來丟給 Dumber 去處理依賴包：

```js
function build() {
  // Merge all js/css/html file streams to feed dumber.
  // dumber knows nothing about .ts/.less/.scss/.md files,
  // gulp-* plugins transpiled them into js/css/html before
  // sending to dumber.
  return merge2(
    gulp.src('src/**/*.json'),
    buildJs('src/**/*.ts'),
    buildHtml('src/**/*.html'),
    buildCss('src/**/*.{scss,css}')
  )
    // Note we did extra call `dr()` here, this is designed to cater watch mode.
    // dumber here consumes (swallows) all incoming Vinyl files,
    // then generates new Vinyl files for all output bundle files.
    .pipe(dr())
    // Terser fast minify mode
    // https://github.com/terser-js/terser#terser-fast-minify-mode
    // It's a good balance on size and speed to turn off compress.
    .pipe(gulpif(isProduction, terser({ compress: false })))
    .pipe(gulp.dest(dist, { sourcemaps: isProduction ? false : '.' }));
}
```

了解了背後的流程後就來真正的跑一次：

```sh
$ npm run build
```

跑完後除了 dist 資料夾內有被打包過的 app-bundle.xxx.js 與 entry-bundle.xxx.js 之外，外面的 index.html 也有被改過，內容的 script 指向 dist 內新的 JavaScript 檔案。

---

至此門外漢的 Aurelia 專案建構全紀錄結束，下一篇來寫簡單的元件。