Chuyển đổi nhanh Web App có sẵn thành Zalo Mini App
Sau khi tìm hiểu về Zalo Mini App, bạn mong muốn có cho riêng mình một Mini App chạy trên Zalo, nhưng lại phân vân vì việc xây dựng một Mini App mới có thể sẽ tốn thêm thời gian, tài nguyên, kinh phí. Bạn nhớ ra rằng mình đã có một phiên bản Web App có thể hoạt động tốt trên mobile, tablet và mong muốn biến nó trở thành Mini App chạy trên Zalo nhanh chóng để tiết kiệm kinh phí, hoặc đơn giản để sử dụng tạm trong thời gian chờ cho một Mini App hoàn chỉnh được phát triển. Hiểu những mong muốn đó, Zalo Mini App đã hỗ trợ bạn thực hiện việc chuyển đổi web app có sẵn sang Mini App. Cùng theo dõi một số vấn đề hay gặp cần lưu ý khi thực hiện nhé.
I. Yêu cầu và chuẩn bị
Tất nhiên, yêu cầu tiên quyết là bạn cần có một project web app đã đảm bảo trải nghiệm tốt cho người dùng trên mobile và tablet. Tiếp đó cần tạo một Zalo Mini App, đặt một cái tên ấn tượng, logo và ảnh bìa chỉn chu để sẵn sàng được tiếp cận đến nhiều người dùng hơn trên Zalo Mini App Store, nếu chưa biết cách tạo Mini App thì có thể tham khảo tại đây nhé. Chuẩn bị xong rồi thì cùng tìm hiểu một số vấn đề thường gặp và lưu ý cần chú ý khi chuyển đổi web app thành Mini App thôi.
II. Phía client
1. Khởi tạo Zalo Mini App trên project có sẵn
Để khởi tạo Zalo Mini App trên project web app đã có sẵn. Đầu tiên bạn cần bộ dev tool: zmp-cli , tìm hiểu thêm cách cài đặt và sử dụng tại đây.
Sau khi đã cài đặt dev tools cần chuyển đến root folder của project, chạy lệnh:
zmp init
Ví dụ cần chuyển project my-app đặt tại ~/miniapp/my-app thành Mini App:
Sau khi đăng nhập thành công chọn Using ZMP to deploy only:
Giao diện sau khi deploy thành công:
Lúc này project của bạn sẽ được tạo thêm file .env và app-config.json tại root folder
File .env: chứa các biến môi trường cần thiết phục vụ cho việc deploy File app-config.json: được dùng để cấu hình chung cho Zalo Mini App.
Trong đó file app-config.json có cấu trúc như sau:
{
"app": {
"title": "My App",
"headerColor": "#1843EF",
"headerTitle": "My App Title",
"textColor": "white",
"leftButton": "back",
"statusBar": "normal",
"actionBarHidden": false
},
"debug": false,
"listCSS": [],
"listSyncJS": [],
"listAsyncJS": []
}
Trong đó, trường app chứa các trường headerTitle, headerColor, textColor, statusBar, actionBarHidden, leftButton được đùng để cấu hình thanh trạng thái và thanh điều hướng của Zalo Mini App. Ngoài ra các trường listCSS, listSyncJS, listAsyncJS sẽ được đề cập bên dưới. Xem thêm tại đây.
2. Cập nhật root element selector
Sau khi deploy, Mini App của bạn sẽ sử dụng index do Zalo Mini App tạo ra thay vì index file của project build ra, tại đây root element mặc định sẽ có id là “app”, nên nếu project của bạn có root element id khác, cần đổi lại root element selector ứng với id là "app"
Ví dụ với React 18:
const root = createRoot(document.getElementById("app"));
root.render(React.createElement(App));
3. Cấu hình module bundler
Một số vấn đề thường gặp đối với project tự build và deploy lên Zalo Mini App là không tải được các static files hay các module khi sử dụng code splitting, nguyên nhân có thể do public path chưa đúng. Bởi lẽ source code sau khi build sẽ được đưa lên cdn của Zalo, đặt trong folder tương ứng với Mini App Id, version, khi build bằng dev tools của Zalo Mini App, public path đã được config sẵn tương ứng với từng version của app, vậy đối với các project tự cấu hình build thì giải quyết th ế nào?
- Đối với project sử dụng Vite module bundler, đơn giản chỉ cần set base="./" trong file config
// vite.config.js
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
export default defineConfig({
plugins: [react()],
base: "./",
build: {
rollupOptions: {
output: {
entryFileNames: "assets/[name].[hash].module.js",
chunkFileNames: "assets/[name].[hash].module.js"
}
}
}
});
- Đối với Project đóng gói bằng webpack thì có chút khác biệt, cần chỉ rõ version của Mini App để chỉ đúng thư mục chứa các assets ứng với version, có thể sử dụng global variable __webpack_public_path__ của webpack để giải quyết vấn đề này, lấy version của Mini App đang chạy tại window.APP_VERSION, xem ví dụ sau:
import React from "react";
import { createRoot } from "react-dom/client";
import App from "./App";
/* eslint-disable */
__webpack_public_path__ = `./${window.APP_VERSION}/`;
const root = createRoot(document.getElementById("app"));
root.render(React.createElement(App));
4. Vấn đề không tải được module khi sử dụng dynamic import khi đóng gói bằng Vite trên iOS
Khi gặp lỗi không tải được trang khi sử dụng dynamic import trên iOS với project đóng gói bằng Vite, có thể tắt option polyfillModulePreload tại file config để khắc phục, như sau:
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
export default defineConfig({
plugins: [react()],
base: "./",
build: {
polyfillModulePreload: false,
rollupOptions: {
output: {
entryFileNames: "assets/[name].[hash].module.js",
chunkFileNames: "assets/[name].[hash].module.js"
}
}
}
});
5. Vấn đề về Router
Đối với project tự xử lý vấn đề routing của app, có thể gặp lỗi không tải được trang chủ hay khi navigate không tải được trang, nguyên nhân có thể do base URL mặc định không đúng, cần điều chỉnh lại thành /zapps/[APP_ID]
Ví dụ sử dụng react-router:
<BrowserRouter basename='/zapps/[ZALO_MINI_APP_ID]' />
Ví dụ sử dụng Reach-router:
<Router basepath='/zapps/[ZALO_MINI_APP_ID]' />
Tương tự với project Angular có thể config lại APP_BASE_HREF
import { Component, NgModule } from "@angular/core";
import { APP_BASE_HREF } from "@angular/common";
@NgModule({
providers: [{ provide: APP_BASE_HREF, useValue: "/zapps/[ZALO_MINI_APP_ID]" }]
})
class AppModule {}
6. Lưu ý về xác thực thông tin người dùng khi gọi API
Đổi với một số Mini App cần xác thực thông tin người dùng sau khi lấy được thông tin người dùng thông qua API của Zalo, bạn có thể định danh user khi request tới API bằng 1 trong những cách sau:
-
Sử dụng trực tiếp Access Token.
-
Tạo ra Authentication Token riêng cho hệ thống của bạn, chúng tôi khuyến nghị bạn nên sử dụng JWT - JSON Web Token.
Với tất cả ứng dụng Zalo Mini App, các API mặc định của trình duyệt sau sẽ không được hỗ trợ:
-
LocalStorage
-
SessionStorage
-
Cookie Vì vậy vui lòng sử dụng Header thay cho Cookie để truyền thông tin xác thực người dùng lên Server của bạn.
const API_URL = `https://yourapidomain.con/`;
fetch(API_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization: Bearer {Your JWT here}'
},
body: {}
});
7. Khai báo các assets cần thiết khi tải trang tại app-config.json
Như đã đề cập ở trên, sau khi deploy, Mini App sẽ sử dụng file index do hệ thống của Zalo Mini App tạo ra, nên cần liệt kê các files cần thiết để khởi tạo app, như css, js module,... bạn có thể xem các file cần thiết được khai báo tại file index.html được build ra trong chính project của bạn và liệt kê trong app-config tại các trường: listCSS, listSyncJS, listAsyncJS, như dưới đây
Ví dụ sau khi build hoàn tất, build folder (ở trong trường hợp này là dist) có cấu trúc như sau:
File index.html có nội dung như sau:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React</title>
<script
type="module"
crossorigin
src="./assets/index.cafa2549.module.js"
></script>
<link rel="stylesheet" href="./assets/index.3fce1f81.css" />
</head>
<body>
<div id="app"></div>
</body>
</html>
Quan sát file index.html sau khi build phía trên, nhận thấy index cần tải script ./assets/index.cafa2549.module.js và css file ./assets/index.3fce1f81.css, vậy ta cần khai báo đường dẫn tới 2 file này vào các trường tương ứng trong app-config.json như sau:
{
"app": {
"title": "My App",
"headerColor": "#ffffff",
"leftButton": "back",
"textColor": "white",
"statusBarColor": "#ffffff"
},
"listCSS": ["assets/index.3fce1f81.css"],
"listSyncJS": ["assets/index.cafa2549.module.js"],
"listAsyncJS": []
}
III. Phía Server
Do ứng dụng của bạn chạy trên hệ thống domain của hệ thống Zalo, vì vậy để gọi được API, yêu cầu Server của bạn trả thêm Header Access-Control-Allow-Origin như sau (Ví dụ với Nodejs):
const allowedOrigins = ["https://h5.zdn.vn/", "zbrowser://h5.zdn.vn/"];
app.use((req, res, next) => {
const origin = req.headers.origin;
if (allowedOrigins.includes(origin)) {
res.setHeader("Access-Control-Allow-Origin", origin);
}
res.header("Access-Control-Allow-Headers", "Content-Type, Authorization");
return next();
});
IV. Deploy
Sau kiểm tra lại các lưu ý nêu trên và tiến hành buid, bạn đã thể deploy Mini App của mình, rất đơn giản với lệnh
zmp deploy
Chọn Deploy your existing project, điền build folder tương ứng
Chờ quá trình deploy diễn ra xong, bạn đã có thể scan QR code hiện lên và trải nghiệm thử Mini App của mình rồi.
V. Kết luận
Không hề phức tạp phải không nào? Trên đây là một số lưu ý và cách giải quyết một số vấn đề thường gặp chúng tôi đúc kết được trong quá trình hỗ trợ các bên chuyển đổi Web App của mình sang Mini App, hy vọng sẽ hữu ích và giúp quá trình chuyển đổi sang Mini App của các bạn trở nên đơn giản hơn. Nếu có khó khăn hay thắc mắc trong quá trình phát triển Mini App đừng ngần ngại hãy đặt câu hỏi cho chúng tôi tại trang Community chính thức của Zalo Mini App, đội ngũ Supporters và mọi người trong cộng đồng sẽ hỗ trợ nhiệt tình.