Next.js + AMP + typescript + styled-components ( + storybook)でやったことと気をつけること
- Next.jsでAMP化するときは、 pagesのコンポーネントに対して、nextAmpでwithAmpをimportし、withAmpで囲う。
import { withAmp, useAmp } from "next/amp";
- withLayoutも使いたいときはそれも囲う
withAmp(withLayout(Index), { hybrid: true });
hybrid: trueをつけているときは、URLに
?amp=1
をつけているときだけAMP化されたHTMLが返るgetInitialProps
はデータをfetchしてSSRしてくれるのでAMPで問題なく動く。amp-customのscriptソースは、_document.tsxで
内に記述する。 これは、理想的にはそれを使うコンポーネント内で指定したいが、複数呼び出すと複数head内にscriptが記述されてしまうのでよくない。amp-customのstyleは、_documentのgetInitialPropsでstyled-componentsのServerStyleSheetからstylesheetを文字列に直し、inlineCssとしてSSR時にhtml内に吐き出すように書く。
static getInitialProps({ renderPage }: { renderPage: any }) { const sheet = new ServerStyleSheet(); const page = renderPage((App: any) => (props: any) => sheet.collectStyles(<App {...props} />), ); const stylesheets = [...sheet.getStyleElement()]; const inlineCss = stylesheets.reduce( (inlineStyles, currentStylesheet) => currentStylesheet ? `${inlineStyles}${ (currentStylesheet.props as any).dangerouslySetInnerHTML.__html }` : inlineStyles, "", ); return { ...page, inlineCss }; }
<style amp-custom="">{(this.props as any).inlineCss}</style>
- ampのカスタムエレメント向けに型を用意する ampのカスタムエレメントやon属性はreact-domが型として未定義の情報なので、jsx.d.tsというような形で型情報を用意する。
declare namespace JSX { interface AmpHtml { children: React.ReactNode; amp?: any; } interface IntrinsicElements { html: AmpHtml; } }
必要な型情報は追加していく。
ampでcssの擬似要素に
content: ""
は許容されてない。 iconなどはicon用の画像をコンポーネント別に用意する必要がある。storybookで見る
preview-head.html
で headタグは足せるので、amp向けのscriptを追加は可能。ただし動作は安定しない。yarn dev の developビルドだと__NEXT_DATAのようなnext.js向けのjavascriptがhtml内にinsertされるので注意。出力したHTMLをamp-validatorとかにかけてもエラーになる。yarn buildして閲覧したhtmlなら大丈夫。
amp-stateは_document.tsxで定義する。
<script type="application/json">
はreactだと内部に記述するjsonをjsonとして読み込まないので書くときには注意が必要。dangerouslySetInnerHtml
を使うか、文字列で記載するようにする。 srcで指定するようにして、外部からjsonを取得するのが迷わないのでオススメ。もしstyled-componentsを使っている場合は、on属性でイベントトリガーを記述する要素にstyleをあててはいけない。on要素がstyled-componentsのレンダリング時に(なぜか)破棄されてしまうので、直接div要素で指定する。
ampのstateを利用する際に
[class]
といった形式では記述できないので、data-amp-bind-class
といったdata-amp-bind-xxx
の形式を用いる。amp-stateは、デバッグコンソールで
AMP.printState()
を呼び出すと確認できる。ただし、URLで#development=1
を指定しておかないと見れないので注意。