마크업 언어
앞에서 설명한 것처럼 미니 앱은 일반 HTML이 아닌 HTML의 방언으로 작성됩니다. Vue.js 텍스트 보간 및 디렉티브를 다뤄본 적이 있다면 바로 익숙해질 것입니다. 하지만 그보다 훨씬 이전에 XML 변환(XSLT)에서 유사한 개념이 존재했습니다. 아래는 WeChat의 WXML 코드 샘플을 보여주지만, 모든 미니 앱 플랫폼(예: Alipay의 AXML, Baidu의 Swan Element, ByteDance의 TTML(DevTools에서는 Bxml이라고 함), Quick App의 HTML)에 동일한 개념이 적용됩니다. Vue.js와 마찬가지로 기본적인 미니 앱 프로그래밍 개념은 모델-뷰-뷰 모델(MVVM)입니다.
데이터 결합
데이터 결합은 Vue.js의 텍스트 보간에 해당합니다.
<!-- wxml -->
<view>{{message}}</view>
// page.js
Page({
data: {
message: "Hello World!",
},
});
목록 렌더링
목록 렌더링은 Vue.js v-for
디렉터리와 같이 작동합니다.
<!-- wxml -->
<view wx:for="{{array}}">{{item}}</view>
// page.js
Page({
data: {
array: [1, 2, 3, 4, 5],
},
});
조건부 렌더링
조건부 렌더링은 Vue.js의 v-if
디렉터리와 같이 작동합니다.
<!-- wxml -->
<view wx:if="{{view == 'one'}}">One</view>
<view wx:elif="{{view == 'two'}}">Two</view>
<view wx:else="{{view == 'three'}}">Three</view>
// page.js
Page({
data: {
view: "three",
},
});
템플릿
HTML 템플릿의 content
클론을 명시적으로 요구하는 대신 WXML 템플릿은 템플릿 정의에 연결된 is
속성을 통해 선언적으로 사용할 수 있습니다.
<!-- wxml -->
<template name="person">
<view>
First Name: {{firstName}}, Last Name: {{lastName}}
</view>
</template>
<template is="person" data="{{...personA}}"></template>
<template is="person" data="{{...personB}}"></template>
<template is="person" data="{{...personC}}"></template>
// page.js
Page({
data: {
personA: { firstName: "Alice", lastName: "Foo" },
personB: { firstName: "Bob", lastName: "Bar" },
personC: { firstName: "Charly", lastName: "Baz" },
},
});
스타일 지정
스타일 지정은 CSS 언어로 이루어집니다. WeChat의 이름은 WXSS입니다.
Alipay에서는 ACSS, Baidu에서는 간단히 CSS라고 하며, ByteDance에서는 TTSS라고 합니다.
두 가지 방법의 공통점은 반응형 픽셀로 CSS를 확장한다는 점입니다. 일반 CSS를 작성할 때 개발자는 너비와 픽셀 비율이 다른 다양한 휴대기기 화면에 맞게 조정할 수 있도록 모든 픽셀 단위를 변환해야 합니다. TTSS는 rpx
단위를 기본 레이어로 지원합니다. 즉, 미니 앱이 개발자의 작업을 인계받고 지정된 화면 너비 750rpx
에 따라 개발자를 대신하여 단위를 변환합니다. 예를 들어 화면 너비가 393px
이고 기기 픽셀 비율이 2.75
인 Pixel 3a 휴대전화에서 반응형 200rpx
는 Chrome DevTools로 검사할 때 실제 기기에서 104px
가 됩니다(393px / 750rpx * 200rpx ≈ 104px). Android에서는 동일한 개념을 밀도 독립형 픽셀이라고 합니다.
/* app.wxss */
.container {
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
padding: 200rpx 0; /* ← responsive pixels */
box-sizing: border-box;
}
구성요소 (이후 참고)는 Shadow DOM을 사용하지 않으므로 페이지에 선언된 스타일은 모든 구성요소에 도달합니다. 일반적인 스타일시트 파일 구성은 전역 스타일의 루트 스타일시트 하나와 미니 앱의 각 페이지에 고유한 개별 페이지별 스타일시트로 구성됩니다. 스타일은 @import
CSS at-rule처럼 작동하는 @import
규칙을 사용하여 가져올 수 있습니다. HTML과 마찬가지로 동적 텍스트 보간을 포함하여 스타일을 인라인으로 선언할 수도 있습니다(이전 참고).
<view style="color:{{color}};" />
스크립트 작성
미니 앱은 JavaScript의 '안전한 하위 집합'을 지원하며, 여기에는 CommonJS 또는 RequireJS를 상기시키는 다양한 구문을 사용하는 모듈을 위한 지원이 포함됩니다.
JavaScript 코드는 eval()
를 통해 실행할 수 없으며 new Function()
로 함수를 만들 수 없습니다. 스크립트 실행 컨텍스트는 기기의 경우 V8 또는 JavaScriptCore이고 시뮬레이터의 경우 V8 또는 NW.js입니다. 빌드 타겟이 이전 WebView 구현이 있는 운영체제인 경우 특정 DevTools가 코드를 ES5로 자동으로 트랜스파일하므로(나중에 참고) 일반적으로 ES6 이상 구문으로 코딩할 수 있습니다. 슈퍼 앱 제공업체의 문서에서는 스크립트 언어를 JavaScript와 혼동해서는 안 되며 JavaScript와 구별된다고 명시적으로 언급합니다. 그러나 이 문구는 주로 모듈이 작동하는 방식, 즉 아직 표준 ES 모듈을 지원하지 않는다는 것을 나타냅니다.
앞서 언급했듯이 미니 앱 프로그래밍 개념은 모델-뷰-뷰모델(MVVM)입니다. 로직 레이어와 뷰 레이어는 서로 다른 스레드에서 실행되므로 장기 실행 작업으로 인해 사용자 인터페이스가 차단되지 않습니다. 웹 용어로 웹 워커에서 실행되는 스크립트라고 생각할 수 있습니다.
WeChat의 스크립트 언어는 WXS, Alipay의 SJS, ByteDance의 SJS라고 합니다.
Baidu는 JS를 언급할 때 이를 언급합니다. 이러한 스크립트는 WeChat의 <wxs>
와 같은 특수한 종류의 태그를 사용하여 포함해야 합니다. 반면 빠른 앱은 일반 <script>
태그와 ES6 JS 구문을 사용합니다.
<wxs module="m1">
var msg = "hello world";
module.exports.message = msg;
</wxs>
<view>{{m1.message}}</view>
모듈은 src
속성을 통해 로드하거나 require()
를 통해 가져올 수도 있습니다.
// /pages/tools.wxs
var foo = "'hello world' from tools.wxs";
var bar = function (d) {
return d;
};
module.exports = {
FOO: foo,
bar: bar,
};
module.exports.msg = "some msg";
<!-- page/index/index.wxml -->
<wxs src="./../tools.wxs" module="tools" />
<view>{{tools.msg}}</view>
<view>{{tools.bar(tools.FOO)}}</view>
// /pages/logic.wxs
var tools = require("./tools.wxs");
console.log(tools.FOO);
console.log(tools.bar("logic.wxs"));
console.log(tools.msg);
JavaScript 브리지 API
미니 앱을 운영체제와 연결하는 JavaScript 브리지를 통해 OS 기능을 사용할 수 있습니다 (강력한 기능에 액세스하기 참고). 또한 여러 편의 메서드를 제공합니다. 개요를 보려면 WeChat, Alipay, Baidu, ByteDance, Quick App의 다양한 API를 확인하세요.
모든 플랫폼에서 웹사이트 caniuse.com에서 영감을 받은 것처럼 보이는 이름의 canIUse()
메서드(실제로 이렇게 호출됨)를 제공하므로 기능 감지는 간단합니다. 예를 들어 ByteDance의 tt.canIUse()
를 사용하면 API, 메서드, 매개변수, 옵션, 구성요소, 속성에 대한 지원 여부를 확인할 수 있습니다.
// Testing if the `<swiper>` component is supported.
tt.canIUse("swiper");
// Testing if a particular field is supported.
tt.canIUse("request.success.data");
업데이트
미니 앱에는 표준화된 업데이트 메커니즘이 없습니다(잠재적 표준화에 관한 논의). 모든 미니 앱 플랫폼에는 미니 앱 개발자가 미니 앱의 새 버전을 업로드할 수 있는 백엔드 시스템이 있습니다. 그러면 슈퍼 앱은 해당 백엔드 시스템을 사용하여 업데이트를 확인하고 다운로드합니다. 일부 슈퍼 앱은 미니 앱 자체가 업데이트 흐름에 영향을 줄 수 있는 방법이 전혀 없이 백그라운드에서 완전히 업데이트를 실행합니다. 다른 슈퍼 앱은 미니 앱 자체를 더 세부적으로 제어할 수 있습니다.
정교한 프로세스의 예로 다음 단락에서는 미니 앱을 위한 WeChat의 업데이트 메커니즘을 자세히 설명합니다. WeChat은 다음 두 가지 시나리오에서 사용 가능한 업데이트를 확인합니다.
- WeChat은 WeChat이 실행되는 동안 최근에 사용한 미니 앱의 업데이트를 정기적으로 확인합니다. 업데이트가 발견되면 업데이트가 다운로드되고 사용자가 다음에 미니 앱을 콜드 스타트할 때 동기식으로 적용됩니다. 미니 앱을 콜드 스타트하는 경우는 사용자가 미니 앱을 열었을 때 미니 앱이 실행 중이 아니었던 경우입니다(WeChat은 미니 앱이 백그라운드에서 5분 동안 실행된 후 강제 종료함).
- WeChat은 미니 앱이 콜드 스타트될 때도 업데이트를 확인합니다. 사용자가 오랫동안 열지 않은 미니 앱의 경우 업데이트가 동기식으로 확인되고 다운로드됩니다. 업데이트가 다운로드되는 동안 사용자는 기다려야 합니다. 다운로드가 완료되면 업데이트가 적용되고 미니 앱이 열립니다. 네트워크 연결이 좋지 않아 다운로드에 실패하더라도 미니 앱은 열립니다. 사용자가 최근에 연 미니 앱의 경우 잠재적인 업데이트가 백그라운드에서 비동기식으로 다운로드되며 사용자가 다음에 미니 앱을 콜드 스타트할 때 적용됩니다.
미니 앱은 UpdateManager
API를 사용하여 이전 업데이트를 선택할 수 있습니다. 다음과 같은 기능을 제공합니다.
- 업데이트 확인이 완료되면 미니 앱에 알립니다.
(
onCheckForUpdate
) - 업데이트가 다운로드되고 사용 가능한 경우 미니 앱에 알립니다.
(
onUpdateReady
) - 업데이트를 다운로드할 수 없는 경우 미니 앱에 알립니다.
(
onUpdateFailed
) - 미니 앱이 사용 가능한 업데이트를 강제 설치할 수 있도록 허용합니다. 이렇게 하면 앱이 다시 시작됩니다. (
applyUpdate
)
WeChat은 백엔드 시스템에서 미니 앱 개발자를 위한 추가 업데이트 맞춤설정 옵션도 제공합니다. 1. 한 가지 옵션을 사용하면 개발자가 이미 특정 최소 버전의 미니 앱이 설치된 사용자의 동기식 업데이트를 선택 해제하고 대신 업데이트를 비동기식으로 강제할 수 있습니다. 2. 개발자는 최소 필수 버전의 미니 앱을 설정할 수도 있습니다. 이렇게 하면 최소 필수 버전보다 낮은 버전에서 비동기 업데이트가 발생하면 업데이트를 적용한 후 미니 앱이 강제로 새로고침됩니다. 또한 업데이트 다운로드에 실패하면 이전 버전의 미니 앱 열기도 차단됩니다.