オープンソース LWC の ShadowRoot をポリフィルする

この記事では、[オープンソース LWC](https://lwc.dev/) のSynthetic Shadow を使って ShadowRoot をポリフィルする方法を紹介します。

## オープンソース LWC と shadow DOM
オープンソース LWC では、デフォルトで [shadow DOM](https://developer.mozilla.org/ja/docs/Web/Web_Components/Using_shadow_DOM) を利用したスコープが形成されます。
しかし、一部ブラウザへの互換性やスタイルシートの適用ルールなどの理由で shadow DOM を使えない場合に備えて [Synthetic Shadow](https://www.npmjs.com/package/@lwc/synthetic-shadow) という LWC の ShadowRoot をポリフィルするためのライブラリが用意されています。
他にもポリフィルする方法はありますが、Synthetic Shadow は Lightning プラットフォームの性能要件に合わせて LWC に最適化されているため推奨されています。


## プロジェクトを作成
まずは、`lwc-create-app` でプロジェクトを作成し、ShadowRoot によるスコープを確認してみます。

```bash
$ npx lwc-create-app use-synthetic-shadow

? Package name for npm use-synthetic-shadow
? Description 
? Author 
? Version 0.0.0
? License MIT
? Who is the GitHub owner of the repository (https://github.com/OWNER/repo) 
? What is the GitHub name of the repository (https://github.com/owner/REPO) use-synthetic-shadow
? Select a package manager npm
? Register web component No
? Use custom Express server configuration No

$ cd use-synthetic-shadow
$ npm run watch
```

ブラウザで要素を確認してみると、#shadow-root ドキュメントフラグメントが確認できます。
<img width="480" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26378/571b5c04-700a-0617-cb55-436a7d05453d.png">


## Synthetic Shadow を利用する
Synthetic Shadow を適用するには `@lwc/synthetic-shadow` をインポートします。
`@lwc/synthetic-shadow` は、プロジェクトの作成と同時にインストールされているので、改めて取得する必要はありません。
`src/index.js` を開いて、`lwc` のインポートより前に `import '@lwc/synthetic-shadow';` を追加するだけです。

```js:src/index.js
import '@lwc/synthetic-shadow';
import { createElement } from 'lwc'; // これより前に @lwc/synthetic-shadow をインポートする
import MyApp from 'my/app';

const app = createElement('my-app', { is: MyApp });
// eslint-disable-next-line @lwc/lwc/no-document-query
document.querySelector('#main').appendChild(app);
```

ブラウザで確認してみると、#shadow-root ドキュメントフラグメントが消えているのが分かります。
<img width="480" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26378/f2ec7e34-d2ee-945f-87ac-bc07b36ea4ce.png">


## [おまけ] Lightning Design System を適用する
shadow DOM とは違い、 Synthetic Shadow ではトップダウンでスタイルシートを適用できます。
今回は、その確認も兼ねて [Lightning Design System(SLDS）](https://lightningdesignsystem.com/)を適用してみます。

まずは、 SLDS の npm パッケージをインストールします。

```bash
$ npm install --save @salesforce-ux/design-system
```

次に、必要なリソースを *dist/* にコピーするため `lwc-services.config.js` を編集します。
そして、`src/index.html` から SLDS を読み込みます。

```js:lwc-services.config.js
module.exports = {
    resources: [
        { from: 'src/resources', to: 'dist/resources' },
        { from: 'node_modules/@salesforce-ux/design-system/assets', to: 'dist/resources/slds' }
    ],
};
```
```html:src/index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <link rel="stylesheet" type="text/css" href="./resources/slds/styles/salesforce-lightning-design-system.min.css" />
</head>
<body>
    <div id="main"></div>
</body>
</html>
```

これで、LWC コンポーネントから SLDS を利用する事ができるようになります。

```html:src/modules/my/app/app.html
<template>
    <button class="slds-button slds-button_brand">Brand Button</button>
</template>
```

<img width="480" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26378/fddc7b4a-40c3-8318-4176-d160e7a7c9a3.png">


## 参考
- [npm - @lwc/synthetic-shadow](https://www.npmjs.com/package/@lwc/synthetic-shadow)
- [github - lwc/packages/@lwc/synthetic-shadow/](https://github.com/salesforce/lwc/tree/master/packages/%40lwc/synthetic-shadow)
- [Lightning Design System - Donwloads](https://lightningdesignsystem.com/downloads/)