LightningWebComponent(OSS)で Bootstrap を読み込む
LightningWebComponent をイジってみて、Web Component としてシンプルだなーOSS版も使ってみるかなーと思ったらいきなりドハマリしたのでメモ。
OSS版 LWC を始める
といってもやり方は恐ろしく単純で
$ npx create-lwc-app my-app
これだけでテンプレができる。
とりあえず Web アプリを指定した。
$ npm run watch
これで http://loclhost:3002 にサーバが立つので実行できる。
Bootstrap を読み込んだ(失敗版)
まず、Bootstrap を読み込んで失敗したケース。
index.html
でこんなことをしてみたのだが
<!-- styles --> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous"> <!-- js --> <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
適用される範囲は LWC アプリケーションの外側のみという残念なことに。
何が起こったのかと思って挙動を調べて見ると、どうも shadow dom
はコンポーネント毎に style が完全独立してて、相互の CSS の影響をうけないんだとかなんとか…
共通的なフォントサイズとかフォントファミリとかどないせーっちゅーねん(汗
と思って調べて見ると
Because native Shadow DOM is enabled out-of-the-box for Open Source, you can’t just use a global stylesheet that then allows to cascade styles across inheriting Lightning web components. Everything is truly encapsulated, which is one of the huge benefits. ネイティブのShadowDOMはオープンソースですぐに使用できるため、継承するLightningWebコンポーネント間でスタイルをカスケードできるグローバルスタイルシートを使用することはできません。すべてが本当にカプセル化されており、これは大きなメリットの1つです。 You will have to rethink your CSS strategy when it comes to building Lightning web components, or if you want to reuse components that you built and styled on Lightning Platform. Lightning Webコンポーネントの構築に関して、またはLightning Platformで構築およびスタイル設定したコンポーネントを再利用する場合は、CSS戦略を再考する必要があります。 On the other side, you can choose with LWC Open Source to use synthetic shadow as an easier way to interoperate with existing UI if needed. 一方、必要に応じて既存のUIと相互運用するためのより簡単な方法として、合成シャドウを使用するようにLWCオープンソースを選択できます。
Oh...
共通CSS取り込み戦略
ということで、共通CSSを取り込み戦略を調べて見ると
実際にやってみると
CSS だけのモジュールを用意して
こんな感じで実行すると
てな感じ。
でも目標はあくまで Bootstrap を使うこと。
なので、一旦は cssCommon を削除する(次のトライの邪魔になる)。
Bootstrap を取り込む戦術
Bootstrap を npm 経由で取り込んで CSS で取り込む。
$ npm install bootstrap
としたら、lwc-services.config.js
ファイルを開いて、resources をいじくります
module.exports = { resources: [ { from: 'src/client/resources/', to: 'dist/resources/' }, { from: 'node_modules/bootstrap/dist', to: 'src/bootstrap' }, { from: 'node_modules/bootstrap/dist', to: 'dist/bootstrap' } ], // 以下略
ここまで書いたら、
npm run build:development
実行するとこんな感じになる
ソースディレクトリに Bootstrap を強制配置。
ここまでやったら、全てのコンポーネントの先頭でこんな事すればまずは Bootstrap が使える。
<template> <link href="/styles/salesforce-lightning-design-system.css" rel="stylesheet" type="text/css" /> </template>
ただし、コレだとコンポーネントすべてで書かなきゃいけないので色々ダメ。
なので、もう少しアレな手段をとってみる。
さっきのように cssCommon コンポーネントを作るけど、今度は Javascript ファイルのみ用意する。
中身はコレ
import { LightningElement } from 'lwc'; export default class CssCommonElement extends LightningElement { _bootStrapCss() { let _bootstrap = '../bootstrap/css/bootstrap.min.css'; const styles = document.createElement('link'); styles.href = _bootstrap; styles.rel = 'stylesheet'; return styles; } connectedCallback() { // テンプレートに無理やり Bootstrap の CSS 挿入 this.template.appendChild(this._bootStrapCss()); } }
connectedCallback()
はライフサイクルイベントの一種で、親コンポーネントの下に配置された際に実行されるコールバック。
つまり、初期化が終わって、コンポーネントが表示待機状態に入ったことを意味する。
ここで、スタイルシートを無理やり適用している。
あとは画面上に表示されるコンポーネント全てで LightningElement の代わりに CssCommonElement を継承する。
import CssCommonElement from 'todo/cssCommon'; export default class App extends CssCommonElement {}
この状態で html テンプレートに
<template> <button class="btn btn-primary">Bootstrap ぼたーん</button> </template>
と記述すれば
ただし、欠点もある…というのも、CSS ではなくて Js (つまり JQuery を使ったDOM操作)を行う機能はうまく取り込めないらしい。
というのも shadow dom
使ってるせいで、id とかがうまく取れないことが原因のようだ…デスヨネ…
ちなみにこの対応で作ったものがコレ
参考にどうぞ