10分钟实现Typora(markdown)编辑器
本章主要內(nèi)容:
介紹我們將在接下來的幾章中構(gòu)建的應(yīng)用程序
配置我們的CSS樣式表,使其看起來更像一個本機(jī)應(yīng)用程序
回顧在Electron中主進(jìn)程和渲染器進(jìn)程之間的關(guān)系
為我們的主進(jìn)程和渲染器進(jìn)程實(shí)現(xiàn)基本功能
在Electron渲染進(jìn)程中訪問Chrome開發(fā)者工具
我們的書簽管理器是一個很好的開始,但它只觸及了我們可以用Electron做什么。
在本章中,我們將更深入地探討,并為與用戶操作系統(tǒng)建立更緊密聯(lián)系的應(yīng)用程序打下基礎(chǔ)。在接下來的幾章中,我們將實(shí)現(xiàn)觸發(fā)操作系統(tǒng)用戶界面,對文件系統(tǒng)進(jìn)行讀寫和訪問剪貼板的功能。
我們正在構(gòu)建一個簡單的Markdown編輯器,它允許我們創(chuàng)建新的或打開現(xiàn)有的Markdown文件,將它們轉(zhuǎn)換為HTML,并將HTML保存到文件系統(tǒng)和剪貼板中。讓我們把這個應(yīng)用程序稱為Fire Sale,因?yàn)樗吘故且粋€廉價編輯器,只是稍微聰明一點(diǎn)而已。
在本章的最后,我們將討論在出現(xiàn)問題時調(diào)試Electron應(yīng)用程序的技術(shù)和工具。
定義我們的應(yīng)用
讓我們從為我們不起眼的小應(yīng)用程序設(shè)置目標(biāo)開始。
對于桌面應(yīng)用程序,我們的許多特性可能看起來有些平庸,這就是重點(diǎn)。它們是桌面應(yīng)用程序的標(biāo)準(zhǔn)配置,但完全超出了傳統(tǒng)web應(yīng)用程序的能力范圍,傳統(tǒng)web應(yīng)用程序無法訪問獨(dú)立瀏覽器選項(xiàng)卡之外的任何內(nèi)容。
我們的應(yīng)用程序?qū)⒂蓛蓚€窗格組成,用戶可以編寫或編輯Markdown和一個右窗格,該窗格以HTML形式呈現(xiàn)用戶的Markdown。在頂部有一系列按鈕,允許用戶從文件系統(tǒng)加載文本文件,并將結(jié)果寫入剪貼板或文件系統(tǒng)。
在應(yīng)用程序的第一階段,我們構(gòu)建了以下的界面。在圖3.1。我們還可以向效果圖(以及隨后的應(yīng)用程序)添加額外的用戶界面元素,但這是一個很好的開始。
圖3.1 我們的應(yīng)用程序的線框顯示,用戶可以在左側(cè)窗格中輸入文本,或者從用戶的文件系統(tǒng)的文件中加載文本。
在這一章中,我們?yōu)槲覀兊膽?yīng)用奠定了基礎(chǔ)。我們創(chuàng)建項(xiàng)目的結(jié)構(gòu),安裝依賴項(xiàng),設(shè)置主進(jìn)程和呈現(xiàn)器進(jìn)程,構(gòu)建用戶界面,并在用戶向左側(cè)窗格輸入文本時實(shí)現(xiàn)markdown到HTML的轉(zhuǎn)換。
我們將在接下來的幾章中分階段構(gòu)建應(yīng)用程序的其余部分。在每一章中,您將下載我們應(yīng)用程序的當(dāng)預(yù)期目標(biāo)代碼。通過這種方式,您可以切換到一個章節(jié),其中包含您感興趣的功能,而不必從頭構(gòu)建整個應(yīng)用程序。
在第一階段,我們的應(yīng)用程序?qū)⒛軌?/p>
打開并保存文件到文件系統(tǒng)
從這些文件獲取Markdown內(nèi)容
將Markdown內(nèi)容呈現(xiàn)為HTML
將生成的HTML保存到文件系統(tǒng)中
將生成的HTML寫入剪貼板
在后面的章節(jié)中,我們的應(yīng)用程序使用本地操作系統(tǒng)接口跟蹤最近打開的文檔。我們可以將Markdown文件從Finder或Windows資源管理器拖放到應(yīng)用程序上,并讓應(yīng)用程序立即打開該Markdown文件。當(dāng)我們右鍵單擊應(yīng)用程序的不同區(qū)域時,應(yīng)用程序?qū)⒂凶约旱淖远x應(yīng)用程序菜單和自定義上下文菜單。
我們還利用了操作系統(tǒng)特有的特性,比如更新應(yīng)用程序的標(biāo)題欄,以顯示當(dāng)前打開的文件,以及自上次保存以來是否已經(jīng)更改。如果計(jì)算機(jī)上的其他應(yīng)用程序在打開文件時更改了文件,我們還實(shí)現(xiàn)了其他功能,比如更新應(yīng)用程序中的內(nèi)容。
奠定基礎(chǔ)
如圖3.2所示的文件結(jié)構(gòu)與我們在前一章中商定并用于書簽管理器的結(jié)構(gòu)非常相似。
為了簡化和清晰,在我們繼續(xù)熟悉Electron時,我們在app/main.js中保存了主進(jìn)程的所有代碼,在app/renderer.js中保存了單渲染器進(jìn)程的所有代碼。我們將app文件夾存儲在基于unix的操作系統(tǒng)上,以便能夠快速生成它,如下面的清單所示?;蛘?,您可以在GitHub上查看這個項(xiàng)目的主分支,網(wǎng)址是https://github.com/electron-in-action/firesale。
圖3.2 我們工程結(jié)構(gòu)
列表3.1 生成應(yīng)用文件結(jié)構(gòu)
mkdir app && touch app/index.html app/main.js app/renderer.js app/style.css
項(xiàng)目的各個部分是
index.html-包含所有為UI提供結(jié)構(gòu)的HTML標(biāo)記
main.js-包含我們的主進(jìn)程的代碼
renderer.js-包含UI的所有交互代碼
style.css-包含樣式的CSS
package.json-包含所有依賴項(xiàng),并在啟動主進(jìn)程時將Electron指向main.js
為了簡單起見,除了Electron之外,我們還從兩個依賴項(xiàng)開始作為運(yùn)行時。我們使用一個名為marked的庫來處理Markdown到HTML轉(zhuǎn)換的繁重工作。
對于這個項(xiàng)目,通過運(yùn)行npm init --yes生成一個package.json。--yes標(biāo)記允許您跳過前一章中的提示。生成package.json之后,運(yùn)行以下命令安裝必要的依賴項(xiàng):
npm install electron marked --save
圖3.3 Electron首先尋找我們的主進(jìn)程,它負(fù)責(zé)生成一個或多個渲染器進(jìn)程,其負(fù)責(zé)顯示我們的UI。
引導(dǎo)程序
在我們package.json的main條目被配置為加載index.js作為應(yīng)用程序的主進(jìn)程。如圖3.3所示,我們需要將其調(diào)整為app/main.js。我們還需要一個渲染器進(jìn)程,為用戶提供應(yīng)用程序的界面。在app/main.js中,讓我們添加如下代碼。
列表3.2 引導(dǎo)主進(jìn)程: ./app/main.js
1 const{ app, BrowserWindow } = require('electron')
2 ?
3 //在頂層聲明mainWindow,以便在“ready”事件完成后不會將其回收為垃圾
4 let mainWindow = null;
5 ?
6 app.on('ready', () => {
7 //使用默認(rèn)屬性創(chuàng)建一個新的BrowserWindow
8 mainWindow = new BrowserWindow({
9 webPreferences: {
10 // webPreferences中的nodeIntegrationInWorker選項(xiàng)設(shè)置為true,Electron5.x以后,缺省為false
11 nodeIntegration: true
12 }
13 })
14 ?
15 //在剛才創(chuàng)建的BrowserWindow實(shí)例中加載app/index.html
16 mainWindow.loadFile('app/index.html');
17 ?
18 mainWindow.on('closed', () => {
19 //在窗口關(guān)閉時將進(jìn)程設(shè)置為null
20 mainWindow = null;
21 });
22 });
這足以啟動我們的應(yīng)用程序。也就是說,由于我們的主進(jìn)程目前在渲染器進(jìn)程中加載了一個空文件,所以沒有發(fā)生太多事情。
實(shí)現(xiàn)用戶界面
在Electron中要獲得圖3.1中效果圖的可行版本,實(shí)現(xiàn)必要的HTML和CSS是相當(dāng)容易的。因?yàn)槲覀冎恍枰С忠粋€瀏覽器,而這個瀏覽器支持web平臺提供的最新和最強(qiáng)大的特性,如圖3.4所示。
圖3.4 主進(jìn)程將創(chuàng)建一個渲染器程序進(jìn)程并告訴它加載index.html。然后,它將像在瀏覽器中一樣加載CSS和JavaScript。
在index.html,我們添加清單3.3中的標(biāo)記來創(chuàng)建圖3.5中的瀏覽器窗口。
圖3.5 開始我們第一個未樣式化的Electron應(yīng)用
列表3.3 我們應(yīng)用的標(biāo)記:./app/index.html
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width,initial-scale=1">
6 <title>Fire Sale</title>
7 <link rel="stylesheet" href="style.css" type="text/css">
8 </head>
9 <body>
10 <!--控件部分在頂部添加了用于打開和保存文件的按鈕。稍后我們將向這些按鈕添加功能。-->
11 <section class="controls">
12 <button id="new-file">New File</button>
13 <button id="open-file">Open File</button>
14 <button id="save-markdown" disabled>Save File</button>
15 <button id="revert" disabled>Revert</button>
16 <button id="save-html">Save HTML</button>
17 <button id="show-file" disabled>Show File</button>
18 <button id="open-in-default" disabled>Open in Default Application</button>
19 </section>
20 <!--我們的應(yīng)用程序允許使用.raw-markdown類編寫和編輯文本區(qū)域中的內(nèi)容,并使用.rendered-html類在div元素中呈現(xiàn)該內(nèi)容。-->
21 <section class="content">
22 <!--<label>標(biāo)簽是可選的,并且包含了這些標(biāo)簽,以使視障用戶更容易訪問應(yīng)用程序。 -->
23 <label for="markdown" hidden>Markdown Content</label>
24 <textarea class="raw-markdown" id="markdown"></textarea>
25 <div class="rendered-html" id="html"></div>
26 </section>
27 </body>
28 <!--在文件末尾的標(biāo)記中,我們需要渲染進(jìn)程的代碼,它位于同一個目錄中的renderer.js中。 -->
29 <script>
30 require('./renderer');
31 </script>
32 </html>
我們的應(yīng)用程序目前還沒有太多需要查看的地方。
如果您和我一樣,您對我在效果圖中引入的兩列接口有點(diǎn)懷疑。在討論如何使用HTML和CSS實(shí)現(xiàn)列時,很少使用easy這個詞。
幸運(yùn)的是,我們可以自信地使用添加到CSS3的名為Flexbox的新布局模式來快速定義應(yīng)用程序的兩列布局。Flexbox使創(chuàng)建頁面布局變得很容易,可以在各種屏幕大小范圍內(nèi)進(jìn)行可預(yù)測的操作,如清單3.4所示。它對CSS來說是相對較新的,直到最近才得到Internet Explorer的支持。
正如我們在第1章和第2章中討論的,我們的應(yīng)用程序總是跟上Chrome的最新版本,所以我們可以放心地使用Flexbox布局模式,而不用擔(dān)心跨瀏覽器兼容性。
使用Flexbox創(chuàng)建頁面布局:./app/style.css
/*選擇一個更新的CSS框模型,它將正確地設(shè)置元素的寬度和高度*/
html {
box-sizing: border-box;
}
?
/* 將此設(shè)置傳遞給頁面上的所有其他元素和偽元素*/
*, *:before, *:after {
box-sizing: inherit;
}
?
html, body {
height: 100%;
width: 100%;
overflow: hidden;
}
?
body {
margin: 0;
padding: 0;
position: absolute;
}
?
/* 在整個應(yīng)用程序中使用操作系統(tǒng)的默認(rèn)字體 */
body, input {
font: menu;
}
?
/*移除瀏覽器圍繞活動輸入字段的默認(rèn)突出顯示*/
textarea, input, div, button {
outline: none;
margin: 0;
}
?
.controls {
background-color: rgb(217, 241, 238);
padding: 10px 10px 10px 10px;
}
button {
font-size: 14px;
background-color: rgb(181, 220, 216);
border: none;
padding: 0.5em 1em;
}
button:hover {
background-color: rgb(156, 198, 192);
}
button:active {
background-color: rgb(144, 182, 177);
}
?
button:disabled {
background-color: rgb(196, 204, 202);
}
?
.container {
display: flex;
flex-direction: column;
min-height: 100vh;
min-width: 100vw;
position: relative;
}
/* 使用Flexbox對齊應(yīng)用程序的兩個窗格*/
.content {
height: 100vh;
display: flex;
}
/* 使用Flexbox將兩個窗格設(shè)置為相同的寬度 */
.raw-markdown, .rendered-html {
min-height: 100%;
max-width: 50%;
flex-grow: 1;
padding: 1em;
overflow: scroll;
font-size: 16px;
}
?
.raw-markdown {
border: 5px solid rgb(238, 252, 250);;
background-color: rgb(238, 252, 250);
font-family: monospace;
}
樣式表有兩個主要目標(biāo)。首先,我們想利用像Flexbox這樣的現(xiàn)代CSS特性來設(shè)計(jì)我們的UI。其次,我們希望采取一些小步驟,使應(yīng)用程序的外觀和感覺更像一個真實(shí)的web應(yīng)用程序(參見圖3.6)。
圖3.6 我們的應(yīng)用程序已經(jīng)使用CSS的現(xiàn)代特性給出了一些基本的樣式。
box-sizing屬性在CSS中處理一個歷史上的奇怪現(xiàn)象,在一個寬度為200像素的元素中添加50個像素的填充將導(dǎo)致它的寬度為300像素(每邊添加50個像素的填充),對于邊框也是一樣。
當(dāng)box-sizing被設(shè)置為border-box時,我們的元素會考慮到我們設(shè)置它們的高度和寬度。總的來說,這是一件好事。在這個CSS規(guī)則中,我們還讓所有其他元素和偽元素都尊重我們通過將box-sizing設(shè)置為border-box所做的艱苦工作。
我們希望我們的應(yīng)用程序能夠適應(yīng)本地應(yīng)用程序。朝著這個方向邁出的重要一步是使用所有其他應(yīng)用程序都使用的系統(tǒng)字體。例如,盡管macOS在整個操作系統(tǒng)中使用San Francisco作為默認(rèn)字體,但它不能作為常規(guī)字體使用。我們將font屬性設(shè)置為menu,它依賴于操作系統(tǒng)來使用它的默認(rèn)字體——即使我們無法訪問它。
瀏覽器在當(dāng)前活動的UI元素周圍設(shè)置一個邊框。在macOS中,這個邊框是藍(lán)色的輝光。您可能從未過多地考慮過它,因?yàn)槲覀円呀?jīng)習(xí)慣了在web上使用它,但是當(dāng)我們開發(fā)桌面應(yīng)用程序時,它看起來并不合適。在我們的應(yīng)用程序中,它看起來尤其糟糕,其中一半的UI實(shí)際上是一個大型文本輸入。通過將outline設(shè)置為none,我們刪除了活動元素周圍的非自然輝光。
在.content、.raw-markdown和.rendered-html規(guī)則中,我們實(shí)現(xiàn)了一個簡單的Flexbox布局,這將使我們的應(yīng)用程序看起來更像我們在圖3.1中介紹的效果。content類的元素將包含我們的兩列。我們將display屬性設(shè)置為flex,以使用前面討論的Flexbox技術(shù)。下一步,我們設(shè)置flex- growth,它指定flex項(xiàng)的增長因子, 當(dāng)然可以。把它看作元素的尺度相對于它的兄弟元素可能是有幫助的。在本例中,我們使用Flexbox將兩列設(shè)置為相等的比例。
優(yōu)雅地顯示瀏覽器窗口
如果你仔細(xì)觀察你的應(yīng)用程序的啟動,您將注意到,在Electron加載index.html并在窗口中呈現(xiàn)DOM之前,窗口完全為空。用戶不習(xí)慣在本地應(yīng)用程序中看到這種情況,我們可以通過重新思考如何啟動窗口來避免這種情況。
如果您認(rèn)為應(yīng)用程序第一次啟動時的虛無閃光是無意義的,考慮主進(jìn)程中的代碼:它創(chuàng)建一個窗口,然后在其中加載內(nèi)容。如果我們隱藏窗口直到內(nèi)容被加載呢?然后,當(dāng)UI準(zhǔn)備好時,我們顯示窗口,并避免短暫地暴露一個空窗口。
列表3.5 當(dāng)DOM就緒時優(yōu)雅地顯示窗口
1 app.on('ready', () => {
2 //使用默認(rèn)屬性創(chuàng)建一個新的BrowserWindow
3 mainWindow = new BrowserWindow({
4 show: false,
5 webPreferences: {
6 // webPreferences中的nodeIntegrationInWorker選項(xiàng)設(shè)置為true,Electron5.x以后,缺省為false
7 nodeIntegration: true
8 }
9 })
10 ?
11 //在剛才創(chuàng)建的BrowserWindow實(shí)例中加載app/index.html
12 mainWindow.loadFile('app/index.html');
13 ?
14 mainWindow.once('ready-to-show', () => {
15 //當(dāng)DOM就緒時顯示窗口。
16 mainWindow.show();
17 });
18
19 mainWindow.on('closed', () => {
20 //在窗口關(guān)閉時將進(jìn)程設(shè)置為null
21 mainWindow = null;
22 });
23 });
我們將一個對象傳遞給BrowserWindow構(gòu)造函數(shù),默認(rèn)情況下將其設(shè)置為hidden。當(dāng)BrowserWindow實(shí)例觸發(fā)它的“ready-to-show”事件時,我們將調(diào)用它的show()方法,這將在UI完全準(zhǔn)備好運(yùn)行后使它不再隱藏。當(dāng)應(yīng)用程序通過網(wǎng)絡(luò)加載遠(yuǎn)程資源時,這種方法甚至更有用,因?yàn)槌跏蓟撁婵赡苄枰L的時間。
實(shí)現(xiàn)基本功能
讓我們把一些基本功能放在適當(dāng)?shù)奈恢蒙稀τ诔鯇W(xué)者,我們希望在左窗格中的Markdown發(fā)生更改時更新右窗格中呈現(xiàn)的HTML視圖(參見圖3.7)。這就是我們唯一的依賴—Marked—發(fā)揮作用的地方。
圖3.7 我們將在左側(cè)窗格中添加一個事件監(jiān)聽器,它將以HTML的形式呈現(xiàn)標(biāo)記并顯示在右側(cè)窗格中。
引入依賴項(xiàng)很容易,因?yàn)槲覀兛梢允褂肗ode的require來引入marked。讓我們在app/renderer.js中添加以下內(nèi)容。
列表3.6 引入依賴: ./app/renderer.js
const marked = require('marked');
現(xiàn)在,我們可以通過變量marked使用Marked。鑒于我們在圖3.7中討論了應(yīng)用程序的功能,您可能已經(jīng)開始懷疑,在開發(fā)應(yīng)用程序時,我們將大量使用#markdown文本區(qū)域和#html元素。讓我們使用一對變量來存儲對每個元素的引用,以便更容易地使用它們,如清單3.7所示。在此過程中,我們還將為UI頂部的每個按鈕創(chuàng)建變量。
列表3.7 緩存DOM選擇器: ./app/renderer.js
const markdownView = document.querySelector('#markdown');
const htmlView = document.querySelector('#html');
const newFileButton = document.querySelector('#new-file');
const openFileButton = document.querySelector('#open-file');
const saveMarkdownButton = document.querySelector('#save-markdown');
const revertButton = document.querySelector('#revert');
const saveHtmlButton = document.querySelector('#save-html');
const showFileButton = document.querySelector('#show-file');
const openInDefaultButton = document.querySelector('#open-in-default');
我們還相當(dāng)頻繁地在htmlView中呈現(xiàn)Markdown,所以我們想給自己一個函數(shù),以便將來更容易實(shí)現(xiàn)。
列表3.8 轉(zhuǎn)換markdown到HTML: ./app/renderer.js
marked將我們要呈現(xiàn)的Markdown內(nèi)容作為第一個參數(shù),并將選項(xiàng)的對象作為第二個參數(shù)。我們希望避免意外的腳本注入,因此我們傳入了一個對象,并將sanitize屬性設(shè)置為true。
最后,我們向markdownView添加了一個事件監(jiān)聽器,它將在keyup上讀取它的內(nèi)容(在textarea元素中,內(nèi)容存儲在它的value屬性中),通過marked運(yùn)行它們,然后將它們加載到htmlView中。結(jié)果如圖3.8所示。
列表3.9 當(dāng)Markdown更改時重新呈現(xiàn)HTML: ./app/renderer.js
1 markdownView.addEventListener('keyup', (event) => {
2 const currentContent = event.target.value;
3 renderMarkdownToHtml(currentContent);
4 });
圖3.8 我們的應(yīng)用程序接受用戶在左窗格中鍵入的內(nèi)容,并在右窗格中將其自動呈現(xiàn)為HTML。該內(nèi)容由用戶提供,不屬于我們的應(yīng)用程序。
基本功能已經(jīng)就緒,我們準(zhǔn)備開始研究只有在Electron應(yīng)用程序中才可能實(shí)現(xiàn)的特性,首先從文件系統(tǒng)中讀寫文件開始。當(dāng)所有這些都完成后,應(yīng)用程序的呈現(xiàn)程序流程應(yīng)該是這樣的。
列表3.10 渲染進(jìn)程: ./app/renderer.js
1 const marked = require('marked');
2 ?
3 const markdownView = document.querySelector('#markdown');
4 const htmlView = document.querySelector('#html');
5 const newFileButton = document.querySelector('#new-file');
6 const openFileButton = document.querySelector('#open-file');
7 const saveMarkdownButton = document.querySelector('#save-markdown');
8 const revertButton = document.querySelector('#revert');
9 const saveHtmlButton = document.querySelector('#save-html');
10 const showFileButton = document.querySelector('#show-file');
11 const openInDefaultButton = document.querySelector('#open-in-default');
12 ?
13 const renderMarkdownToHtml = (markdown) => {
14 htmlView.innerHTML = marked(markdown, { sanitize: true });
15 };
16 ?
17 markdownView.addEventListener('keyup', (event) => {
18 const currentContent = event.target.value;
19 renderMarkdownToHtml(currentContent);
20 });
調(diào)試Electron應(yīng)用程序
在理想的世界中,我們在編寫代碼時永遠(yuǎn)不會出錯。
接口和方法永遠(yuǎn)不會在不同的版本之間更改,而且您的作者不必每次發(fā)布本書中應(yīng)用程序使用的依賴項(xiàng)的新版本時都屏住呼吸。
我們并不生活在那個世界上。因此,我們可以使用開發(fā)工具幫助我們跟蹤并有望消除缺陷。
調(diào)試渲染器進(jìn)程
到目前為止,一切都進(jìn)行得相當(dāng)順利,但可能不久之后我們就必須調(diào)試一些棘手的情況。因?yàn)镋lectron應(yīng)用程序是基于Chrome的,所以我們在構(gòu)建Electron應(yīng)用程序時可以使用Chrome開發(fā)者工具就不足為奇了(圖3.9)。
調(diào)試渲染器過程相對簡單。Electron的默認(rèn)應(yīng)用程序菜單提供了一個命令來打開應(yīng)用程序中的Chrome開發(fā)工具。在第6章中,我們將學(xué)習(xí)如何創(chuàng)建我們自己的自定義菜單,并在您不希望將其公開給用戶的情況下消除此功能。
還有另外兩種訪問開發(fā)人員工具的方法。
在任何時候,您都可以按macOS上的Command-Option-I或Windows或Linux上的Control-Shift-I打開工具(圖3.10)。此外,您還可以通過編程方式觸發(fā)開發(fā)人員工具。
BrowserWindow實(shí)例上的webcontent屬性有一個名為openDevTools()的方法。如清單3.11所示,這個方法將在調(diào)用它的BrowserWindow中打開開發(fā)工具。
圖3.9 Chrome開發(fā)工具在渲染器過程中可用,就像在基于瀏覽器的應(yīng)用程序中一樣。
圖3.10 該工具可以在Electron提供的默認(rèn)菜單中開或關(guān)。您還可以使用Windows上的Control-Shift-I或macOS上的Command-Option-I來觸發(fā)它們。
列表3.11 從主流程打開開發(fā)者工具: ./app/main.js
1 app.on('ready', () => {
2 mainWindow = new BrowserWindow({
3 show: false,
4 webPreferences: {
5 nodeIntegration: true
6 }
7 });
8
9 mainWindow.loadFile(`app/index.html`);
10 ?
11 ?
12 mainWindow.once('ready-to-show', () => {
13 mainWindow.show();
14 mainWindow.webContents.openDevTools(); //我們可以通過編程方式在主窗口加載開發(fā)工具時立即打開它。
15 });
16 ?
17 mainWindow.on('closed', () => {
18 mainWindow = null;
19 });
20 });
21
調(diào)試主進(jìn)程
調(diào)試主進(jìn)程并不容易。Node Inspector是調(diào)試Node.js應(yīng)用程序的常用工具,為了提供一個可以調(diào)試主進(jìn)程的方法,Electron 提供了 --inspect開關(guān)。使用如下的命令行開關(guān)來調(diào)試 Electron 的主進(jìn)程:--insepct=[port] 當(dāng)這個開關(guān)用于 Electron 時,它將會監(jiān)聽 V8 引擎中有關(guān) port 的調(diào)試器協(xié)議信息。 默認(rèn)的port 是 5858。
electron --inspect=5858 your/appCopy
使用VSCode進(jìn)行主進(jìn)程調(diào)試
Visual Studio Code是一個免費(fèi)的開放源碼的IDE,適用于Windows、Linux和macOS,并且是由Microsoft在Electron之上構(gòu)建的。Visual Studio Code提供了一組用于調(diào)試節(jié)點(diǎn)應(yīng)用程序的豐富工具,這使得調(diào)試Electron應(yīng)用程序比前面提到的要容易得多。
設(shè)置構(gòu)建任務(wù)的一種快速方法是讓Visual Studio Code在沒有構(gòu)建任務(wù)的情況下構(gòu)建應(yīng)用程序。 在Windows上按Control-Shift-B或在macOS上按Command-Shift-B,將提示您創(chuàng)建一個構(gòu)建任務(wù),如圖3.11所示。
圖3.11 在沒有適當(dāng)?shù)臉?gòu)建任務(wù)的情況下觸發(fā)構(gòu)建任務(wù),Visual Studio Code將提示為您創(chuàng)建一個。
列表3.12 在Windows的Visual Studio Code中設(shè)置構(gòu)建任務(wù): task.json
1 {
2 // 有關(guān) tasks.json 格式的文檔,請參見
3 // https://go.microsoft.com/fwlink/?LinkId=733558
4 "version": "2.0.0",
5 "tasks": [
6 {
7 "type": "npm",
8 "script": "start",
9 "problemMatcher": []
10 }
11 ]
12 }
現(xiàn)在,當(dāng)您按下Windows上的Control-Shift-B或macOS上的Command-Shift-B時,您的電子應(yīng)用程序?qū)印_@不僅對于在Visual Studio Code中設(shè)置調(diào)試非常重要,而且通常也是啟動應(yīng)用程序的一種方便方法。下一步是設(shè)置Visual Studio Code來啟動應(yīng)用程序,并將其連接到其內(nèi)置調(diào)試器(圖3.12)。
要創(chuàng)建啟動任務(wù),請轉(zhuǎn)到上面的終端選項(xiàng)卡,并單擊配置默認(rèn)生成任務(wù)。Visual Studio Code將詢問您想要創(chuàng)建哪種配置文件。選擇Node并用清單3.13替換文件的內(nèi)容。
圖3.12 在Debug選項(xiàng)卡中,單擊gear, Visual Studio Code將創(chuàng)建一個配置文件,用于代表您啟動調(diào)試器。
列表3.13 為Windows的Visual Studio代碼設(shè)置啟動任務(wù)
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug Main Process",
"type": "node",
"request": "launch",
"cwd": "${workspaceRoot}",
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron",
"windows": {
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron.cmd"
},
"args" : ["."],
"outputCapture": "std"
}
]
}
有了這個配置文件,您可以單擊主進(jìn)程中任何一行的左邊緣來設(shè)置斷點(diǎn),然后按F5運(yùn)行應(yīng)用程序。 執(zhí)行將在斷點(diǎn)處暫停,允許您檢查調(diào)用堆棧,確定范圍內(nèi)的變量,并與活動控制臺進(jìn)行交互。斷點(diǎn)并不是調(diào)試代碼的唯一方法。 您還可以監(jiān)視特定的表達(dá)式,或者在拋出未捕獲異常時將其放入調(diào)試器(圖3.13)。
圖3.13 內(nèi)置在Visual Studio Code中的調(diào)試器允許您暫停應(yīng)用程序的執(zhí)行,并順便檢查bug。
您很可能沒有使用Visual Studio Code。這很好。這并不是本書的先決條件,使用您最熟悉的文本編輯器或IDE幾乎肯定沒問題。 此外,Visual Studio Code并不是唯一支持調(diào)試主進(jìn)程。例如,您可以在這里找到配置WebStorm的詳細(xì)信息:http://mng.bz/Y5T6。
總結(jié)
在接下來的幾章中,我們將制做一個markdown到html編輯器。
Flexbox受到現(xiàn)代瀏覽器的支持,允許我們輕松地實(shí)現(xiàn)一個雙窗格界面,當(dāng)用戶改變窗口的大小時,這個界面將進(jìn)行調(diào)整。
Chrome開發(fā)工具在所有渲染器進(jìn)程中都可用,可以從默認(rèn)的電子應(yīng)用程序、鍵盤快捷鍵或主進(jìn)程觸發(fā)。
此時Electron中還沒有完全支持Node Inspector檢查器。
Visual Studio代碼提供了一組豐富的工具,用于調(diào)試應(yīng)用程序主進(jìn)程中的問題。
總結(jié)
以上是生活随笔為你收集整理的10分钟实现Typora(markdown)编辑器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Marketing Cloud里CSRF
- 下一篇: 个体户需要报税做账吗 个体户要报税做账吗