DEV Community

Cover image for Vue 3、Tailwind CSS 3、esbuild、rollup.js 開發初始檔
Let's Write
Let's Write

Posted on • Edited on • Originally published at letswrite.tw

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

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.js
  • package.json
  • rollup.config.js
  • tailwind.config.js

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

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

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

Tailwind 的路徑是寫在 package.json 的 dev-tailwindbuild-tailwind 二行裡,預設如下:

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

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

$ npm install
$ yarn
Enter fullscreen mode Exit fullscreen mode

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

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

$ npm run dev-js
或
$ yarn dev-js
Enter fullscreen mode Exit fullscreen mode

編譯 tailwind.css 的指令為:

$ npm run dev-tailwind
或
$ yarn dev-tailwind
Enter fullscreen mode Exit fullscreen mode

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

$ npm run build-js
或
$ yarn build-js
Enter fullscreen mode Exit fullscreen mode

編譯 tailwind.css 的指令為:

$ npm run build-tailwind
或
$ yarn build-tailwind
Enter fullscreen mode Exit fullscreen mode

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

$ npm run build
或
$ yarn build
Enter fullscreen mode Exit fullscreen mode

同時打包這邊,有多寫了一個 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 dev-js 時,會出現一個通知,像這樣:

esbuild 通知

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

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

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

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


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 可以寫成陣列,官方文件 範例:

require('esbuild').buildSync({
  entryPoints: ['a.js', 'b.js'],
  bundle: true,
  write: true,
  outdir: 'out',
})
Enter fullscreen mode Exit fullscreen mode

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

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

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

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

entryPoints: {
    out1: 'a.js',
    out2: 'b.js',
},
Enter fullscreen mode Exit fullscreen mode

輸出的檔案就會變成:

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

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

outExtension: { '.js': '.min.js' }
Enter fullscreen mode Exit fullscreen mode

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

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

Cannot use "watch" with a synchronous build
Enter fullscreen mode Exit fullscreen mode

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

rollup.js

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

export default [{
    input: 'a.js',
    output: {
        file: 'dist/a.js', format: 'cjs'
    }
},
{
    input: 'b.js',
    output: {
        file: 'dist/b2.js', format: 'es'
    }
}];
Enter fullscreen mode Exit fullscreen mode

如果有用到 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
Enter fullscreen mode Exit fullscreen mode

esbuild

require('dotenv').config();

const entry = process.env.ENTRY.split(',');
require('esbuild').build({
  entryPoints: entry,
  bundle: true,
  write: true,
  outdir: './dist/',
  outExtension: { '.js': '.min.js' }
})
Enter fullscreen mode Exit fullscreen mode

rollup.js

require('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],
    plugins,
    output: {
      file: output[i],
      format: 'iife'
    }
  }
  resultArray.push(item);
}

export default resultArray;
Enter fullscreen mode Exit fullscreen mode

Top comments (0)