KV Storage - 웹 최초의 내장 모듈

브라우저 공급업체와 웹 성능 전문가들은 지난 10년 동안 localStorage가 느려서 웹 개발자가 더 이상 사용해서는 안 된다고 주장해 왔습니다.

사실 이런 말을 하는 사람도 틀린 것은 아닙니다. localStorage는 기본 스레드를 차단하는 동기식 API이며 이 API에 액세스할 때마다 페이지가 상호작용할 수 없게 될 수 있습니다.

문제는 localStorage API가 너무나도 간단하고 localStorage의 유일한 비동기 대안은 IndexedDB인데, IndexedDB는 사용 편의성이나 친근한 API로 알려져 있지 않습니다.

따라서 개발자는 사용하기 어려운 방법과 성능에 좋지 않은 방법 중에서 선택해야 합니다. 또한 localStorage API의 단순성을 제공하면서 실제로 비동기 스토리지 API를 사용하는 라이브러리가 있지만, 앱에 이러한 라이브러리 중 하나를 포함하면 파일 크기 비용이 발생하고 성능 예산이 소모될 수 있습니다.

하지만 파일 크기 비용을 지불하지 않고도 localStorage API의 단순성을 통해 비동기 스토리지 API의 성능을 얻을 수 있다면 어떨까요?

곧 제공될 예정입니다. Chrome은 기본 제공 모듈이라는 새로운 기능을 실험하고 있으며, 가장 먼저 제공할 기능은 KV Storage라는 비동기 키/값 저장소 모듈입니다.

하지만 KV 스토리지 모듈에 관해 자세히 알아보기 전에 기본 제공 모듈의 의미를 설명해 드리겠습니다.

내장 모듈이란 무엇인가요?

내장 모듈은 브라우저와 함께 제공되므로 다운로드할 필요가 없다는 점을 제외하고는 일반 JavaScript 모듈과 같습니다.

기존 웹 API와 마찬가지로 내장 모듈은 표준화 프로세스를 거쳐야 합니다. 각 모듈에는 출시 전에 설계 검토와 웹 개발자와 다른 브라우저 공급업체 모두의 지원을 확인해야 하는 자체 사양이 있습니다. Chrome에서 내장 모듈은 모든 새 API를 구현하고 제공하는 데 사용하는 것과 동일한 실행 프로세스를 따릅니다.

기존 웹 API와 달리 내장 모듈은 전역 범위에 노출되지 않으며 가져오기를 통해서만 사용할 수 있습니다.

내장 모듈을 전역으로 노출하지 않으면 많은 이점이 있습니다. 새 JavaScript 런타임 컨텍스트 (예: 새 탭, 작업자 또는 서비스 작업자)를 시작할 때 오버헤드가 추가되지 않으며 실제로 가져오지 않는 한 메모리 또는 CPU를 사용하지 않습니다. 또한 코드에 정의된 다른 변수와 이름 충돌이 발생할 위험이 없습니다.

내장 모듈을 가져오려면 접두사 std: 뒤에 내장 모듈의 식별자를 사용합니다. 예를 들어 지원되는 브라우저에서는 다음 코드로 KV Storage 모듈을 가져올 수 있습니다(지원되지 않는 브라우저에서 KV Storage 폴리필을 사용하는 방법은 아래 참고).

import storage, {StorageArea} from 'std:kv-storage';

KV 스토리지 모듈

KV 저장소 모듈은 단순성 측면에서 localStorage API와 유사하지만 API 모양은 실제로 JavaScript Map에 더 가깝습니다. getItem(), setItem(), removeItem() 대신 get(), set(), delete()이 사용됩니다. 또한 localStorage에서 사용할 수 없는 다른 맵과 유사한 메서드(예: keys(), values(), entries())가 있으며 Map와 마찬가지로 키가 문자열이 아니어도 됩니다. 구조화된 직렬화 가능 유형이 될 수 있습니다.

Map와 달리 모든 KV Storage 메서드는 약속 또는 비동기 반복자를 반환합니다. 이 모듈의 핵심은 localStorage와 달리 동기식이 아니라는 점입니다. 전체 API를 자세히 보려면 사양을 참고하세요.

위의 코드 예에서 알 수 있듯이 KV Storage 모듈에는 기본 내보내기 storage 하나와 이름이 지정된 내보내기 StorageArea 하나가 있습니다.

storage'default'라는 이름의 StorageArea 클래스의 인스턴스이며 개발자가 애플리케이션 코드에서 가장 자주 사용하는 것입니다. StorageArea 클래스는 추가 격리가 필요한 경우에 제공됩니다(예: 데이터를 저장하고 기본 storage 인스턴스를 통해 저장된 데이터와의 충돌을 방지하려는 서드 파티 라이브러리). StorageArea 데이터는 이름이 kv-storage:${name}인 IndexedDB 데이터베이스에 저장되며, 여기서 이름은 StorageArea 인스턴스의 이름입니다.

다음은 코드에서 KV 스토리지 모듈을 사용하는 방법의 예입니다.

import storage from 'std:kv-storage';

const main = async () => {
  const oldPreferences = await storage.get('preferences');

  document.querySelector('form').addEventListener('submit', async () => {
    const newPreferences = Object.assign({}, oldPreferences, {
      // Updated preferences go here...
    });

    await storage.set('preferences', newPreferences);
  });
};

main();

브라우저가 내장 모듈을 지원하지 않으면 어떻게 해야 하나요?

브라우저에서 네이티브 JavaScript 모듈을 사용하는 데 익숙하다면 적어도 지금까지는 URL 이외의 항목을 가져오면 오류가 발생한다는 것을 알고 있을 것입니다. std:kv-storage은(는) 유효한 URL이 아닙니다.

그러면 모든 브라우저에서 내장 모듈을 지원할 때까지 기다려야 코드에서 사용할 수 있나요?라는 질문이 생깁니다. 다행히 그렇지 않습니다.

import maps라는 실험 중인 다른 기능 덕분에 한 브라우저라도 내장 모듈을 지원하는 즉시 실제로 내장 모듈을 사용할 수 있습니다.

지도 가져오기

가져오기 맵은 본질적으로 개발자가 가져오기 식별자를 하나 이상의 대체 식별자로 별칭 지정할 수 있는 메커니즘입니다.

이는 런타임 시 브라우저가 전체 애플리케이션에서 특정 가져오기 식별자를 확인하는 방식을 변경하는 방법을 제공하므로 매우 유용합니다.

내장 모듈의 경우 애플리케이션 코드에서 모듈의 폴리필을 참조할 수 있지만 내장 모듈을 지원하는 브라우저는 대신 해당 버전을 로드할 수 있습니다.

KV Storage 모듈에서 작동하도록 가져오기 맵을 선언하는 방법은 다음과 같습니다.

<!-- The import map is inlined into your page -->
<script type="importmap">
{
  "imports": {
    "/path/to/kv-storage-polyfill.mjs": [
      "std:kv-storage",
      "/path/to/kv-storage-polyfill.mjs"
    ]
  }
}
</script>

<!-- Then any module scripts with import statements use the above map -->
<script type="module">
  import storage from '/path/to/kv-storage-polyfill.mjs';

  // Use `storage` ...
</script>

위 코드의 핵심은 URL /path/to/kv-storage-polyfill.mjsstd:kv-storage과 원래 URL /path/to/kv-storage-polyfill.mjs이라는 가지 서로 다른 리소스에 매핑된다는 점입니다.

따라서 브라우저가 해당 URL(/path/to/kv-storage-polyfill.mjs)을 참조하는 가져오기 문을 발견하면 먼저 std:kv-storage를 로드하려고 시도하고, 로드할 수 없으면 /path/to/kv-storage-polyfill.mjs 로드로 대체합니다.

다시 말하지만, 이 기법이 작동하려면 브라우저에서 가져오기 맵을 지원할 필요가 없으며 또는 내장 모듈을 지원할 필요가 없습니다. 가져오기 문에 전달되는 URL이 폴리필의 URL이기 때문입니다. 폴리필은 실제로 대체가 아니라 기본값입니다. 내장 모듈은 점진적인 개선사항입니다.

모듈을 전혀 지원하지 않는 브라우저는 어떻게 되나요?

가져오기 맵을 사용하여 내장 모듈을 조건부로 로드하려면 실제로 import 문을 사용해야 합니다. 즉, 모듈 스크립트(<script type="module">)를 사용해야 합니다.

현재 80% 이상의 브라우저에서 모듈을 지원하며, 지원하지 않는 브라우저의 경우 module/nomodule 기법을 사용하여 기존 번들을 제공할 수 있습니다. nomodule 빌드를 생성할 때는 모든 폴리필을 포함해야 합니다. 모듈을 지원하지 않는 브라우저는 내장 모듈도 지원하지 않을 것이기 때문입니다.

KV 스토리지 데모

이전 브라우저를 계속 지원하면서 내장 모듈을 사용할 수 있음을 보여주기 위해 위에서 설명한 모든 기법을 통합하고 현재 모든 브라우저에서 실행되는 데모를 만들었습니다.

  • 모듈, 가져오기 맵, 내장 모듈을 지원하는 브라우저는 불필요한 코드를 로드하지 않습니다.
  • 모듈과 가져오기 맵을 지원하지만 내장 모듈은 지원하지 않는 브라우저는 브라우저의 모듈 로더를 통해 KV 저장소 폴리필을 로드합니다.
  • 모듈을 지원하지만 가져오기 맵을 지원하지 않는 브라우저도 브라우저의 모듈 로더를 통해 KV Storage 폴리필을 로드합니다.
  • 모듈을 전혀 지원하지 않는 브라우저는 기존 번들 (<script nomodule>를 통해 로드됨)에서 KV Storage 폴리필을 가져옵니다.

이 데모는 Glitch에서 호스팅되므로 소스를 볼 수 있습니다. README에도 구현에 관한 자세한 설명이 있습니다. 빌드 방법이 궁금하다면 언제든지 살펴보세요.

네이티브 내장 모듈이 실제로 작동하는 모습을 보려면 실험용 웹 플랫폼 기능 플래그(chrome://flags/#enable-experimental-web-platform-features)를 사용 설정한 상태에서 Chrome 74 이상에서 데모를 로드해야 합니다.

DevTools의 소스 패널에 폴리필 스크립트가 표시되지 않으므로 내장 모듈이 로드되고 있는지 확인할 수 있습니다. 대신 내장 모듈 버전이 표시됩니다. 재미있는 사실: 실제로 모듈의 소스 코드를 검사하거나 브레이크포인트를 설정할 수도 있습니다.

Chrome DevTools의 KV Storage 모듈 소스

의견 보내기

이 소개를 통해 내장 모듈로 무엇을 할 수 있는지 맛볼 수 있었습니다. 기대하시기 바랍니다. 개발자가 KV Storage 모듈과 여기에서 설명하는 모든 새 기능을 사용해 보고 의견을 보내주시면 감사하겠습니다.

이 도움말에 언급된 각 기능에 관한 의견을 제공할 수 있는 GitHub 링크는 다음과 같습니다.

사이트에서 현재 localStorage를 사용하는 경우 KV Storage API로 전환하여 모든 요구사항을 충족하는지 확인해야 합니다. KV Storage 출처 체험판에 가입하면 지금 바로 이러한 기능을 배포할 수 있습니다. 모든 사용자가 향상된 저장용량 성능의 이점을 누릴 수 있으며 Chrome 74 이상 사용자는 추가 다운로드 비용을 지불하지 않아도 됩니다.