iT邦幫忙

第 12 屆 iThome 鐵人賽

1
Software Development

自己用的工具自己做! 30天玩轉VS Code Extension之旅系列 第 32

Day32 | 在WebView裡使用Router的問題與解法!

大家好,今天是第三十二天,也是賽程結束後的第二天。

昨天介紹了我們會在Webview裡使用的套件,今天會介紹一下在webview裡使用router時實際遇到的問題與解決方法。並會以專案的情境做個示範,最後附上解決問題時參考的一些資源。

在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下面看到這樣的錯誤訊息。

好的,那要怎麼避免這個狀況呢?

解決方法


  • 解法一: 使用MemoryRouter

在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現在也不會有任何錯誤訊息。

  • 解法二: 使用HashRouter

在網址列裡的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位置觸發錯誤。

明天我們繼續實作,我們明天見,掰掰!

參考資料



上一篇
Day31 | 提供程式碼編輯的editor區域
下一篇
Day33 | 賽後中場休息 X 復刊時間
系列文
自己用的工具自己做! 30天玩轉VS Code Extension之旅36
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言