この前の技術書典3でWeb Componentsの本を頒布したんですが、その時にサークルのウェブサイトをPolymerを使って作ったのでその感想をまとめておこうかなと思います。
https://inutetraplus.netlify.com/
(画像が重いのは目をつぶってください…)
ちなみに、電子版をBOOTHでも販売してます。
イヌでもわかるWeb Components
作り方
今回はpolymer-starter-kit
という公式テンプレートを使いました。
Polymer CLIが必要なのでインストールしましょう。
npm install -g polymer-cli
あと、Polymer2はまだbowerを使っているので、入ってない人はこちらもインストールしましょう。
npm install -g bower
プロジェクトフォルダを作成し、テンプレートを生成しましょう。
mkdir my-app
cd my-app
polymer init polymer-2-starter-kit
polymer-starter-kitの中身
中身はこんな感じになってます。
├── README.md
├── bower.json
├── images
├── index.html
├── manifest.json
├── package.json
├── polymer.json
├── service-worker.js
├── src
│ ├── my-app.html
│ ├── my-icons.html
│ ├── my-view1.html
│ ├── my-view2.html
│ ├── my-view3.html
│ ├── my-view404.html
│ └── shared-styles.html
├── sw-precache-config.js
└── test
├── index.html
└── my-view1.html
Polymerで必要なものがだいたい一通り揃ってるとても優秀なスターターキット。
ルーティングやServiceWorkerの設定ファイルとかも生成されます。
src
配下のmy-app.html
がルートコンポーネントのファイルで、ルーティングや共通パーツ(ヘッダー、フッターなど)の読み込みなどを行います。
その他のmy-viewX.html
が各ページのコンポーネントです。HTML/CSS/JSをこれらのファイルの中に書きます。
ルーティングの設定
ルーティングはmy-app.html
に記述します。
スターターキットではapp-route
とiron-pages
というコンポーネントを使ってルーティングをしています。
<app-location
route="{{route}}"
url-space-regex="^[[rootPath]]">
</app-location>
<app-route
route="{{route}}"
pattern="[[rootPath]]:page"
data="{{routeData}}"
tail="{{subroute}}">
</app-route>
<iron-pages
selected="[[page]]"
attr-for-selected="name"
fallback-selection="view404"
role="main">
<my-view1 name="view1"></my-view1>
<my-view2 name="view2"></my-view2>
<my-view3 name="view3"></my-view3>
<my-view404 name="view404"></my-view404>
</iron-pages>
static get properties() {
return {
page: {
type: String,
reflectToAttribute: true,
observer: '_pageChanged',
},
routeData: Object,
subroute: String,
// This shouldn't be neccessary, but the Analyzer isn't picking up
// Polymer.Element#rootPath
rootPath: String,
};
}
static get observers() {
return [
'_routePageChanged(routeData.page)',
];
}
_routePageChanged(page) {
// If no page was found in the route data, page will be an empty string.
// Default to 'view1' in that case.
this.page = page || 'view1';
// Close a non-persistent drawer when the page & route are changed.
if (!this.$.drawer.persistent) {
this.$.drawer.close();
}
}
_pageChanged(page) {
// Load page import on demand. Show 404 page if fails
var resolvedPageUrl = this.resolveUrl('my-' + page + '.html');
Polymer.importHref(
resolvedPageUrl,
null,
this._showPage404.bind(this),
true);
}
_showPage404() {
this.page = 'view404';
}
ページコンポーネントの命名規則を変えたいときはvar resolvedPageUrl = this.resolveUrl('my-' + page + '.html');
の部分を変更します。
Header、Drawer
スターターキットではapp-layout
というコンポーネントを使ってレイアウトを構築しています。
これはPolymer公式のレイアウトコンポーネントで、マテリアルデザインっぽい感じになります。
これを使わないといけないというわけではないですが、今回のウェブサイト制作では、このレイアウトのまま作成しました。
<app-drawer-layout fullbleed narrow="{{narrow}}">
<!-- Drawer content -->
<app-drawer id="drawer" slot="drawer" swipe-open="[[narrow]]">
<app-toolbar>Menu</app-toolbar>
<iron-selector selected="[[page]]" attr-for-selected="name" class="drawer-list" role="navigation">
<a name="view1" href="[[rootPath]]view1">View One</a>
<a name="view2" href="[[rootPath]]view2">View Two</a>
<a name="view3" href="[[rootPath]]view3">View Three</a>
</iron-selector>
</app-drawer>
<!-- Main content -->
<app-header-layout has-scrolling-region>
<app-header slot="header" condenses reveals effects="waterfall">
<app-toolbar>
<paper-icon-button icon="my-icons:menu" drawer-toggle></paper-icon-button>
<div main-title>My App</div>
</app-toolbar>
</app-header>
<iron-pages
selected="[[page]]"
attr-for-selected="name"
fallback-selection="view404"
role="main">
<my-view1 name="view1"></my-view1>
<my-view2 name="view2"></my-view2>
<my-view3 name="view3"></my-view3>
<my-view404 name="view404"></my-view404>
</iron-pages>
</app-header-layout>
</app-drawer-layout>
使ってみた感想
- CLIがあって環境設定とか特になくても使えるのが嬉しい
- 学習コストは低いと思う(他のライブラリに比べれば)
- HTML/CSSにスコープが設定されて幸せ
- CSSとHTMLが近いので見通しが良い
- CSSで変数が使えるの嬉しい
- CSSをどこまで共通にするか悩んだ
- ルーティングまわりのイベントハンドリングがややこしい
- ServiceWorkerの設定とかもやりやすくて良い
- カルーセルなどのコンポーネントは少ないし挙動が怪しかったりするので、自分で実装したほうが良さそう
- 今後に期待