Photo by Rubén Bagüés
在前一篇文章介紹了如何在 Rails 使用 Webpacker,接下來這篇就我們就來實際安裝幾個 JavaScript 套件來試試手感吧!
安裝 jQuery
在各種前端框架橫行的現在,jQuery 這種看起來相對比較樸實無華且枯燥的 JS 套件就好像沒什麼人想用了。在 Rails 5.1.0 的時候,DHH 把以往一直預設安裝的 jQuery 給拿掉了,所以如果想要使用 jQuery 的話就得自己再手動裝回來,通常會使用 jquery-rails 這個套件。
即然都拔掉了為什麼還會想裝回來?因為還是有一些套件是依賴 jQuery 在做事的,例如在下一篇文章會介紹到的 Twitter Bootstrap 就是其中一個。
接下來我們就試著使用 Webpacker 來把 jQuery 裝回來吧!
Step1: 安裝 jQuery
這裡我們不使用 Gem,而是使用 yarn 來安裝:
$ yarn add --dev jquery
這個指令執行完成後,會自動在根目錄的 package.json 加上 jQuery 相關的設定:
1 2 3 4 5 6 7 8 9 10 11 | |
同時也會把 jQuery 套件放一份在專案裡的 node_modules 目錄裡。
Step2: 引用 jQuery
如同前面介紹的做法,如果 jQuery 想要全站都可以使用的話,可以直接把 jQuery 在 app/javascript/pack/application.js 裡把它引用進來:
1 2 3 4 | |
跟上一篇介紹到的 import '../cch' 的相對目錄寫法不同,這裡的 import 'jquery' 會去 node_modules 目錄裡去找 jQuery,這樣就可以把 jQuery 引用進來了。讓我們來試一下:
1 2 3 4 5 6 7 | |
寫過 jQuery 的人應該都看過這個 $ 符號是 jQuery 的招牌符號,$().ready() 則是在 DOM 載入完成之後執行裡面的那個 callback function,所以理論上上面這幾行應該可以在瀏覽器的 console 裡看到 You're so sweet! 的字樣,但打開瀏覽器執行一下,發現這個訊息:
Uncaught ReferenceError: $ is not defined
咦?以前不是直接加上 <script src="..."></script> 就可以用了嗎?現在怎麼不行了?就,以前你是直接用別人打包好的檔案,現在你是自己打包啊。這有幾種解決方法,第一種,就是直接在 import 的時候把 $ 明白的寫出來:
1 2 3 4 5 6 7 | |
這樣就有 $ 符號可以用了。另一種做法,就是直接在 Webpack 的環境設定檔上動手腳,讓 $ 變成全站都能用:
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
透過 Webpack 的 ProvidePlugin 來自動幫我們載入模組,就不用自己手動 import 或 require 了。
參考資料:https://webpack.js.org/plugins/provide-plugin/
改了這個設定檔,記得重開 foreman(或 rails server)才會生效。這樣一來即使沒有寫 import 'jquery',也可以直接使用 $ 符號了。
順利引入 jQuery 之後,讓我們繼續來 View(也就是 HTML 的頁面)寫一小段 jQuery:
1 2 3 4 5 6 7 8 9 10 | |
這應該也是很常見的寫法,就是直接在 HTML 頁面裡寫 JavaScript,我們暫且先不討論在 2019 年還這樣寫是不是適當,但重新整理之後,發現…咦?怎麼發生錯誤了:
Uncaught ReferenceError: $ is not defined
又是 not defined!不是 jQuery 有安裝了嗎?而且剛剛在 app/javascript/cch/smile.js 裡寫的時候在 Webpack 編譯的過程也沒事?為什麼這個 $ 又會沒定義?
Step 3: 設定 $ 符號
原本我也以為天真的以為這些 JavaScript 套件就只要 import 進來就沒事了,但看起來沒這麼單純。
前端世界真複雜 Orz
原來,的確是引入了 jQuery 沒錯,但那個 $ 符號並不會就這樣生效,如果去翻一下 jQuery 原始碼的最後幾行是這樣寫的:
1 2 3 | |
資料來源:https://code.jquery.com/jquery-3.4.1.js
簡單的說,就是如果使用 Webpack 打包的情境下是沒有瀏覽器的 window 物件的,所以自然就沒有 $ 或是 jQuery 這幾個全域變數,所以在執行到上面那段程式碼的時候才會出現 $ is not defined 的錯誤訊息。
那該怎麼辦?即然它沒有做 $,那我們就自己手動自己做。
1 2 3 4 5 6 | |
剛剛在前面透過 Webpack 的 ProvidePlugin 把 $ 變全域變數,在這邊再手動把它塞給 window,讓它在 View 也可以正常使用,這樣剛剛的 $ not defined 的問題就可以解決了。
只是,在前端越來越複雜的情況下,應該也越來越少人會在 HTML 裡塞 JavaScript 了才是?不過如果你還是有這個需求的話,上面這樣手動把 $ 設定到 window 物件也是一個解法。
今日是何日之 Date Picker
看完了 jQuery,我們來試個漂亮一點的小玩意兒吧!這次來試個可以在網頁上點選日期的小工具:flatpickr。
點開網站說明,雖然它可以用 CDN 的方式安裝,但我們就來練習把它一併打包到我們的專案裡試試看。
Step 1:安裝 flatpickr
起手式都差不多,都是用 yarn 或 npm 把套件拉回來:
$ yarn add --dev flatpickr
這個指令除了把套件拉回 node_modules 之外,同樣也會自動修改 package.json 的內容。
Step 2:串接 JavaScript
根據手冊上的記載,它的使用方法是這樣:
1
| |
這行看起來應該有點熟悉吧!接著我在專案的 app/javascript/ 目錄裡建立一個名為 utils 的目錄,並在裡面新增一個名為 datepicker.js 的檔案,內容如下:
1 2 3 4 5 6 7 | |
這裡為什麼要取名 utils 目錄以及 datepicker.js 檔案?其實沒什麼特別的原因,就只是不想把程式都寫在同一個檔案裡而已 :)
透過 import 語法把 flatpickr 套件引入,根據手冊的說明,只要呼叫 flatpickr 函數並把指定的 DOM 元件的 id(或 class)名稱傳給它就可以正常運作了,所以,接下來我在頁面上新增一個 id 叫做 theCutePicker 的 input 元素:
1 2 3 4 5 6 | |
這時候畫面上除了一個輸入框之外,應該還沒什麼變化,因為雖然剛剛好像在 utils/datepicker.js 檔案裡引入了 flatpickr,但還沒讓它引進整個專案,所以接下來:
1 2 3 4 | |
這時再回到瀏覽器應該會發現畫面有些變化了,但看起來不像是我們期望的效果啊!畫面上出現大大的箭頭、日期跟星期都跑到不對的地方,看了一下 Console 並沒有 JavaScript 的錯誤,應該是 CSS 沒設定的樣子。
是的,就是這樣,一樣再翻了一下手冊的說明,應該還要有一個 flatpickr.min.css 需要一併引入。其實這個 CSS 檔也一併在安裝的時候拉回 node_modules 裡了:

這個 CSS 檔就放在 node_modules/flatpickr/dist 目錄裡,即然知道在哪裡就簡單了!讓我們回到 datepicker.js 檔案加上一行:
1 2 3 4 5 6 7 8 | |
就這樣把它 import 進來,然後再回到瀏覽器看看:

搞定,瞧瞧這精美的 Date Picker!
等等…好像哪裡怪怪的,為什麼剛剛是在一個 JavaScript 檔案裡面 import 一個 CSS 檔案?可以這樣嗎?
這個嘛,其實對 Webpack 來說,所有的東西都是 JavaScript,而這也是下一篇文章要再說明的內容。
小結
基本上在 Rails 裡使用 Webpack 打包,一開始會很不習慣,特別對新手來說更是痛苦,因為這等於是一次要處理兩個生態圈,所以頭暈是正常的,不過我應該慢慢的就會習慣它了(吧)。
那 CSS 跟其它像是圖片或是字型之類的 Assets 呢?介紹完了 JavaScript,下一篇就讓我們來看看這些檔案要怎麼處理吧 :)