在终端应用程序 Hyper 中获取并排预览
大家好,我是Takuya。
我正在发布YouTube 内容,分享我的开发工作流程。
想要在终端应用中并排预览
对于网页编程教程来说,并排展示代码和输出效果会很棒。
通常情况下,只需排列两个窗口即可:一个编辑器和一个浏览器。
但这很烦人,因为每次制作教程时,你都必须并排对齐这两个窗口。
Hyper是一款使用 Web 标准构建的终端应用程序,曾经具有内置的 WebView 功能:
如上所示,它在终端窗口右侧显示了预览。
看起来非常简洁。
因此,您无需单独的预览窗口即可制作教程。
但看起来该功能已因安全原因被删除:
那是三年前的事了,一个相当老的问题。
我理解在 Electron 应用中加载网页的风险。
然而,webview
最近Electron 默认禁止集成 NodeJS。所以,我认为嵌入 Hyper 是安全的,尤其是在你了解自己在做什么的情况下。
破解 Hyper 以恢复内置的 webview 功能
因此,我决定将这个功能重新引入 Hyper,并成功实现了。
它的样子如下:
演示视频:
如何构建
我已经built-in-webview
为 hack 创建了分支:
https://github.com/craftzdog/hyper/tree/built-in-webview
克隆此 repo 并按照如下方式自行构建。
npm i
npm run dev
# On another terminal session
npm run app
如何使用
按 向右拆分窗口Cmd-D
。
然后,输入echo <URL-to-open>
并点击Return
。
在终端中点击 URL。
然后,窗格将变成加载 URL 的 Web 视图。
我如何破解 Hyper
检查差异
首先,您必须允许webview
标签app/ui/window.ts
:
const winOpts: BrowserWindowConstructorOptions = {
minWidth: 370,
minHeight: 190,
backgroundColor: toElectronBackgroundColor(cfg.backgroundColor || '#000'),
titleBarStyle: 'hiddenInset',
title: 'Hyper.app',
// we want to go frameless on Windows and Linux
frame: process.platform === 'darwin',
transparent: process.platform === 'darwin',
icon,
show: Boolean(process.env.HYPER_DEBUG || process.env.HYPERTERM_DEBUG || isDev),
acceptFirstMouse: true,
webPreferences: {
nodeIntegration: true,
navigateOnDragDrop: true,
enableRemoteModule: true,
- contextIsolation: false
+ contextIsolation: false,
+ webviewTag: true
},
...options_
};
Hyper 部分保留了旧实现,您可以复用它们。
终端组件已经拥有url
prop,
您可以webview
在组件拥有url
prop 时进行显示。
在中lib/components/term.tsx
,像这样更改终端组件类:
@@ -430,18 +436,35 @@ export default class Term extends React.PureComponent<TermProps> {
style={{padding: this.props.padding}}
onMouseUp={this.onMouseUp}
>
- {this.props.customChildrenBefore}
- <div ref={this.onTermWrapperRef} className="term_fit term_wrapper" />
- {this.props.customChildren}
- {this.props.search ? (
- <SearchBox
- search={this.search}
- next={this.searchNext}
- prev={this.searchPrevious}
- close={this.closeSearchBox}
+ {this.props.url ? (
+ <webview
+ src={this.props.url}
+ style={{
+ background: '#fff',
+ position: 'absolute',
+ top: 0,
+ left: 0,
+ display: 'inline-flex',
+ width: '100%',
+ height: '100%'
+ }}
/>
) : (
- ''
+ <>
+ {this.props.customChildrenBefore}
+ <div ref={this.onTermWrapperRef} className="term_fit term_wrapper" />
+ {this.props.customChildren}
+ {this.props.search ? (
+ <SearchBox
+ search={this.search}
+ next={this.searchNext}
+ prev={this.searchPrevious}
+ close={this.closeSearchBox}
+ />
+ ) : (
+ ''
+ )}
+ </>
)}
<style jsx global>{`
并且,更改 URL 点击处理程序以分派操作,而不是在外部浏览器中打开页面:
@@ -160,7 +160,13 @@ export default class Term extends React.PureComponent<TermProps> {
this.term.loadAddon(
new WebLinksAddon(
(event: MouseEvent | undefined, uri: string) => {
- if (shallActivateWebLink(event)) void shell.openExternal(uri);
+ // if (shallActivateWebLink(event)) void shell.openExternal(uri);
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call
+ store.dispatch({
+ type: 'SESSION_URL_SET',
+ uid: props.uid,
+ url: uri
+ });
},
{
// prevent default electron link handling to allow selection, e.g. via double-click
在 中lib/reducers/sessions.ts
,添加 reducer,SESSION_URL_SET
如下所示:
@@ -11,7 +11,8 @@ import {
SESSION_SET_XTERM_TITLE,
SESSION_SET_CWD,
SESSION_SEARCH,
- SESSION_SEARCH_CLOSE
+ SESSION_SEARCH_CLOSE,
+ SESSION_URL_SET
} from '../constants/sessions';
import {sessionState, session, Mutable, ISessionReducer} from '../hyper';
@@ -129,6 +130,9 @@ const reducer: ISessionReducer = (state = initialState, action) => {
}
return state;
+ case SESSION_URL_SET:
+ return state.setIn(['sessions', action.uid, 'url'], action.url);
+
default:
return state;
}
它非常有效!
在线关注我
- 看看我的应用程序Inkdrop - 一款 Markdown 笔记应用程序
- 订阅新闻通讯http://eepurl.com/dNgJo6
- 推特https://twitter.com/inkdrop_app
- YouTube 频道https://youtube.com/c/devaslife
- 博客https://blog.inkdrop.app/
- Discord 社区https://discord.gg/QfsG5Kj
- Instagram https://instagram.com/craftzdog