마크업 언어
앞에서 설명한 것처럼 미니 앱은 일반 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}};" />
스크립트 작성
미니 앱은 CommonJS 또는 RequireJS를 연상시키는 다양한 문법을 사용하는 모듈에 대한 지원을 포함하는 JavaScript의 '안전한 하위 집합'을 지원합니다.
JavaScript 코드는 eval()
를 통해 실행할 수 없으며 new Function()
를 사용하여 함수를 만들 수 없습니다. 스크립트 실행 컨텍스트는 기기의 경우 V8 또는 JavaScriptCore이고 시뮬레이터의 경우 V8 또는 NW.js입니다. 빌드 타겟이 이전 WebView 구현이 있는 운영체제인 경우 특정 DevTools가 코드를 ES5로 자동으로 트랜스파일하므로(나중에 참고) 일반적으로 ES6 이상 구문으로 코딩할 수 있습니다. 슈퍼 앱 제공업체의 문서에서는 스크립트 언어를 JavaScript와 혼동해서는 안 되며 JavaScript와 구별된다고 명시적으로 언급합니다. 그러나 이 문구는 주로 모듈이 작동하는 방식, 즉 아직 표준 ES 모듈을 지원하지 않는다는 것을 나타냅니다.
앞서 언급했듯이 미니 앱 프로그래밍 개념은 model-view-viewmodel (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를 사용하여 이전 업데이트를 선택할 수 있습니다. 이 API는 다음과 같은 기능을 제공합니다.
- 업데이트 확인이 완료되면 미니 앱에 알립니다.
(
onCheckForUpdate
) - 업데이트가 다운로드되어 사용 가능해지면 미니 앱에 알립니다.
(
onUpdateReady
) - 업데이트를 다운로드할 수 없는 경우 미니 앱에 알립니다.
(
onUpdateFailed
) - 미니 앱이 사용 가능한 업데이트를 강제 설치하도록 허용하면 앱이 다시 시작됩니다.
(
applyUpdate
)
WeChat은 백엔드 시스템에서 미니 앱 개발자를 위한 추가 업데이트 맞춤설정 옵션도 제공합니다. 1. 한 가지 옵션을 사용하면 개발자가 이미 특정 최소 버전의 미니 앱이 설치된 사용자의 동기식 업데이트를 선택 해제하고 대신 업데이트를 비동기식으로 강제할 수 있습니다. 2. 개발자는 최소 필수 버전의 미니 앱을 설정할 수도 있습니다. 이렇게 하면 최소 필수 버전보다 낮은 버전에서 비동기 업데이트가 발생하면 업데이트를 적용한 후 미니 앱이 강제로 새로고침됩니다. 또한 업데이트 다운로드에 실패하면 이전 버전의 미니 앱 열기도 차단됩니다.