数日前に、SVGスプライトを作成するためのwebpackローダーであるsvg-sprite-loaderの完全に更新されたバージョンがリリースされました。 内部では、それがどのように機能し、開発者の生活を楽にするかについて詳しく説明します。
モジュールとしての画像
webpackの場合、どのファイルもモジュールです。 この概念に従って、ビューのインポート時にSVGを処理するようにsvg-sprite-loaderが構成されました。
import twitterLogo from './logos/twitter.svg';
画像の内容は<symbol>
変換され、モジュールに転送されます。これにより、シンボルとスプライトを操作するためのクライアントコードが生成されます。 このコードは、プログラムの実行中に通常のモジュールとして呼び出されます。 結果のコードは次のようになります。
// , <symbol> import SpriteSymbol from 'svg-sprite-loader/runtime/symbol'; // -, SVG import globalSprite from 'svg-sprite-loader/runtime/browser-sprite'; // const symbol = new SpriteSymbol({ /* symbol data */ }); // globalSprite.add(symbol); // SpriteSymbol export default symbol;
したがって、最初はプレーンテキストであるSVGファイルは、フィールドid
、 viewBox
、およびcontent
を持つオブジェクトになり、後でマークアップ<svg><use xlink:href="#id"></svg>
viewBox
<svg><use xlink:href="#id"></svg>
ます。 ただし、このようなリンクが機能するには、すべてのキャラクターを含むスプライトがページの一部である必要があります。 すべての文字を格納するglobalSpriteシングルトンオブジェクトを覚えていますか? そのコードは次のようになります。
import BrowserSprite from '…'; const sprite = new BrowserSprite(); document.addEventListener('DOMContentLoaded', () => { sprite.mount(document.body); }); export default sprite;
つまり、 DOMContentLoaded
イベントDOMContentLoaded
とすぐに、スプライトがページに自動的に挿入されDOMContentLoaded
。 1行のイメージインポートで、それをオブジェクトに変換し、スプライトを作成しました。スプライト自体は、必要なときに必要な場所に描画されます。 便利に。 ただし、シンボルを手動で参照する必要があります。
この問題は、テンプレートエンジンを使用して解決できます。 Reactの例を使用して、スプライトシンボルを描画するコンポーネントを作成します。
// icon.jsx export default function Icon({glyph, viewBox = '0 0 16 16', className = 'icon', …props}){ return ( <svg className={className} viewBox={viewBox} {…props}> <use xlinkHref={`#${glyph}`} /> </svg> ); }
ローダーとの組み合わせで、その使用は次のようになります。
import Icon from './icon.jsx'; import twitterLogo from './logos/twitter.svg'; <Icon glyph={twitterLogo.id} viewBox={twitterLogo.viewBox} />
便利に。 ただし、キャラクターのIDとviewBoxを指定する必要があります。 しかし、SVGをインポートするときに、返されるのはシンボルオブジェクトではなく、レンダリングにこのシンボルを使用するコンポーネントである場合はどうでしょうか。 これは、SVGイメージ上でバインディングを生成するNode.jsモジュールへのパスを示すruntimeGenerator
オプションのおかげで可能です。 このようなジェネレーターの例は、 ここにあります 。 次のコードが生成されます。
import React from 'react'; import SpriteSymbol from 'runtime/symbol'; import globalSprite from 'runtime/global-browser-sprite'; import Icon from './icon.jsx'; const symbol = new SpriteSymbol({ /* symbol data */ }); globalSprite.add(symbol); export default function TwitterIcon({…props}) { return <Icon glyph={symbol.id} viewBox={symbol.viewBox} {…props} />; }
そして、画像をインポートすると、事前定義されたプロパティを持つReactコンポーネントがすでに返されます:
import TwitterLogo from './logos/twitter.svg'; render( <div> <TwitterLogo width="100" /> <TwitterLogo fill="red" /> <TwitterLogo fill="blue" style={{width: 600}} /> </div>, document.querySelector('.app') );
便利に。 そして、これらすべてをインポートの1行で行います。
サーバー側のレンダリング
ブラウザでオンザフライでスプライトを作成することは確かに便利ですが、コードレンダリングUIがサーバー上で機能する場合はどうなりますか? DOMおよびブラウザイベントはありません。スプライトはどのようにレンダリングされますか? これらの目的のために、svg-sprite-loaderは、すべてのランタイム環境で機能する同形バージョンのスプライトの使用を提案します。 彼は環境について何も知らないので、手動でレンダリングを呼び出す必要があります。 サーバーでページをレンダリングする例:
import template from 'page-view.twig'; import globalSprite from 'svg-sprite-loader/runtime/sprite'; // id const symbols = globalSprite.symbols.reduce((acc, s) => { acc[s.id] = s; return acc; }, {}); // '<svg><symbol id="…">…</symbol>…</svg>' const sprite = sprite.stringify(); const content = template.render({ sprite, symbols });
スプライトを描画するには、 sprite
変数を表示し、 symbols
オブジェクトを使用してsymbols
を挿入する必要があります。
// layout.twig <body> {{ sprite }} // pages/about.twig <svg viewBox="{{ symbols.twitter.viewBox }}"> <use xlink:href="#{{ symbols.twitter.id }}" /> </svg> </body>
Reactの場合、すべてがブラウザーと同じように機能し、インポート時にコンポーネントをコンパイルできます。
別個のファイルとしてのスプライト
しかし、マークアップで<svg><use … /></svg>
コンストラクトを<svg><use … /></svg>
できない場合、または多くの手直しが必要な場合はどうでしょうか? SPAを作成しない場合は、マークアップからではなくスタイルからインターフェイスイメージをインポートする方が論理的であるため、誰もがSVGをバックグラウンドイメージとして使用することにすでに慣れています。
この場合、特別なモードが提供されます。これはまったく異なる方法で機能し、追加のプラグイン(ローダーに付属)が必要です。 そのようなインポートがあるとします:
.logo { backgroung-image: url(./logos/twitter.svg); }
ローダーはプラグインと組み合わせて次のことを行います。
すべての画像は
<symbol>
変換され、スプライトに配置されます。スプライトは別個のファイル(デフォルトではsprite.svg)として作成されます。
- すべての画像インポートは、最後にシンボルのIDを持つスプライトパスに置き換えられます。
.logo { backgroung-image: url(sprite.svg#twitter); }
このアプローチでは、 SVGスタック手法を適用できます。これは、Safari(モバイルおよびデスクトップ)および4.4.4までのAndroidブラウザーを除くすべてのブラウザーでサポートされています。 しかし、いつものようにポリフィルがあります。
自動設定
ローダーは、主なことを理解するのに十分な環境の知識を持っています。
- 抽出モード-SVGがCSS / SCSS / LESS / Stylus / HTMLからインポートされた場合-スプライトは別のファイルとして作成されます。
- 環境-ブラウザのwebpackによってコードが収集された場合( ターゲット:browser )、 ブラウザのスプライトモジュールが使用されます。 それ以外の場合、同形バージョン。
- モジュールのエクスポート形式-webpack 1の場合、ローダーはそのようなエクスポート
module.exports = …
生成しますmodule.exports = …
以前のexport default …
これは、ほとんどの場合、ローダーのデフォルト設定で十分であることを意味します。
// webpack 1 module: { loaders: [ { test: /\.svg$/, loader: 'svg-sprite-loader' } ] } // webpack 2 module: { rules: [ { test: /\.svg$/, loader: 'svg-sprite-loader' } ] }
他に何
- ローダーをビットマップ画像(pngまたはjpg)に設定すると、base64でエンコードされ、
<svg><image xlink:href="base64data"></svg>
ラップされます。 これは、開発中にロゴ/アイコンのベクターバージョンがまだ描画されておらず、結果を表示する必要がある場合に便利です。 - ブラウザーのランデブーモジュールは、内部でSVGスプライトを操作する際の多くの問題を解決します。 その構成とソースコードを参照してください。
- 抽出ローダーモードでは、 任意の数のスプライトまたは各チャンクのスプライトを作成できます。