MoreRSS

site iconJadeYang | 杨琼璞修改

晚晴幽草轩。90后,生于陕西,居于深圳。热爱文学、武术、科技,曾就职于博雅互动和大疆创新。
请复制 RSS 到你的阅读器,或快速订阅到 :

Inoreader Feedly Follow Feedbin Local Reader

JadeYang | 杨琼璞的 RSS 预览

生财有迹 | 您专属的资产跟踪与分析工具

2024-08-28 20:20:00

生财有迹(Wealth Tracker)是一款专注于个人资产分析的应用程序。其核心功能是:全面记录并展示用户的资产状况,帮助用户轻松了解财务现状;运用 AI 能力,结合每种资产的特性和当前环境,提供适宜的财务建议。

生财有迹 - 效果预览

项目愿景

在当今多元化的经济环境中,个人资产管理变得日益重要。它往往分散于各类金融账户和服务中,例如银行存款与理财产品、移动支付平台(如微信支付、支付宝)、公积金、医保账户、货币基金(例如余额宝)、债券、各种股票及基金产品、房地产、贵金属、外部借款(尽量不做此配置🤫)以及其他投资等等(对于部分朋友,或许还有贷款、欠款等负债)。这些账户中的数额在不断变动,使得快速准确地了解个人总资产状况成为一项挑战。

本项目旨在提供一个高效、直观的解决方案,以应对个人资产管理中的分散性和复杂性。生财有迹专注于账户余额及整体数额,避免深陷于单笔收支的琐碎细节。其目标是通过简化操作流程,帮助用户揭示个人资产的整体变化趋势,并通过友好的用户界面,使用户能够轻松记录和洞悉自己的财务信息。如欲了解更多,可移步至博文:生财有迹 | 您专属的资产跟踪与分析工具

核心特性

  • 简洁易用的操作界面:用户可以通过几个简单的步骤快速上手,无需任何复杂的财务知识。
  • 丰富的数据可视化:通过图表和图形,直观展示资产变化,帮助用户轻松掌握财务状况。
  • 本地部署的灵活性:部署在哪里由用户决定,确保数据的私密性、安全性,以及可扩展性。
  • 开源的代码架构:项目的源代码完全开放,欢迎参与贡献,以不断改进和完善工具的功能。

通过这些特性,希望建立一个用户友好、透明且可信赖的个人财分析工具,帮助用户更全面地掌握自己的财务状况。

在线体验

为了让您更直观地了解 生财有迹 的功能和特性,已在服务器上使用 pm2 部署了一个演示版本。该演示环境填充了模拟数据,方便您全面体验各项功能。无论您是想评估工具的实用性,还是出于好奇想一探究竟,欢迎访问以下链接进行体验:

https://fund.niceshare.site/

请注意,这是一个公共演示环境,因此请勿在其中输入任何真实的个人财务信息。建议您在体验后,考虑按照本文档的指导,在自己的环境中部署和使用”生财有迹”,以确保您的财务数据的隐私和安全。

如果您在使用过程中遇到任何问题或有反馈意见,欢迎通过项目的 GitHub 页面 与我们联系。您的宝贵意见将帮助我们不断改进这一工具,以更好地满足用户的需求。

先决条件

说明用户在安装和使用前,需要准备的一些先决条件,譬如:您需要安装或升级 Node.js(>= 16.*),推荐使用 PnpmYarn 作为首选包管理工具。

如何使用?

使用 Docker

使用 docker compose

1
2
3
4
5
6
7
8
9
10
11
12
13
14
version: '3.8'
services:
wealth-tracker:
image: nicejade/wealth-tracker
container_name: wealth-tracker
ports:
- '8888:8888'
volumes:
- ./data:/app/data
restart: unless-stopped
volumes:
data:

这将在后台启动服务,并且效果与下面的 docker run 命令相同。使用 Docker Compose 可以更方便地管理多个容器,并且配置更易读和维护。

或者 docker run

1
docker run -d -p 8888:8888 -v "$(pwd)/data:/app/data" nicejade/wealth-tracker

如果您在本地部署,只需打开网址——http://localhost:8888 即可访问。如果在服务器运行,可通过 http://[Server-IP]:8888 来访问,您也可以指定其他端口。

使用 Node.js

1
2
3
4
5
6
7
8
# clone project
git clone https://github.com/nicejade/wealth-tracker.git
# install & run for client
cd client && pnpm i && pnpm start
# install & run for srever
cd server && pnpm i && pnpm start

本项目客户端采用 Svelte 框架,基于 Vite 所构建,默认 5173 端口,只需打开网址—— http://localhost:5173 即可访问。

命名由来

在项目开发初期,有为应用取中文名为:”财富追踪器”(英文名:Wealth Tracker)。这个名称初看简洁明了,似乎完美契合产品理念。然而,随着开发深入,逐渐显现出其局限性:

  • 概念范畴过广:”财富”一词涵盖范围极广,不仅包括金钱资产,还可能指代时间、知识、经历,甚至是绝美容颜等无形价值。
  • 功能定位不够精准:该应用实际上专注于能被精确计算和记录、且已经形成的有形资产,而非泛泛追踪所有形式的”财富”。

这种认知更新促使重新思考产品定位和命名。偶然想到了两个颇具启发性的成语:”生财有道”和”生财有术”;而应用的核心功能恰恰是记录资产增长的轨迹。基于这一灵感,最终确定将应用命名为”生财有迹“。这个名字巧妙地结合了几个要素:

  1. “迹”与”记”同音,暗示了记录的功能。
  2. “生”与”升”同音,象征着资产的增长。
  3. 整体保留了”生财”的概念,与原有的资产主题保持一致。

“生财有迹”这个新名称不仅准确反映出产品功能定位,传达了产品理念,还蕴含了对用户资产增长的美好祝愿,希望您也会喜欢。

给予支持

生财有迹项目开源且免费,然而设计与编码需耗费时间和精力。如若您对其使用感到满意,请考虑通过以下方式进行小额捐赠:


生财有迹 - 微信赞赏码

微信扫码赞助




Buy Me A Coffee

路线图

“生财有迹”项目正处于积极的设计和研发阶段,致力于在功能丰富与易用性之间寻求平衡,以满足用户日益增长的个人财务管理需求。未来开发重点包括增强数据可视化能力、加强数据安全性、以及提升 AI 辅助分析功能等。

  • 更新资产数据记录;
  • 资产数据可视化;
  • 查阅数据记录详情;
  • 设置阶段性目标;
  • 资产数据安全性;
  • 借助 AI 辅助分析;

特别鸣谢

本项目的开发过程中,依赖并受益于以下优秀的开源技术和工具(未包含全部)。它们不仅提供了强大的功能,还促进了项目的高效开发和稳定运行。

  • Svelte: 作为一种新兴的前端框架,Svelte 通过其创新的编译时技术,让我们的 Web 应用更加轻量和高效。它减少了我们需要编写的样板代码,同时提高了运行时的性能。
  • TailwindCSS: 通过提供实用主义的 CSS 类,TailwindCSS 极大地简化了样式设计的过程。它使得我们能够快速构建美观且响应式的用户界面,同时保持代码的清晰和维护性。
  • Vite: 作为一个现代化的前端构建工具,Vite 通过其快速的冷启动和即时的模块热更新,极大地提高了我们的开发效率。它利用了原生 ES 模块特性,使得项目构建更加高效。
  • Flowbite: 提供了一系列预构建的组件和模板,Flowbite 极大地加快了我们的开发流程。它帮助我们快速实现了复杂的用户界面元素,同时保持了代码的可定制性和可维护性。
  • Axios: 作为一个基于 Promise 的 HTTP 客户端,Axios 简化了我们的 Web 应用中与 API 的交互。它的易用性和广泛的功能集使得我们能够轻松处理 HTTP 请求和响应。
  • Day.js: 作为一个轻量级的 JavaScript 日期库,Day.js 提供了直观的 API 来处理日期和时间。它使得我们在应用中处理复杂的日期计算变得简单且可靠。
  • Node.js: 作为一个高效的 JavaScript 运行环境,Node.js 使得服务器端开发变得前所未有的简单和快速。它的事件驱动和非阻塞 I/O 模型极大地提高了我们的应用性能和响应速度。
  • Fastify: 这个高性能的 Node.js Web 框架为我们提供了一个简单且强大的接口来构建 RESTful API。它的低开销和高度可扩展性使得我们的后端服务既快速又稳定。
  • SQLite3: 作为一个轻量级的数据库引擎,SQLite3 为我们提供了一个无需配置的本地存储解决方案。它的简单性和高效性使得开发者在本地部署应用时能够轻松管理数据。
  • Sequelize: 作为一个强大的 ORM 框架,Sequelize 为我们提供了一种简单且直观的方式来管理数据库关系。它的灵活性和功能丰富性使得我们能够轻松实现复杂的数据操作和查询。

在此,对上述技术和工具的开发者和社区,致以崇高的敬意和衷心的感谢❤️。正是得益于他们的卓越贡献,生财有迹才能得以成功构建并持续优化。同时,也要感谢如 ChatGPT、Github Copilot、PoeKimi 等 AI 工具在开发过程中提供的宝贵支持,它们显著提高了工作效率和体验。

如何将 Tailwind CSS 引入快应用开发提升编码效率?

2023-07-19 20:20:00

Tailwind CSS,在 Web 开发领域,已经成为各种框架、开发人员标配;已经有大量实例证明,基于 Tailwind CSS 来编写样式,可以为开发者节省诸多时间;而且,能够优化减小代码体积、提升运行性能,是非常棒的技术套件。 快应用 开发,同样基于 Web 技术栈,理论上也完全可以使用 Tailwind CSS;在实际开发过程中,该如何使用 Tailwind CSS 呢?本文旨在对此做些许分享。

Tailwind CSS 的工作原理是扫描所有 HTML 文件、JavaScript 组件和任何其他模板的类名,生成相应的样式,然后将它们写入静态 CSS 文件。它快速、灵活、可靠,且运行时间为零。官方提供 Tailwind CLI 、PostCSS、Play CDN 等使用方式;下面主要讲下如何基于 Tailwind CLI 方式,在应用开发中使用 Tailwind CSS:

Tailwind CSS 可为快应用开发带来哪些好处?

Tailwind CSS 是一种现代的 CSS 框架,它提供了一组预定义的 CSS 类,用于快速开发现代 Web 应用程序。Tailwind 的核心理念是为开发者提供一种灵活的方法来构建自定义的 UI 组件,而不需要编写大量的 CSS 代码。

Tailwind CSS 的工作原理是扫描所有 HTML 文件、JavaScript 组件和任何其他模板的类名,生成相应的样式,然后将它们写入静态 CSS 文件。它快速、灵活、可靠,且运行时间为零。

在快应用开发中引入,可以为项目带来四方面的好处:更快的编写效率更小的代码总体积更高的运行效率更易于项目维护。更详细说明如下:

  • 预定义的 CSS 类可以减少样式的冗余,从而减小 CSS 文件的体积。
  • 大量配套设施,可以提高开发效率,不必手动编写大量的 CSS 代码。
  • 提供了自动优化工具,可以删除未使用的 CSS 代码。
  • 代码体积减小,可以减少下载、加载、解析等步骤耗时。
  • 使 CSS 样式更规范化,避免冗余的样式和复杂的选择器,优化性能。
  • 拥有活跃的社区和文档,可以帮助开发者快速上手和解决问题。

Tailwind CSS:当今最流行 CSS 框架;相信借助其巧妙设计、结合强大生态,您也会偏爱用它来塑造 UI;如果必须要手动编码:那无需频繁滚动编辑区,无需于 template 与 style 之间横跳,无需绞尽脑汁为类命名,无需再编写重复的 CSS……是多么美妙。

Tailwind CSS

如何在项目中使用 Tailwind CSS?

安装 Tailwind CSS 依赖

通过 npm 安装 tailwindcss 并创建 tailwind.config.js 文件,具体命令如下:

1
2
3
4
pnpm install -D tailwindcss
# OR
# npm install -D tailwindcss
npx tailwindcss init

配置您的模板路径

在文件中添加所有模板文件的路径 tailwind.config.js,参考性配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
const colors = require('tailwindcss/colors')
const selfCustomColors = {
brand: {
DEFAULT: '#1e293b',
},
warn: {
DEFAULT: '#f59e0b',
},
link: {
DEFAULT: '#0ea5e9',
},
mark: {
DEFAULT: '#ff4582',
},
}
module.exports = {
mode: 'jit',
content: [
'./src/**/*.{ux,html,js,svelte,vue,ts}',
'./node_modules/flowbite/**/*.js',
],
purge: {
enabled: true,
content: [
'./src/**/*.{ux,html,js,svelte,vue,ts}',
'./node_modules/flowbite/**/*.js',
],
},
// https://tailwindcss.com/docs/configuration#core-plugins
corePlugins: {
preflight: false, // disable base/reset styles
container: false, // disable container component
content: false, // disable `content` utility
accentColor: false, // disable `accent-color` utility
accessibility: false, // disable `appearance` utility
appearance: false, // disable `appearance` utility
aspectRatio: false, // disable `aspect-ratio` utility
backgroundOpacity: false, // disable `background-opacity` utility
backdropBlur: false, // disable `backdrop-blur` utility
backdropBrightness: false, // disable `backdrop-brightness` utility
backdropContrast: false, // disable `backdrop-contrast` utility
backdropGrayscale: false, // disable `backdrop-grayscale` utility
backdropHueRotate: false, // disable `backdrop-hue-rotate` utility
backdropInvert: false, // disable `backdrop-invert` utility
backdropOpacity: false, // disable `backdrop-opacity` utility
backdropSaturate: false, // disable `backdrop-saturate` utility
backdropSepia: false, // disable `backdrop-sepia` utility
blur: false, // disable `blur` utility
borderCollapse: false, // disable `border-collapse` utility
borderOpacity: false, // disable `border-opacity` utility
borderSpacing: false, // disable `border-spacing` utility
boxShadow: false, // disable `box-shadow` utility
boxShadowColor: false, // disable `box-shadow-color` utility
boxDecorationBreak: false, // disable `box-decoration-break` utility
boxSizing: false, // disable `box-sizing` utility
breakAfter: false, // disable `break-after` utility
breakBefore: false, // disable `break-before` utility
breakInside: false, // disable `break-inside` utility
brightness: false, // disable `brightness` utility
captionSide: false, // disable `caption-side` utility
caretColor: false, // disable `caret-color` utility
clear: false, // disable `clear` utility
contrast: false, // disable `contrast` utility
divideColor: false, // disable `divide-color` utility
divideOpacity: false, // disable `divide-opacity` utility
divideStyle: false, // disable `divide-style` utility
divideWidth: false, // disable `divide-width` utility
float: false, // disable `float` utility
fontVariantNumeric: false, // disable `font-variant-numeric` utility
hyphens: false, // disable `hyphens` utility
isolation: false, // disable `isolation` utility
lineClamp: false, // disable `line-clamp` utility
mixBlendMode: false, // diable `mix-blend-mode` utility
listStyleImage: false, // disable `list-style-image` utility
listStylePosition: false, // disable `list-style-position` utility
listStyleType: false, // disable `list-style-type` utility
objectPosition: false, // disable `object-position` utility
opacity: false, // disable `opacity` utility
outlineColor: false, // disable `outline-color` utility
outlineOffset: false, // disable `outline-offset` utility
outlineStyle: false, // disable `outline-style` utility
outlineWidth: false, // disable `outline-width` utility
overscrollBehavior: false, // disable `overscroll-behavior` utility
placeContent: false, // disable `place-content` utility
placeItems: false, // disable `place-items` utility
placeSelf: false, // disable `place-self` utility
placeholderOpacity: false, // disable `placeholder-opacity` utility
resize: false, // disable `resize` utility
ringColor: false, // disable `ring-color` utility
ringOffsetColor: false, // disable `ring-offset-color` utility
ringOffsetWidth: false, // disable `ring-offset-width` utility
ringOpacity: false, // disable `ring-opacity` utility
space: false, // disable `space-between` utility
textDecorationThickness: false, // disable `text-decoration-thickness` utility
textOpacity: false, // disable `text-opacity` utility
textTransform: false, // disable `text-transform` utility
textUnderlineOffset: false, // disable `text-underline-offset` utility
touchAction: false, // disable `touch-action` utility
userSelect: false, // disable `user-select` utility
verticalAlign: false, // disable `vertical-align` utility
whitespace: false, // disable `whitespace` utility
wordBreak: false, // disable `word-break` utility
willChange: false, // disable `will-change` utility
},
darkMode: false,
theme: {
colors: { ...colors, ...selfCustomColors },
extend: {
width: ({ theme }) => ({
auto: 'auto',
...theme('spacing'),
}),
height: ({ theme }) => ({
auto: 'auto',
...theme('spacing'),
}),
spacing: {
'1/2': '2px',
'1': '4px',
'3/2': '6px',
'2': '8px',
'5/2': '10px',
'3': '12px',
'7/2': '14px',
'4': '16px',
'5': '20px',
'6': '24px',
'7': '28px',
'8': '32px',
'9': '36px',
'10': '40px',
'11': '44px',
'12': '48px',
'14': '56px',
'16': '64px',
'20': '80px',
'24': '96px',
'28': '112px',
'32': '128px',
'36': '144px',
'40': '160px',
'44': '176px',
'48': '192px',
'52': '208px',
'56': '224px',
'60': '240px',
'72': '288px',
'80': '320px',
'96': '384px',
},
borderWidth: {
'DEFAULT': '1px',
'0': '0px',
'2': '2px',
'4': '4px',
'8': '8px',
},
borderRadius: {
'none': '0',
'': '1px',
'sm': '2px',
'DEFAULT': '4px',
'md': '6px',
'lg': '8px',
'xl': '12px',
'2xl': '16px',
'3xl': '24px',
},
fontSize: {
'xm': ['12px', { lineHeight: '16px' }],
'sm': ['14px', { lineHeight: '20px' }],
'base': ['16px', { lineHeight: '24px' }],
'lg': ['18px', { lineHeight: '28px' }],
'xl': ['20px', { lineHeight: '28px' }],
'2xl': ['24px', { lineHeight: '32px' }],
'3xl': ['30px', { lineHeight: '36px' }],
'4xl': ['36px', { lineHeight: '40px' }],
'5xl': ['48px', { lineHeight: '60px' }],
'6xl': ['60px', { lineHeight: '60px' }],
'7xl': ['72px', { lineHeight: '60px' }],
'8xl': ['96px', { lineHeight: '60px' }],
'9xl': ['128px', { lineHeight: '60px' }],
}
},
},
variants: {
extend: {},
},
plugins: [],
}

将 Tailwind 指令添加到您的 CSS 中

@tailwind 将 Tailwind 每个层的指令添加到您的主 CSS 文件中。

1
2
3
4
5
/* input.css */
/* @tailwind base; */
@tailwind components;
@tailwind utilities;

启动 Tailwind CLI 构建过程

运行 CLI 工具来扫描模板文件中的类并构建 CSS,参考性命令如下:

1
npx tailwindcss -i ./src/input.css -o ./src/output.css --watch

这是看起来路径简短的方式,实际上这个 input.cssoutput.css,无论是名字,或是它存在的路径,皆可以自行指定,您可以按照自己喜欢的方式、或是团队约定俗成的形式;譬如统一存放在:src/assets/styles 目录下。

需要补充说明的是:在团队开发中,输入上述命令,略显繁琐,可以在 package.json 注入命令(如下示例);如此以下,您只需在「终端」运行 pnpm tailwindcssnpm run tailwindcss 命令即可。

1
2
3
"scripts": {
"tailwindcss": "npx tailwindcss -i ./src/input.css -o ./src/output.css --watch",
}

开始在 UX 中使用 Tailwind CSS

将已编译的 CSS 文件,在 .ux (非 app.ux)文件中,通过 @import 方式引入;

1
2
3
<style>
@import './../../output.css';
</style>

现在,即可在 .uxtemplate 中,开始使用 Tailwind 的实用程序类来设置内容的样式,如下面这段代码示例:

1
2
3
4
5
6
<template>
<div class="bg-blue-300 w-full flex flex-col justify-center items-center">
<text class="text-red-600">TailwindCSS Area</text>
<text class="text-red-600">Awesome TailwindCSS</text>
</div>
</template>

当您写完保存之后,打开 output.css 即可如下的 CSS 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/* @tailwind base; */
.flex {
display: flex
}
.w-full {
width: 100%
}
.flex-col {
flex-direction: column
}
.items-center {
align-items: center
}
.justify-center {
justify-content: center
}
.bg-blue-300 {
background-color: #93c5fd
}
.text-red-600 {
color: #dc2626
}

至此,在 快应用 开发中引入 Tailwind CSS 的准备工作,已经初步完成,您可以与 Tailwind CSS 开启愉快合作之旅,从而促使高效编码、提前完工。假如,您对 Tailwind CSS 尚不熟悉,可通过查阅 Tailwind CSS Doc ,亦可在线体验—— Tailwind Playground

需要补充说明的是,使用 Tailwind CSS 并不破坏您原来的 CSS 书写✍🏻方式;您完全可以结合喜欢的预处理器(如 Sass、Less、Stylus),来共同工作,而无需做更多设置(如下代码示例);但我以为当您熟悉 Tailwind CSS 之后,大有可能也会“移情而别恋”。

1
2
3
4
5
6
7
8
9
10
11
12
<style lang="scss">
@import './../../assets/styles/style.scss';
@import './../../assets/styles/output.css';
.primary-btn {
width: 90 * $size-factor;
height: 16 * $size-factor;
background-color: $brand;
border-radius: 8 * $size-factor;
color: $white;
}
</style>

如何基于 Tailwind CSS 提升开发效率?

安装 Tailwind CSS IntelliSense 扩展

您可以在应用开发工具的「扩展市场」,通过关键字 Tailwind 检索”Tailwind CSS IntelliSense“扩展——适用于 Visual Studio Code 的智能 Tailwind CSS 工具,用户提供自动完成、语法突出显示和 linting 等高级功能来增强 Tailwind 开发体验;略作适配即可支持 *.ux;详细设置,可参见: Tailwind CSS IntelliSense

Tailwind CSS IntelliSense 提升 ux 开发效率

默认情况下,编辑“字符串”内容时(例如在 JSX 属性值中),开发工具中不会触发完成。更新设置 editor.quickSuggestions 可能会改善您的体验:

1
2
3
"editor.quickSuggestions": {
"strings": "on"
}

参考基于 Tailwind CSS 组件的开源库

Tailwind CSS 生态发展繁荣超乎想象,就连其衍生产品也不可胜数;如 Flowbite ——包含 600 多个 UI 组件、部分和页面的开源库进行开发,该库使用 Tailwind CSS 的实用程序类构建并在 Figma 中设计。它不仅能充当 Tailwind CSS 插件使用,也可以拷贝到项目直接使用,还可以在线查阅效果(支持多种屏幕设备类型),挑选匹配实现方案;在仍是基于组件树构建页面的时代,极大提升页面搭建效率。如: pagination 组件:

Tailwind CSS Flowbite Pagination


常见问题及说明

如果您熟悉 Web 开发,针对上述教程,您可能会有诸多疑惑;实际上,笔者在实践之时,也有发现,只不过因为各种机制限制,目前只能如此。下面就与诸君分享,期可解惑:

不能在 script 标签中,引入输出 CSS 文件么?

按 Web 开发习惯,在 app.ux 文件中可以直接 import 输出 CSS 文件(如下代码所示),那为何未建议如此呢?

1
2
3
<script>
import './output.css'
</script>

因为这样做会报如下错误;具体是缺乏与之匹配的 loader;当然,可以使用 css-loaderstyle-loader 来处理 CSS 文件,详见 ChatGPT | You may need an appropriate loader….

1
2
3
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| /* @tailwind base; */

但在快应用开发过程中,却不能生效;因为 style-loader 的作用是将 CSS 注入 DOM,其中用到了诸多浏览器 API(document),而快应用的开发虽然是基于前端技术栈,但其运行环境止于 v8,实际的渲染是由 Android 底层完成,并未走浏览器这条路,因此无法工作。在构建工具优化、兼容之前,通过 style 标签中引入 CSS,成了主要选择。

为何在 tailwind.config.js 禁用如此多样式?

Tailwind corePlugins 部分允许您完全禁用 Tailwind 通常默认生成的类(如果您的项目不需要它们);这个设计对于快应用实在必要的紧,在上述示例中,对 text-opacity 等样式进行禁用,也是无奈之举。具体原因在于以下两点:

其一:快应用标准虽然基于 Web 技术栈,但只是 Web 标准子集,如蛮多 CSS 属性并不能很好的支持;其二:默认情况下,TailwindCSS 会将样式属性的值存储为 CSS 变量(例如 --tw-text-opacity),以便进行动态计算和响应式设计。

如此一来,在 template 中使用类 text-red-300border-spacing-1,输出的便是如下 CSS;这样的写法,在快应用中并不能得到正确解析,也就无法起到期待效果,于是禁用便成了必须要做之事。当然,这样禁用也好处:利于输出更小提及的 CSS 文件。其他属性亦复如是。

1
2
3
4
5
6
7
8
9
.text-red-300 {
--tw-text-opacity: 1;
color: rgb(252 165 165 / var(--tw-text-opacity))
}
.border-spacing-1 {
  --tw-border-spacing-x: 4px;
  --tw-border-spacing-y: 4px;
  border-spacing: var(--tw-border-spacing-x) var(--tw-border-spacing-y)
}

为何要在 input.css 中移除 @tailwind base;

这么做主要未解决问题: How disable default styles for : before and : after

1
2
3
4
5
/* input.css */
/* @tailwind base; */
@tailwind components;
@tailwind utilities;

在一般 Web 开发过程中,会将 base、components、utilities 等指令,都添加到 CSS 文件项目中;但,在快应用开发过程中,这无疑是累赘;因为它的存在,会使得 output.css 输出较多对项目没有裨益额外内容(如下代码所示),故而移除;这与通过 corePlugins 禁用基础样式(preflight)、禁用容器组件(container)作用类似。

1
2
3
4
5
6
7
8
*, ::before, ::after {
--tw-border-spacing-x: 0;
......
}
::backdrop {
--tw-border-spacing-x: 0;
......
}

为什么要在配置中通过 theme 自定义长度单位?

修改长度单位从 rempx,这也是不得已而为之。 快应用 标准对 长度单位 的支持,在 1070 及以下版本仅支持长度单位 px%。从 1080 版本开始,新增了长度单位 dp。它无法支持 rem,就只能自定义设置为 px;在通过 theme 自定义长度单位,是 Tailwind CSS 官方提供的功能,以此能够实现更精细的样式控制;虽然操作不难,但属性较多、约定繁杂。后续时间如果允许,将探索 rem to px 批量转换插件来实现,以达到快速修改。如果您感兴趣,可以查阅 Tailwind CSS 完整版本配置—— config.full.js

其他暂未解决问题

  • 少部分类名写法,快应用构建不支持

在 Tailwind CSS 机制中,支持使用类名诸如 h-[100px] w-1/3 (对应生成 CSS 如下),然而,在快应用构建工具暂不支持这类名,于是乎这样写便不会生效,当然也不会造成什么问题;后续亟待打包工具优化。

1
2
3
4
5
6
.h-\[100px\] {
height: 100px
}
.w-1\/3 {
width: 33.333333%
}

在打包(Toolkit)未解决该问题之前,您可以手动写一个 class,或者使用内联样式(style)来兼容;在这种情况下,更推荐后者;因为引入 Tailwind CSS 的开发模式中,基本不用手写 class,即无需滚动到 style 标签或跳转 less、(s)css、文件,那么直接在 template 中使用内联更为便捷。

1
2
3
4
5
6
7
<div class="training-list-width" style="width: 326px;"></div>
<style>
.training-list-width {
width: 326px;
}
</style>
  • 快应用构建,资源存在重复引用问题

前文中提到,在 script 标签中 import CSS 资源,暂时未得到支持;但,在 style 标签中 @import 的 CSS 文件,被 A、B 两个页面(*.ux)引入,那么对应的 css 内容,就会被打入对应页面(即便有的内容没有被使用),从而导致代码体积略有增加(即便参考 如何优化「快应用」rpk 包体积? 一文中的方法,也不可避免)。这是快应用构建本身存在的问题,使用 Tailwind CSS 也不例外。后续需要打包工具优化。

以上,就是在 快应用 开发过程中,引入 Tailwind CSS 所需的操作、以及常见问题说明。肯定还有异常更多情况没有考虑到,后续会逐步补充;如果您在实际运用过程中,欢请留言交流、反馈、分享。

2023 年 07 月 05 日写于〔深圳福田〕

猜您可能感兴趣的文章

关于「晚晴幽草轩」博客缓更说明

2023-05-01 20:20:00

晚晴幽草轩 于 2014 年,采用 Hexo 所搭建;专注互联网开发,以及分享优质网站、AI 应用、效率工具、心得感悟等内容;至今已近 9 年。只不过它是本地 Markdown 静态博客,不能随时在线更新,已然不适如今之快节奏;每有新的见闻、感悟,有在以下几个在线平台进行记载:

  • 倾城之链:基于 Vue2Node.js 等技术栈,所搭建的在线导航平台,用以记录所遇见的有价值网站,每周定期更新。
  • 静轩之别苑,由 Ghost 所驱动,2019 年 元月基于 Docker 部署于阿里云服务器,用于记录技术相关心得。
  • 悠然宜想亭, 2021 年 3 月 基于 Flarum(一款优雅简洁论坛软件)所搭建的“社区型个人博客”,至今有记录文章近 300 篇,不定期更新。
  • 半缘修道观 ,2022 年 11 月,基于 MemosDocker Compose 所搭建的“个人微博/推特/备忘录📕”,用于记录学习、感悟、电影、投资、娱乐、科普、代码、 ChatGPT 等相关内容,不到半年已记录近 200 条,是目前更新最为频繁的平台。

除此之外,闲暇时间,有构建些 Web 应用,诸如:玉桃文飨轩 (Markdown 在线转图片)、素问智聊斋(ChatGPT 在线客户端),感兴趣朋友可移步以了解更多。后续如果有写值得分享的长篇,依旧会同步至「晚晴幽草轩」。

2025 年 5 月 02 日写于〔深圳福田〕

素问智聊斋,非官方 ChatGPT 在线客户端,免费可用

2023-04-10 20:20:00

素问智聊斋,非官方 ChatGPT 在线客户端,旨在提供更便捷的 ChatGPT 访问体验;它基于非官方 ChatGPT APISvelteTailwindCSSVite 和 NodeJS 所搭建,无需账号,零配置,即可与 ChatGPT 畅聊;支持自定义 OPENAI API KEY。

素问智聊斋,非官方 ChatGPT 在线客户端

目标与哲学

OpenAI 于 2022 年 11 月推出的超级对话模型 ChatGPT, 受到来自世界各地的认可和赞誉,令人印象深刻。然而,由于一些原因,如果没有正确搭建相应的环境(🪜),ChatGPT 在部分地区就无法正常使用。鉴于此,搭建了这个服务,以便用户能够方便地使用 ChatGPT。当然,条件允许您可前往 OpenAI 官网上注册、登录、申请专属 API KEY。此外,为了保障用户的数据安全,本服务的操作过程中不会存储任何使用者的数据,因此可以放心使用(备注:这段介绍有使用本服务加以润色)。

适用场景

  • 没有注册 Open AI 账号,导致无法使用 ChatGPT 时;
  • 因为网络环境限制,无法正常使用 ChatGPT 时;
  • 具备账号,想让远方亲人、朋友快速体验 ChatGPT;

补充说明:承诺后台不会保存任何数据;基于 API KEY 发起的对话内容,会同步到对应账号;如果您习惯使用桌面客户端,类似项目有: lencx/ChatGPT

诞生初衷

最原始的动机,是因为:以上两点适用场景所对应的诉求,我觉得都需要。但,这并不足以缘起这个项目,更详细的阐述如下:

作为颇爱折腾的技术人员,ChatGPT 自然是要体验;有请时在美国的朋友,帮着注册®️了账号;然而,蛮多时候即便采用科学上网,设备却无法成功登陆 ChatGPT 官网地址 。恰逢一个契机——帮朋友写几行关于 ChatGPT 的示例;当痛点(Motivation:动机)碰上可执行性(Ability:能力),外加适当的 触发条件 (Trigger),福格行为模型(BJ Foog’s Behaviour Model)已全部满足,于是乎, 素问智聊斋 就有了诞生的充足理由。

命名来源

早在 关于“悠然宜想亭”的由来,以及未来 一文提及,对于网站取名多是五个字;或是兴趣的原因,其后缀带有 亭台楼阁、轩榭廊舫,殿庭苑斋 其中一个;其中大部分已被使用;因为「Chat」的应为对应的是「对话、聊天」;于是,「斋」字就这么定下;AI 对应智能,所以「智聊」也就应景而生。

原本命名为「智聊问异斋」,后觉不妥,略阅资料,遂修改为 素问智聊斋;素问:最早或于《黄帝内经》;釋名:“「素者,本也;問者,黃帝問於岐伯也」”。另有解释为:“ 即问本,探索人与自然的根本性问题 ”。当想 ChatGPT 说:“解释下「素问」”,它给出以下解释:

「素问」是一种中国古代哲学思想,它强调对本质的探究。它的核心思想是:任何事物都有其本质,而且这个本质不受时间和空间的束缚,所以要理解它,就必须通过探究本质来探索事物的真相。

技术选型

前端采用了 SvelteTypeScriptTailwindCSSFlowbiteMDSvexVite 、 等流行技术栈,而后台则采用 Fastify 框架;在服务器上,则基于 Nginxpm2 进行部署;其中 Svelte、TailwindCSS、MDSvex 等工具,极大提升了编写代码的舒适度,令人青睐有加。

思考感悟

关于 ChatGPT(或其他 AI 产品),相信接触过它的人们,或多或少都会有自己的感受;目前为止,吾有以下几点看法:

  • 类似 ChatGPT 这样的 AI 产品,必将像如今的手机一般,成为绝大部分人类生活必需品,这很难以人类意志为转移;
  • 毕竟是工具,使用乃至产生依赖,倒无不可;但也不能荒废自身,我辈仍须保持深度学习习惯,及提高学习能力;
  • AI 会进而加剧人与人之间的差异;因为不喜欢折腾或探究新鲜事物的人,很难尽早去接触它,而是等时代浪潮拍打过来。

未来规划

新注册 Open AI 账号,为 API Key 调用费用赠送 18$,为期三个月;4 月 1 日过期之后,为使得服务能够正常运行,有继续购买它的服务。ChatGPT 的价格为:0.002 美元 1000 个 tokens(约为 750 个英文单词),GPT4 则更贵一些;当使用费用超过所能承受的能力,外加服务器使用费用,或可能考虑植入定量商业化措施。现如今,如果您认为 素问智聊斋 对您有一定价值,可以考虑为发起 赞助

其他作品

以上介绍内容,部分使用 ChatGPT 加以润色 。截止目前,它可以协助人类,已经很多,诸如学术论文、内容创作、翻译、数据分析、研究咨询、简历和求职信、广告文案、编写小说、个人陈述、 SEO 优化等等,如果想让它更好帮助到您,可以移步 ChatGPT 中文调教指南 ,学习怎么让它在不同场景,更好听理解您的指令。

您可能感兴趣的文章

为什么说 WebAssembly 让 Web 的未来更光明?

2022-12-30 21:21:00

WebAssembly 堪称一个革命性的技术,它给 Web 带来了更多的可能性,对于 CPU 密集型的应用,比如图片、音频、视频、直播、机器学习、AR、VR、游戏、在线会议、在线文档、在线 IDE、在线游戏等等,WebAssembly 既可以帮助 Web 突破性能瓶颈,也可以让 Web 得以利用其他语言的代码库。随着越来越多业务跟服务转战云端,基于 Web 本身优势,外有 WebAssembly 技术性能加持,在可预见的未来,WebAssembly 可让 Web 再次绽放。

WebAssembly 历史起源

WebAssembly 起源于 Mozilla 员工的一个业余项目。2010 年,在 Mozilla 从事 Android Firefox 开发的 Alon Zakai,为了把他以前开发的游戏引擎移植到浏览器上运行,利用业余时间开发了一款名叫 Emscripten 的编译器,可以把 C++ 代码通过 LLVM IR 编译成 JavaScript 代码。

到了 2011 年底,Emscripten 甚至能够成功编译 Python 和 Doom 等大型 C++ 项目,Mozilla 此时觉得这个项目很有前途,于是成立团队并邀请 Alon 全职开发这个项目。2013 年 Alon 和其他成员一起提出了 asm.js 规范,asm.js 是 JavaScript 语言的一个严格子集,试图通过“减少动态特性”和”添加类型提示“的方式帮助浏览器提升 JavaScript 优化空间。相较于完整的 JavaScript 语言,裁剪后的 asm.js 更靠近底层,更适合作为编译器目标语言。

asm.js 只提供两种数据类型:32 位带符号整数,64 位带符号浮点数,其他数据类型比如字符串、布尔值或者对象,asm.js 一概不提供,它们都是以数值的形式存在,保存在内存中,通过 TypedArray 调用。类型的声明也有固定写法:变量 | 0 表示整数,+变量 表示浮点数。例如下面一段代码:

1
2
3
4
5
6
7
8
9
function MyAsmModule() {
"use asm"; // 告诉浏览器这是个 asm.js 模块
function add(x, y) {
x = x | 0; // 变量 | 0 表示整数
y = y | 0;
return (x + y) | 0;
}
return { add: add };
}

支持 asm.js 的引擎提前识别出了类型,可以进行激进的 JIT(即时编译)优化,甚至是 AOT(事先编译)编译,大幅提升性能。不支持 asm.js 按普通 JavaScript 代码执行也不会影响运行结果。

但是 asm.js 的缺点也很明显,那就是“底层”得不够彻底,例如代码仍然是文本格式;代码编写仍然受 JavaScript 语法限制;浏览器仍然需要完成解析脚本、解释执行、收集性能指标、JIT 编译等一系列步骤。如果采用像 Java 类文件那样的二进制格式,不仅能缩小文件体积,减少网络传输时间和解析时间,还能选用更接近机器的字节码,这样 AOT/JIT 编译器实现起来会更轻松,效果也更好。

与此同时,Google 的 Chrome 团队也在试图解决 JavaScript 性能问题,但方向有所不同。Chrome 给出的解决方案是 NaCl(Google Native Client)和 PNaCl(Portable NaCl)。通过 NaCl/PNaC1,Chrome 浏览器可以在沙箱环境中直接执行本地代码。

asm.js 和 NaCl/PNaC1 技术各有优缺点,二者可以取长补短。Mozilla 和 Google 也看到了这一点,所以从 2013 年开始,两个团队就经常交流和合作。后来他们决定结合两个项目的长处,合作开发一种基于字节码的技术。到了 2015 年,“WebAssembly” 确定为正式名称并对外公开,W3C 成立了 WASM 社区小组(成员包括 Chrome、Edge、Firefox 和 WebKit),致力于推动 WASM 技术的发展。

  • 2016 年 Rust 1.14 发布,开始支持 WASM。
  • 2017 年 Google 决定放弃 PNaCl 技术;四大浏览器 Chrome、Edge、Safari、Firefox 更新版本开始支持 WASM。
  • 2018 年 Go 1.11 发布,开始支持 WASM。
  • 2019 年 Emscripten 更新为默认使用 LLVM 编译为 WASM 代码,停止对 asm.js 的支持;WebAssembly 成为万维网联盟(W3C)的推荐标准,与 HTML,CSS 和 JavaScript 一起成为 Web 的第四种语言。
  • 2021 年 1 月 6 日,Wasmer(🚀支持 WASI 和 Emscripten 的领先 WebAssembly 运行时) 1.0.0 版本发布。
  • 2022 年 09 月 20,Wasmtime(WebAssembly 的快速安全运行时) 的官方 1.0 版本发布。

全面认识 WebAssembly

WebAssembly 诞生背景

Web 平台的成熟催生了复杂而苛刻的网络应用,如交互式三维可视化,音频和视频软件,以及游戏。随着伴随着这一点,Web 上代码的效率和安全性变得比以往更加重要。然而,作为唯一的网络内置语言——JavaScript 并没有很好地满足这些要求,特别是作为编译目标。来自四个主要浏览器供应商的工程师们迎接挑战,合作设计了一个可移植的低级字节码,称为 WebAssembly 。它提供了紧凑的表示、高效的验证和编译,以及安全的低至无开销的执行。WebAssembly 不是致力于一个特定的编程模型,而是 WebAssembly 是对现代硬件的抽象,使其与语言、硬件和平台无关,其使用范围不只是 Web 浏览器;就目前而言,Node.js、Deno、 WebAssembly 运行时 等环境都可使用。

WebAssembly 是什么?

WebAssembly 是一种新的编码方式,可以在现代的网络浏览器中运行 - 它是一种低级的类汇编语言,具有紧凑的二进制格式,可以接近原生的性能运行,并为诸如 C / C ++ 等语言提供一个编译目标,以便它们可以在 Web 上运行。它也被设计为可以与 JavaScript 共存,允许两者一起工作。WebAssembly 是可移植体积小加载快并且兼容 Web 浏览器的全新类汇编语言格式,其具有高效安全开放标准等特性。

WebAssembly (缩写为Wasm)是基于堆栈的虚拟机的二进制指令格式。其设计目的不是为手写代码,而是为诸如 C、C++、Rust 等低级语言提供一个高效的、可移植的编译目标,支持在 Web 上部署客户端和服务器应用程序。

WebAssembly 试图取代 JavaScript 吗?

不会。在 WebAssembly 常见问题 中,作者给出了明确说明:“WebAssembly 旨在补充而非替代 JavaScript。随着时间的推移,WebAssembly 将允许许多语言被编译到 Web,而 JavaScript 具有令人难以置信的势头,并将继续保持 Web 的单一、特权( 如上所述 )动态语言。此外,预计 JavaScript 和 WebAssembly 将在许多配置中一起使用”。

理解 WebAssembly 文件格式

编译器 VS 解释器

  • 源代码(source code):由开发者基于 JavaScript、TypeScript 等编程语言直接提供,主要用来给人类阅读、维护的文本格式。即便是压缩、混淆后,依然是文本格式。
  • AST:抽象语法树(Abstract Syntax Tree,AST),或简称语法树(Syntax tree),是源代码语法结构的一种抽象表示。它以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。之所以说语法是“抽象”的,是因为这里的语法,并不会表示出真实语法中出现的每个细节。
  • 汇编代码:(Assembly Code),是介于高级语言和机器码之间的一种中间语言(也是人看的懂的语言)。它比机器代码高一级,比高级语言低一级。而且,它的语法类似于英语,但比高级编程语言更难。它经过转译最终也会成为机器码,所以抽象上来说,它和字节码是同一级别的。可以简单将其理解为机器语言的助记符,便于人们理解和记忆。像用地址符号(Symbol)或标号(Label)代替指令或操作数的地址,常见的 x86 汇编指令有 MOV、PUSH、POP 等。
  • 字节码:(Byte Code)是一种包含 执行程序、由一序列 OP 代码(操作码)/数据对 组成的二进制文件。 字节码是一种 中间码,它比机器码更抽象,需要 直译器转译 后才能成为机器码的中间代码(通常不是人类可读的语言)。
  • 机器码:(Machine Code),学名 机器语言指令,有时也被称为 原生码(Native Code),是电脑的 CPU 可直接解读 的数据(即计算机只认识 0 和 1)。
  • WebAssembly 文本格式 :推荐扩展名是 .wat(WebAssembly Text Format),是另外一种输出格式,是使用 “S- 表达式” 的文本格式,可以近似理解为与二进制等价的汇编代码。部分浏览器的开发者工具支持将 WASM 转换成 WAT 查看,便于在线调试。社区提供了 wasm2watwat2wasm 等成熟的工具将二者进行转换,可以在 WebAssembly/wabt (WebAssembly Binary Toolkit) 工具集中找到,所以也是可以直接编写 WAT 再转换成 WASM。
  • WebAssembly 二进制格式.wasm) :WebAssembly 的最终形式,是一种低级字节码,基于 16 进制表示;无需解析,只要解码并且检查确认代码,即可编译为机器码
  • WASI:(WebAssembly System Interface),一种与不同操作系统通信统一标准;它是为 WASM 专门设计一套引擎无关(engine-indepent)、面向非 Web 系统(non-Web system-oriented)的 API 标准;遵循可移植性、安全性两大原则。WASI 在 WASM 字节码与虚拟机之间,增加了一层“系统调用抽象层”。

WebAssembly 优缺点

从 WebAssembly 诞生背景及目标来看,它所要解决的是 JavaScript 语言本身限制,不足以应对 CPU 密集型应用的问题。因此,优缺点比较对象是 JavaScript、以及 Native Client 和 asm.js 等尝试“解决 Web 上安全快速代码”的方案。

Native Client:是一个沙箱,用于在浏览器中高效、安全地运行已编译的 C 和 C++ 代码,独立于用户的操作系统。它已于 2020 年弃用,支持将于 2021 年 6 月结束。
Asm.js:代码在很多方面类似于 C,但它仍然是可以在所有当前引擎中运行的完全有效的 JavaScript。Firefox 是目前唯一可以做到这一点的浏览器。已被弃用。

WebAssembly VS JavaScript 优点

更好性能

WebAssembly 和 JS 运行过程对比

  • 下载
    • JS 是高级语言,便于开发者阅读和编写,文件体积比汇编语言大。
    • WebAssembly 不是设计用于手动编写的,也不是供人类阅读的。代码被编译为 WebAssembly 之后,字节码会以二进制格式而不是文本格式表示,这可以减小文件大小,从而支持快速传输和下载。
  • 解析/解码
    • JS 需要先通过词法分析、语法分析生成 AST,然后再由 AST 生成字节码。
    • WebAssembly 是一种字节码,不需要进行解析,只需要解码并且检查确认代码没有错误就可以了。
  • 编译(优化、反优化):
    • JS 是弱语言类型,无法预知变量类型。JIT 监测热点代码,在代码执行若干次后,优化编译器才将其编译为机器码并优化。如果数据类型被动态修改,优化编译器会进行反优化,下次执行时会回退到解释器解释执行。
    • WebAssembly 代码是静态类型的,即可以预知变量持有的值的类型。WebAssembly 代码可以从一开始就编译为机器码,无须先监测,因此第一次运行代码就可以看到性能提升。WebAssembly 更接近机器码,在编译阶段不需要做太多的优化;WebAssembly 代码的类型是确定的,不存反优化的阶段。
    • WebAssembly 二进制文件的设计方式使得模块验证可以在一轮内完成,其结构也支持并行编译文件的不同部分。
    • 浏览器厂商引入了流编译技术,在浏览器下载和接收文件时,该技术可以将 WebAssembly 代码编译为机器码。流编译支持 WebAssembly 模块下载完毕,即进行初始化,这样会显著加速模块的启动过程。
  • 执行
    • JS 是一种编程语言,更注重开发效率和代码可读性,开发者编写的代码不一定能发挥 JIT (just-in-time) 的优化机制。
    • WebAssembly 被设计为编译目标,专注于提供更加理想的指令(执行效率更高的指令)给机器,执行效率更高。
  • 垃圾回收
    • JS 引擎会自动进行垃圾回收,垃圾回收可能会在一个不合适的时机启动并造成性能损耗。大多数浏览器已经能给垃圾回收安排一个合理的启动时间,但还是会增加性能开销。
    • WebAssembly 不支持垃圾回收,内存操作都是手动控制的(像 C、C++一样),性能由开发者控制。

便携且安全

WebAssembly 独立于平台、独立于硬件和独立于语言,它对设备或浏览器没有任何特殊要求,这增强了其便携性;其设计原则是与其他 Web 技术和谐共处,并保持向后兼容。代码在内存安全的沙盒环境中进行验证和执行,可以防止安全漏洞和数据损坏。此外,像其他 Web 代码一样,它遵循浏览器的同源策略和授权策略。

支持多线程

WebAssembly 不直接支持多线程。但是,WebAssembly 程序可以在宿主环境中执行,这个宿主环境可能支持多线程。因此,WebAssembly 程序间可以通过宿主环境来协调多线程(通过 Web Worker、共享线性内存 SharedArrayBufferWebAssembly atomics )。详情可参见文章: Using WebAssembly threads from C, C++ and Rust

集成已有库

如果应用程序使用 C/C++、Rust 或任何其他兼容语言,WebAssembly 可以轻松地将代码或桌面应用程序用于 Web。如今(2022 年 12 月)生态已经非常丰富,除了用于 Rust 的 wasm-pack 和用于 C/C++Emscripten 之外,还有 AssemblyScriptTinyGo 凡此种种,详情可参见: Awesome Wasm Compilers

WebAssembly VS JavaScript 缺陷

尽管 WebAssembly 具有很多优点,但目前仍存在些缺陷,譬如:

  • 旧浏览器不支持:它只能在支持 WebAssembly 的浏览器(或 runtime)中运行;倘若环境不支持,需要使用其他方式来实现(假如要考虑兼容);
  • 不能直接访问 DOM:WebAssembly 目前还不能直接访问浏览器的 DOM 元素;如果代码要访问浏览器 DOM,需要调用 JavaScript 方法来实现( 已有计划实现 );
  • 存在局限:比起 JavaScript,编写相关代码不够灵活,需要经过编译;需要手动分配内存,且缺少用于自动内存管理的垃圾收集 (GC)(尽管有计划添加 GC);

显而易见,没有技术会是银弹,只有把技术放在适用的场景下才能达到事半功倍的效果;在开发效率,与运行效率两者之间,无法同时做到最优;根据不同环境、需求,做平衡才是更优的选择。因此,除了计划解决的部分,WebAssembly 携带部分缺陷在所难免;毕竟它是对 JavaScript 的补充。

WebAssembly 应用场景

WASM 并不是为了优化您的网站,而是为了在执行以下任务时将浏览器(和服务器端运行时,如 Node.js、Deno)提升到一个新的水平:

  • 机器学习:TensorFlow.js;
  • 视频编辑:Clipchamp、Mastershot;
  • 实时合作编辑:Figma;
  • 游戏开发:Unity Web;
  • AR/VR 直播应用:(非常低的延迟);
  • 音乐编辑和流媒体: FFMPEG.WASM
  • 平台仿真:AutoCAD、Google Earth;
  • 加密解密:JSVMP(编译及二进制特性);
  • 开发工具:vim web、SQLlite web;
  • 图像识别及处理: Squoosh.app ,多线程客户端图像压缩;
  • 开发人员工具:(编辑器、编译器、调试器……);
  • 代替 JavaScript 框架:Yew、Blazor、Tokamak、Prism;
  • …….

更多使用场景可参见: WebAssembly Use Cases ;任何需要大量编码和大量性能调整的事物,都是 WASM 的完美用例。如需使用 WASM 的开源项目列表,您可以访问 Made with WebAssembly 这个社区。下面是些声名远扬的项目:

  • Tensorflow :是将 AI 和 ML 带给 JS 开发人员的主要库之一;在它 添加了 wasm 后端支持后 ,与普通 JS 版本相比,模型的性能平均提高了 10 倍。
  • Unity :作为主要的游戏开发引擎之一,它能够将您的项目导出为与 Web 兼容。从 2018 年开始,这个过程是通过 编译成 WebAssembly 来完成的。这是正确使用 WASM 的强大功能的完美示例。
  • Google Earth :该产品已经存在超过 15 年,曾经是一个桌面应用程序。 现在感谢 WASM,他们通过将旧代码编译为 WASM 将其 移植到网络中(就像 Autodesk 为其 CAD 应用程序所做的一样)。
  • Yew :有没有想过将 Rust 用于您的网络应用程序?现在你可以了,感谢 Yew 和 Web Assembly 给我们带来的力量。你不仅可以将 Rust 用于你的 UI,而且这个框架还提供了一个多线程环境来工作。Github 拥有 26kb Star(备注:目前还不是 1.0。准备好因破坏 API 更改而进行重大重构)。
  • Blazor :构建美观的 Web 应用,使用 .NET 和 C# 的强大功能构建全栈 Web 应用程序,而无需编写一行 JavaScript。生态可参见 awesome-blazor
  • Pyodide :是基于 WebAssembly 的浏览器和 Node.js 的 Python 发行版。

WebAssembly 主要的几个概念

为了理解 WebAssembly 是如何在 Web 运行的,需要了解几个关键概念:

  1. Instance :一个包含它在运行时用到的所有状态,包含 Memory、Table、以及一系列导入值的 Module,一个 Instance 类似一个 ES2015 的模块,它被加载到具有特定导入集的特定全局变量中
  2. Module :通过浏览器编译成为可执行机器码的 WebAssembly 二进制文件,Module 是无状态的,类似 Blob,能够在 Window 和 Worker 之间通过 postMessage 共享,一个 Module 声明了类似 ES2015 模块类似的 import 和 export。
  3. Memory :一个可调整大小的 ArrayBuffer,其中包含由 WebAssembly 的低层次内存访问指令读取和写入的线性字节数组。
  4. Table :一个可调整大小的类型化引用数组(如函数),然而处于安全和可移植性的原因,不能作为原始字节存储在内存中。

WebAssembly 的 JavaScript API 提供给开发者创建 Module、Memory、Table 和 Instance 的能力,给定一个 WebAssembly 的 Instance,JS 代码可以同步的调用它的 exports – 被作为普通的 JavaScript 函数导出。任意 JavaScript 函数可以被 WebAssembly 代码同步的调用,通过将 JavaScript 函数作为 imports 传给 WebAssembly Instance。

因为 JavaScript 能够完全控制 WebAssembly 代码的下载、编译和运行,所以 JavaScript 开发者可以认为 WebAssembly 只是 JavaScript 的一个新特性:可以高效的生成高性能的函数。

1
2
import {foo} from "./myModule.wasm";
foo();

在未来, WebAssembly 模块可以以 ES2015 的模块加载形式加载,如通过 import<script type="module">,意味着 JS 可以获取、编译、和导入一个 WebAssembly 模块,就像导入 ES2015 模块一样简单。详见: WebAssembly 的 ES 模块集成提案

如何在应用里使用 WebAssembly?

WebAssembly 给 Web 平台添加了两块内容:一种二进制格式代码,以及一系列可用于加载和执行二进制代码的 API。时值 2022 年,生态已颇具规模,详情可参见: Awesome Wasm ;主要流行的入口有:

  • 使用 EMScripten 来移植 C / C++ 应用;
  • 编写 Rust 应用,然后将 WebAssembly 作为它的输出;
  • 使用 AssemblyScript ,它是一门类似 TypeScript 的语言,能够编译成 WebAssembly 二进制;

对于 Web 开发者来说,可是使用类 TypeScript 的形式来尝试 WebAssembly 的编写,而不需要学习 C 或 Rust 的细节,那么 AssemblyScript 或将会是最好的选择。AssemblyScript 将 TypeScript 的变体编译为 WebAssembly,使得 Web 开发者可以使用 TypeScript 兼容的工具链,例如 Prettier 、VSCode Intellisense,你可以查看 AssemblyScript 文档 来了解如何使用。

补充说明,如今已有大量的工具库被编译为 WebAssembly,并做了封装;譬如 Photon (一个高性能的 Rust 图像处理库,它编译为 WebAssembly,允许在本地和 Web 上进行安全、快速的图像处理),其使用方式与其他 npm 包没有区别;在基于 Vue3 开发的作品: 玉桃文飨轩 中就有使用,如您感兴趣,可移步源码实现: markdown2png

参考资料及资源网站

资源网站

参考资料

您可能感兴趣的文章

近十年新兴行业技术,及简单介绍

2022-12-12 21:21:00

著名 IT 咨询公司 Gartner(高德纳),有一个”技术热门度曲线”模型(Gartner Hype Cycle)。该模型认为,一门技术的发展要经历五个阶段:启动期泡沫期低谷期爬升期高原期;该公司每年都会公布当年的热门技术图;基于所提及的新兴技术, 如果没有接触,难以知道是用来做什么的。本文旨在科普这些行业技术。

Gartner 技术热门度曲线

  • 启动期(Innovation Trigger):该技术刚刚诞生,还只是一个概念,不具有可用性,无法评估商业潜力。媒体有所报道,引起了外界的兴趣。
  • 泡沫期(Peak of Inflated Expectations):该技术逐步成型,出现了个别成功的案例,一些激进的公司开始跟进。媒体开始大肆报导,伴有各种非理性的渲染,产品的知名度达到高峰。
  • 低谷期(Trough of Disillusionment):该技术的局限和缺点逐步暴露,对它的兴趣开始减弱。基于它的产品,大部分被市场淘汰或者失败,只有那些找到早期用户的公司艰难地活了下来。媒体对它的报道逐步冷却,前景不明。
  • 爬升期(Slope of Enlightenment):该技术的优缺点越来越明显,细节逐渐清晰,越来越多的人开始理解它。基于它的第二代和第三代产品出现,更多的企业开始尝试,可复制的成功使用模式出现。媒体重新认识它,业界这一次给予了高度的理性的关注。
  • 高原期(Plateau of Productivity):经过不断发展,该技术慢慢成为了主流。技术标准得到了清晰定义,使用起来越发方便好用,市场占有率越来越高,进入稳定应用阶段。配合它的工具和最佳实践,经过数代的演进,也变得非常成熟了。业界对它有了公认的一致的评价。

一门技术到底前景如何,很难准确预测;但是它的热门程度却是可以衡量的(比如在社交媒体提及次数的增长幅度)。风险投资跟热门程度高度正相关,越热门的技术越容易拿到投资。

用户可以基于 Gartner 技术热门度曲线,判断技术处在哪一个阶段,确定它的热门程度。简单的使用规则为:”争取风险投资,要选择热门的技术;解决实际问题, 要选择可靠的技术。

简单说,处于启动期的技术,风险很大,不确定性极高,但是一旦成功,回报可能也很高,适合创业公司;处于高原期的技术,非常可靠,风险低,有成熟的解决方案和配套工具,适合大公司和企业的内部应用。

反之,如果一门技术已处于高原期了,就代表它非常成熟;人们对它能干什么和不能干什么,都已经很是了解,也难以产生新的期待,技术本身的潜力已经不大,所以用它拿不到投资,只能用来干活。

2022 年 Gartner 新兴技术成熟度曲线公布最新技术趋势

2022 年 Gartner 新兴技术成熟度曲线公布最新技术趋势

2021 年 Gartner 新兴技术成熟度曲线公布最新技术趋势

2021 年 Gartner 新兴技术成熟度曲线公布最新技术趋势

XR、AR、VR、MR

什么是扩展现实 (XR)?

扩展现实 (XR):是一个“包罗万象”的术语,指的是增强或取代我们对世界的看法的技术。这通常是通过将计算机文本和图形叠加或浸入现实世界和虚拟环境,甚至是两者的结合。

XR 包括增强现实 (AR)虚拟现实 (VR)混合现实 (MR)。虽然所有三个“现实”都有共同的重叠特征和要求,但每个都有不同的目的和底层技术。

XR 将在元宇宙中发挥基础性作用。“互联网的下一次发展”将把真实、数字和虚拟世界融合到新的现实中,通过 Arm 驱动的“网关”设备(例如 VR 耳机或一副 AR 智能眼镜)进行访问。

XR 技术有一些基本的相似之处:所有 XR 可穿戴设备的核心部分是能够使用视觉输入方法(例如对象、手势和注视跟踪)来导航世界并显示上下文相关信息。深度感知和映射也可以通过深度和位置特征来实现。

什么是增强现实 (AR)?

增强现实 (AR) ,通过将我们看到的内容、与计算机生成的信息叠加在一起,增强了我们对现实世界的看法。如今,这项技术在智能手机 AR 应用程序中很普遍,这些应用程序需要用户将手机放在面前。通过从相机中获取图像并进行实时处理,该应用程序能够显示上下文信息、或提供似乎植根于现实世界的游戏和社交体验。

尽管智能手机 AR 在过去十年中取得了显着进步,但其应用仍然有限。越来越多的重点是通过可穿戴智能眼镜提供更全面的 AR 体验。这些设备必须将超低功耗处理器与包括深度感知和跟踪在内的多个传感器结合在一起,所有这些都在一个轻巧舒适的外形中,足以长时间佩戴。

AR 智能眼镜需要在用户移动时始终在线、直观且安全的导航。这需要在深度、遮挡(当 3D 空间中的一个对象从视图中挡住另一个对象时)、语义、位置、方向、位置、姿势以及手势和眼睛跟踪等功能方面取得重大进展。

什么是虚拟现实 (VR)?

虚拟现实 (VR), 完全取代了用户的视野,让他们沉浸在计算机生成的虚拟环境中。这种 XR 技术已经存在了一段时间,并在逐步改进。它主要用于娱乐体验,例如游戏、音乐会、电影或体育,但它也在加速进入社交领域。对于 VR,沉浸式娱乐体验将需要高清渲染管道、体积捕捉、6DoF 运动跟踪和面部表情捕捉等功能。

VR 还用作培训、教育和医疗保健(例如康复)的工具。为了让最终用户获得这些体验(并且也是无缝的),VR 技术的重点通常是高质量的视频和渲染以及超低延迟。

最后,VR 设备现在正在通过 RecRoom 等平台增强视频会议体验,这些平台可以在不同的虚拟世界中进行虚拟聚会。现在支持 Oculus Quest 的 RecRoom 在 2020 年 Arm 新现实系列的第三集中 出现,讨论了 VR 的沉浸式体验。

什么是混合现实 (MR)?

MR 介于 AR 和 VR 之间,因为它融合了真实世界和虚拟世界。此类 XR 技术存在三个关键场景。第一种是通过智能手机或 AR 可穿戴设备将虚拟对象和角色叠加到现实环境中,反之亦然。可参见 Microsoft 教程: 什么是混合现实

2016 年风靡全球的 Pokémon Go 手机游戏,通过智能手机摄像头将虚拟 Pokémon 覆盖在现实环境中。这通常被吹捧为革命性的 AR 游戏,但它实际上是 MR 的一个很好的例子——将现实世界环境与计算机生成的对象混合在一起

混合现实也开始用于使 VR 真实世界玩家能够叠加到视频游戏中,从而将真实世界的人物带到 Twitch 或 YouTube 等游戏流媒体平台上。以上内容,出自文章: XR、AR、VR、MR:现实有何不同? (发表于 2022 年 4 月 1 日)。

数字孪生

数字孪生是一种旨在精确反映物理对象的虚拟模型。 会给研究对象(例如,风力涡轮机)配备与重要功能方面相关的各种传感器。 这些传感器产生与物理对象性能各个方面有关的数据,例如,能量输出、温度和天气条件等等。 然后将这些数据转发至处理系统并应用于数字副本。

一旦获得此类数据,虚拟模型便可用于运行模拟、研究性能问题并生成可能的改进方案;所有这些都是为了获取富有价值的洞察成果,然后将之再应用于原始物理对象。

数字孪生与模拟

尽管模拟和数字孪生都是利用数字模型来复制系统的各种流程,但数字孪生实际上是一个虚拟环境,对于研究来说内容特别丰富。 数字孪生和模拟之间的区别主要是规模问题: 模拟通常研究的是一个特定流程,而数字孪生本身可运行任意数量的实用模拟项目来研究多个流程。

当然,二者之间的差异远不止如此。 例如,模拟通常不会从获得实时数据中受益。 但数字孪生是围绕双向信息流设计的。当对象传感器向系统处理器提供相关数据时,该信息流首次出现。然后,当处理器将其得出的洞察成果与原始源对象共享时,该信息流会再次出现。

数字孪生拥有的数据更加优质且不断更新,且覆盖了更加广泛的诸多领域;除此之外,虚拟环境还具备更强的计算能力,因此,与标准模拟相比,数字孪生能够从更有利的角度研究更多问题,具备更大的最终潜力来改进产品和流程。

数字孪生的优点

  • 促进研发:利用数字孪生能够更高效地研究和设计产品,生成与潜在性能结果相关的大量数据。 根据这些信息得出的洞察成果可帮助企业在开始生产之前就能进行必要的产品改进。
  • 效率更高:即使在新产品投入生产后,数字孪生也有助于真实反映和监控生产系统,以期在整个制造流程中获得和保持最高效率。
  • 产品生命末期管理:数字孪生甚至可以帮助制造商决定如何处理生命周期结束并需要通过回收或其他措施进行最终处理的产品。 通过使用数字孪生,制造商能够确定哪些产品材料可以回收。

4D 打印技术

4D 打印技术,是指由 3D 技术打印出来的结构,能够在外界激励下、发生形状或者结构的改变,直接将材料与结构的变形设计内置到物料当中,简化了从设计理念到实物的造物过程,让物体能自动组装构型,实现了产品设计、制造和装配的一体化融合

4D 打印构成要素

4D 打印的主要构成要素可以分为四个部分:智能或刺激反馈材料4D 打印设备外部刺激因子智能化设计过程

4D 打印主要优势

  1. 实物可从一种形态转换成另一种形态,提供了最大限度的产品设计自由度。
  2. 可在打印部件中嵌入驱动、逻辑及感知等能力,且无需额外的时间和成本。
  3. 可在同一批次产品中定制生产。
  4. 生产个性化产品是 4D 打印的独特优势。
  5. 可先打印极其简单的结构,然后通过外部刺激转变成具有复杂功能的结构和系统。
  6. 一旦制造出 4D 打印材料并嵌入动态功能,生产成品的功能将超过预期。
  7. 可从根本上消除供应链和组装线。
  8. 利用设计和编程实现物质世界的数字化。
  9. 数字文件可发送到世界任何地点,并收集合适的三维像素,制造所需产品。
  10. 三维像素的设计和制造将成为新兴行业,所带来的影响将异常深远。
  11. 将激发科学家和工程师想象各种多功能动态物体,之后进行物质编程,并利用 4D 打印实现,“物质程序化”这一新领域可能将兴起。

4D 打印应用领域

4D 打印可应用领域有:生物、医疗领域军事工业领域产品设计领域、交通工具、建筑与航空航天领域、教育领域。

4D 打印的原理

4D 打印让快速建模有了根本性的转变。与 3D 打印的预先建模然后使用物料成形并不一样,4D 打印直接将设计内置到物料当中,简化了从“设计理念”到“实物”的创物过程。让物体如机器般“自动”创造,不需要连接任何复杂的机电设备。为了充分应用这一新技术,Autodesk 公司的研发团队进一步设计了新软件 Cyborg,可以用于自我组装和可编程的模拟材料,实现设计的优化和材料的折叠。

虚拟助理

虚拟助理(virtual assistant)是一种能替个人执行任务或服务的软件代理(software agent)。有时候“聊天机器人”泛指虚拟助理,亦或专指网络聊天使用的软件机器人(有时候更专指娱乐而非实用的网络聊天)。但也可以指一种职业,或者企业组织,其乃是透过网络执行远端服务。其能依据使用者输入的内容、位置感测而完成相对应的任务或提供相关服务,同时也具有从网络上寻找并提供使用者各种资讯(像是天气、交通状况、新闻、股市行情、行程或零售价格等)的能力。

至 2017 年,随着新产品进入市场,虚拟助理的功能与运用正快速扩张。一项 2017 年 5 月的线上调查显示,美国的市占率依次为苹果 Siri(34%)、Google 个人助理(19%)、Amazon Alexa(6%)及微软 Cortana(4%)。搭载这些助理的智慧扬声器也有着巨大的变化;苹果直到 2017 年 6 月才宣布其智慧扬声器。脸书的 M 虚拟助理 预计 2017 年在 Facebook Messenger 上会有数亿的用量。

互动方式

虚拟助理的作业媒介:

  • 文字(网络聊天),尤其是即时通讯等的应用程序。
  • 语音,例如 Amazon Echo 上的 Alexa 或是 iPhone 上的 Siri 。
  • 利用照相或上传图像,例如三星 Galaxy S8 上的 Bixby。

有些虚拟助理的使用方式多样,例如 Google 智能助理在 Google Allo app 用文字,Google Home 智慧扬声器则用语音。虚拟助理,利用自然语言处理(NLP)从使用者的文字、语音输入,找到相应的可执行指令。许多助理利用人工智能的技巧,包括 机器学习 ,不断学习。

用语音启动虚拟助理,可能需要用到“唤醒词”(wake word),这是一个或一组词,例如 Alexa、“嗨,Siri”(Apple iPhone、Mac 等),“小 v 小 v”( vivo ) 或者 OK Google。

可提供的服务

虚拟助理可提供多样的服务,尤其是 Amazon Alexa 和 Google 个人助理,日新月异,包括:

  • 提供资讯,例如气象、来自维基百科或 IMDB 的事实,设定闹钟、待办事项、购物清单等。
  • 播放串流服务的音乐例如 Spotify 和 Pandora,播放广播或有声书。
  • 从串流服务例如 Netflix,在电视上播放影片、电视节目或电影。
  • 辅助、取代真人的客服、取代真人推广推销(在国内经常遇到,不胜其烦)。

IPFS

IPFS(InterPlanetary File System),一般翻译为“星际文件系统”,它由 Protocol Lab 提出,始于 2014 年,发明者: Juan Benet ;它是一种点对点(P2P)的分布式文件系统(用来存储数据的技术);但更确切的说 IPFS 是一种传输协议。IPFS 将 HTTP 视为对手,宣传上要对标 HTTP。

IPFS 它是一个基于内容寻址的、分布式的、新型超媒体传输协议。 IPFS 支持创建完全分布式的应用。 它旨在使网络更快、更安全、更开放。 IPFS 是一个分布式文件系统,它的目标是将所有计算设备连接到同一个文件系统,从而成为一个全球统一的存储系统。实现互联网中永久可用、数据可以永久保存(理论上,访问量越大,越能保证)。

HTTP(超文本传输协议)是目前最常用的传输协议。在网上找到想要的内容,就要输入网址,网址多是 HTTP 开头。HTTP 通过域名、IP 及多个中心服务器的中转,再进行文件的上传下载。HTTP 的功绩无可取代,现在人们上网都要依赖于 HTTP。但 HTTP 也存在一些问题,比如性能效率不是非常高,过度依赖于中心服务器与主干网络等等。

IPFS 与之相比,它是一种多中心化的解决方案,内容寻址不是通过域名、IP,而是通过唯一 HASH 密钥来进行数据寻找。IPFS 是个分布式文件存储系统,文件数据并不储存在一个中心化的服务器中,而是存储在网络上所有符合条件的电脑中。当然,IPFS 不止如此,还有很多其他的特性,层次与应用范围也超过了简单的 P2P 下载。

如果您对 IPFS 感兴趣,可以参见 IPFS 入门笔记IPFS 如何冲击我们熟知的网络世界 等文章。

2022 年 11 月 ~ 12 月 03 日写于〔深圳福田〕

您可能感兴趣(/有用)的文章: