大家好,今天是第三十二天,也是賽程結束後的第二天。
昨天介紹了我們會在Webview裡使用的套件,今天會介紹一下在webview裡使用router時實際遇到的問題與解決方法。並會以專案的情境做個示範,最後附上解決問題時參考的一些資源。
前面Webview的章節提過了,在vscode裡面使用javascript跟存取靜態資源(本地的png、svg等等),會受到限制。
除此之外,我們沒辦法給定Webview本身存取html的url。因此,在使用一些正常使用router library的狀況,router並不會作用。
讓我們先使用react router的來做個示範。
首先,讓我們使用React Router,創建簡單的RouterPage元件。
RouterPage.tsx
:
import React from 'react';
import {
BrowserRouter as Router,
Switch,
Route,
Link,
useHistory,
} from "react-router-dom";
export default function RouterPage() {
return (
<Router>
<div>
<h1>With Browser Router</h1>
<nav>
<ul>
<li><Link to="/snippets">snippets</Link></li>
<li><Link to="/extensions">extensions</Link></li>
</ul>
</nav>
<Switch>
<Route path="/snippets">
<Snippets />
</Route>
<Route path="/extensions">
<Extensions />
</Route>
<Route path="/">
<Snippets />
</Route>
</Switch>
</div>
</Router>
);
}
function Snippets() {
const history = useHistory();
return <h2 onClick={()=> history.push('/extensions')}>Snippets</h2>;
}
function Extensions() {
const history = useHistory();
return <h2 onClick={()=> history.push('/')}>Extensions</h2>;
}
依我們的需求,我們應該要有兩個頁面分別負責自訂的snippet與第三方extension的管理,因此我們在上面簡單宣告Snippets與Extensions的component,並設定導航的路由。同時,我們在component上綁定點擊事件,在點擊當下的頁面後就讓即跳轉到另一個component上。
完成RouterPage後,我們將其import於App.tsx中給上層的App元件使用
import RouterPage from './router/router';
...
function App() {
return (
<RouterPage/>
);
配置好WebviewPanel的相關設定後,我們啟動extension查看結果,可以看到頁面,並顯示了Snippets元件。
我們改換點擊extensions的超連結
可以看到,並不會起作用。
BrowserRouter是使用瀏覽器Html5的History,他在改變url時,會與vscode的url格式起衝突,因此我們會在Webview Devtool下面看到這樣的錯誤訊息。
好的,那要怎麼避免這個狀況呢?
在React Router裡面,提供了一種MemoryRouter,在不讀寫瀏覽器的網址列的狀況下導航頁面,通常是用於測試與React native非瀏覽器的環境。MemoryRouter可以直接規避這個問題,讓我們先將import的BrowserRouter改為MemoryRouter,並將With Browser Router的標題改為With Memory Router。
import {
useHistory,
MemoryRouter as Router,
Switch,
Route,
Link
} from "react-router-dom";
接下來我們一樣使用yarn build(或npm run build)指令,再重新載入webview。
現在我們點擊超連結,就可以順利切換元件,點擊元件也可以正常觸發效果。
Webview Devtool現在也不會有任何錯誤訊息。
在網址列裡的Hash是一個#符號,指示瀏覽器要滑動到的位置。例如:
https://stackoverflow.com/questions/31079081/programmatically-navigate-using-react-router/31079244#31079244
點擊下去後,瀏覽器就會自動滑到編號是31079244的回答的位置。
hash符號主要與瀏覽器端的行為有關,因此,在瀏覽器將網址請求發送到後端時,通常hash符號會被忽略,不會將hash符號一起送至後端。
我們可以在chrome的devtool裡很清楚的看到上面網址輸下後的請求會被自動忽略掉#31079244。
除此之外,hash位置改變時,會被瀏覽器的history記錄起來,因此在剛才輸入網址後,我們可以按上一步回到沒有hash值的同網頁。也因為有這個特性,hash值很適合用於處理router的動作,react router也提供了HashRouter讓我們使用。
現在,讓我們將上面範例裡的Router改為HashRouter驗證是否正常吧!
import {
...
HashRouter as Router,
...
} from "react-router-dom";
重新載入Webview後,可以確認HashRouter一樣可以在Webview裡正常運作。
好的,以上就是我們今天分享的內容。在處理router問題的解法上,筆者事先參考了How to use React Routing into Webview for VSCode extensions?這篇文章跟stackoverflow上的回答解法,主要介紹了MemoryRouter來避免Webview裡的router問題。
在實際測試後,我們也可以驗證HashRouter會運作正常,推測原因是hash值會自動被WebView瀏覽器請求所忽略,因此也就不會請求不一樣的url位置觸發錯誤。
明天我們繼續實作,我們明天見,掰掰!