LoginSignup
100
61

More than 5 years have passed since last update.

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

Last updated at Posted at 2019-04-16

明日の 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 やる

100
61
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
100
61