"앱 안에 웹 페이지를 띄워야 할 때, iframe 대신 webview나 BrowserView를 쓴다" — 보안과 성능 면에서 차이가 있습니다.


세 가지 임베딩 방식 비교

방식프로세스보안유연성상태
<iframe>렌더러와 공유낮음제한적사용 가능
<webview>별도 프로세스높음높음비권장 (deprecated)
BrowserView별도 프로세스높음보통Electron 30에서 제거
WebContentsView별도 프로세스높음높음Electron 30+ 권장

webview 태그

HTML
<!-- 렌더러 HTML에서 사용 -->
<webview
  src="https://example.com"
  style="width: 100%; height: 500px;"
  preload="./webview-preload.js"
  partition="persist:external"
  webpreferences="contextIsolation=yes">
</webview>
JAVASCRIPT
// main.js — webview 활성화 필요
const win = new BrowserWindow({
  webPreferences: {
    webviewTag: true,  // webview 태그 사용 허용
    preload: path.join(__dirname, 'preload.js'),
  },
});

webview 이벤트

JAVASCRIPT
const webview = document.querySelector('webview');

webview.addEventListener('did-start-loading', () => {
  console.log('로딩 시작');
});

webview.addEventListener('did-finish-load', () => {
  console.log('로딩 완료');
});

webview.addEventListener('did-fail-load', (event) => {
  console.error('로딩 실패:', event.errorDescription);
});

// JavaScript 실행
const title = await webview.executeJavaScript('document.title');

// 네비게이션
webview.loadURL('https://example.com');
webview.goBack();
webview.goForward();
webview.reload();

WebContentsView (Electron 30+ 권장)

JAVASCRIPT
const { app, BaseWindow, WebContentsView } = require('electron');

app.whenReady().then(() => {
  const win = new BaseWindow({ width: 1200, height: 800 });

  // 메인 UI 뷰
  const mainView = new WebContentsView({
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
    },
  });
  win.contentView.addChildView(mainView);
  mainView.setBounds({ x: 0, y: 0, width: 800, height: 800 });
  mainView.webContents.loadFile('index.html');

  // 외부 콘텐츠 뷰
  const externalView = new WebContentsView({
    webPreferences: {
      // 외부 콘텐츠에는 제한된 권한
      preload: path.join(__dirname, 'external-preload.js'),
      sandbox: true,
    },
  });
  win.contentView.addChildView(externalView);
  externalView.setBounds({ x: 800, y: 0, width: 400, height: 800 });
  externalView.webContents.loadURL('https://example.com');

  // 윈도우 리사이즈 시 뷰 크기 조정
  win.on('resized', () => {
    const [width, height] = win.getSize();
    mainView.setBounds({ x: 0, y: 0, width: width - 400, height });
    externalView.setBounds({ x: width - 400, y: 0, width: 400, height });
  });
});

보안 고려사항

JAVASCRIPT
// 외부 콘텐츠는 반드시 별도 세션 + 제한된 권한으로
const externalView = new WebContentsView({
  webPreferences: {
    sandbox: true,
    contextIsolation: true,
    nodeIntegration: false,
    partition: 'persist:external',  // 별도 세션
  },
});

// 네비게이션 제한
externalView.webContents.on('will-navigate', (event, url) => {
  const allowed = ['https://example.com'];
  if (!allowed.some(a => url.startsWith(a))) {
    event.preventDefault();
  }
});

// 새 창 열기 차단
externalView.webContents.setWindowOpenHandler(() => {
  return { action: 'deny' };
});

면접 포인트 정리

  • <webview> 태그는 deprecated, WebContentsView로 마이그레이션 권장
  • 외부 콘텐츠는 반드시 별도 세션과 샌드박스로 격리
  • WebContentsView로 분할 화면(Split View) 구현 가능
  • 네비게이션 제한, 새 창 차단 등 보안 설정 필수

Webview 비교를 다뤘으면, 다음은 Electron 마이그레이션을 알아봅시다.

댓글 로딩 중...