Vue 3、Tailwind CSS 3、esbuild、rollup.js 開發初始檔

Vue 3、Tailwind CSS 3、esbuild、rollup.js 開發初始檔
Vue 3、Tailwind CSS 3、esbuild、rollup.js 開發初始檔

2024.06.22 更新:rollup 版本更新至 4.18.0,刪除 Babel。
2024.06.19 更新:esbuild 版本更新至 0.21.5。
2023.04.20 更新:調整 yarn dev、build 的命令。
2022.10.10 更新:新增多檔案編譯功能。

本篇要解決的問題

最近開始用 Vue3 在開發,也看了幾個 Youtube 上有關 Vue3 的教學,雖然官網很推薦 SFC(Single-File Component) 的開發方式,但前端工程師們應該都會有個狀況:不是每個案子來,都是可以讓我們自由的開始下一個 npm init vue@latest 後就快快樂樂地開發的,有些時候我們是接手之前的人寫的案子,這些案子如果沒意外,大部份是後端渲染的方式,也就是我們可能會收到 .php、.cshtml、.aspx …… etc.

這時用 SFC 就有點不切實際,但如果我們又要用 Vue 來開發呢?就得用 CDN 的方式,或是把 Vue 給 import 進一個 JS 檔裡。

這時候又會產生另一個問題,就是當我們 import 了 Vue、Pinia,再加上其它我們需要的 JS 檔後,編譯工具的編譯速度會愈來愈慢、愈來愈慢……

愈來愈慢、愈來愈慢、愈來愈慢……

這陣子 August 得用 Windows 開發,改用 Prepros 這套工具開發時,編譯 JS 檔需要到十幾秒,暈,那我整個專案改完,等待的編譯時間加起來都夠我看完一本哈利波特第一集了。

所以囉,有問題就要去解決問題,而不是去解決之前的工程師 XD,就決定做一個可以加快開發速度的初始檔,剛好前陣子看到了 esbuild 這套速度快到飛高高的編譯工具,就拿它來開發時使用。

本篇最後完成的初始檔,共有以下設定:

之所以打包時不用 esbuild 而用 rollup.js,是因為 esbuild 還不支援將 JS 編譯成 ES5 的版本,為了讓專案可以支援大部份瀏覽器,在打包時還是改用 rollup.js。

之所以開發時不直接用 rollup.js,是因為經 August 人體實驗證明,rollup.js 裡的 rollup-plugin-esbuild 這個套件使用時,編譯速度是可以縮到一秒多,但直接用 esbuild 卻可以不到一秒,在這個超高音速導彈都已經被製作出來的時代,還是愈快愈好。

本篇的初始檔有放上 GitHub,取用前麻煩分享本篇,或是 GitHub 上打個星星,你的小小動作對本站都是大大的鼓勵。

https://github.com/letswritetw/vue3_tailwind3_esbuild_rollup


安裝、使用

GitHub 下載整包檔案後,必備的檔案如下:

  • dist/
  • src/
  • .babelrc
  • esbuild.config.mjs
  • package.json
  • rollup.config.mjs
  • tailwind.config.js

除了以上的資料夾及檔案,其它的都可以刪掉沒關係。

esbuild.config.mjs、rollup.config.mjs 這二個檔案裡有寫了輸入、輸出的 JS 檔案路徑,預設如下:

  • 輸入:./src/main.js
  • 輸出:./dist/main.min.js

Tailwind 的路徑是寫在 package.json 的 css:devcss:build 二行裡,預設如下:

  • 輸入:./src/tailwind.css
  • 輸出:./dist/tailwind.min.css

準備使用時,先輸入指令安裝 package:

$ npm install
或
$ yarn

package.json 裡的 scripts 部份有寫了指令碼。

開發 時,編譯 main.js 的指令為:

$ npm run js:dev
或
$ yarn js:dev

編譯 tailwind.css 的指令為:

$ npm run css:dev
或
$ yarn css:dev

打包 時,編譯 main.js 的指令為:

$ npm run js:build
或
$ yarn js:build

編譯 tailwind.css 的指令為:

$ npm run css:build
或
$ yarn css:build

也有寫上一次打包 JS 跟 Tailwind 的指令:

$ npm run build
或
$ yarn build

同時打包這邊,有多寫了一個 remove-dist-js,會先刪掉 ./dist/main.min.js、./dist/main.min.js.map 這二個檔案,不過寫的 command-line 是用 macOS 的,如果你是用 Windows 的電腦就會失敗,把 yarn remove-dist-js 這行刪掉就行。

另外同時打包的指令用的是 yarn,沒安裝的朋友需事先裝好 Yarn,或是把 build 裡的 yarn 都改成 npm run xxxxx

以上,祝大家使用愉快~~


esbuild 開發時通知

開發時使用的 esbuild 裡,August 有加上通知,分別是執行 esbuild 時、有錯誤時。

執行 yarn js:dev 時,會出現一個通知,像這樣:

esbuild 通知
esbuild 通知

對,麻煩讓本站偷偷打個小廣告這樣 XD。

如果想要修改通知,就在 esbuild.config.mjs 這個檔案裡。

除了會跳出訊息通知,在終端機上也可以看到完整的錯誤資訊:

終端機會顯示完整錯誤訊息
終端機會顯示完整錯誤訊息

Vue 3、Pinia

本專案用的是 Vue 3 + Pinia,裡面附的程式碼是 Composition API 的寫法,對,因為想在同事們之間炫技就做了這個微錯誤的決定(未來有機會會說明 XD),有時間會加上 Options API 用的範例檔。


多檔案編譯

有時候我們無法像 SPA 一樣只產一支 JS 檔就打遍天下,比如接手的專案很舊了,每個頁面的檔案散落在世界各地。

把四散的 JS 併成一支會很花時間,又想到就算完成也沒辦法算進績效裡時,就會睜隻眼閉隻眼的針對每個頁面去寫一支 JS 檔來進行修改。

對,不用掙扎了,實務上案子會一直來一直來,來到天荒地老,如果公司大大大主管沒有想翻新,整個打掉重練程式的話,需求能怎麼解決就怎麼解決。

即便真的花了時間整併 JS,還不一定每個功能都能正常運作,而且真的也無法寫進績裡,所以能用最簡單的方式解決,就用最簡單的方式吧。

現在假設我們有二個頁面:A.html、B.html,裡面各自引用了 a.js、b.js,總不能在改頁面時,改 A 就手動改一次 entryPoints 的路徑,改 B 時再去手動改一次路徑,一天之內又改 A 又改 B,我跳進去了我又跳出來了,可以這樣嗎?而且這還只是改二個頁面而已。

所以囉,我們的實際需求,esbuild 跟 rollup.js 的神人相信也經歷過,看了二邊的文件,有提供同時編譯多個檔案的說明。

esbuild

esbuild 的多檔編譯比較簡單,因為它的 entryPoints 可以寫成陣列,官方文件 範例:

import * as esbuild from 'esbuild'

await esbuild.build({
  entryPoints: ['a.js', 'b.js'],
  bundle: true,
  write: true,
  outdir: 'out',
})

entryPoints 裡寫要編譯的檔案有哪些。

outdir 寫要輸出的資料夾名稱。比方範例寫的是 out,那最後編譯出的檔案就會是:

./outdir/a.js、./outdir/b.js。

如果想要改變輸出的檔名,那就將 entryPoints 從陣列改為物件:

entryPoints: {
  out1: 'a.js',
  out2: 'b.js',
}

輸出的檔案就會變成:

./out/out1.js、./out/out2.js

然後,你們知道的,工程師會有工程師的堅持,一般來說,壓縮過的檔案 August 會習慣加上 *.min.js 的檔名,所以要再加工一下,在原本的 outdir 後再加入一行:

outExtension: { '.js': '.min.js' }

這樣輸出的 .js 就會變成 .min.js 了。

最後在 esbuild 這邊要提的是,官方文件的範例用的是 buildSync,實際開發時會遇到一個錯誤:

Cannot use "watch" with a synchronous build

watch 模式下不能用 buildSync,因此本專案寫的時候是用 build

rollup.js

rollup 的方式稍微麻煩一些些,每編譯一個檔案,就要寫進一個物件裡,所以當有多個檔案要編譯,就要寫多個物件出來,官方文件 範例:

// rollup.config.js (building more than one bundle)
export default [
  {
    input: 'main-a.js',
    output: {
      file: 'dist/bundle-a.js',
      format: 'cjs'
    }
  },
  {
    input: 'main-b.js',
    output: [
      {
        file: 'dist/bundle-b1.js',
        format: 'cjs'
      },
      {
        file: 'dist/bundle-b2.js',
        format: 'es'
      }
    ]
  }
];

如果有用到 plugins,就每一個物件裡都要寫,所以在寫的時候可以把 plugins 命成一個變數,就不必相同的東西一直重複寫。

.env

本篇最後的檔案,開發時用 esbuild,打包時用 rollup.js,為了避免相同的 input、output 分開在二個檔案裡,就引入了 .env 的方式,把 input、output 寫在 .env 檔中,然後二個檔案再各自引用。

.env 用的是 dotenv 這個 package。

以下是 August 在本專案裡的寫法,要編譯的檔案有二個:

  • ./src/main.js
  • ./src/main2.js

目標輸出的檔案是:

  • ./dist/main.min.js
  • ./dist/main2.min.js

.env

ENTRY=./src/main.js,./src/main2.js
OUTPUT=./dist/main.min.js,./dist/main2.min.js

esbuild

import * as esbuild from 'esbuild';
const dotenv = await import('dotenv');
dotenv.config();
const entry = process.env.ENTRY.split(',');
let ctx = await esbuild.context({
  entryPoints: entry,
  bundle: true,
  write: true,
  outdir: './dist/',
  outExtension: { '.js': '.min.js' }
});

rollup.js

const dotenv = await import('dotenv');
dotenv.config();

const plugins = [ ... ];

const entry = process.env.ENTRY.split(',');
const output = process.env.OUTPUT.split(',');

const resultArray = [];
for(let i in entry) {
  const item = {
    input: entry[i],
    output: {
      file: output[i],
      format: 'iife', // amd, cjs, esm, iife, umd
      sourcemap: false,
      name: 'app',
      plugins: [terser()]
    }
  }
  resultArray.push(item);
}

export default resultArray;
Summary
Vue 3、Tailwind CSS 3、esbuild、rollup.js 開發初始檔
Article Name
Vue 3、Tailwind CSS 3、esbuild、rollup.js 開發初始檔
Description
本文詳細介紹如何使用 Vue 3、Tailwind CSS 3、esbuild 和 rollup.js 快速開發網站。文章涵蓋了從安裝、配置到開發的完整流程,並提供了實用的代碼範例和技巧,幫助開發者提升開發效率和產品質量。
August
Let's Write
Let's Write
https://letswritetw.github.io/letswritetw/dist/img/logo_512.png
訂閱
通知
guest

0 Comments
最舊
最新
Inline Feedbacks
看所有留言