mirror of
https://github.com/woodchen-ink/clash-and-dashboard.git
synced 2025-07-18 14:01:56 +08:00
Add: jsbridge supported
This commit is contained in:
parent
6d90543192
commit
9d5268107e
@ -9,7 +9,7 @@ module.exports = merge(commonConfig, {
|
|||||||
'react-hot-loader/patch', // activate HMR for React
|
'react-hot-loader/patch', // activate HMR for React
|
||||||
'webpack-dev-server/client?http://localhost:8080',// bundle the client for webpack-dev-server and connect to the provided endpoint
|
'webpack-dev-server/client?http://localhost:8080',// bundle the client for webpack-dev-server and connect to the provided endpoint
|
||||||
'webpack/hot/only-dev-server', // bundle the client for hot reloading, only- means to only hot reload for successful updates
|
'webpack/hot/only-dev-server', // bundle the client for hot reloading, only- means to only hot reload for successful updates
|
||||||
'./index.tsx' // the entry point of our app
|
'./index.ts' // the entry point of our app
|
||||||
],
|
],
|
||||||
devServer: {
|
devServer: {
|
||||||
hot: true, // enable HMR on the server
|
hot: true, // enable HMR on the server
|
||||||
|
@ -6,7 +6,7 @@ const commonConfig = require('./common')
|
|||||||
|
|
||||||
module.exports = merge(commonConfig, {
|
module.exports = merge(commonConfig, {
|
||||||
mode: 'production',
|
mode: 'production',
|
||||||
entry: './index.tsx',
|
entry: './index.ts',
|
||||||
output: {
|
output: {
|
||||||
filename: 'js/bundle.[hash].min.js',
|
filename: 'js/bundle.[hash].min.js',
|
||||||
path: resolve(__dirname, '../../dist'),
|
path: resolve(__dirname, '../../dist'),
|
||||||
|
12
src/index.ts
Normal file
12
src/index.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import renderApp from './render'
|
||||||
|
import { isClashX, setupJsBridge } from './lib/jsBridge'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Global entry
|
||||||
|
* Will check if need setup jsbridge
|
||||||
|
*/
|
||||||
|
if (isClashX()) {
|
||||||
|
setupJsBridge(renderApp)
|
||||||
|
} else {
|
||||||
|
renderApp()
|
||||||
|
}
|
@ -1,28 +0,0 @@
|
|||||||
import * as React from 'react'
|
|
||||||
import { render } from 'react-dom'
|
|
||||||
import { AppContainer } from 'react-hot-loader'
|
|
||||||
import App from './components/App'
|
|
||||||
|
|
||||||
const rootEl = document.getElementById('root')
|
|
||||||
|
|
||||||
render(
|
|
||||||
<AppContainer>
|
|
||||||
<App />
|
|
||||||
</AppContainer>,
|
|
||||||
rootEl
|
|
||||||
)
|
|
||||||
|
|
||||||
// Hot Module Replacement API
|
|
||||||
declare let module: { hot: any }
|
|
||||||
|
|
||||||
if (module.hot) {
|
|
||||||
module.hot.accept('./components/App', () => {
|
|
||||||
const NewApp = require('./components/App').default
|
|
||||||
render(
|
|
||||||
<AppContainer>
|
|
||||||
<NewApp />
|
|
||||||
</AppContainer>,
|
|
||||||
rootEl
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
91
src/lib/jsBridge.ts
Normal file
91
src/lib/jsBridge.ts
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
/**
|
||||||
|
* For support ClashX runtime
|
||||||
|
*
|
||||||
|
* Clash Dashboard will use jsbridge to
|
||||||
|
* communicate with ClashX
|
||||||
|
*
|
||||||
|
* Before React app rendered, jsbridge
|
||||||
|
* should be checked if initialized,
|
||||||
|
* and also should checked if it's
|
||||||
|
* ClashX runtime
|
||||||
|
*
|
||||||
|
* @author jas0ncn
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* declare javascript bridge API
|
||||||
|
*/
|
||||||
|
export interface JsBridge {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a javascript bridge event handle
|
||||||
|
*/
|
||||||
|
registerHandler: (eventName: string, callback: (data: any, responseCallback: (param: any) => void) => void) => void
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call a native handle
|
||||||
|
*/
|
||||||
|
callHandler: (handleName: string, data: any, responseCallback: (responseData: any) => void) => void
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Who knows
|
||||||
|
*/
|
||||||
|
disableJavscriptAlertBoxSafetyTimeout: () => void
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
|
||||||
|
interface Window {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Global jsbridge instance
|
||||||
|
*/
|
||||||
|
WebViewJavascriptBridge?: JsBridge | null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Global jsbridge init callback
|
||||||
|
*/
|
||||||
|
WVJBCallbacks?: Function[]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* setup a jsbridge before app render
|
||||||
|
* @param {Function} cb callback when jsbridge initialized
|
||||||
|
* @see https://github.com/marcuswestin/WebViewJavascriptBridge
|
||||||
|
*/
|
||||||
|
export function setupJsBridge (callback = jsBridge => {}) {
|
||||||
|
/**
|
||||||
|
* You need check if inClashX first
|
||||||
|
*/
|
||||||
|
if (!isClashX()) {
|
||||||
|
return callback(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window.WebViewJavascriptBridge) {
|
||||||
|
return callback(window.WebViewJavascriptBridge)
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup callback
|
||||||
|
if (window.WVJBCallbacks) {
|
||||||
|
return window.WVJBCallbacks.push(callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
window.WVJBCallbacks = [callback]
|
||||||
|
|
||||||
|
const WVJBIframe = document.createElement('iframe')
|
||||||
|
WVJBIframe.style.display = 'none'
|
||||||
|
WVJBIframe.src = 'https://__bridge_loaded__'
|
||||||
|
document.documentElement.appendChild(WVJBIframe)
|
||||||
|
setTimeout(() => document.documentElement.removeChild(WVJBIframe), 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if perched in ClashX Runtime
|
||||||
|
*/
|
||||||
|
export function isClashX () {
|
||||||
|
return navigator.userAgent === 'ClashX Runtime'
|
||||||
|
}
|
30
src/render.tsx
Normal file
30
src/render.tsx
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import * as React from 'react'
|
||||||
|
import { render } from 'react-dom'
|
||||||
|
import { AppContainer } from 'react-hot-loader'
|
||||||
|
import App from './components/App'
|
||||||
|
|
||||||
|
const rootEl = document.getElementById('root')
|
||||||
|
|
||||||
|
// Hot Module Replacement API
|
||||||
|
declare let module: { hot: any }
|
||||||
|
|
||||||
|
export default function renderApp () {
|
||||||
|
render(
|
||||||
|
<AppContainer>
|
||||||
|
<App />
|
||||||
|
</AppContainer>,
|
||||||
|
rootEl
|
||||||
|
)
|
||||||
|
|
||||||
|
if (module.hot) {
|
||||||
|
module.hot.accept('./components/App', () => {
|
||||||
|
const NewApp = require('./components/App').default
|
||||||
|
render(
|
||||||
|
<AppContainer>
|
||||||
|
<NewApp />
|
||||||
|
</AppContainer>,
|
||||||
|
rootEl
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,6 @@
|
|||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"noImplicitAny": false,
|
"noImplicitAny": false,
|
||||||
"noUnusedLocals": true,
|
"noUnusedLocals": true,
|
||||||
"noUnusedParameters": true,
|
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"target": "es5",
|
"target": "es5",
|
||||||
"jsx": "react",
|
"jsx": "react",
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
"extends": "tslint-config-standard",
|
"extends": "tslint-config-standard",
|
||||||
"rules": {
|
"rules": {
|
||||||
"indent": [true, "spaces", 4],
|
"indent": [true, "spaces", 4],
|
||||||
"ter-indent": [true, 4]
|
"ter-indent": [true, 4],
|
||||||
|
"no-empty": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user