@adaptive-ds/assets-optimizer 0.1.0 → 0.2.0
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.
- package/README.md +36 -15
- package/bun.lock +12 -12
- package/changelogs/2026-04-18_v0.2.0.md +32 -0
- package/package.json +1 -1
- package/assets-optimizer.code-workspace +0 -8
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @adaptive-ds/assets-optimizer
|
|
2
2
|
|
|
3
|
-
Process, hash, sync, and clean image assets for web projects that keep originals outside git and
|
|
3
|
+
Process, hash, sync, and clean image assets for web projects that keep originals outside git and optionally sync through any `rclone` remote, with a separate pass for web videos.
|
|
4
4
|
|
|
5
5
|
This package is built for a workflow with two local directories:
|
|
6
6
|
|
|
@@ -11,7 +11,7 @@ This package is built for a workflow with two local directories:
|
|
|
11
11
|
|
|
12
12
|
It is designed for projects where:
|
|
13
13
|
|
|
14
|
-
- originals live
|
|
14
|
+
- originals may live on an `rclone` remote and be synced locally
|
|
15
15
|
- optimized outputs should be deterministic and aggressively cacheable
|
|
16
16
|
- output filenames should change when either the source file or the transform changes
|
|
17
17
|
- old optimized files should be removed locally and remotely
|
|
@@ -19,8 +19,16 @@ It is designed for projects where:
|
|
|
19
19
|
|
|
20
20
|
## Diagrams
|
|
21
21
|
|
|
22
|
+
### Overview
|
|
23
|
+
|
|
22
24
|

|
|
25
|
+
|
|
26
|
+
### Images
|
|
27
|
+
|
|
23
28
|

|
|
29
|
+
|
|
30
|
+
### Videos
|
|
31
|
+
|
|
24
32
|

|
|
25
33
|
|
|
26
34
|
## What It Does
|
|
@@ -28,20 +36,20 @@ It is designed for projects where:
|
|
|
28
36
|
`assetsOptimize()` performs the full asset pipeline:
|
|
29
37
|
|
|
30
38
|
1. Resolves the project name from `package.json.name`
|
|
31
|
-
2.
|
|
32
|
-
3.
|
|
39
|
+
2. If `rcloneRemote` is configured, uses that project name as the base path on the remote
|
|
40
|
+
3. If `rcloneRemote` is configured, syncs originals between the remote and `images`
|
|
33
41
|
4. Scans transform folders like `1920x1080_jpg`
|
|
34
42
|
5. Processes matching image source files with `sharp`
|
|
35
43
|
6. Writes flat optimized images into `public/images`
|
|
36
44
|
7. Names image files as `<basename>_<hash>.<ext>`
|
|
37
45
|
8. Skips already-generated images
|
|
38
46
|
9. Deletes stale optimized images locally
|
|
39
|
-
10.
|
|
40
|
-
11.
|
|
47
|
+
10. If `rcloneRemote` is configured, uploads missing optimized images to the remote with cache headers
|
|
48
|
+
11. If `rcloneRemote` is configured, deletes stale optimized images from the remote
|
|
41
49
|
12. Runs a separate optional video pass from `videos` to `public/videos`
|
|
42
50
|
13. Generates a `.jpg` preview beside each processed video using the processed video dimensions
|
|
43
51
|
14. Keeps video filenames unchanged and skips any processed video or preview that already exists
|
|
44
|
-
15.
|
|
52
|
+
15. If `rcloneRemote` is configured, uploads missing processed videos and previews to the remote without deleting manual variants
|
|
45
53
|
16. Generates `src/app/assets/imageList.ts` and `src/app/assets/videoList.ts` by default
|
|
46
54
|
17. Prints a clear summary of what changed
|
|
47
55
|
|
|
@@ -95,8 +103,8 @@ public/videos/
|
|
|
95
103
|
Video behavior:
|
|
96
104
|
|
|
97
105
|
- if both local `videos` and remote `video-originals` are missing, the video pass does nothing
|
|
98
|
-
- source videos sync through `video-originals`
|
|
99
|
-
- processed videos sync through `video-processed`
|
|
106
|
+
- if `rcloneRemote` is configured, source videos sync through `video-originals`
|
|
107
|
+
- if `rcloneRemote` is configured, processed videos sync through `video-processed`
|
|
100
108
|
- missing processed videos are created with `ffmpeg`
|
|
101
109
|
- missing preview images are created as `.jpg` files beside processed videos
|
|
102
110
|
- existing processed videos are skipped and preserved as manual transformations
|
|
@@ -150,21 +158,21 @@ If you call `assetsOptimize()` with no arguments, it uses:
|
|
|
150
158
|
- `imageOptimizedDir`: `./public/images`
|
|
151
159
|
- `allowRootImageFiles`: `false`
|
|
152
160
|
- `processVideos`: `true`
|
|
153
|
-
- `
|
|
154
|
-
- `
|
|
161
|
+
- `videoOriginalsDir`: `./videos`
|
|
162
|
+
- `videoOptimizedDir`: `./public/videos`
|
|
155
163
|
- `imageListOutputPath`: `./src/app/assets/imageList.ts`
|
|
156
164
|
- `videoListOutputPath`: `./src/app/assets/videoList.ts`
|
|
157
165
|
- `generateImageList`: `true`
|
|
158
166
|
- `generateVideoList`: `true`
|
|
159
167
|
- `videoPreviewQuality`: `80`
|
|
160
|
-
- `rcloneRemote`:
|
|
168
|
+
- `rcloneRemote`: not set
|
|
161
169
|
- `remoteImageOriginalsDir`: `image-originals`
|
|
162
170
|
- `remoteImageOptimizedDir`: `image-processed`
|
|
163
171
|
- `remoteVideoOriginalsDir`: `video-originals`
|
|
164
172
|
- `remoteVideoProcessedDir`: `video-processed`
|
|
165
173
|
- `cacheControlHeader`: `public,max-age=31536000,immutable`
|
|
166
174
|
|
|
167
|
-
|
|
175
|
+
If you set `rcloneRemote` to `leo` for a project named `moramontage`, the remote paths become:
|
|
168
176
|
|
|
169
177
|
- `leo:moramontage/image-originals`
|
|
170
178
|
- `leo:moramontage/image-processed`
|
|
@@ -189,6 +197,8 @@ await assetsOptimize()
|
|
|
189
197
|
|
|
190
198
|
This generates optimized images, processed videos, video preview JPGs, `imageList.ts`, and `videoList.ts` in one run. Existing image alt text and existing video preview alt text are preserved when the generated files already exist.
|
|
191
199
|
|
|
200
|
+
When `rcloneRemote` is omitted, all remote sync, upload, and cleanup steps are skipped.
|
|
201
|
+
|
|
192
202
|
## API
|
|
193
203
|
|
|
194
204
|
```ts
|
|
@@ -203,6 +213,7 @@ const result = await assetsOptimize(options)
|
|
|
203
213
|
interface OptimizeImagesWebOptions {
|
|
204
214
|
cwd?: string
|
|
205
215
|
projectName?: string
|
|
216
|
+
logLevel?: 0 | 1 | 2 | 3
|
|
206
217
|
processImages?: boolean
|
|
207
218
|
imageOriginalsDir?: string
|
|
208
219
|
imageOptimizedDir?: string
|
|
@@ -211,8 +222,8 @@ interface OptimizeImagesWebOptions {
|
|
|
211
222
|
imageListImportPath?: string
|
|
212
223
|
generateImageList?: boolean
|
|
213
224
|
processVideos?: boolean
|
|
214
|
-
|
|
215
|
-
|
|
225
|
+
videoOriginalsDir?: string
|
|
226
|
+
videoOptimizedDir?: string
|
|
216
227
|
videoListOutputPath?: string
|
|
217
228
|
videoListImportPath?: string
|
|
218
229
|
generateVideoList?: boolean
|
|
@@ -226,6 +237,13 @@ interface OptimizeImagesWebOptions {
|
|
|
226
237
|
}
|
|
227
238
|
```
|
|
228
239
|
|
|
240
|
+
`logLevel` controls runtime logging:
|
|
241
|
+
|
|
242
|
+
- `0`: no logs
|
|
243
|
+
- `1`: summary plus explicit worked-on files
|
|
244
|
+
- `2`: level 1 plus all CLI calls
|
|
245
|
+
- `3`: level 2 plus command output
|
|
246
|
+
|
|
229
247
|
### `OptimizeImagesWebResult`
|
|
230
248
|
|
|
231
249
|
```ts
|
|
@@ -252,12 +270,15 @@ interface OptimizeImagesWebResult {
|
|
|
252
270
|
import { assetsOptimize } from "@adaptive-ds/assets-optimizer"
|
|
253
271
|
|
|
254
272
|
await assetsOptimize({
|
|
273
|
+
logLevel: 1,
|
|
255
274
|
processImages: true,
|
|
256
275
|
imageOriginalsDir: "./assets/originals",
|
|
257
276
|
imageOptimizedDir: "./assets/optimized",
|
|
258
277
|
allowRootImageFiles: false,
|
|
259
278
|
imageListOutputPath: "./src/app/assets/imageList.ts",
|
|
260
279
|
processVideos: true,
|
|
280
|
+
videoOriginalsDir: "./videos",
|
|
281
|
+
videoOptimizedDir: "./public/videos",
|
|
261
282
|
videoListOutputPath: "./src/app/assets/videoList.ts",
|
|
262
283
|
videoPreviewQuality: 80,
|
|
263
284
|
rcloneRemote: "leo",
|
package/bun.lock
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"configVersion": 1,
|
|
4
4
|
"workspaces": {
|
|
5
5
|
"": {
|
|
6
|
-
"name": "@adaptive-ds/
|
|
6
|
+
"name": "@adaptive-ds/assets-optimizer",
|
|
7
7
|
"dependencies": {
|
|
8
8
|
"image-size": "^2.0.2",
|
|
9
9
|
"sharp": "^0.34.5",
|
|
@@ -17,25 +17,25 @@
|
|
|
17
17
|
},
|
|
18
18
|
},
|
|
19
19
|
"packages": {
|
|
20
|
-
"@biomejs/biome": ["@biomejs/biome@2.4.
|
|
20
|
+
"@biomejs/biome": ["@biomejs/biome@2.4.12", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.4.12", "@biomejs/cli-darwin-x64": "2.4.12", "@biomejs/cli-linux-arm64": "2.4.12", "@biomejs/cli-linux-arm64-musl": "2.4.12", "@biomejs/cli-linux-x64": "2.4.12", "@biomejs/cli-linux-x64-musl": "2.4.12", "@biomejs/cli-win32-arm64": "2.4.12", "@biomejs/cli-win32-x64": "2.4.12" }, "bin": { "biome": "bin/biome" } }, "sha512-Rro7adQl3NLq/zJCIL98eElXKI8eEiBtoeu5TbXF/U3qbjuSc7Jb5rjUbeHHcquDWeSf3HnGP7XI5qGrlRk/pA=="],
|
|
21
21
|
|
|
22
|
-
"@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.4.
|
|
22
|
+
"@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.4.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-BnMU4Pc3ciEVteVpZ0BK33MLr7X57F5w1dwDLDn+/iy/yTrA4Q/N2yftidFtsA4vrDh0FMXDpacNV/Tl3fbmng=="],
|
|
23
23
|
|
|
24
|
-
"@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.4.
|
|
24
|
+
"@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.4.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-x9uJ0bI1rJsWICp3VH8w/5PnAVD3A7SqzDpbrfoUQX1QyWrK5jSU4fRLo/wSgGeplCivbxBRKmt5Xq4/nWvq8A=="],
|
|
25
25
|
|
|
26
|
-
"@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.4.
|
|
26
|
+
"@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.4.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-tOwuCuZZtKi1jVzbk/5nXmIsziOB6yqN8c9r9QM0EJYPU6DpQWf11uBOSCfFKKM4H3d9ZoarvlgMfbcuD051Pw=="],
|
|
27
27
|
|
|
28
|
-
"@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.4.
|
|
28
|
+
"@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.4.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-FhfpkAAlKL6kwvcVap0Hgp4AhZmtd3YImg0kK1jd7C/aSoh4SfsB2f++yG1rU0lr8Y5MCFJrcSkmssiL9Xnnig=="],
|
|
29
29
|
|
|
30
|
-
"@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.4.
|
|
30
|
+
"@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.4.12", "", { "os": "linux", "cpu": "x64" }, "sha512-8pFeAnLU9QdW9jCIslB/v82bI0lhBmz2ZAKc8pVMFPO0t0wAHsoEkrUQUbMkIorTRIjbqyNZHA3lEXavsPWYSw=="],
|
|
31
31
|
|
|
32
|
-
"@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.4.
|
|
32
|
+
"@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.4.12", "", { "os": "linux", "cpu": "x64" }, "sha512-dwTIgZrGutzhkQCuvHynCkyW6hJxUuyZqKKO0YNfaS2GUoRO+tOvxXZqZB6SkWAOdfZTzwaw8IEdUnIkHKHoew=="],
|
|
33
33
|
|
|
34
|
-
"@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.4.
|
|
34
|
+
"@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.4.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-B0DLnx0vA9ya/3v7XyCaP+/lCpnbWbMOfUFFve+xb5OxyYvdHaS55YsSddr228Y+JAFk58agCuZTsqNiw2a6ig=="],
|
|
35
35
|
|
|
36
|
-
"@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.4.
|
|
36
|
+
"@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.4.12", "", { "os": "win32", "cpu": "x64" }, "sha512-yMckRzTyZ83hkk8iDFWswqSdU8tvZxspJKnYNh7JZr/zhZNOlzH13k4ecboU6MurKExCe2HUkH75pGI/O2JwGA=="],
|
|
37
37
|
|
|
38
|
-
"@emnapi/runtime": ["@emnapi/runtime@1.
|
|
38
|
+
"@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="],
|
|
39
39
|
|
|
40
40
|
"@img/colour": ["@img/colour@1.1.0", "", {}, "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ=="],
|
|
41
41
|
|
|
@@ -103,7 +103,7 @@
|
|
|
103
103
|
|
|
104
104
|
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
|
105
105
|
|
|
106
|
-
"typescript": ["typescript@6.0.
|
|
106
|
+
"typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="],
|
|
107
107
|
|
|
108
108
|
"undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="],
|
|
109
109
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
## [0.2.0] - 2026-04-18
|
|
2
|
+
|
|
3
|
+
### 🚀 Features
|
|
4
|
+
|
|
5
|
+
- Init project, ts, biome, git, license, readme, src
|
|
6
|
+
- *(video)* Add video processing, separate code into image/video/shared folders
|
|
7
|
+
- Rename project to @adaptive-ds/assets-optimizer
|
|
8
|
+
- *(list)* Generate image/video list, rename main function to assetsOptimize
|
|
9
|
+
- Allow specifying logging level, allow skipping remote if not configured
|
|
10
|
+
- *(rclone)* Add rclone functions to be used by consumers
|
|
11
|
+
|
|
12
|
+
### 🐛 Bug Fixes
|
|
13
|
+
|
|
14
|
+
- *(ts)* Remove deprecated downlevelIteration, configure lib rootDir
|
|
15
|
+
|
|
16
|
+
### 🤖 CI
|
|
17
|
+
|
|
18
|
+
- Setup github oidc publishing
|
|
19
|
+
|
|
20
|
+
### 🚜 Refactor
|
|
21
|
+
|
|
22
|
+
- Simplify, remove clone remote calls, should be done by callers
|
|
23
|
+
|
|
24
|
+
### 📚 Documentation
|
|
25
|
+
|
|
26
|
+
- *(readme)* Update, add explanation diagrams
|
|
27
|
+
- *(readme)* Replace r2 with rclone remote
|
|
28
|
+
- *(readme)* Add headings for diagrams
|
|
29
|
+
|
|
30
|
+
### ⚙️ Miscellaneous Tasks
|
|
31
|
+
|
|
32
|
+
- Add release script, format code with biome, add package metadata
|
package/package.json
CHANGED