flet-box 1.0.3 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (172) hide show
  1. package/README.md +10 -0
  2. package/bin/cli.js +15 -0
  3. package/bin/commands/checkApi.js +761 -0
  4. package/bin/commands/create.js +77 -5
  5. package/bin/utils/dtsProps.js +191 -0
  6. package/bin/utils/moduleExports.js +165 -0
  7. package/bin/utils/neutralise.js +64 -0
  8. package/bin/utils/templates.js +366 -27
  9. package/docs/CONTRIBUTING.md +156 -0
  10. package/docs/README.md +68 -0
  11. package/docs/arquitectura.md +164 -0
  12. package/docs/cli/README.md +542 -0
  13. package/docs/guides/README.md +33 -0
  14. package/docs/guides/app-templates.md +197 -0
  15. package/docs/guides/compatibility.md +95 -0
  16. package/docs/guides/embedding.md +284 -0
  17. package/docs/guides/first-app.md +208 -0
  18. package/docs/guides/frontend-services.md +171 -0
  19. package/docs/guides/minification-and-protection.md +260 -0
  20. package/docs/guides/mobile-and-platforms.md +439 -0
  21. package/docs/guides/online-updates.md +196 -0
  22. package/docs/guides/router.md +282 -0
  23. package/docs/guides/state.md +283 -0
  24. package/docs/guides/syntax-philosophy.md +150 -0
  25. package/docs/guides/utilities.md +241 -0
  26. package/docs/guides/widget-structure.md +163 -0
  27. package/docs/server/README.md +68 -0
  28. package/docs/server/START_HERE.md +121 -0
  29. package/docs/server/api.md +225 -0
  30. package/docs/server/data-services.md +300 -0
  31. package/docs/server/deployment.md +113 -0
  32. package/docs/server/security.md +196 -0
  33. package/docs/services/README.md +79 -0
  34. package/docs/services/RamStore.md +84 -0
  35. package/docs/services/Session.md +84 -0
  36. package/docs/services/Storage.md +88 -0
  37. package/docs/services/http.md +86 -0
  38. package/docs/tools/README.md +138 -0
  39. package/docs/tools/animation.md +87 -0
  40. package/docs/tools/async-ids-log.md +80 -0
  41. package/docs/tools/device.md +132 -0
  42. package/docs/tools/introspection.md +67 -0
  43. package/docs/tools/lists.md +96 -0
  44. package/docs/tools/markdown.md +79 -0
  45. package/docs/tools/reactivity.md +288 -0
  46. package/docs/tools/state.md +103 -0
  47. package/docs/tools/styling.md +92 -0
  48. package/docs/tools/text-and-time.md +89 -0
  49. package/docs/tools/theme.md +102 -0
  50. package/docs/tools/validation.md +75 -0
  51. package/docs/tools/visual-effects.md +84 -0
  52. package/docs/widget/Accordion.md +144 -0
  53. package/docs/widget/AdMob.md +144 -0
  54. package/docs/widget/AdSense.md +133 -0
  55. package/docs/widget/AdaptiveScaffold.md +105 -0
  56. package/docs/widget/AlertDialog.md +103 -0
  57. package/docs/widget/AnimatedBox.md +130 -0
  58. package/docs/widget/AnimatedText.md +123 -0
  59. package/docs/widget/AppBar.md +118 -0
  60. package/docs/widget/Audio.md +135 -0
  61. package/docs/widget/Avatar.md +119 -0
  62. package/docs/widget/Badge.md +128 -0
  63. package/docs/widget/BottomNavigation.md +116 -0
  64. package/docs/widget/BottomSheet.md +125 -0
  65. package/docs/widget/Button.md +137 -0
  66. package/docs/widget/COMMON_PROPS.md +150 -0
  67. package/docs/widget/Card.md +125 -0
  68. package/docs/widget/Carousel.md +151 -0
  69. package/docs/widget/Chart.md +151 -0
  70. package/docs/widget/Checkbox.md +118 -0
  71. package/docs/widget/Chip.md +126 -0
  72. package/docs/widget/CircularBar.md +168 -0
  73. package/docs/widget/CircularChart.md +164 -0
  74. package/docs/widget/CodeViewer.md +130 -0
  75. package/docs/widget/CollapsibleSideBar.md +112 -0
  76. package/docs/widget/Column.md +129 -0
  77. package/docs/widget/Container.md +136 -0
  78. package/docs/widget/DataTable.md +150 -0
  79. package/docs/widget/Divider.md +109 -0
  80. package/docs/widget/DraggBox.md +129 -0
  81. package/docs/widget/Drawer.md +135 -0
  82. package/docs/widget/DrawerItem.md +98 -0
  83. package/docs/widget/Dropdown.md +139 -0
  84. package/docs/widget/DroppBox.md +152 -0
  85. package/docs/widget/FloatingActionButton.md +120 -0
  86. package/docs/widget/GridView.md +140 -0
  87. package/docs/widget/Icon.md +117 -0
  88. package/docs/widget/Image.md +125 -0
  89. package/docs/widget/Input.md +151 -0
  90. package/docs/widget/Inspector.md +92 -0
  91. package/docs/widget/InstallButton.md +128 -0
  92. package/docs/widget/ListTile.md +132 -0
  93. package/docs/widget/ListView.md +138 -0
  94. package/docs/widget/Markdown.md +175 -0
  95. package/docs/widget/MatrixRain.md +122 -0
  96. package/docs/widget/Modal.md +129 -0
  97. package/docs/widget/Pagination.md +135 -0
  98. package/docs/widget/ParallaxBox.md +128 -0
  99. package/docs/widget/ProgressBar.md +130 -0
  100. package/docs/widget/QRCode.md +117 -0
  101. package/docs/widget/README.md +188 -0
  102. package/docs/widget/Radio.md +123 -0
  103. package/docs/widget/Rating.md +131 -0
  104. package/docs/widget/Row.md +131 -0
  105. package/docs/widget/START_HERE.md +146 -0
  106. package/docs/widget/Scaffold.md +152 -0
  107. package/docs/widget/Skeleton.md +130 -0
  108. package/docs/widget/Slider.md +146 -0
  109. package/docs/widget/SnackBar.md +102 -0
  110. package/docs/widget/Stack.md +128 -0
  111. package/docs/widget/Stepper.md +145 -0
  112. package/docs/widget/Switch.md +118 -0
  113. package/docs/widget/Tabs.md +124 -0
  114. package/docs/widget/Text.md +133 -0
  115. package/docs/widget/Tooltip.md +145 -0
  116. package/docs/widget/TreeView.md +176 -0
  117. package/docs/widget/Video.md +127 -0
  118. package/docs/widget/_template.md +61 -0
  119. package/package.json +4 -2
  120. package/src/animations/AnimatedBox.js +32 -1
  121. package/src/animations/AnimatedText.js +7 -3
  122. package/src/animations/MatrixRain.js +37 -12
  123. package/src/animations/ParallaxBox.js +16 -3
  124. package/src/animations/animate.js +187 -58
  125. package/src/animations/index.js +1 -0
  126. package/src/core/runApp.js +13 -1
  127. package/src/create-index.sh +1 -1
  128. package/src/index.d.ts +227 -91
  129. package/src/index.js +1 -0
  130. package/src/navigations/AdaptiveScaffold.js +11 -2
  131. package/src/navigations/AppBar.js +8 -2
  132. package/src/navigations/BottomNavigation.js +24 -5
  133. package/src/navigations/DrawerItem.js +16 -3
  134. package/src/navigations/Scaffold.js +8 -1
  135. package/src/navigations/Tabs.js +40 -8
  136. package/src/tools/dimensions.js +11 -3
  137. package/src/tools/useState.js +139 -101
  138. package/src/utils/getWidgetProps.js +5 -3
  139. package/src/widget-factory/assignProps.js +30 -11
  140. package/src/widget-factory/processProps.js +17 -5
  141. package/src/widget-factory/reactiveValue.js +172 -0
  142. package/src/widget-factory/translateProps.js +777 -901
  143. package/src/widget-factory/warnings.js +15 -0
  144. package/src/widget-factory/widgetFactory.js +27 -0
  145. package/src/widgets/Accordion.js +6 -5
  146. package/src/widgets/AlertDialog.js +7 -5
  147. package/src/widgets/Audio.js +30 -8
  148. package/src/widgets/BottomSheet.js +24 -1
  149. package/src/widgets/Chart.js +4 -1
  150. package/src/widgets/Checkbox.js +16 -8
  151. package/src/widgets/CircularBar.js +12 -1
  152. package/src/widgets/CircularChart.js +4 -1
  153. package/src/widgets/CodeViewer.js +26 -8
  154. package/src/widgets/DataTable.js +11 -2
  155. package/src/widgets/Dropdown.js +5 -1
  156. package/src/widgets/FloatingActionButton.js +4 -7
  157. package/src/widgets/Image.js +7 -2
  158. package/src/widgets/Input.js +119 -6
  159. package/src/widgets/Inspector.js +16 -10
  160. package/src/widgets/ListView.js +80 -30
  161. package/src/widgets/Markdown.js +53 -8
  162. package/src/widgets/Modal.js +24 -1
  163. package/src/widgets/Pagination.js +6 -3
  164. package/src/widgets/ProgressBar.js +16 -13
  165. package/src/widgets/QRCode.js +9 -2
  166. package/src/widgets/Radio.js +11 -8
  167. package/src/widgets/Slider.js +26 -4
  168. package/src/widgets/SnackBar.js +20 -2
  169. package/src/widgets/Stack.js +36 -3
  170. package/src/widgets/Stepper.js +4 -3
  171. package/src/widgets/Switch.js +8 -5
  172. package/src/widgets/TreeView.js +3 -2
@@ -0,0 +1,208 @@
1
+ # Chapter 0 · Your first FletBox app, step by step
2
+
3
+ This page is for **absolute beginners**. You do not need to know any trick — you only need a text editor, a terminal, and the [FletBox CLI](../cli/README.md) installed. At the end you will have a working app with a button and a list.
4
+
5
+ ## Before you start
6
+
7
+ FletBox is not published to the npm registry, so first you install the CLI once and link it globally:
8
+
9
+ ```bash
10
+ git clone https://github.com/kuko53348/flet-box.git
11
+ cd flet-box
12
+ npm link # link the flet-box CLI globally
13
+ ```
14
+
15
+ Then create an empty project, link the framework into it, and start the dev server:
16
+
17
+ ```bash
18
+ cd ..
19
+ flet-box create my-app
20
+ cd my-app
21
+ npm link flet-box # or: npm install ../path/to/flet-box
22
+ npm run dev
23
+ ```
24
+
25
+ Open your browser at `http://localhost:8000`. You should see "Hello FletBox" (or a small welcome screen). If you do, everything is working.
26
+
27
+ ## Step 1: the smallest app
28
+
29
+ Open the file the CLI created (usually `src/app.js`). Edit it to this:
30
+
31
+ ```javascript
32
+ import { runApp, Text } from "flet-box";
33
+
34
+ const app = Text({ text: "Hello, world!" });
35
+
36
+ runApp(app, "root");
37
+ ```
38
+
39
+ `Text` makes a piece of text. `runApp` puts your app on the page, inside an element with `id="root"`. Save the file and look at the browser: it says "Hello, world!".
40
+
41
+ ## Step 2: a button that counts
42
+
43
+ A button is a `Button` widget. It can run code when you press it. Inside that code we build a counter.
44
+
45
+ ```javascript
46
+ import { runApp, Column, Text, Button } from "flet-box";
47
+
48
+ async function main() {
49
+ const [count, setCount] = useState("counter", 0);
50
+
51
+ const app = Column({
52
+ gap: 12,
53
+ children: [
54
+ Text({ text: `You pressed ${count} times` }),
55
+ Button({
56
+ text: "Add one",
57
+ onPress: () => setCount((previous) => previous + 1),
58
+ }),
59
+ ],
60
+ });
61
+
62
+ runApp(app, "root");
63
+ }
64
+
65
+ main();
66
+ ```
67
+
68
+ Wait — we used `useState` but did not import it. Fix the import line:
69
+
70
+ ```javascript
71
+ import { runApp, Column, Text, Button, useState } from "flet-box";
72
+ ```
73
+
74
+ What just happened?
75
+
76
+ - `useState("counter", 0)` creates a value stored under the key `"counter"`, starting at `0`.
77
+ - `count` is the current value.
78
+ - `setCount` is the function that changes it.
79
+ - When we press the button, we tell FletBox to run the screen again with the new value, so the text updates.
80
+
81
+ `Column` stacks its `children` vertically, one under the other, with `gap` space between them.
82
+
83
+ ## Step 3: write and add tasks
84
+
85
+ Now the fun part — a real todo list. A `Row` puts widgets side by side. An `Input` is a text box, and its `.value` holds what the user typed.
86
+
87
+ ```javascript
88
+ import { runApp, Column, Row, Text, Input, Button, useState } from "flet-box";
89
+
90
+ async function main() {
91
+ const tasks = Column({ gap: 8, children: [] });
92
+ const [allTasks, setAllTasks] = useState("tasks", [], tasks, "children");
93
+
94
+ const input = Input({ placeholder: "Write a task" });
95
+
96
+ const app = Column({
97
+ gap: 16,
98
+ children: [
99
+ Text({ text: "My tasks", type: "h2" }),
100
+ Row({
101
+ gap: 8,
102
+ children: [
103
+ input,
104
+ Button({
105
+ text: "Add",
106
+ onPress: () => {
107
+ if (input.value.trim() === "") return;
108
+ setAllTasks([...allTasks, input.value]);
109
+ input.value = "";
110
+ },
111
+ }),
112
+ ],
113
+ }),
114
+ tasks,
115
+ ],
116
+ });
117
+
118
+ runApp(app, "root");
119
+ }
120
+
121
+ main();
122
+ ```
123
+
124
+ Type something in the box, press **Add**, and watch it appear in the list below.
125
+
126
+ How it works:
127
+
128
+ - `tasks` is an empty `Column` — it will hold the rows of the list.
129
+ - The 4th argument of `useState` (“children”) tells FletBox: *when this state changes, update the `children` of `tasks`*.
130
+ - `setAllTasks([...allTasks, input.value])` puts the new task at the end of the list. FletBox then re-renders `tasks` with the new rows.
131
+ - Clearing `input.value` empties the box so you can write the next task.
132
+
133
+ ## Step 4: make each task removable
134
+
135
+ Giving every task its own "x" button means each row is a small `Row` with a `Text` and a `Button`. We rebuild the whole list whenever it changes, using the widget's own `update` method:
136
+
137
+ ```javascript
138
+ import { runApp, Column, Row, Text, Input, Button } from "flet-box";
139
+
140
+ let allTasks = [];
141
+ const tasks = Column({ gap: 8, children: [] });
142
+ const input = Input({ placeholder: "Write a task" });
143
+
144
+ const taskRow = (task) =>
145
+ Row({
146
+ gap: 8,
147
+ children: [
148
+ Text({ text: task }),
149
+ Button({
150
+ text: "x",
151
+ size: "small",
152
+ onPress: () => {
153
+ allTasks = allTasks.filter((item) => item !== task);
154
+ render();
155
+ },
156
+ }),
157
+ ],
158
+ });
159
+
160
+ const render = () => tasks.update({ children: allTasks.map(taskRow) });
161
+
162
+ const addTask = () => {
163
+ if (input.value.trim() === "") return;
164
+ allTasks.push(input.value);
165
+ input.value = "";
166
+ render();
167
+ };
168
+
169
+ const app = Column({
170
+ gap: 16,
171
+ children: [
172
+ Text({ text: "My tasks", type: "h2" }),
173
+ Row({
174
+ gap: 8,
175
+ children: [
176
+ input,
177
+ Button({ text: "Add", onPress: addTask }),
178
+ ],
179
+ }),
180
+ tasks,
181
+ ],
182
+ });
183
+
184
+ runApp(app, "root");
185
+ ```
186
+
187
+ - `taskRow` builds one line: the task name plus a small **x** button.
188
+ - `render()` asks `tasks` to replace its children with the current list, rebuilt as rows.
189
+ - Pressing **x** removes that task from `allTasks` and re-renders.
190
+
191
+ This app grows with you: the widgets you used — `Row`, `Column`, `Text`, `Input`, `Button` — are the same ones every FletBox screen is built from. To go deeper into shared, automatic state, read the [State guide](state.md).
192
+
193
+ ## What is next
194
+
195
+ You just built a real app. Now learn what widgets look like and how to mix them:
196
+
197
+ - **[Start here](../widget/START_HERE.md)** — how to read the widget book.
198
+ - **[The widget book](../widget/README.md)** — all widgets, in order, from basic to advanced.
199
+
200
+ ---
201
+
202
+ ## Continue reading
203
+
204
+ - **Previous:** [The FletBox Book](../README.md) — front cover.
205
+ - **Next:** [Start here](../widget/START_HERE.md) — how to read the widget book.
206
+ - **Index:** [Guides index](README.md).
207
+
208
+ You are reading **Chapter 0 · Your first app** (before Chapter 1).
@@ -0,0 +1,171 @@
1
+ # Frontend services
2
+
3
+ FletBox includes three browser storage layers and a small HTTP client. Choose the layer based on how long the data should live.
4
+
5
+ ## Choose a storage layer
6
+
7
+ | Service | Lifetime | Best for |
8
+ | --- | --- | --- |
9
+ | `RamStore` | Until the page is reloaded | Shared reactive UI state. |
10
+ | `Session` | Until the browser tab/session ends | Temporary session data. |
11
+ | `Storage` | Until the user or app removes it | Small persistent preferences. |
12
+
13
+ None of these services should be used for passwords, private keys, or security secrets.
14
+
15
+ ## RamStore
16
+
17
+ `RamStore` keeps values in memory and can notify subscribers:
18
+
19
+ ```javascript
20
+ import { getRam, saveRam, subscribeRam } from "flet-box";
21
+
22
+ saveRam("cart", [{ id: 1, name: "Book" }]);
23
+ const cart = getRam("cart");
24
+
25
+ const unsubscribe = subscribeRam((key, newValue, oldValue) => {
26
+ if (key === "cart") {
27
+ console.log({ newValue, oldValue });
28
+ }
29
+ });
30
+
31
+ unsubscribe();
32
+ ```
33
+
34
+ Values disappear when the page reloads.
35
+
36
+ ## Session storage
37
+
38
+ Use `Session` for data that should survive navigation but not remain as a permanent preference:
39
+
40
+ ```javascript
41
+ import { getSession, saveSession, deleteSession } from "flet-box";
42
+
43
+ saveSession("checkout-step", 2);
44
+ const step = getSession("checkout-step");
45
+ deleteSession("checkout-step");
46
+ ```
47
+
48
+ The data is backed by `sessionStorage`.
49
+
50
+ ## Persistent storage
51
+
52
+ Use `Storage` for small preferences:
53
+
54
+ ```javascript
55
+ import { getData, saveData, deleteData } from "flet-box";
56
+
57
+ saveData("preferences", {
58
+ theme: "dark",
59
+ language: "en",
60
+ });
61
+
62
+ const preferences = getData("preferences");
63
+ deleteData("preferences");
64
+ ```
65
+
66
+ The data is backed by `localStorage` and serialized as JSON.
67
+
68
+ ## Storage rules
69
+
70
+ - Use namespaced keys such as `fletbox:preferences`.
71
+ - Store small values only.
72
+ - Handle `null` when a key does not exist.
73
+ - Do not store credentials or sensitive tokens unless you understand the security tradeoff.
74
+ - Do not call `clearAllData()` in a shared page unless you intentionally want to clear every local-storage key for that origin.
75
+ - Do not call `clearAllSession()` in a shared page unless you intentionally want to clear every session-storage key for that origin.
76
+ - Use a server-side session or secure platform storage for sensitive authentication data.
77
+
78
+ ## Check availability
79
+
80
+ Storage can be disabled by browser privacy settings, sandboxing, or restricted contexts:
81
+
82
+ ```javascript
83
+ import { isStorageAvailable, isSessionAvailable } from "flet-box";
84
+
85
+ if (isStorageAvailable()) {
86
+ saveData("visited", true);
87
+ }
88
+
89
+ if (isSessionAvailable()) {
90
+ saveSession("step", 1);
91
+ }
92
+ ```
93
+
94
+ ## HTTP requests
95
+
96
+ The HTTP helpers use `fetch` and return parsed JSON when the response content type is JSON:
97
+
98
+ ```javascript
99
+ import { httpGet, httpPost } from "flet-box";
100
+
101
+ const users = await httpGet("/api/users", {
102
+ params: { page: 1 },
103
+ });
104
+
105
+ const created = await httpPost("/api/users", {
106
+ body: { name: "Ada" },
107
+ });
108
+ ```
109
+
110
+ Available helpers:
111
+
112
+ ```text
113
+ httpGet
114
+ httpPost
115
+ httpPut
116
+ httpPatch
117
+ httpDelete
118
+ httpRequest
119
+ ```
120
+
121
+ ## Headers and authentication
122
+
123
+ ```javascript
124
+ const data = await httpGet("/api/private", {
125
+ headers: {
126
+ Authorization: `Bearer ${token}`,
127
+ },
128
+ });
129
+ ```
130
+
131
+ Never hardcode a private secret in frontend source code. A bearer token in browser code must be treated as accessible to the user and protected by server-side authorization.
132
+
133
+ ## Timeout and errors
134
+
135
+ ```javascript
136
+ try {
137
+ const data = await httpGet("/api/slow", {
138
+ timeout: 5000,
139
+ });
140
+ console.log(data);
141
+ } catch (error) {
142
+ console.error("Request failed:", error.message);
143
+ }
144
+ ```
145
+
146
+ Non-2xx responses throw an error containing `response` and, when available, parsed response data in `error.data`.
147
+
148
+ ## Query parameters
149
+
150
+ ```javascript
151
+ const result = await httpGet("/api/search", {
152
+ params: {
153
+ query: "widgets",
154
+ page: 2,
155
+ },
156
+ });
157
+ ```
158
+
159
+ Use encoded values through the `params` option instead of manually concatenating user input into URLs.
160
+
161
+ ## Service API status
162
+
163
+ Every storage and HTTP function is declared in `src/index.d.ts`, exported from `src/index.js`, and detailed on the [services reference pages](../services/README.md). The runtime also exports namespace objects (`RamStore`, `Session`, `Storage`) that group each layer.
164
+
165
+ ---
166
+
167
+ ## Continue reading
168
+
169
+ - **Previous:** [Routing with FletBox](router.md)
170
+ - **Next:** [Services index](../services/README.md) — the full reference
171
+ - **Index:** [Guides index](README.md) · [The FletBox Book](../README.md)
@@ -0,0 +1,260 @@
1
+ # Minify and protect a FletBox build
2
+
3
+ > **Level: Advanced.** This page is for shipping — skip it on a first read. It follows [the FletBox CLI](../cli/README.md) in the book's reading path.
4
+
5
+ FletBox can produce a smaller production build by bundling only the code used by the application, removing development whitespace, and applying tree shaking.
6
+
7
+ This guide explains two different goals:
8
+
9
+ - **Minification** reduces file size and load time.
10
+ - **Code protection** makes the generated JavaScript harder to read, but cannot make browser code truly secret.
11
+
12
+ ## What `createBundle` does
13
+
14
+ The FletBox bundle process uses esbuild with production-oriented options:
15
+
16
+ ```bash
17
+ flet-box createBundle
18
+ ```
19
+
20
+ Aliases:
21
+
22
+ ```bash
23
+ flet-box build
24
+ flet-box bundle
25
+ npm run build
26
+ ```
27
+
28
+ The build process bundles `src/app.js` and writes the result to `dist/src/app.js` with options equivalent to:
29
+
30
+ ```text
31
+ --bundle
32
+ --format=esm
33
+ --minify
34
+ --tree-shaking=true
35
+ --target=es2020
36
+ ```
37
+
38
+ It also copies the HTML file, assets, fonts, service worker, and `run.sh` when they exist.
39
+
40
+ ## Basic production workflow
41
+
42
+ ```bash
43
+ # Install dependencies
44
+ npm install
45
+
46
+ # Create the optimized web build
47
+ npm run build
48
+
49
+ # Inspect the generated output
50
+ find dist -maxdepth 3 -type f
51
+
52
+ # Preview the production build
53
+ cd dist
54
+ ./run.sh
55
+ ```
56
+
57
+ Always test the `dist` directory, not only the development server. A development build and a production build can behave differently.
58
+
59
+ ## What minification changes
60
+
61
+ Minification normally:
62
+
63
+ - Removes unnecessary whitespace.
64
+ - Removes comments that are not required at runtime.
65
+ - Shortens local variable names when safe.
66
+ - Compresses expressions.
67
+ - Removes unreachable code.
68
+ - Combines imported modules into the application bundle.
69
+ - Removes unused exports through tree shaking.
70
+
71
+ Minification does not change the intended public behavior of the application.
72
+
73
+ ## Reduce bundle size
74
+
75
+ ### Import only what you use
76
+
77
+ Prefer focused imports:
78
+
79
+ ```javascript
80
+ import { Button, Container, Text } from "flet-box";
81
+ ```
82
+
83
+ Avoid importing a large internal surface when a focused import is enough. The bundler can remove unused code more effectively when imports are statically analyzable.
84
+
85
+ ### Avoid unnecessary dependencies
86
+
87
+ Every dependency can add code, assets, initialization time, and security maintenance. Add a package only when it solves a real problem.
88
+
89
+ ### Keep assets outside JavaScript
90
+
91
+ Images, fonts, videos, and large data files should usually remain assets instead of being embedded into JavaScript strings. Copy only the assets required by the application.
92
+
93
+ ### Use lazy loading for large features
94
+
95
+ For large optional screens, load code only when the user needs it:
96
+
97
+ ```javascript
98
+ const openReports = async () => {
99
+ const module = await import("./screens/ReportsScreen.js");
100
+ return module.ReportsScreen();
101
+ };
102
+ ```
103
+
104
+ The exact loading strategy depends on your application and server. Test lazy routes in the final `dist` directory.
105
+
106
+ ### Remove development-only code
107
+
108
+ Keep debug panels, test data, verbose logs, and development-only routes out of the production entry point.
109
+
110
+ ```javascript
111
+ if (import.meta.env?.DEV) {
112
+ console.log("Development information");
113
+ }
114
+ ```
115
+
116
+ Use a build setup that actually replaces environment flags before relying on them. Do not assume every bundler provides `import.meta.env` automatically.
117
+
118
+ ## Protecting browser code: the honest rule
119
+
120
+ JavaScript shipped to a browser can be downloaded, inspected, and debugged by the user. Minification and obfuscation can slow down casual inspection, but they cannot provide real secrecy.
121
+
122
+ Never put these values in frontend code:
123
+
124
+ - Passwords.
125
+ - Private API keys.
126
+ - JWT signing secrets.
127
+ - Database credentials.
128
+ - SMTP passwords.
129
+ - Cloud service private keys.
130
+ - Internal security rules that must remain secret.
131
+
132
+ Keep sensitive operations in FletBox Server or another backend and expose only the minimum API needed by the frontend.
133
+
134
+ ## Minification versus obfuscation
135
+
136
+ ### Minification
137
+
138
+ Recommended for every production build:
139
+
140
+ ```bash
141
+ flet-box build
142
+ ```
143
+
144
+ It reduces size and removes readable formatting. It is usually fast and has low runtime risk.
145
+
146
+ ### Obfuscation
147
+
148
+ Obfuscation changes code structure and names to make manual reading more difficult. It can increase bundle size, reduce performance, make debugging harder, and break code that depends on function names or dynamic property access.
149
+
150
+ Use obfuscation only after measuring its impact. It is not a replacement for authentication, authorization, or server-side protection.
151
+
152
+ If an obfuscator is introduced, run it only on the final browser bundle and test:
153
+
154
+ - Application startup.
155
+ - Router navigation.
156
+ - Event handlers.
157
+ - Dynamic imports.
158
+ - PWA installation.
159
+ - Capacitor Android builds.
160
+ - Capacitor iOS builds.
161
+
162
+ ## Source maps
163
+
164
+ Source maps make production debugging easier but also make original source code easier to recover. Decide intentionally whether to publish them.
165
+
166
+ For a private staging build, source maps can be useful. For a public production build, do not publish source maps unless you understand the exposure and have access controls.
167
+
168
+ The current FletBox shell build does not enable source maps by default. If you add them, keep them out of public hosting when the source is private.
169
+
170
+ ## Protect API calls
171
+
172
+ The frontend is not a safe place for secrets. Protect backend routes instead:
173
+
174
+ ```javascript
175
+ import { authenticate, hasRole } from "flet-box-server";
176
+
177
+ const routes = Api({
178
+ "/admin/report": {
179
+ GET: {
180
+ handler: createReport,
181
+ middleware: [authenticate, hasRole("admin")],
182
+ },
183
+ },
184
+ });
185
+ ```
186
+
187
+ The browser may know that this endpoint exists, but it should not be able to use it without a valid token and role.
188
+
189
+ ## Protect the production build pipeline
190
+
191
+ Use a repeatable build process:
192
+
193
+ ```bash
194
+ rm -rf dist
195
+ npm ci
196
+ npm run build
197
+ ```
198
+
199
+ Then verify:
200
+
201
+ ```bash
202
+ # Check that the bundle exists
203
+ test -s dist/src/app.js
204
+
205
+ # Check that development secrets are not present
206
+ grep -R "JWT_SECRET\|password\|apiKey" dist || true
207
+ ```
208
+
209
+ Do not print or commit secret values while checking files. The example searches names only; inspect matches carefully.
210
+
211
+ ## Capacitor builds
212
+
213
+ Build the web code before synchronizing native projects:
214
+
215
+ ```bash
216
+ npm run build
217
+ npx cap sync android
218
+ npx cap sync ios
219
+ ```
220
+
221
+ Then create a debug Android APK:
222
+
223
+ ```bash
224
+ cd android
225
+ ./gradlew assembleDebug
226
+ ```
227
+
228
+ For a production APK or an Android App Bundle, use the release tasks:
229
+
230
+ ```bash
231
+ ./gradlew assembleRelease
232
+ ./gradlew bundleRelease
233
+ ```
234
+
235
+ The AAB is the usual format for Google Play. Release artifacts must be signed with a production key.
236
+
237
+ Minification reduces the web payload inside the native application. It does not replace Android or iOS signing, secure storage, transport security, or native permission review.
238
+
239
+ ## Production checklist
240
+
241
+ - Run `npm run build` from a clean state.
242
+ - Confirm tree shaking is active.
243
+ - Inspect the size of `dist/src/app.js`.
244
+ - Remove development routes and debug data.
245
+ - Do not ship secrets in frontend code.
246
+ - Decide whether source maps should be private.
247
+ - Test the actual `dist` output.
248
+ - Test direct navigation to SPA routes.
249
+ - Test PWA and Capacitor builds when used.
250
+ - Use HTTPS for API calls.
251
+ - Protect backend routes with authentication and authorization.
252
+ - Keep signing keys and deployment credentials outside Git.
253
+
254
+ ---
255
+
256
+ ## Continue reading
257
+
258
+ - **Previous:** [The FletBox CLI](../cli/README.md)
259
+ - **Next:** [Build FletBox for mobile and other platforms](mobile-and-platforms.md) — Appendix B
260
+ - **Index:** [Guides index](README.md) · [The FletBox Book](../README.md)