fix: support image processing on CPUs without x86-64-v2
Some checks failed
Test and deploy / Verify production build (push) Failing after 15m8s
Some checks failed
Test and deploy / Verify production build (push) Failing after 15m8s
This commit is contained in:
@@ -57,6 +57,11 @@ Drizzle Kit, npm installs, or a compiler at runtime. Startup applies the committ
|
|||||||
SQL migrations and seeds samples only when the database is empty. `/api/health`
|
SQL migrations and seeds samples only when the database is empty. `/api/health`
|
||||||
checks database readiness without rendering the portfolio.
|
checks database readiness without rendering the portfolio.
|
||||||
|
|
||||||
|
Sharp uses native image processing where supported and includes a WebAssembly
|
||||||
|
fallback for servers without the required x86-64 CPU features. The fallback
|
||||||
|
preserves uploads and image optimization, but can use more CPU time. Keep
|
||||||
|
`@img/sharp-wasm32` at the same version as `sharp` when upgrading.
|
||||||
|
|
||||||
Use one application instance with a local filesystem. Do not mount the SQLite
|
Use one application instance with a local filesystem. Do not mount the SQLite
|
||||||
database over NFS/SMB, use an ephemeral serverless disk, or run multiple replicas
|
database over NFS/SMB, use an ephemeral serverless disk, or run multiple replicas
|
||||||
against the same data volume. PostgreSQL would be the next step if those become
|
against the same data volume. PostgreSQL would be the next step if those become
|
||||||
|
|||||||
@@ -3,7 +3,12 @@ const nextConfig = {
|
|||||||
output: 'standalone',
|
output: 'standalone',
|
||||||
serverExternalPackages: ['better-sqlite3'],
|
serverExternalPackages: ['better-sqlite3'],
|
||||||
outputFileTracingIncludes: {
|
outputFileTracingIncludes: {
|
||||||
'/*': ['./migrations/**/*'],
|
'/*': [
|
||||||
|
'./migrations/**/*',
|
||||||
|
'./node_modules/@img/sharp-wasm32/**/*',
|
||||||
|
'./node_modules/@emnapi/runtime/**/*',
|
||||||
|
'./node_modules/tslib/**/*',
|
||||||
|
],
|
||||||
},
|
},
|
||||||
outputFileTracingExcludes: {
|
outputFileTracingExcludes: {
|
||||||
'*': ['./data/**/*', './backups/**/*', './**/auth-secret', './**/*.sqlite*', './.env*'],
|
'*': ['./data/**/*', './backups/**/*', './**/auth-secret', './**/*.sqlite*', './.env*'],
|
||||||
|
|||||||
3
package-lock.json
generated
3
package-lock.json
generated
@@ -8,6 +8,7 @@
|
|||||||
"name": "portfolio-v2-antigravity",
|
"name": "portfolio-v2-antigravity",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@img/sharp-wasm32": "0.35.4",
|
||||||
"better-auth": "^1.7.5",
|
"better-auth": "^1.7.5",
|
||||||
"better-sqlite3": "^13.0.3",
|
"better-sqlite3": "^13.0.3",
|
||||||
"drizzle-orm": "^0.45.2",
|
"drizzle-orm": "^0.45.2",
|
||||||
@@ -456,7 +457,6 @@
|
|||||||
"resolved": "https://package-mirror.liara.ir/artifactory/api/npm/npm/@emnapi/runtime/-/runtime-1.11.3.tgz",
|
"resolved": "https://package-mirror.liara.ir/artifactory/api/npm/npm/@emnapi/runtime/-/runtime-1.11.3.tgz",
|
||||||
"integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==",
|
"integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tslib": "^2.4.0"
|
"tslib": "^2.4.0"
|
||||||
}
|
}
|
||||||
@@ -1610,7 +1610,6 @@
|
|||||||
"resolved": "https://package-mirror.liara.ir/artifactory/api/npm/npm/@img/sharp-wasm32/-/sharp-wasm32-0.35.4.tgz",
|
"resolved": "https://package-mirror.liara.ir/artifactory/api/npm/npm/@img/sharp-wasm32/-/sharp-wasm32-0.35.4.tgz",
|
||||||
"integrity": "sha512-zQnl4Kwp7Q6NHsENtU2T/00Zi+w3AQNwz3+UaTyVBy2FpXrzXzGjndpK61onhZjRtRpQXxCTeqw19bVyXOh7jA==",
|
"integrity": "sha512-zQnl4Kwp7Q6NHsENtU2T/00Zi+w3AQNwz3+UaTyVBy2FpXrzXzGjndpK61onhZjRtRpQXxCTeqw19bVyXOh7jA==",
|
||||||
"license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
|
"license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emnapi/runtime": "^1.11.3"
|
"@emnapi/runtime": "^1.11.3"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
"maintenance": "tsx --env-file-if-exists=.env scripts/maintenance.ts"
|
"maintenance": "tsx --env-file-if-exists=.env scripts/maintenance.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@img/sharp-wasm32": "0.35.4",
|
||||||
"better-auth": "^1.7.5",
|
"better-auth": "^1.7.5",
|
||||||
"better-sqlite3": "^13.0.3",
|
"better-sqlite3": "^13.0.3",
|
||||||
"drizzle-orm": "^0.45.2",
|
"drizzle-orm": "^0.45.2",
|
||||||
|
|||||||
26
tests/sharp-fallback.test.mjs
Normal file
26
tests/sharp-fallback.test.mjs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import { spawnSync } from 'node:child_process';
|
||||||
|
import test from 'node:test';
|
||||||
|
|
||||||
|
test('image processing falls back to WebAssembly without native CPU support', () => {
|
||||||
|
// Isolate the native-binding simulation from the rest of the test process.
|
||||||
|
const result = spawnSync(process.execPath, ['-e', `
|
||||||
|
const Module = require('node:module');
|
||||||
|
const original = Module._load;
|
||||||
|
Module._load = function (id, ...args) {
|
||||||
|
if (id.endsWith('.node') && !id.includes('wasm32')) {
|
||||||
|
const error = new Error('Simulated unavailable native binding');
|
||||||
|
error.code = 'MODULE_NOT_FOUND';
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
return original.call(this, id, ...args);
|
||||||
|
};
|
||||||
|
const sharp = require('sharp');
|
||||||
|
(async () => {
|
||||||
|
const image = await sharp({ create: { width: 8, height: 8, channels: 3, background: '#336699' } }).webp().toBuffer();
|
||||||
|
const metadata = await sharp(image).metadata();
|
||||||
|
if (metadata.format !== 'webp' || metadata.width !== 8 || metadata.height !== 8) throw new Error('Image round trip failed');
|
||||||
|
})().catch(error => { console.error(error); process.exitCode = 1; });
|
||||||
|
`], { encoding: 'utf8', timeout: 30000 });
|
||||||
|
assert.equal(result.status, 0, result.stderr || result.error?.message);
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user