Nuxt.jsでAMP HTMLをgenerateする方法
エンジニア向けの記事です。それも、Nuxt.jsでgenerate(出力)するファイルをAMPにしたい!というエンジニア向けです。
前提
・特にamp用のmodulesとかは使いません。色んなところに落ちてるコードを引っ張って作った感じです。
・単一ファイルコンポーネントで作ってます。なのでCSSは「ページ用スタイル」「共通スタイル」みたいな感じで分かれてます。
・SCSS使ってます。共通スタイルはコンパイル後にstyleタグに突っ込みます。
コード
とにかくAMP化に必要な部分だけに絞ってます
/nuxt.config.js
やってること:ページ生成するときにAMP化するjsを呼び出してます
import ampify from './plugins/ampify'
...
export default {
mode: 'universal',
...
head: {
base: {
href: 'router.base'
},
...
link: [
{ hid: 'canonical', rel: 'canonical', href: '/' },
...
]
},
...
hooks: {
// This hook is called before serving the html to the browser
'render:route': (url, page, { req, res }) => {
page.html = ampify(page.html)
}
},
...
}
/pages/*.vue
やってること:ページごとにcanonical urlを最適なものに変えてます
※hrefはいい感じにフルパス入れといてください。ここをいい感じにする方法は今度別の記事で書きます
<template>
</template>
<script>
export default {
head() {
link: [{
hid: 'canonical',
rel: 'canonical',
href: `${process.env.SITE_URL}${this.$router.history.base}${this.$route.path}`
}]
}
}
</script>
/plugins/ampify.js
やってること:CSSとかJSとか色々整理してAMPとして使えるようにしてます。ここが一番のキモです。
※ファイル名は適当なのでなんでもいいです
const ampBoilerplate = '<style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style><noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>'
const fs = require('fs')
module.exports = (html) => {
// CSSを一つのstyleタグにまとめる
let styleConcat = ''
html = html.replace(/<style.*?>(.*?)<\/style>/gi, (_match, main) => {
styleConcat += main
return ''
})
// 共有CSSを最後に追加
const globalStyle = fs.readFileSync('assets/css/style.css', 'utf8')
html = html.replace('</head>', `<style amp-custom>${styleConcat}${globalStyle}</style></head>`)
// charsetを消す
html = html.replace(/@charset "UTF-8";/gi, '')
// AMP HTMLしか使わないので、amphtmlのlinkは消す
html = html.replace(/<link[^>]*rel="(?:amphtml)?"[^>]*>/gi, '')
// ⚡マークをHTMLタグに追加
html = html.replace(/<html/gi, '<html ⚡ id="html"')
// baseタグを上に持ってくる
let baseTag = ''
html = html.replace(/<base href="(.*?)">/gi, (_match) => {
baseTag = _match
return ''
})
html = html.replace('</title>', `</title>${baseTag}`)
// preloadとprefetchタグを消す
html = html.replace(/<link[^>]*rel="(?:preload|prefetch)?"[^>]*>/gi, '')
// ld+json以外のJSを消す
html = html.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, (match) => {
if (match.includes('type="application/json"') || match.includes('type="application/ld+json"') || match.includes('cdn.ampproject.org')) {
return match.replace(/"/g, '"')
}
return ''
})
// AMP用script読み込み準備
const ampScript = '<script async src="https://cdn.ampproject.org/v0.js"></script>'
// AMPボイラープレートとAMP用scriptをheadの終了直前には
html = html.replace('</head>', ampScript + ampBoilerplate + '</head>')
return html
}
/assets/scss/style.scss
好きなscssを書く(共通CSSとかの、最優先で効いてほしいスタイルをここで当てる)。
全ページにあたるので注意
/package.json
やること:パッケージ管理
※パッケージ管理はyarn使ってます。npm使っている人はファイル名とか違うのでご注意。
※他にも必要なパッケージあったらごめんなさい
{
...
"scripts": {
"dev": "node-sass --include-path assets assets/scss/style.scss assets/css/style.css --output-style compressed -w & nuxt",
"generate": "node-sass --include-path assets assets/scss/style.scss assets/css/style.css --output-style compressed & nuxt generate",
...
},
"dependencies": {
"nuxt": "^2.6.3",
...
},
"devDependencies": {
"fs": "^0.0.1-security",
"node-sass": "^4.13.1",
"sass-loader": "^7.1.0",
...
}
}
コマンド
yarn run dev
ローカルがAMP化して立ち上がります
yarn run generate
distにページが生成されます
まとめ
とりあえずamp化するための関数組んで、ビルドフックで呼び出せばOKです。
実際は他にもあった方がいいものとかがあるので、それは別の記事で解説します。
参考にしたサイト
https://medium.com/the-web-tub/making-a-website-with-nuxt-vue-and-amp-3ef904819de6
https://www.aintek.xyz/posts/create-amp-with-nuxtjs (non sslなので気をつけて)