v2.0.0: Dependency Freeze #56

Merged
Rubicon merged 8 commits from depfreeze-v2.0.0 into master 2025-01-04 10:59:51 +00:00
15 changed files with 87 additions and 67 deletions

View file

@ -1 +0,0 @@
>0.3% and not dead, firefox>=98, safari>=15.4, chrome>=84

View file

@ -8,17 +8,17 @@ Tutu is a comfortable experience for tooting. Designed to work on any device - d
The code is built against those targets and Tutu must run on those platforms: The code is built against those targets and Tutu must run on those platforms:
| Firefox | Safari | iOS | Chrome | Edge | | Firefox | Safari | iOS | Chrome & Edge |
| ------- | ------ | ----- | ------ | ---- | | ------- | ------ | ----- | ------------- |
| 98 | 15.4 | 15.4 | 84 | 87 | | 115 | 15.6 | 15.6 | 108 |
Tutu trys to push the Web technology to its limit. Some features might not be available on the platform does not meet the requirement. Tutu trys to push the Web technology to its limit. Some features might not be available on the platform does not meet the requirement.
## The "Next" Branch ## The "Nightly" Branch
The "next" branch of the app is built on every commit pushed into "master". You can tatse latest change but risks your data. Tutu built on the latest code, called the nightly version. You can tatse latest change but risks your data.
[Launch Tutu (Next)](https://master.tututheapp.pages.dev) [Launch Tutu (Nightly)](https://master.tututheapp.pages.dev)
## Build & Depoly ## Build & Depoly

BIN
bun.lockb

Binary file not shown.

32
docs/versioning.md Normal file
View file

@ -0,0 +1,32 @@
# Versioning & Development Cycle
The versioning policy follows the [Semantic Versioning](https://semver.org/).
Since Tutu is an app for the end user, we redefine the some words in the policy:
- API changes: the app is no longer available on certain platforms.
## Development Cycle
Dependency Freeze -> Development -> Release
### Dependency Freeze
This step is for:
- Update dependencies
- Prepare the new version (like, bump the version number).
New dependencies should not be added in this step.
### Development
In this step, dependencies can only be updated if it's required to fix bugs.
New dependencies should be added as their use, in this step.
### Release
The version is released to production in this step.
Before the next development step, new versions can still be released to
fix bugs.

View file

@ -1,7 +1,7 @@
{ {
"$schema": "https://json.schemastore.org/package", "$schema": "https://json.schemastore.org/package",
"name": "tutu", "name": "tutu",
"version": "1.1.0", "version": "2.0.0",
"description": "", "description": "",
"private": true, "private": true,
"type": "module", "type": "module",
@ -17,33 +17,33 @@
"author": "Rubicon", "author": "Rubicon",
"license": "Apache-2.0", "license": "Apache-2.0",
"devDependencies": { "devDependencies": {
"@solid-devtools/overlay": "^0.30.1", "@solid-devtools/overlay": "^0.33.0",
"@suid/vite-plugin": "^0.3.1", "@suid/vite-plugin": "^0.3.1",
"@testing-library/webdriverio": "^3.2.1", "@testing-library/webdriverio": "^3.2.1",
"@types/hammerjs": "^2.0.46", "@types/hammerjs": "^2.0.46",
"@types/masonry-layout": "^4.2.8", "@types/masonry-layout": "^4.2.8",
"@vite-pwa/assets-generator": "^0.2.6", "@vite-pwa/assets-generator": "^0.2.6",
"@wdio/cli": "^9.4.5", "@wdio/cli": "^9.5.1",
"@wdio/lighthouse-service": "^9.4.5", "@wdio/lighthouse-service": "^9.5.1",
"@wdio/local-runner": "^9.4.5", "@wdio/local-runner": "^9.5.1",
"@wdio/mocha-framework": "^9.4.4", "@wdio/mocha-framework": "^9.5.0",
"@wdio/spec-reporter": "^9.4.4", "@wdio/spec-reporter": "^9.5.0",
"postcss": "^8.4.49", "postcss": "^8.4.49",
"prettier": "^3.3.3", "prettier": "^3.4.2",
"tsx": "^4.19.2", "tsx": "^4.19.2",
"typescript": "^5.6.3", "typescript": "^5.7.2",
"vite": "^5.4.11", "vite": "^6.0.7",
"vite-plugin-package-version": "^1.1.0", "vite-plugin-package-version": "^1.1.0",
"vite-plugin-pwa": "^0.20.5", "vite-plugin-pwa": "^0.21.1",
"vite-plugin-solid": "^2.10.2", "vite-plugin-solid": "^2.11.0",
"vite-plugin-solid-styled": "^0.11.1", "vite-plugin-solid-styled": "^0.11.1",
"wdio-vite-service": "^2.0.0", "wdio-vite-service": "^2.0.0",
"wdio-wait-for": "^3.0.11", "wdio-wait-for": "^3.0.11",
"workbox-build": "^7.3.0", "workbox-build": "^7.3.0",
"wrangler": "^3.86.1" "wrangler": "^3.99.0"
}, },
"dependencies": { "dependencies": {
"@formatjs/intl-localematcher": "^0.5.7", "@formatjs/intl-localematcher": "^0.5.10",
"@nanostores/persistent": "^0.10.2", "@nanostores/persistent": "^0.10.2",
"@nanostores/solid": "^0.5.0", "@nanostores/solid": "^0.5.0",
"@solid-primitives/event-listener": "^2.3.3", "@solid-primitives/event-listener": "^2.3.3",
@ -52,7 +52,7 @@
"@solid-primitives/map": "^0.4.13", "@solid-primitives/map": "^0.4.13",
"@solid-primitives/page-visibility": "^2.0.17", "@solid-primitives/page-visibility": "^2.0.17",
"@solid-primitives/resize-observer": "^2.0.26", "@solid-primitives/resize-observer": "^2.0.26",
"@solidjs/router": "^0.15.1", "@solidjs/router": "^0.15.2",
"@suid/icons-material": "^0.8.1", "@suid/icons-material": "^0.8.1",
"@suid/material": "^0.18.0", "@suid/material": "^0.18.0",
"blurhash": "^2.0.5", "blurhash": "^2.0.5",
@ -65,7 +65,7 @@
"masto": "^6.10.1", "masto": "^6.10.1",
"nanostores": "^0.11.3", "nanostores": "^0.11.3",
"normalize.css": "^8.0.1", "normalize.css": "^8.0.1",
"solid-devtools": "^0.30.1", "solid-devtools": "^0.33.0",
"solid-js": "^1.9.3", "solid-js": "^1.9.3",
"solid-styled": "^0.11.1", "solid-styled": "^0.11.1",
"solid-transition-group": "^0.2.3", "solid-transition-group": "^0.2.3",

View file

@ -51,7 +51,7 @@ function animateSlideInFromBottom(element: HTMLElement, reverse?: boolean) {
} }
const BottomSheet: ParentComponent<BottomSheetProps> = (props) => { const BottomSheet: ParentComponent<BottomSheetProps> = (props) => {
let element: HTMLDialogElement; let element!: HTMLDialogElement;
let animation: Animation | undefined; let animation: Animation | undefined;
const child = children(() => props.children); const child = children(() => props.children);

View file

@ -108,7 +108,7 @@ function animateGrowFromTopLeft(
* - Use {@link MenuItem} from SUID as children. * - Use {@link MenuItem} from SUID as children.
*/ */
const Menu: Component<MenuProps> = (oprops) => { const Menu: Component<MenuProps> = (oprops) => {
let root: HTMLDialogElement; let root!: HTMLDialogElement;
const windowSize = useWindowSize(); const windowSize = useWindowSize();
const [props, rest] = splitProps(oprops, [ const [props, rest] = splitProps(oprops, [
"open", "open",

View file

@ -1,38 +1,27 @@
//! This module has side effect. //! This module has side effect.
//! It recommended to include the module by <script> tag. //! It recommended to include the module by <script> tag.
if (typeof window.crypto.randomUUID === "undefined") {
// TODO: this polyfill can be removed in 2.0, see https://code.lightstands.xyz/Rubicon/tutu/issues/36
// Chrome/Edge 92+
// https://stackoverflow.com/a/2117523/2800218
// LICENSE: https://creativecommons.org/licenses/by-sa/4.0/legalcode
window.crypto.randomUUID =
function randomUUID(): `${string}-${string}-${string}-${string}-${string}` {
return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, (c) =>
(
+c ^
(crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (+c / 4)))
).toString(16),
) as `${string}-${string}-${string}-${string}-${string}`;
};
}
if (typeof Promise.withResolvers === "undefined") { if (typeof Promise.withResolvers === "undefined") {
// Chrome/Edge 119, Firefox 121, Safari/iOS 17.4 // Chrome/Edge 119, Firefox 121, Safari/iOS 17.4
// Promise.withResolvers is generic and works with subclasses - the typescript built-in decl // Promise.withResolvers is generic and works with subclasses - the typescript built-in decl
// could not handle the subclassing case. // could not handle the subclassing case.
(Promise.prototype as any).withResolvers = function <T>(this: AnyPromiseConstructor<T>) { (Promise.prototype as any).withResolvers = function <T>(
let resolve!: PromiseWithResolvers<T>["resolve"], reject!: PromiseWithResolvers<T>["reject"]; this: AnyPromiseConstructor<T>,
) {
let resolve!: PromiseWithResolvers<T>["resolve"],
reject!: PromiseWithResolvers<T>["reject"];
// These variables are expected to be set after `new this()` // These variables are expected to be set after `new this()`
const promise = new this((resolve0, reject0) => { const promise = new this((resolve0, reject0) => {
resolve = resolve0; resolve = resolve0;
reject = reject0; reject = reject0;
}) });
return { return {
promise, resolve, reject promise,
} resolve,
} reject,
};
};
} }

View file

@ -38,7 +38,7 @@ function clamp(input: number, min: number, max: number) {
} }
const MediaViewer: ParentComponent<MediaViewerProps> = (props) => { const MediaViewer: ParentComponent<MediaViewerProps> = (props) => {
let rootRef: HTMLDialogElement; let rootRef!: HTMLDialogElement;
type State = { type State = {
ref?: HTMLElement; ref?: HTMLElement;

View file

@ -17,7 +17,7 @@ const PullDownToRefresh: Component<{
linkedElement?: HTMLElement; linkedElement?: HTMLElement;
onRefresh?: () => void; onRefresh?: () => void;
}> = (props) => { }> = (props) => {
let rootElement: HTMLDivElement; let rootElement!: HTMLDivElement;
const [pullDown, setPullDown] = createSignal(0); const [pullDown, setPullDown] = createSignal(0);
const stopPos = () => 160; const stopPos = () => 160;

View file

@ -23,7 +23,7 @@ type ChooseTootLangProps = {
}; };
const ChooseTootLang: Component<ChooseTootLangProps> = (props) => { const ChooseTootLang: Component<ChooseTootLangProps> = (props) => {
let listRef: HTMLUListElement; let listRef!: HTMLUListElement;
const [t] = createTranslator( const [t] = createTranslator(
(code) => (code) =>
import(`./i18n/${code}.json`) as Promise<{ import(`./i18n/${code}.json`) as Promise<{

View file

@ -17,7 +17,7 @@ export function PreviewCard(props: {
src: mastodon.v1.PreviewCard; src: mastodon.v1.PreviewCard;
alwaysCompact?: boolean; alwaysCompact?: boolean;
}) { }) {
let root: HTMLAnchorElement; let root!: HTMLAnchorElement;
createEffect(() => { createEffect(() => {
if (props.alwaysCompact) { if (props.alwaysCompact) {

View file

@ -33,7 +33,7 @@ type TootPollProps = {
}; };
const TootPoll: Component<TootPollProps> = (props) => { const TootPoll: Component<TootPollProps> = (props) => {
let list: HTMLUListElement; let list!: HTMLUListElement;
const { vote } = useTootEnv(); const { vote } = useTootEnv();
const now = useTimeSource(); const now = useTimeSource();

View file

@ -2,8 +2,8 @@
"compilerOptions": { "compilerOptions": {
"strict": true, "strict": true,
"target": "ESNext", "target": "ESNext",
"module": "esnext", "module": "ESNext",
"moduleResolution": "node", "moduleResolution": "bundler",
"allowSyntheticDefaultImports": true, "allowSyntheticDefaultImports": true,
"esModuleInterop": true, "esModuleInterop": true,
"noEmit": true, "noEmit": true,

View file

@ -4,7 +4,7 @@ import solidStyled from "vite-plugin-solid-styled";
import suid from "@suid/vite-plugin"; import suid from "@suid/vite-plugin";
import { VitePWA } from "vite-plugin-pwa"; import { VitePWA } from "vite-plugin-pwa";
import version from "vite-plugin-package-version"; import version from "vite-plugin-package-version";
import manifest from "./manifest.config"; import manifest from "./manifest.config.js";
import { GetManualChunk } from "rollup"; import { GetManualChunk } from "rollup";
import devtools from "solid-devtools/vite"; import devtools from "solid-devtools/vite";
import { resolve } from "node:path"; import { resolve } from "node:path";
@ -70,17 +70,17 @@ export default defineConfig(({ mode }) => {
plugins: [ plugins: [
devtools({ devtools({
autoname: true, autoname: true,
locator: { locator: devConf["DEV_LOCATOR_EDITOR"]
targetIDE: ? {
(devConf["DEV_LOCATOR_EDITOR"] as targetIDE: devConf["DEV_LOCATOR_EDITOR"] as
| "vscode" | "vscode"
| "atom" | "atom"
| "webstorm" | "webstorm"
| "vscode-insiders" | "vscode-insiders",
| "") || undefined, componentLocation: true,
componentLocation: true, jsxLocation: true,
jsxLocation: true, }
}, : undefined,
}), }),
suid(), suid(),
solid(), solid(),
@ -147,7 +147,7 @@ export default defineConfig(({ mode }) => {
devSourcemap: true, devSourcemap: true,
}, },
build: { build: {
target: ["firefox98", "safari15.4", "ios15.4", "chrome84", "edge87"], target: ["firefox115", "safari15.6", "ios15.6", "chrome108", "edge108"],
sourcemap: true, sourcemap: true,
rollupOptions: { rollupOptions: {
output: { output: {