你以為 React 什麼都幫你處理好了嗎?
set: 踩坑分享
tags: React
category: Front-End
description: 你以為 React 什麼都幫你處理好了嗎?
created_at: 2022/05/23 17:30:00
前言
React
確實已經幫忙做掉了好多事( 我指的是 create-react-app
),在環境的部分已經設定好了很多 (像是 )Webpack
不常用或不熟的人可能就會搞一陣子
順便偷偷廣告一下,如果要快速幫你裝好像是 Eslint
、Prettier
、Tailwindcss
之類的環境,可以考慮我做的 cmd
: https://github.com/LaiJunBin/lai-cmd
至於為什麼會寫這一篇呢,因為我以為 React
有設定好 Webpack
、 也使用了 Babel
幫忙轉譯,我就以為他應該有幫忙套上一些 Polyfill
去支援一些舊的瀏覽器支援新的語法。 很理所當然地以為他都幫我做好了
大綱
這一篇主要講兩點
關於 Polyfill
首先是 Polyfill
這個東西,從當初當選手的時候就有聽過這個詞,主要是拿來修復一些舊版瀏覽器不支援新的 JavaScript
語法的類似補丁的東西;但是當初當選手只要在比賽場地中做完當下能 Run 就可以交差了,也沒有後續維護之類的問題 (雖然時間相對緊湊),所以也沒特別去使用過。
而前陣子在實習公司有個案子就有個功能我使用到了 matchAll
這個函數,在 iOS 12
炸掉才發現原來 React
沒有幫忙做掉這個部分。
所以首先你要先有一個空的或既有的專案,再來實驗以下的內容。
首先在你的 App.js
加入下面這一段
function App() {
console.log(''.matchAll) // <-- 這一行,沒有括號哦!
return (
// 略
);
}
沒有呼叫函數的話可以印出那個函數的定義,如果他不存在就會是 undefined
,但是一般現在瀏覽器應該都支援,就會看到下面的結果。
ƒ matchAll() { [native code] }
那再來看看這個函數的支援度:
順帶一提: Safari
的版本是跟 iOS
版本一致的。
所以就這麼剛好,Safari 12
剛好不支援,所以如果你剛好有舊的裝置或是模擬器可以測,或是找找看有沒有別的函數支援度更差的來實驗來玩(?)
因為特別開舊的 Demo
來貼圖呈現好像也沒什麼太大意義,畢竟就只是個 Undefined
與 ƒ matchAll() { [native code] }
的差異 (?
所以以下就用文字來描述吧 (反正你也應該是有問題才會來用,所以應該是有環境的)
首先既然要有補丁(Polyfill
),那你要嘛自己寫或是找現成的,自己寫可能會比較麻煩,而且可能沒處理好就有 bug(?)
,如果是自己寫補丁來實現某件事,我更傾向於換個寫法達到同樣的目的。(除非你有大量地方用到真的需要先抽一層出來,或是你已經沒辦法改既有的 code
了)
舉例來說假設你要做 matchAll
這件事情,就先想想真的有必要使用他才能抓出你要的資訊嗎?
或許這個舉例不太好,不過懂我的意思就好,我這次爆炸是用在於我拿他來抓取路由參數。
Example:
/users/:id/xxx/:yyy/zzz
而你想抓出 id
與 yyy
,你不只可以使用 matchAll
, 其實你使用單純的 split
再加以判斷,也可以達到一樣的效果。
再來就開始安裝 Polyfill
吧,這邊使用的是 core-js
: https://www.npmjs.com/package/core-js
基本上非常簡單,照著他的說明安裝然後 import
基本上就能動了。
安裝 core-js
npm i core-js
安裝好之後,以我們這次的範例是 matchAll
這個函數,所以可以去找 string
相關的類別做引入(當然你也可以直接引入整包)
如果整包的話是
import 'core-js/actual';
如果部分引入功能(feature)的話是
import 'core-js/features/string/match-all';
然後你可能打開 開發伺服器 Dev Server
之後發現,咦 怎麼沒有反應,還是一樣 Undefined
啊,這可能要檢查你的 package.json
{
//...
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
主要是這個 browserslist
的值,他代表你的這個應用程式要支援到哪種等級的瀏覽器,這個設定會給很多工具的設定檔吃,他會決定他要不要做事。
所以可能你的 development
的值並沒有涵蓋到你當前測試的環境,以我的例子來說,我如果偷懶我就打 iOS 12
,那在開發模式下就也會生效了。
詳細的設定可以去參考 browserslist
可以放哪些東西。(https://github.com/browserslist/browserslist)
關於 Source Map
關於 Source Map
這個的話大家應該就比較不陌生了,簡單來說就是前端工具 build
你還有沒有辦法檢視真正的原始碼, 也就代表著被壓過的原始碼還能不能好好 debug
,因為被編譯完大概都長這樣
(()=>{var e={7057:(e,t,a)=>{function n(e){return(n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}!function(){"use strict";var e={},t={};try{"undefined"!=typeof window&&(e=window),"undefined"!=typeof document&&(t=document)}catch(e){}var a=(e.navigator||{}).userAgent,n=void 0===a?"":a,r=e,i=t,o=(r.document,!!i.documentElement&&!!i.head&&"function"==typeof i.addEventListener&&i.createElement,~n.indexOf("MSIE")||n.indexOf("Trident/"),function(){try{return!0}catch(e){return!1}}());
我只從開頭隨便截個一小段,這種東西非常難閱讀,在執行過程如果有噴錯,在 F12
的 主控台(Console)
雖然會顯示哪邊怎麼了,但如果在沒有 Source Map
的情形下點過去就是一坨奇怪的東西(類似上面這樣),而如果你有開啟 Source Map
這個功能,則會在你點出錯的行數導向過去的時候,會幫你映射到你的原始碼,不再是經過壓縮的樣子難以 debug
。
另外你也可以透過 F12
的 原始碼(Source)
去直接看別人的 Code
,如果對方沒關你就可以把他看光光
而因為我最一開始是寫 Vue
, Vue
在你 build
的時候會自動幫你關掉這個功能,所以我以為,對 又是我以為,我以為 React
也有幫忙做掉這件事XD
結果並沒有,要自己手動關。 所以說不定你去找一些 react 寫的網站別人也沒關ㄛ~
既然我原本以為他有幫我關,那就代表我很舊的專案也都沒關XDD (side project..)
關掉的方式很簡單,這邊提供幾種做法
- 從
env
關 (比較推薦)
GENERATE_SOURCEMAP=false
- 附加在指令前面 (但是 windows 可能需要額外裝套件)
"scripts": {
"start": "react-scripts start",
"build": "GENERATE_SOURCEMAP=false react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}