Node.js AMP Optimizer ๊ฐ์ด๋
์ด ๊ฐ์ด๋์์๋ AMP Optimizer์ Node.js ๋ฒ์ ์ ์ค์ ํ๊ณ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ์ค๋ช ํฉ๋๋ค.
์ค์
๋ค์์ ์ฌ์ฉํ์ฌ NPM์ ํตํด ์ค์นํฉ๋๋ค.
npm install @ampproject/toolbox-optimizer
์ฌ์ฉ
AMP Optimizer API๋ HTML ๋ฌธ์์ด์ ์ ๋ ฅํ์ฌ ํด๋น HTML ๋ฌธ์์ด์ ์ต์ ํ๋ ๋ฒ์ ์ ๋ฐํํฉ๋๋ค. ๊ธฐ๋ณธ ์ฌ์ฉ ์ฌ๋ก๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
const AmpOptimizer = require('@ampproject/toolbox-optimizer');
// create the AMP Optimizer instance
const ampOptimizer = AmpOptimizer.create();
const html = '<h1>Hello World!</h1>';
const optimizedHtml = await ampOptimizer.transformHtml(html);
๋น๋ ํ์์ผ๋ก ์ต์ ํ๋ AMP ์์ฑ
์ ์ ์ฌ์ดํธ์ ๊ฒฝ์ฐ ์ฌ์ดํธ ๋น๋ ์ ๋น๋ ํ์์ผ๋ก AMP ํ์ด์ง๋ฅผ ์ต์ ํํ๋ ๊ฒ์ด ์ต์ ์ ๋๋ค. ๋น๋๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํด๋น ํ์ด์ง๋ฅผ Gulp.js์ ํตํฉํ๋ ์์๋ฅผ ํ์ธํด ๋ณด์ธ์. ์ด ์์์๋ ์ฌ์ฉ์ ์ง์ ๋ณํ์ด ์ถ๊ฐ๋์ด src ํด๋์ ๋ชจ๋ HTML ํ์ผ์ ์ต์ ํํฉ๋๋ค.
const {src, dest} = require('gulp');
const through2 = require('through2');
const AmpOptimizer = require('@ampproject/toolbox-optimizer');
const ampOptimizer = AmpOptimizer.create();
function build(cb) {
return src('src/*.html')
.pipe(
through2.obj(async (file, _, cb) => {
if (file.isBuffer()) {
const optimizedHtml = await ampOptimizer.transformHtml(
file.contents.toString()
);
file.contents = Buffer.from(optimizedHtml);
}
cb(null, file);
})
)
.pipe(dest('dist/'));
}
exports.default = build;
๋ ๋ ํ์
๋์ ํ์ด์ง์ ๊ฒฝ์ฐ ์๋ฒ์์ ํ์ด์ง๋ฅผ ๋ ๋๋งํด์ผ ํ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค. ์ด๋ฐ ๊ฒฝ์ฐ์ ํ์ด์ง ๋ ๋๋ง ํ AMP Optimizer๋ฅผ ์คํํ ์ ์์ต๋๋ค. Express.js ์๋ฒ๋ก์ ์ํ ํตํฉ์ ํ์ธํ์ธ์. AMP ์ต์ ํ๋ฅผ Express ๋ผ์ฐํฐ๋ก ํตํฉํ๋ ํ ๊ฐ์ง ๋ฐฉ์์ ํ ํ๋ฆฟ์ด ๋ ๋๋ง๋ ํ ์ฝ๋ฐฑํ๋ ๊ฒ์ ๋๋ค.
const express = require('express');
const router = express.Router();
const AmpOptimizer = require('@ampproject/toolbox-optimizer');
const ampOptimizer = AmpOptimizer.create();
router.get('/', (req, res) => {
const locals = {title: 'Express with AMP Optimizer'};
res.render('index', locals, async (err, html) => {
const optimizedHtml = await ampOptimizer.transformHtml(html);
res.send(optimizedHtml);
});
});
module.exports = router;
๊ตฌ์ฑ
AMP Optimizer๋ ๋๋ค์์ ๊ฒฝ์ฐ ์ ์ ํ ์๋ํ๋ ํฉ๋ฆฌ์ ์ธ ๊ธฐ๋ณธ ๊ตฌ์ฑ์ ์ ๊ณตํฉ๋๋ค. ํ์ง๋ง ํน์ ์ฌ์ฉ ์ฌ๋ก์ ๋ฐ๋ผ ๋ณํ์ ์ฌ์ฉ์ ์ง์ ํ ์๋ ์์ต๋๋ค. ๊ฐ๋ฅํ ๋ชจ๋ ์ต์ ์ ์ ์ฒด ๋ชจ๊ณก์ ์ฌ๊ธฐ์์ ํ์ธํ์ธ์.
๋ช ๊ฐ์ง ์ค์ ์ต์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
lts: true๋ AMP ๋ฐํ์ ๋ฐ ์ปดํฌ๋ํธ์ ์์ ์ ์ธ ์ฅ๊ธฐ URL ํ์ฑํ ์ ์ฌ์ฉ๋ฉ๋๋ค.verbose: true๋ ์ธ๋ถ์ ์ธ ๋๋ฒ๊ทธ ์ถ๋ ฅ ๊ฐ์ ์ฌ์ฉ๋ฉ๋๋ค. ํนํ AMP ์์ฉ๊ตฌ๋ฅผ ์ญ์ ํ ์ ์๋ ์ด์ ๋ฅผ ์๋ณํ๋ ๋ฐ ์ ์ฉํฉ๋๋ค.imageOptimizer: ์ฃผ์ด์ง ์ด๋ฏธ์ง src์ srcset URL์ ๊ณ์ฐํ๋ ํจ์๋ฅผ ์ ๊ณตํ์ฌ ์๋ ์ด๋ฏธ์ง srcset ์์ฑ์ ํ์ฑํํฉ๋๋ค. ํจ์๋ ์ฃผ์ด์ง ๋๋น์src์ด๋ฏธ์ง ๋ฒ์ ์ ๊ฐ๋ฆฌํค๋ URL์ ๋ฐํํด์ผ ํฉ๋๋ค. ์ด๋ฏธ์ง๊ฐ ์ง์๋์ง ์๋ ๊ฒฝ์ฐ ๊ฑฐ์ง ๊ฐ์(Falsy) ๊ฐ์ ๋ฐํํด์ผ ํฉ๋๋ค. ๋ค์ ์น์ ์์ ์์ธํ ๋ด์ฉ์ ํ์ธํ์ธ์.
์ด๋ฏธ์ง ์ต์ ํ
AMP Optimizer๋ layout ์ ์๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ฃผ์ด์ง amp-img์ srcset ๊ฐ์ ์์ฑํ ์ ์์ต๋๋ค. ์ ์ ํ ์๋ํ๋ ค๋ฉด ์ด๋ฏธ์ง์ src๋ฅผ ๋งคํํ๋ ํจ์ ๋ฐ ํฌ๊ธฐ๊ฐ ๋ณ๊ฒฝ๋ srcset ์์ค ๊ฐ์ width๋ฅผ ์ ๊ณตํด์ผ ํฉ๋๋ค. ์ด๋ฏธ์ง ํฌ๊ธฐ ๋ณ๊ฒฝ์ AMP Optimizer๋ฅผ ํตํด ์ํ๋์ง ์์ต๋๋ค. ๋ฐ๋ผ์ ๋น๋ ํ์์ผ๋ก(์: ์ ์ ์ฌ์ดํธ) ๋๋ thumbor ๋ฑ์ ์ด๋ฏธ์ง ํธ์คํ
์๋น์ค๋ก ์ํ๋์ด์ผ ํฉ๋๋ค.
๋ค์์ src์ ์ด๋ฏธ์ง ๋๋น๋ฅผ ์ถ๊ฐํ ๊ตฌํ ์์์
๋๋ค.
const ampOptimizer = AmpOptimizer.create({
// parameters are the amp-img `src` and the `width` of the to be generated srcset source value
imageOptimizer: (src, width) => {
// we cannot rename if the image does not have a file extension
const index = src.lastIndexOf('.');
if (index === -1) {
// return null means we won't generate a srcset source value for this width
return null;
}
const prefix = src.substring(0, index);
const postfix = src.substring(index, src.length);
return `${prefix}.${width}w${postfix}`;
};
})
์ด ๊ตฌํ์ ์ฌ์ฉํ์ฌ AMP Optimizer๋ ๋ค์ amp-img ์ ์ธ์ ๋ณํํฉ๋๋ค.
<!-- Injects srcset for responsive layout -->
<amp-img
src="image1.png"
width="400"
height="800"
layout="responsive"
></amp-img>
<!-- Ignores existing srcset -->
<amp-img
layout="fill"
srcset="image-1x.png 1x,
image-2x.png 2x"
></amp-img>
๋ณํ๋ ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
<!-- Injects srcset for responsive layout -->
<amp-img
src="image1.png"
width="400"
height="800"
layout="responsive"
srcset="image1.470w.png 470w, image1.820w.png 820w, image1.1440w.png 1440w"
></amp-img>
<!-- Ignores existing srcset -->
<amp-img
layout="fill"
srcset="image-1x.png 1x,
image-2x.png 2x"
></amp-img>
layout=responsive ์ฌ์ฉ ์์๋ ์ต์ ์ด๋ฏธ์ง ํฌ๊ธฐ๋ฅผ ์ง์ ํ๋ ๋ฐ width ๋ฐ height ์์ฑ์ ์ฌ์ฉํฉ๋๋ค. ์๋ฅผ ๋ค์ด ๋ชจ๋ฐ์ผ์์ ํ์ด๋ก ์ด๋ฏธ์ง๋ฅผ ํ ๋ธ๋ฆฌ๋๋ก ํ์ํ๋ ค๋ฉด width=320์ด ํ์ํฉ๋๋ค. -
Written by @sebastianbenz