62
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

posted at

updated at

Organization

AMP で任意の JS を実行できる amp-script を試してみた

明日の AMP Conf のための事前に動かしてみた。

amp-script とは何か

今まで https://github.com/ampproject/amphtml に登録された一部のJSしか出来なかったAMPだが、amp-script を使うと任意の JS を実行できる。ただし、 WebWorker コンテキストの中でのみ。

本来ならDOMが存在しないWebWorkerだが、しかしDOMに触れないわけではない。 WebWorker の中に DOM と似たようなオブジェクトが実装されており、それを操作することでメインスレッドのJSに反映される。

この DOM がすごい2018: worker-dom - mizchi's blog

amp-script を導入する

static/index.html
  <head>
    <!-- ... -->
    <script async src="https://cdn.ampproject.org/v0.js"></script>
    <script
      async
      custom-element="amp-script"
      src="https://cdn.ampproject.org/v0/amp-script-0.1.js"
    ></script>
  </head>
  <body>
    <amp-script layout="container" src="/main.js">
      <button id="hello">Insert Hello World!</button>
    </amp-script>
  </body>
static/main.js
const button = document.getElementById("hello");
button.addEventListener("click", () => {
  const el = document.createElement("h1");
  el.textContent = "Hello World!";
  document.body.appendChild(el);
});

このコードは実際には main-thread で実行されておらず web-worker での実行されている。
ここで具体的にどういうコードを書けるかは https://github.com/ampproject/worker-dom の demo を参照

この例は単純すぎるDOM操作だが、 preact も動くとのこと。 React が動くは不明だが、worker-dom のソースコードを読んだ限り考慮されてはいる。

AMP用 CORS サーバーを立てる

このままではまだ動かない。このコードを AMP として動かすには、AMP用に動くことを証明する Header を付与する必要がある。

CORS in AMP - amp.dev を参考に、雑に node サーバーを立てた。

server.js
const express = require("express");
const app = express();

app.set("port", process.env.PORT || 3000);

app.use((req, res, next) => {
  const host = req.get("host");
  const protocol = host.startsWith("localhost") ? "http" : "https";
  const origin = protocol + "://" + req.get("host");
  res.set("Access-Control-Allow-Origin", origin);
  res.set("AMP-Access-Control-Allow-Source-Origin", origin);
  res.set(
    "Access-Control-Allow-Headers",
    "Origin, X-Requested-With, Content-Type, Accept"
  );
  res.set("Access-Control-Allow-Methods", "GET, POST, OPTIONS, HEAD, PUT");
  res.set("Access-Control-Allow-Credentials", "true");
  next();
});

app.use(express.static(__dirname + "/static"));

app.listen(app.get("port"), function() {
  console.log("Listening on port " + app.get("port"));
});
package.json
{
  "name": "tryamp",
  "version": "1.0.0",
  "main": "index.js",
  "author": "mizchi <miz404@gmail.com>",
  "license": "MIT",
  "scripts": {
    "now-start": "node server.js"
  },
  "dependencies": {
    "express": "^4.16.4"
  }
}

(npm install などは略)

こういう構成を意図してる。

server.js
package.json
static/
  hello.js
  index.html

ローカルで動くのもなんなので now.sh にデプロイ

npm i -g now
now deploy

https://tryamp-ywasobhymt.now.sh/ にデプロイした。

開発者フラグを立てる

(この節は将来的に不要)

まだ動かない。 https://tryamp-ywasobhymt.now.sh/ (または localhost のサーバー) で DevTools を開いて AMP.toggleExperiment('amp-script') を eval する。この状態でリロードするとやっと有効になる

おわり

次は preact + typescript やる

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
62
Help us understand the problem. What are the problem?