zcompress-vite-plugin 0.1.4 → 0.1.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.
package/README.md CHANGED
@@ -74,6 +74,13 @@ zcompress({
74
74
  })
75
75
  ```
76
76
 
77
+ 也可用环境变量(不改代码):
78
+
79
+ ```bash
80
+ export ZCOMPRESS_BINARY=/absolute/path/to/zcompress
81
+ npm run build
82
+ ```
83
+
77
84
  默认 `failOnError: true`,失败会直接中断构建(不会静默跳过压缩)。
78
85
 
79
86
  ## License
@@ -161,6 +168,13 @@ zcompress({
161
168
  })
162
169
  ```
163
170
 
171
+ Or use env var (no code change):
172
+
173
+ ```bash
174
+ export ZCOMPRESS_BINARY=/absolute/path/to/zcompress
175
+ npm run build
176
+ ```
177
+
164
178
  Default `failOnError: true` ensures builds fail loudly (instead of silently skipping compression).
165
179
 
166
180
  ## License
package/index.js CHANGED
@@ -49,14 +49,18 @@ const DEFAULT_OPTIONS = {
49
49
 
50
50
  /**
51
51
  * Find the zcompress binary.
52
- * Order: 1) downloaded by postinstall 2) local zig build 3) PATH
52
+ * Order: 1) ZCOMPRESS_BINARY env 2) downloaded by postinstall 3) local zig build 4) PATH
53
53
  */
54
54
  function findBinary() {
55
- // 1) postinstall-downloaded binary inside package
55
+ // 1) explicit env override
56
+ const envBinary = process.env.ZCOMPRESS_BINARY;
57
+ if (envBinary) return envBinary;
58
+
59
+ // 2) postinstall-downloaded binary inside package
56
60
  const packagedBin = join(__dirname, 'bin', process.platform === 'win32' ? 'zcompress.exe' : 'zcompress');
57
61
  if (existsSync(packagedBin)) return packagedBin;
58
62
 
59
- // 2) local zig build
63
+ // 3) local zig build
60
64
  const zigPaths = [
61
65
  join(process.cwd(), 'zig-out', 'bin', 'zcompress'),
62
66
  join(process.cwd(), 'zig-out', 'bin', 'zcompress.exe'),
@@ -65,7 +69,7 @@ function findBinary() {
65
69
  if (existsSync(p)) return p;
66
70
  }
67
71
 
68
- // 3) PATH
72
+ // 4) PATH
69
73
  return 'zcompress';
70
74
  }
71
75
 
package/install.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  /**
4
4
  * Postinstall script — downloads the prebuilt zcompress binary from GitHub Releases.
5
- * Falls back gracefully if the binary can't be downloaded (e.g. air-gapped, unsupported platform).
5
+ * Falls back gracefully if binary can't be fetched.
6
6
  */
7
7
 
8
8
  import { createWriteStream, existsSync, chmodSync, mkdirSync, unlinkSync, readFileSync } from 'node:fs';
@@ -20,10 +20,10 @@ const pkgJson = JSON.parse(readFileSync(join(__dirname, 'package.json'), 'utf8')
20
20
  const VERSION = pkgJson.version;
21
21
 
22
22
  const PLATFORM_MAP = {
23
- 'darwin-arm64': 'zcompress-macos-arm64',
24
- 'darwin-x64': 'zcompress-macos-x64',
25
- 'linux-x64': 'zcompress-linux-x64',
26
- 'win32-x64': 'zcompress-windows-x64.exe',
23
+ 'darwin-arm64': 'zcompress-macos-arm64',
24
+ 'darwin-x64': 'zcompress-macos-x64',
25
+ 'linux-x64': 'zcompress-linux-x64',
26
+ 'win32-x64': 'zcompress-windows-x64.exe',
27
27
  };
28
28
 
29
29
  function getPlatformKey() {
@@ -33,8 +33,54 @@ function getPlatformKey() {
33
33
  }
34
34
 
35
35
  function getBinaryName() {
36
- const key = getPlatformKey();
37
- return PLATFORM_MAP[key] || null;
36
+ return PLATFORM_MAP[getPlatformKey()] || null;
37
+ }
38
+
39
+ function request(url) {
40
+ return new Promise((resolve, reject) => {
41
+ get(url, {
42
+ headers: {
43
+ 'User-Agent': 'zcompress-vite-plugin-install',
44
+ Accept: 'application/vnd.github+json',
45
+ },
46
+ }, (res) => resolve(res)).on('error', reject);
47
+ });
48
+ }
49
+
50
+ async function fetchJson(url) {
51
+ const res = await request(url);
52
+ if (res.statusCode !== 200) {
53
+ throw new Error(`HTTP ${res.statusCode}`);
54
+ }
55
+ const chunks = [];
56
+ for await (const chunk of res) chunks.push(chunk);
57
+ return JSON.parse(Buffer.concat(chunks).toString('utf8'));
58
+ }
59
+
60
+ async function downloadToFile(url, destPath) {
61
+ const res = await request(url);
62
+
63
+ // Follow redirect (GitHub release assets usually 302)
64
+ if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
65
+ return downloadToFile(res.headers.location, destPath);
66
+ }
67
+
68
+ if (res.statusCode !== 200) {
69
+ throw new Error(`HTTP ${res.statusCode}`);
70
+ }
71
+
72
+ const file = createWriteStream(destPath);
73
+ await pipeline(res, file);
74
+ }
75
+
76
+ async function resolveFallbackAssetUrl(binaryName) {
77
+ // Fallback strategy: use latest release asset for this platform when current version asset is missing.
78
+ const latest = await fetchJson(`https://api.github.com/repos/${REPO}/releases/latest`);
79
+ const asset = (latest.assets || []).find((a) => a.name === binaryName);
80
+ if (!asset?.browser_download_url) {
81
+ throw new Error('Latest release has no matching asset');
82
+ }
83
+ return asset.browser_download_url;
38
84
  }
39
85
 
40
86
  async function downloadBinary() {
@@ -52,56 +98,55 @@ async function downloadBinary() {
52
98
  return true;
53
99
  }
54
100
 
55
- const url = `https://github.com/${REPO}/releases/download/v${VERSION}/${binaryName}`;
56
- console.log(`[zcompress] ↓ Downloading ${url} ...`);
101
+ mkdirSync(BIN_DIR, { recursive: true });
57
102
 
103
+ const versionedUrl = `https://github.com/${REPO}/releases/download/v${VERSION}/${binaryName}`;
104
+ const tried = [];
105
+
106
+ // Attempt 1: exact npm version
58
107
  try {
59
- mkdirSync(BIN_DIR, { recursive: true });
60
-
61
- await new Promise((resolve, reject) => {
62
- const file = createWriteStream(destPath);
63
- get(url, (response) => {
64
- // Follow redirects
65
- if (response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
66
- get(response.headers.location, (redirectRes) => {
67
- pipeline(redirectRes, file).then(resolve).catch(reject);
68
- }).on('error', reject);
69
- return;
70
- }
71
- if (response.statusCode !== 200) {
72
- file.close();
73
- unlinkSync(destPath);
74
- reject(new Error(`HTTP ${response.statusCode}`));
75
- return;
76
- }
77
- pipeline(response, file).then(resolve).catch(reject);
78
- }).on('error', reject);
79
- });
80
-
81
- // Make executable on Unix
82
- if (process.platform !== 'win32') {
83
- chmodSync(destPath, 0o755);
84
- }
108
+ tried.push(versionedUrl);
109
+ console.log(`[zcompress] ↓ Downloading ${versionedUrl} ...`);
110
+ await downloadToFile(versionedUrl, destPath);
85
111
 
112
+ if (process.platform !== 'win32') chmodSync(destPath, 0o755);
86
113
  console.log(`[zcompress] ✓ Binary installed: ${destPath}`);
87
114
  return true;
88
115
  } catch (err) {
89
- if (String(err.message).includes('HTTP 404')) {
90
- console.log(`[zcompress] Release asset not found for v${VERSION}: ${binaryName}`);
91
- console.log(`[zcompress] ⚠ Expected URL: ${url}`);
92
- console.log('[zcompress] This usually means the npm version was published before uploading binary assets to GitHub Releases.');
116
+ // cleanup partial
117
+ try { unlinkSync(destPath); } catch {}
118
+
119
+ // If 404 or similar, try latest release as fallback
120
+ const msg = String(err?.message || err);
121
+ if (!msg.includes('404')) {
122
+ console.log(`[zcompress] ⚠ Download failed (${msg}).`);
93
123
  } else {
94
- console.log(`[zcompress] ⚠ Could not download binary (${err.message}).`);
124
+ console.log(`[zcompress] ⚠ Asset missing for v${VERSION}: ${binaryName}`);
95
125
  }
126
+ }
127
+
128
+ // Attempt 2: latest release fallback
129
+ try {
130
+ const latestAssetUrl = await resolveFallbackAssetUrl(binaryName);
131
+ tried.push(latestAssetUrl);
132
+ console.log(`[zcompress] ↓ Falling back to latest release asset: ${latestAssetUrl}`);
133
+ await downloadToFile(latestAssetUrl, destPath);
134
+
135
+ if (process.platform !== 'win32') chmodSync(destPath, 0o755);
136
+ console.log(`[zcompress] ✓ Binary installed from latest release: ${destPath}`);
137
+ return true;
138
+ } catch (err) {
139
+ try { unlinkSync(destPath); } catch {}
140
+ console.log(`[zcompress] ⚠ Fallback download failed (${err.message}).`);
141
+ console.log('[zcompress] Tried URLs:');
142
+ for (const u of tried) console.log(` - ${u}`);
96
143
  console.log('[zcompress] ℹ Build from source: cd zcompress && zig build -Doptimize=ReleaseFast');
97
- // Clean up partial download
98
- try { unlinkSync(destPath); } catch (_) { /* ignore */ }
99
144
  return false;
100
145
  }
101
146
  }
102
147
 
103
148
  // Run download, but don't fail install if it doesn't work
104
- downloadBinary().catch(() => {
105
- console.log('[zcompress] Binary download skipped. The plugin requires the zcompress CLI.');
106
- console.log('[zcompress] ℹ Install it via: brew install zcompress OR zig build install');
149
+ downloadBinary().catch((err) => {
150
+ console.log(`[zcompress] Binary download skipped (${err.message}).`);
151
+ console.log('[zcompress] ℹ Install it manually and set plugin option `binaryPath`.');
107
152
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zcompress-vite-plugin",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "High-performance multi-threaded asset compression for Vite — powered by Zig",
5
5
  "type": "module",
6
6
  "main": "index.js",