전자 응용 프로그램의 체계 구조

안녕하세요!난 워델이야!나의 여가 시간(그리고 내가 자야 할 때)에 나는 나의 응용 프로그램Lyricistant을 해킹했다.긴 과정이 될 테니 안전벨트를 매라.

그럼 발라드가 뭐예요?


Lyricistant은 표면적으로 보면 매우 간단한 응용 프로그램이다.그것의 구호는 다음과 같다.

Lyricistant is a writing app geared toward helping you write lyrics, poetry, or anything else you desire!


나는 리릭터에게 자신의 음악을 위해 가사를 쓰도록 했지만, 진정한 개발자 스타일로, 나는 내가 만들기 시작한 것보다 훨씬 많은 것이 될 때까지 계속 팽창해 왔다.
itwebsite로 넘어가면 가사를 입력할 수 있는 큰 텍스트 영역이 대부분이다.일부 텍스트를 입력하면 커서 근처에 단어와 관련된 라임 목록이 표시됩니다.
아주 간단하죠?그러나 2022년 2월에 세 번째 활발한 발전의 해로 접어들 것이다.그것도 2022년에 500회 이상 쉽게 제출될 전망이다.이렇게 간단한 일을 왜 이렇게 오랫동안 완성하지 못했지?
공평하게 말하자면, 하나의 프로젝트가 존재하는 시간과 제출 횟수는 프로젝트의 복잡성을 공평하게 평가할 수 없지만, 여전히 이렇다.이것은 영광스러운 <textarea>버전과 <ul>버전입니다. 약간의 자바스크립트가 그것을 연결합니다!이건 좀 멍청하지 않니?
Lyricitant가 이렇게 복잡한 원인은 매우 많지만, 오늘 우리는 큰 원인을 토론할 것이다. Lyricitant는 처음에는 전자 응용 프로그램이었는데, 지금은 같은 코드 라이브러리에서 완전히 사용할 수 있는 오프라인 전자 응용 프로그램과 웹 사이트를 구축했다.여기에 우리가 오늘 토론하고 싶지 않은 다른 응용 프로그램도 추가되었다.그런데 가장 멋있는 부분은 뭐예요?
사용자 인터페이스 코드를 전혀 몰라요...🤫

전자는 크롬+노드일 뿐이다.뭐 그리 대단한 것이 있느냐?


내가 처음으로 Electron을 가사 작자로 선택했을 때, 나도 같은 생각을 했다.나는 사이트를 위해 UI 코드를 작성하는 것처럼 UI 코드를 작성하기만 하면 된다. 그러나 이렇게 하면 언제든지 Node를 사용할 수 있다.
하지만, 이 노드의 함정은 전자가 당신들을 포획하는 방식 중의 하나입니다!
일단 네가 노드에 의존하기 시작하면, 그것은 틀림없이 쉽게 멈추지 않을 것이다.읽기 및 쓰기 파일을 주로 처리하는 응용에 있어 이것은 이중적인 사실이다.fs.readFile부터 <input type="file">까지 간단한 번역이 없습니다.
Node 외에 또 하나의 큰 문제가 있습니다. Electron은 두 개의 프로세스가 직렬로 연결되어 있습니다. structured clone algorithm 지원하는 데이터로만 그들 사이를 통신할 수 있습니다.기본 데이터, 대상 텍스트, 그룹, 그리고... 을 보낼 수 있습니다.별거 아니야.
주요 과정은 당신이 좋아하는 모든 일을 하게 한다.렌더링 프로세스가 사용자 인터페이스 코드를 실행합니다.
일반 전자 응용 프로그램의 통신은 다음과 같습니다.
// in Electron's main process
browserWindow.webContents.send('data-from-main', {hello: 'world'})
ipcMain.on('data-from-renderer', (event, data) => {
  console.log(data.kendrick) // logs 'here'
}
// in Electron's renderer process (i.e., a BrowserWindow)
ipcRenderer.on('data-from-main', (event, data) => {
  console.log(data.hello); // logs 'world'
  ipcRenderer.send('data-from-renderer', {kendrick: 'here'});
});
상상해 보세요. 당신은 코드 라이브러리를 가지고 있습니다. 그 안에 많은 청중들이 있습니다. 당신은 내가 Lyricontant를 웹에 이식하기로 결정했을 때 겪은 고통을 느낄 수 있을 것입니다.

좋아, 나는 너의 발악을 이해할 수 있을 것 같아.당신은 어떻게 그 청중들을 벗어났습니까?


좋아...난 없어!
전자의 프로세스 간 통신 (IPC) 은 전자와의 결합이 매우 긴밀하기 때문에 매우 나쁘다.UI 코드는 운영 프로세스와 통신하는 방법을 알 수 있도록 실행 중임을 알아야 합니다.
그러나 우리가 자신의 전자 불가지 논리로 전자의 IPC를 포장하는 것을 막을 수 있는 것은 아무것도 없다.이것이 바로 내가 한 일이다.
입력Delegate.
export interface Delegate {
  send(channel: string, ...args: any[]): void;
  on(channel: string, listener: (...args: any[]) => void): void;
}
Electron에서 실행할 때, 우리는 UI 코드에 Delegate 에이전트를 제공하여 Electron의 ipcMain에 두 프로세스 사이의 통신을 제공했다.Lyricontant는 이 대상을 플랫폼 의뢰라고 부른다.
Electron의 주 프로세스에서 실행되는 코드도 제공되며, 이와 유사한 객체를 Renderer Delegate라고 합니다.UI가 플랫폼을 사용하여 데이터를 전송할 때 메인스트림(MainStream) 코드는 렌더링을 통해 데이터를 가져옵니다.또한 메인스트림(MainStream) 루틴 코드는 렌더링기를 사용하여 UI로 데이터를 전송하도록 위임할 수도 있습니다.
하지만 네트워크에서 실행될 때...

잠깐만요.네, Electron의 IPC를 포장할 수 있지만, 브라우저는 여전히 프로세스를 하나만 줍니다.너는 데이터를 보낼 만한 것이 없다.


Web Workers 당신과 이야기하고 싶지만, 저는 처음에 이렇게 하지 않았습니다.
하나의 프로세스만 있어도, 우리는 스스로 탐지기를 호출해서 Electron의 두 프로세스 모델을 모의할 수 있다.
class WebPlatformDelegate {
  getListeners(channel: string) {
    // return the listeners set on `on`
  }

  send(channel: string, args: any[]) {
    rendererDelegate.getListeners(channel)
      .forEach((listener) => listener(...args));
  }

  on(channel: string, listener: (...args: any[]) => void) {
    addListener(channel, listener);
  }
}

class WebRendererDelegate {
  getListeners(channel: string) {
    // return the listeners set on `on`
  }

  send(channel: string, args: any[]) {
    platformDelegate.getListeners(channel)
      .forEach((listener) => listener(...args));
  }

  on(channel: string, listener: (...args: any[]) => void) {
    addListener(channel, listener);
  }
}

알겠습니다. 당신들은 이미 한 과정에서 전자의 두 과정을 성공적으로 모의했습니다.그러나 어떻게 노드가 없는 문제를 해결합니까?


우리 반전을 통제하는 것에 대해 이야기합시다.만약 당신이 나 같은 안드로이드 개발자라면, 예를 들어 Dagger에 의존해 보세요.만약 당신이 React 개발자라면 생각해 보세요useContext.노드 개발자라면 서비스 포지셔닝 모드를 고려하십시오.
패턴이 어떻든 생각은 같다.우리는 플랫폼에 특정한 코드와 알 수 없는 플랫폼의 코드를 분리할 것이다.
새 파일을 저장하는 것을 예로 들다.사용자가 새 파일을 저장하려고 할 때, 서정자는 많은 일을 해야 한다.
전자적으로 실행할 때:
  • 사용자 인터페이스에 표시된 현재 텍스트를 가져옵니다.
  • 사용자가 파일을 저장할 위치를 선택할 수 있는 대화 상자를 표시합니다.
  • 사용자가 선택한 파일에 데이터를 저장합니다.
  • 파일을 저장하는 경로는 사용자가 다시 저장을 클릭할 때 다시 선택할 필요가 없도록 합니다.
  • 웹에서 실행할 때:
  • 사용자 인터페이스에 표시된 현재 텍스트를 가져옵니다.
  • 마커 URL to a blob of the current text as its href. 생성 <a>
  • 프로그래밍 방식의 클릭<a> 표시.
  • 브라우저에 파일을 저장합니다.
  • 첫 번째는 플랫폼 불가지론이다.전자판이든 인터넷판이든이 단계의 논리는 완전히 같다.나머지 단계는 모두 플랫폼에 특정되어 있다.
    제어 반전을 사용하여 이러한 단계를 일반 단계와 분리할 수 있습니다.Lyricitant는 플랫폼에 특정한 절차를 제공하도록 강요합니다.파일 저장의 경우 다음과 같이 표시됩니다.
    interface FileMetadata {
      /**
       * A unique way of identifying a file, dependent on the platform in question. For instance, against a Desktop
       * platform, we would expect this to be a file path, such as "/Desktop/myfile.txt". On Android, we might expect this
       * to be a content URI, such as "content://documents/1".
       */
      path: string;
      /**
       * A human displayable name that refers to this file in question. If the path can double as a human displayable name,
       * this can be omitted.
       */
      name?: string;
    }
    
    interface Files {
      saveFile: (data: ArrayBuffer, path?: string) => Promise<FileMetadata>;
    }
    
    Files 인터페이스를 사용하면, Lyritiant가 UI에서 텍스트를 검색하면, 이 텍스트를 ArrayBuffer 주입된 Files 로 보내고, 그 텍스트가 가지고 있을 수 있는 모든 path (Electron의 네 번째 단계를 기억하십니까?)이렇게 하면 Files 파일을 저장하는 작업을 완성할 수 있다.
    이런 모델을 따르면 우리는 다양한 일을 할 수 있고 어느 플랫폼에서 운영되는지 영원히 알 수 없다!

    그래, 그런데 그 일반적인 절차는?


    잘했어.
    우리는 또 컨트롤 반전을 사용하여 이 문제를 처리한다.이러한 흔한 절차는 여러 플랫폼에서 공유할 수 있지만 플랫폼 자체가 이 절차를 처리하는 것이 무엇인지 알 필요가 없다.
    a 아이디어Manager를 입력합니다.간단한 이름, 알아요.인터페이스도 간단하다.
    interface Manager {
      register(): void;
    }
    
    Google은 공공 기능을 하나의 Manager 로 나누고, 관리자는 렌더링 의뢰에 탐지기를 등록하고, 플랫폼에 특정한 클래스를 주입하여 플랫폼에 특정한 논리를 처리하며, 렌더링 의뢰를 통해 데이터를 UI로 전송합니다.
    서정자는 몇 개Managers:FileManagerPreferencesManager로 한 쌍의 부부를 명명했다.이것들은 서정 기능의 핵심이다.플랫폼이 무엇이든지 파일을 열고 기본 설정을 관리해야 합니다.
    모든 플랫폼이 필요로 하는 매니저 목록을 설정하고 플랫폼이 시작될 때 전화를 걸어야 한다register.그들은 모든 통용 코드를 무료로 받았다.현재 파일을 저장하거나 Lyricationant를 마지막으로 닫았을 때 저장되지 않은 데이터를 불러올 염려가 없습니다.
    그러나 일부 기능은 일부 플랫폼에만 중요하다.예를 들어, Electron만이 사용자가 프로그램을 종료하려고 할 때의 알림을 관리하기 위해 사용한다.그것은 다른 공공 코드와 함께 저장되지 않기 때문에 전자에 특정한 기능을 사용할 수 있다.Electron은 QuitManager 매니저 목록에 추가하고 매니저 친구에게 등록해서 Electron만을 위해 일을 완성합니다.인터넷은 그것의 존재를 모른다.

    나는 tl 하나를 얻을 수 있다.박사너무 많아!


    그럼요!
    서정시에는 세 가지'유형'의 코드가 있다.
  • UI 코드(예: UI 렌더링 React 코드)
  • 플랫폼별 코드(예: 노드를 사용하여 파일을 저장하는 전자 코드(예: QuitManager)
  • 플랫폼은 코드와 무관하다(예를 들어 UI와 플랫폼의 특정 코드 간의 조화로운 코드, 예를 들어 Filess 처리).
  • Electron에서는 플랫폼별 코드와 플랫폼별 알 수 없는 코드가 주 프로세스에서 실행됩니다.UI 코드는 렌더링 프로세스에서 실행됩니다.
    웹에서 모든 코드는 동일한 프로세스에서 실행됩니다.(적어도 지금은 그렇다! 다음 발라드 버전 유의!)

    와, 같은 코드 라이브러리에서 하나의 전자 응용 프로그램과 하나의 사이트를 구축하는 데만 많은 구조가 필요하다.


    너 지금 나한테 얘기하는 거야!어쨌든 그것은 완벽하지 않다. 지금은 심지어 그렇지 않다.환매 협정은 이에 대해 많은 조정을 진행했지만 아직 새로운 버전을 내놓지 않았지만 생각은 대동소이하다.
    나는 모든 사람이 이렇게 무거운 일을 해야 한다고 생각하지 않는다.UI 코드에서 플랫폼 검사를 수행하면 많은 애플리케이션이 정상적으로 작동할 수 있습니다.노드에 전혀 의존하지 않고 브라우저 API만 사용하면 더 많은 기능을 사용할 수 있습니다.서정자는 좀 특이하다. 주로 내가 그것을 쓰는 사람이기 때문에 필요한 것보다 더 복잡한 것을 좋아한다.🙃
    설령 이 점을 고려한다 하더라도, 나는 그중의 일부 내용이 재미있거나, 적어도 전자 응용 프로그램을 만드는 것을 고려하고 있는 사람들에게 약간의 도움이 되기를 바란다.

    와델 바그비 / 리릭


    도움이 되는 시 쓰는 조수!

    좋은 웹페이지 즐겨찾기