Skip to content
This repository was archived by the owner on Jan 7, 2025. It is now read-only.

Commit e64811b

Browse files
committed
Migrate to Telegram SDK
1 parent b777d51 commit e64811b

20 files changed

+483
-643
lines changed

README.md

+3-72
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Vanilla JS example
22

33
> ⚠️ Please, avoid using vanilla JavaScript if possible on Telegram Mini Apps
4-
> platform. It is better to use ES modules at least. [Learn more](#about-iife).
4+
> platform. It is better to use ES modules at least.
55
66
This example shows how developer could use Vanilla JavaScript to start developing at
77
Telegram Mini Apps platform.
@@ -10,7 +10,7 @@ This template demonstrates how developers can implement an application on the Te
1010
Mini Apps platform using the following technologies and libraries
1111

1212
- [TON Connect](https://docs.ton.org/develop/dapps/ton-connect/overview)
13-
- [@telegram-apps SDK](https://docs.telegram-mini-apps.com/packages/telegram-apps-sdk)
13+
- [Telegram SDK](https://core.telegram.org/bots/webapps#initializing-mini-apps)
1414

1515
> This boilerplate was created using [pnpm](https://pnpm.io/). Therefore, it is required to use
1616
> it for this project as well.
@@ -73,15 +73,9 @@ devices in the same network with the current device.
7373
To view the application, you need to open the `Local`
7474
link (`http://localhost:3000` in this example) in your browser.
7575

76-
It is important to note that some libraries in this template, such as `@telegram-apps/sdk`, are not
76+
It is important to note that some libraries in this template, such as Telegram SDK, are not
7777
intended for use outside of Telegram.
7878

79-
Nevertheless, they appear to function properly. This is because the `dist/js/mockEnv.ts` file, which is
80-
imported in the application's entry point (`dist/index.html`), employs the `mockTelegramEnv` function
81-
to simulate the Telegram environment. This trick convinces the application that it is running in a
82-
Telegram-based environment. Therefore, be cautious not to use this function in production mode
83-
unless you fully understand its implications.
84-
8579
### Run Inside Telegram
8680

8781
Although it is possible to run the application outside of Telegram, it is recommended to develop it
@@ -108,69 +102,6 @@ to [@BotFather](https://t.me/botfather). Then, navigate
108102
to [https://web.telegram.org/k/](https://web.telegram.org/k/), find your bot, and launch the
109103
Telegram Mini App. This approach provides the full development experience.
110104

111-
## About IIFE
112-
113-
### Dependencies
114-
115-
Some of the packages use other `@tma.js` packages as dependencies. In this case there are 2
116-
ways of importing them:
117-
118-
1. **By inserting another `script` tag which loads the dependency**.
119-
This way makes usage of package with a lot of dependencies almost unreal.
120-
2. **By inlining these packages**.
121-
This way leads to code duplication between several packages using the same package as dependency.
122-
123-
As you can see, there is no optimal solution between both of them. As the additional problem
124-
developer gets here, is bundler is unable to
125-
use [tree shaking](https://stackoverflow.com/questions/45884414/what-is-tree-shaking-and-why-would-i-need-it),
126-
making browser to load the code not used in the application. Imagine using the only 1 function from
127-
some library like `lodash`, but fully load it.
128-
129-
### Unknown target
130-
131-
The other problem developer can face is IIFE packages are built for the specific browser of specific
132-
version. So, the package author does not know which target he should choose as long as he doesn't
133-
know it when creating such package. That's why the the package target should be lowered to support
134-
most part of browsers, but this also make final bunlde bigger.
135-
136-
### Conclusion
137-
138-
Unfortunately, developer is unable to avoid these problems when using IIFE format. This is the
139-
reason why it is recommended to use modern technologies along with ESM format.
140-
141-
### When there is no other choice
142-
143-
First of all, it is required to load the package. Developer could use [JSDelivr](https://www.jsdelivr.com/)
144-
to do it:
145-
146-
```html
147-
148-
<head>
149-
<script src="https://cdn.jsdelivr.net/npm/@telegram-apps/sdk/dist/index.iife.js"></script>
150-
</head>
151-
```
152-
153-
Loaded packages of `@telegram-apps` in IIFE format are accessible by path `window.telegramApps.*`:
154-
155-
```html
156-
157-
<head>
158-
<script src="https://cdn.jsdelivr.net/npm/@telegram-apps/sdk/dist/index.iife.js"></script>
159-
</head>
160-
<body>
161-
<script>
162-
var sdk = window.telegramApps.sdk;
163-
console.log(sdk.retrieveLaunchData());
164-
</script>
165-
</body>
166-
```
167-
168-
> ⚠️ In this example we did not specify the exact version of required package. In this case,
169-
> JSDelivr CDN will return the latest version of the package which in some cases may lead to
170-
> unexpected behavior. To prevent such case, specify the exact version.
171-
172-
173-
174105
## Deploy
175106

176107
This boilerplate uses GitHub Pages as the way to host the application externally. GitHub Pages

dist/index.html

+1-5
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,14 @@
2424
<link href="css/link.css" rel="stylesheet">
2525
<link href="css/displayData.css" rel="stylesheet">
2626

27-
<script src="https://cdn.jsdelivr.net/npm/@telegram-apps/[email protected]/dist/index.iife.js"></script>
27+
<script src="https://telegram.org/js/telegram-web-app.js"></script>
2828
<script src="https://unpkg.com/@tonconnect/[email protected]/dist/tonconnect-ui.min.js"></script>
2929
<script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
3030
</head>
3131
<body>
3232
<noscript>You need to enable JavaScript to run this app.</noscript>
3333
<div id="root"></div>
3434
<script src="js/utils.js"></script>
35-
<!-- Uncomment next line for local development outside Telegram Mini App -->
36-
<!-- <script src="js/mockEnv.js"></script> -->
37-
<script src="js/initNavigrator.js"></script>
38-
<script src="js/initComponents.js"></script>
3935
<script src="js/initTonConnect.js"></script>
4036

4137
<script src="js/components/DisplayData.js"></script>

dist/js/components/DisplayData.js

+37-36
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,41 @@
1-
class DisplayData {
2-
constructor({ rows }) {
3-
this.el = $('<div/>');
4-
this.setRows(rows);
5-
}
1+
function isRGB(value) {
2+
return /^#[a-f0-9]{3,6}$/i.test(value);
3+
}
64

7-
/**
8-
* @returns {HTMLDivElement}
9-
*/
10-
element() {
11-
return this.el[0];
12-
}
5+
function DisplayData(options) {
6+
var rows = options.rows;
7+
this.el = $('<div/>');
8+
this.setRows(rows);
9+
}
1310

14-
setRows(rows) {
15-
this.el.empty().append(
16-
...rows.map(row => {
17-
const lineValue = $('<span class="display-data__line-value"/>');
18-
if (typeof row.value === 'string' && window.telegramApps.sdk.isRGB(row.value)) {
19-
lineValue.append(new RGB({ color: row.value }).element());
20-
} else if (row.value === false) {
21-
lineValue.text('❌');
22-
} else if (row.value === true) {
23-
lineValue.text('✔️');
24-
} else if (row.value === undefined) {
25-
lineValue.html('<i>empty</i>');
26-
} else if (row.value instanceof HTMLElement) {
27-
lineValue.append(row.value);
28-
} else {
29-
lineValue.append(row.value.toString());
30-
}
11+
/**
12+
* @returns {HTMLDivElement}
13+
*/
14+
DisplayData.prototype.element = function() {
15+
return this.el[0];
16+
};
3117

32-
return $('<div class="display-data__line"/>').append(
33-
$('<span class="display-data__line-title"/>').text(row.title),
34-
lineValue,
35-
);
36-
}),
18+
DisplayData.prototype.setRows = function(rows) {
19+
this.el.empty().append.apply(this.el, rows.map(function(row) {
20+
var lineValue = $('<span class="display-data__line-value"/>');
21+
if (typeof row.value === 'string' && isRGB(row.value)) {
22+
lineValue.append(new RGB({ color: row.value }).element());
23+
} else if (row.value === false) {
24+
lineValue.text('❌');
25+
} else if (row.value === true) {
26+
lineValue.text('✔️');
27+
} else if (row.value === undefined) {
28+
lineValue.html('<i>empty</i>');
29+
} else if (row.value instanceof HTMLElement) {
30+
lineValue.append(row.value);
31+
} else {
32+
lineValue.append(row.value.toString());
33+
}
34+
35+
return $('<div class="display-data__line"/>').append(
36+
$('<span class="display-data__line-title"/>').text(row.title),
37+
lineValue
3738
);
38-
return this;
39-
}
40-
}
39+
}));
40+
return this;
41+
};

dist/js/components/Link.js

+28-27
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,33 @@
1-
class Link {
2-
constructor({ href, class: className }, context) {
3-
const targetUrl = new URL(href, window.location.toString());
4-
const currentUrl = new URL(window.location.toString());
5-
const isExternal = targetUrl.protocol !== currentUrl.protocol
6-
|| targetUrl.host !== currentUrl.host;
1+
function Link(options, context) {
2+
var href = options.href;
3+
var className = options.class;
4+
5+
var targetUrl = new URL(href, window.location.toString());
6+
var currentUrl = new URL(window.location.toString());
7+
var isExternal = targetUrl.protocol !== currentUrl.protocol || targetUrl.host !== currentUrl.host;
78

8-
this.el = $('<a/>')
9-
.attr('class', 'link')
10-
.addClass(className ?? '')
11-
.attr('href', isExternal ? href : context.navigator.renderPath(href));
9+
this.el = $('<a/>')
10+
.attr('class', 'link')
11+
.addClass(className || '')
12+
.attr('href', isExternal ? href : '#' + href);
1213

13-
if (isExternal) {
14-
this.el.on('click', (e) => {
15-
e.preventDefault();
16-
context.utils.openLink(targetUrl.toString());
17-
});
18-
}
14+
if (isExternal) {
15+
this.el.on('click', function(e) {
16+
e.preventDefault();
17+
context.getWebApp().openLink(targetUrl.toString());
18+
});
1919
}
20+
}
2021

21-
appendChild(...children) {
22-
this.el.append(...filterChildren(children));
23-
return this;
24-
}
22+
Link.prototype.appendChild = function() {
23+
var children = Array.prototype.slice.call(arguments);
24+
this.el.append.apply(this.el, filterChildren(children));
25+
return this;
26+
};
2527

26-
/**
27-
* @returns {HTMLAnchorElement}
28-
*/
29-
element() {
30-
return this.el[0];
31-
}
32-
}
28+
/**
29+
* @returns {HTMLAnchorElement}
30+
*/
31+
Link.prototype.element = function() {
32+
return this.el[0];
33+
};

dist/js/components/Page.js

+25-24
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,29 @@
1-
class Page {
2-
constructor({ title }) {
3-
this.el = $('<div class="page"/>').append($('<h1/>').text(title));
4-
}
1+
function Page(options) {
2+
var title = options.title;
3+
this.el = $('<div class="page"/>').append($('<h1/>').text(title));
4+
}
55

6-
appendChild(...children) {
7-
this.el.append(...filterChildren(children));
8-
return this;
9-
}
6+
Page.prototype.appendChild = function() {
7+
var children = Array.prototype.slice.call(arguments);
8+
this.el.append.apply(this.el, filterChildren(children));
9+
return this;
10+
};
1011

11-
/**
12-
* @returns {HTMLDivElement}
13-
*/
14-
element() {
15-
return this.el[0];
16-
}
12+
/**
13+
* @returns {HTMLDivElement}
14+
*/
15+
Page.prototype.element = function() {
16+
return this.el[0];
17+
};
1718

18-
setDisclaimer(disclaimer) {
19-
if (this.disclaimer) {
20-
this.disclaimer.empty().append(...toArray(disclaimer));
21-
} else {
22-
this.disclaimer = $('<div class="page__disclaimer"/>')
23-
.append(...toArray(disclaimer))
24-
.insertAfter(this.el.children('h1'));
25-
}
26-
return this;
19+
Page.prototype.setDisclaimer = function(disclaimer) {
20+
if (this.disclaimer) {
21+
this.disclaimer.empty().append.apply(this.disclaimer, toArray(disclaimer));
22+
} else {
23+
var disclaimerEl = $('<div class="page__disclaimer"/>');
24+
this.disclaimer = disclaimerEl
25+
.append.apply(disclaimerEl, toArray(disclaimer))
26+
.insertAfter(this.el.children('h1'));
2727
}
28-
}
28+
return this;
29+
};

dist/js/components/PageComponent.js

+10-12
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
1-
class PageComponent {
2-
constructor(page) {
3-
this.page = page;
4-
}
1+
function PageComponent(page) {
2+
this.page = page;
3+
}
54

6-
/**
7-
* @param {HTMLElement} root
8-
* @returns {void}
9-
*/
10-
render(root) {
11-
$(root).empty().append(this.page.element());
12-
}
13-
}
5+
/**
6+
* @param {HTMLElement} root
7+
* @returns {void}
8+
*/
9+
PageComponent.prototype.render = function(root) {
10+
$(root).empty().append(this.page.element());
11+
};

dist/js/components/RGB.js

+21-20
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
1-
class RGB {
2-
/**
3-
* @param {{ color: string; class?: string }}
4-
*/
5-
constructor({ color, class: className }) {
6-
this.el = $('<span/>')
7-
.attr('class', 'rgb')
8-
.addClass(className ?? '')
9-
.append(
10-
$(`<i class="rgb__icon" style="background-color: ${color}"/>`),
11-
color,
12-
);
13-
}
1+
/**
2+
* @param {{ color: string; class?: string }} options
3+
*/
4+
function RGB(options) {
5+
var color = options.color;
6+
var className = options.class;
7+
8+
this.el = $('<span/>')
9+
.attr('class', 'rgb')
10+
.addClass(className || '')
11+
.append(
12+
$('<i class="rgb__icon"/>').css('background-color', color),
13+
color
14+
);
15+
}
1416

15-
/**
16-
* @returns {HTMLSpanElement}
17-
*/
18-
element() {
19-
return this.el[0];
20-
}
21-
}
17+
/**
18+
* @returns {HTMLSpanElement}
19+
*/
20+
RGB.prototype.element = function() {
21+
return this.el[0];
22+
};

0 commit comments

Comments
 (0)