ask-sdk-jsx-for-aplを使って、TypeScriptでAlexa APLを作る
AlexaLive 2020でask-sdk-jsx-for-aplが発表され、APLをついにReactライクに作れるようになりました。 Reactめっちゃ書いてるマンとしては見逃せないので、早速触ってみます。 Inst […]
目次
AlexaLive 2020でask-sdk-jsx-for-aplが発表され、APLをついにReactライクに作れるようになりました。
Reactめっちゃ書いてるマンとしては見逃せないので、早速触ってみます。
Install
以下の3ライブラリを追加します。
$ npm install -S ask-sdk-jsx-for-apl react react-dom
また、TypeScriptでReactを使うには@typesも必要なので追加しましょう。
$ npm install -D @types/react @types/react-dom
Check and update tsconfig.json
tsconfig.json
の設定が以下のようになっているか確認しましょう。
compilerOptions.jsx = 'react'
compilerOptions.esModuleInterop = true
こんな感じになっていればとりあえずOKです。
{
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"noImplicitAny": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"outDir": "./dist",
"esModuleInterop": true,
"jsx": "react",
"allowJs": false
},
"include": [
"./src/**/*"
]
}
Create APL by React
ということで早速APLを書いていきます。
import React from 'react';
import { APL, MainTemplate, Container, Text } from 'ask-sdk-jsx-for-apl';
/**
* Class component
*/
export class LaunchAplDocument extends React.Component {
private readonly launchMessage = 'Welcome to my first JSX for APL skill!';
render() {
return (
<APL theme="dark">
<MainTemplate>
<Container
alignItems="center"
justifyContent="spaceAround">
<Text
text={this.launchMessage}
fontSize="50px"
color="rgb(251,184,41)" />
</Container>
</MainTemplate>
</APL>
);
}
}
/**
* Functional Component
*/
export const LaunchAplDocumentFC: React.FC = () => {
const launchMessage = 'Welcome to my first JSX for APL skill!';
return (
<APL theme="dark">
<MainTemplate>
<Container
alignItems="center"
justifyContent="spaceAround">
<Text
text={launchMessage}
fontSize="50px"
color="rgb(251,184,41)" />
</Container>
</MainTemplate>
</APL>
);
}
作成したAPLは、AplDocument
クラスを利用してaddDirective
します。
import React from 'react'
import { RequestHandler } from 'ask-sdk-core';
import { AplDocument } from 'ask-sdk-jsx-for-apl';
import { LaunchAplDocument } from './LaunchRequest.apl';
export const LaunchRequestHandler: RequestHandler = {
async canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === "LaunchRequest"
},
async handle(handlerInput) {
return handlerInput.responseBuilder
.speak("Hello! It's a nice development. How are you?")
.reprompt("How are you?")
.addDirective(
new AplDocument(
<LaunchAplDocument />
).getDirective()
)
.getResponse()
}
}
export default LaunchRequestHandler
Trouble shooting
Error: TS2352: Conversion of type ‘RegExp’ to type ‘LaunchAplDocument’ may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to ‘unknown’ first.
.tsx
でJSXを書いていない場合、このエラーに遭遇します。
.ts
ファイルを必要に応じて .tsx
にリネームしましょう。
Error: TS2686: ‘React’ refers to a UMD global, but the current file is a module. Consider adding an import instead.
JSXが記述されているファイルでは、必ずimport React from 'react'
しましょう。
Test your APL Component by Jest
Reactなので、もちろんJestでテストできます。
import React from 'react';
import {
APL,
MainTemplate,
Container,
Text,
AplDocument
} from 'ask-sdk-jsx-for-apl'
const LaunchAplDocumentFC: React.FC = () => {
const launchMessage = 'Welcome to my first JSX for APL skill!';
return (
<APL theme="dark">
<MainTemplate>
<Container
alignItems="center"
justifyContent="spaceAround">
<Text
text={launchMessage}
fontSize="50px"
color="rgb(251,184,41)" />
</Container>
</MainTemplate>
</APL>
);
}
describe('AplDocument', () => {
const directive = new AplDocument(<LaunchAplDocumentFC />).getDirective()
it('should get RenderDocument Directive', () => {
expect(directive).toEqual({
"document": {
"import": [],
"mainTemplate": {
"items": [
{
"alignItems": "center",
"items": [
{
"color": "rgb(251,184,41)",
"fontSize": "50px",
"items": [],
"text": "Welcome to my first JSX for APL skill!",
"type": "Text"
}
],
"justifyContent": "spaceAround",
"type": "Container"
}
],
"parameters": []
},
"theme": "dark",
"type": "APL",
"version": "1.3"
},
"type": "Alexa.Presentation.APL.RenderDocument"
})
})
})
Use snapshot testing to check the component update
Jestには戻り値が変わったかどうかを検知できるスナップショットテストがあります。
import React from 'react';
import {
APL,
MainTemplate,
Container,
Text,
AplDocument
} from 'ask-sdk-jsx-for-apl'
const LaunchAplDocumentFC: React.FC = () => {
const launchMessage = 'Welcome to my first JSX for APL skill!';
return (
<APL theme="dark">
<MainTemplate>
<Container
alignItems="center"
justifyContent="spaceAround">
<Text
text={launchMessage}
fontSize="50px"
color="rgb(251,184,41)" />
</Container>
</MainTemplate>
</APL>
);
}
describe('AplDocument', () => {
const directive = new AplDocument(<LaunchAplDocumentFC />).getDirective()
it('should match snapshot', () => {
expect(directive).toMatchSnapshot()
})
})
一度テストを実行してスナップショットを作っておきます。
その後、Textのcolorをrgb(251,184,41)
から rgb(255,184,41)
に変更してみると、以下のようにJestでエラーがでます。
Snapshot name: `AplDocument should match snapshot 1`
- Snapshot - 1
+ Received + 1
@@ -14,11 +14,11 @@
"items": Array [
Object {
"alignItems": "center",
"items": Array [
Object {
- "color": "rgb(251,184,41)",
+ "color": "rgb(255,184,41)",
"fontSize": "50px",
"items": Array [],
"text": "Welcome to my first JSX for APL skill!",
"type": "Text",
},
29 | const directive = new AplDocument(<LaunchAplDocumentFC />).getDirective()
30 | it('should match snapshot', () => {
> 31 | expect(directive).toMatchSnapshot()
| ^
32 | })
33 | it('should get RenderDocument Directive', () => {
想定している変更であれば、-u
オプションを使ってスナップショットテストを更新しましょう。もしそうでない場合は・・・バグなので要修正です。