Closed nstuyvesant closed 5 years ago
Hello, does this occur as a result of a "watch", where the input SVG file might be updated and the build-process triggered? If so you may need to delay the start via the underlying awaitWriteFinish
setting of chokidar
.
(You don't need to use image.clone()
as this code is not using Streams.)
Hi @lovell,
The SVG that's used as a source does not change (always located at client/assets/images/logo.svg). The file is linked to my first post. It was generated by Adobe Illustrator CC. You might wonder why I would repeatedly generate the images every build - didn't want the PNGs sitting around with the sources (and besides, you made sharp so fast that it only takes about a second to generate all my PNGs). ;-)
Here's the output of me creating two builds - ten minutes apart...
Nates-iMac:shy nates$ gulp build
[12:07:20] Requiring external module @babel/register
[12:07:24] Using gulpfile ~/dev/shy/gulpfile.babel.js
[12:07:24] Starting 'build'...
[12:07:24] Starting 'clean:dist'...
[12:07:24] Finished 'clean:dist' after 21 ms
[12:07:24] Starting 'inject:scss'...
[12:07:24] gulp-inject 21 files into app.scss.
[12:07:24] Finished 'inject:scss' after 89 ms
[12:07:24] Starting 'transpile:server'...
[12:07:25] Finished 'transpile:server' after 661 ms
[12:07:25] Starting 'build:images'...
[12:07:25] Starting 'build:icons'...
[12:07:25] Starting 'copy:fonts'...
[12:07:25] Finished 'copy:fonts' after 600 ms
[12:07:25] gulp-imagemin: Minified 9 images (saved 414 kB - 25.6%)
[12:07:25] Finished 'build:images' after 768 ms
[12:07:30] Finished 'build:icons' after 5.14 s
[12:07:30] Starting 'copy:dist'...
[12:07:30] Starting 'copy:dist:server'...
[12:07:30] Starting 'copy:dist:client'...
[12:07:30] Starting 'webpack:dist'...
[12:07:30] Finished 'copy:dist:server' after 165 ms
[12:07:33] Finished 'copy:dist' after 2.89 s
[12:07:33] Finished 'copy:dist:client' after 2.96 s
(node:70859) [DEP0097] DeprecationWarning: Using a domain property in MakeCallback is deprecated. Use the async_context variant of MakeCallback or the AsyncResource class instead.
[12:07:47] Version: webpack 4.29.6
Built at: 03/03/2019 12:07:47 PM
Asset Size Chunks Chunk Names
app.72ea4e1a3ba8e2e08bb6.css 190 KiB 0 [emitted] app
app.c08a4aba024bdb727dd2.js 987 KiB 0 [emitted] [big] app
app.c08a4aba024bdb727dd2.js.map 4.54 MiB 0 [emitted] app
index.html 16.1 KiB [emitted]
Entrypoint app [big] = app.72ea4e1a3ba8e2e08bb6.css app.c08a4aba024bdb727dd2.js app.c08a4aba024bdb727dd2.js.map
[12:07:47] Finished 'webpack:dist' after 17 s
[12:07:47] Starting 'image:cache-busting'...
[12:07:47] Finished 'image:cache-busting' after 44 ms
[12:07:47] Starting 'build:icons-sharp'...
[12:07:48] Finished 'build:icons-sharp' after 1.06 s
[12:07:48] Finished 'build' after 24 s
Nates-iMac:shy nates$ gulp build
[12:17:14] Requiring external module @babel/register
[12:17:16] Using gulpfile ~/dev/shy/gulpfile.babel.js
[12:17:16] Starting 'build'...
[12:17:16] Starting 'clean:dist'...
[12:17:16] Finished 'clean:dist' after 20 ms
[12:17:16] Starting 'inject:scss'...
[12:17:16] gulp-inject 21 files into app.scss.
[12:17:16] Finished 'inject:scss' after 76 ms
[12:17:16] Starting 'transpile:server'...
[12:17:17] Finished 'transpile:server' after 623 ms
[12:17:17] Starting 'build:images'...
[12:17:17] Starting 'build:icons'...
[12:17:17] Starting 'copy:fonts'...
[12:17:17] Finished 'copy:fonts' after 431 ms
[12:17:17] gulp-imagemin: Minified 9 images (saved 414 kB - 25.6%)
[12:17:17] Finished 'build:images' after 655 ms
[12:17:21] Finished 'build:icons' after 4.76 s
[12:17:21] Starting 'copy:dist'...
[12:17:21] Starting 'copy:dist:server'...
[12:17:21] Starting 'copy:dist:client'...
[12:17:21] Starting 'webpack:dist'...
[12:17:22] Finished 'copy:dist:server' after 155 ms
[12:17:24] Finished 'copy:dist:client' after 2.67 s
[12:17:24] Finished 'copy:dist' after 2.68 s
[12:17:29] Version: webpack 4.29.6
Built at: 03/03/2019 12:17:29 PM
Asset Size Chunks Chunk Names
app.72ea4e1a3ba8e2e08bb6.css 190 KiB 0 [emitted] app
app.c08a4aba024bdb727dd2.js 987 KiB 0 [emitted] [big] app
app.c08a4aba024bdb727dd2.js.map 4.54 MiB 0 [emitted] app
index.html 16.1 KiB [emitted]
Entrypoint app [big] = app.72ea4e1a3ba8e2e08bb6.css app.c08a4aba024bdb727dd2.js app.c08a4aba024bdb727dd2.js.map
[12:17:29] Finished 'webpack:dist' after 7.15 s
[12:17:29] Starting 'image:cache-busting'...
[12:17:29] Finished 'image:cache-busting' after 39 ms
[12:17:29] Starting 'build:icons-sharp'...
[12:17:29] 'build:icons-sharp' errored after 6.89 ms
[12:17:29] Error: Input file has corrupt header: glib: SVG has no elements
[12:17:29] 'build' errored after 13 s
(sharp:70913): GLib-CRITICAL **: 12:17:29.175: g_hash_table_lookup: assertion 'hash_table != NULL' failed
(sharp:70913): GLib-CRITICAL **: 12:17:29.176: g_hash_table_lookup: assertion 'hash_table != NULL' failed
(sharp:70913): GLib-CRITICAL **: 12:17:29.176: g_hash_table_lookup: assertion 'hash_table != NULL' failed
(sharp:70913): GLib-CRITICAL **: 12:17:29.176: g_hash_table_lookup: assertion 'hash_table != NULL' failed
(sharp:70913): GLib-CRITICAL **: 12:17:29.176: g_hash_table_lookup: assertion 'hash_table != NULL' failed
(sharp:70913): GLib-CRITICAL **: 12:17:29.176: g_hash_table_insert_internal: assertion 'hash_table != NULL' failed
(sharp:70913): GLib-CRITICAL **: 12:17:29.176: g_hash_table_lookup: assertion 'hash_table != NULL' failed
Segmentation fault: 11
Small comment... had to use clone() because I'm passing the same image object repeatedly. I tried it without clone() and was finding the resulting images were picking up effects from previous calls. For example, my first two calls to the render() function set a purple background. Once I got to the third invocation where it's supposed to have a transparent background, it was purple.
Best, Nate
Also, building the images with sharp is the last gulp task and it's executed serially...
gulp.task('build',
gulp.series(
'clean:dist',
'inject:scss',
'transpile:server',
gulp.parallel('build:images', 'build:favicons', 'copy:fonts'),
gulp.parallel('copy:dist', 'copy:dist:server', 'copy:dist:client', 'webpack:dist'),
'image:cache-busting',
'build:icons-sharp'
)
);
Thanks for all the extra info. Rather than create a singleton sharp
instance and clone it in render()
, I'd probably create a new sharp
instance per invocation of render()
, perhaps passing the filesystem path instead. (I'm not sure this is the problem, but it will help remove the possibility of this being some kind of mutation side-effect.)
I notice the build:icons-sharp
task fails after only 6.89 ms so this does still feel like a missing or not-yet-complete file. Could one of the previous tasks modify the file referenced by paths.client.svgIcon
?
We've been having this exact same problem ourselves for over a month now as well.
I'd probably create a new sharp instance per invocation of render(), perhaps passing the filesystem path instead. (I'm not sure this is the problem, but it will help remove the possibility of this being some kind of mutation side-effect.)
Going to see if this ^ helps / changes the frequency we're seeing this happen!
Thanks @lovell. Made your suggested change and 10 builds without errors.
Here's the new function:
const render = renderConfig => {
const image = sharp(paths.client.svgIcon);
const { width } = renderConfig; // required properties
if(!width) throw new Error('Gulp error in \'dist:client:assets:images:icons\': Width is a required parameter.');
let { height, name, scale, background } = renderConfig; // optional properties
scale = scale || 100;
height = height || width; // assume a square if height not provided
// If name is provided, assume dist/client, else dist/client/assets/images
name = name ? `./${paths.dist}/${clientPath}/${name}` : `./${paths.dist}/${clientPath}/assets/images/logo-${width}x${height}.png`;
// Calculate width & height of scaled square logo (rounded)
const smallerLength = Math.min(width, height);
const logoLength = Math.round(smallerLength * scale / 100);
// Calculate padding to center scaled logo within width x height box
const top = Math.floor((height - logoLength) / 2); // if fractional, smaller padding at the top
const bottom = Math.ceil((height - logoLength) / 2);
const left = Math.floor((width - logoLength) / 2); // if fractional, smaller padding on left
const right = Math.ceil((width - logoLength) / 2);
image
.resize(logoLength)
.extend({
top,
bottom,
left,
right,
background: background ? background : { r: 0, g: 0, b: 0, alpha: 0 }
});
if(background) image.flatten({ background });
return image.toFile(name);
};
Just experienced the problem again. 10 seconds later, I was able to do a build.
Also encountered (intermittently) when I replaced:
const image = sharp(paths.client.svgIcon);
with
const image = sharp('client/assets/images/logo.svg');
I'm now running the gulp task by itself with the hard-coded path...
Nates-iMac:shy nates$ date
Wed Mar 13 11:04:14 EDT 2019
Nates-iMac:shy nates$ gulp dist:client:assets:images:icons
[11:04:19] Requiring external module @babel/register
[11:04:21] Using gulpfile ~/dev/shy/gulpfile.babel.js
[11:04:21] Starting 'dist:client:assets:images:icons'...
[11:04:22] Finished 'dist:client:assets:images:icons' after 952 ms
Nates-iMac:shy nates$ gulp dist:client:assets:images:icons
[11:04:23] Requiring external module @babel/register
[11:04:25] Using gulpfile ~/dev/shy/gulpfile.babel.js
[11:04:25] Starting 'dist:client:assets:images:icons'...
[11:04:26] Finished 'dist:client:assets:images:icons' after 971 ms
Nates-iMac:shy nates$ gulp dist:client:assets:images:icons
[11:04:29] Requiring external module @babel/register
[11:04:31] Using gulpfile ~/dev/shy/gulpfile.babel.js
[11:04:31] Starting 'dist:client:assets:images:icons'...
[11:04:32] Finished 'dist:client:assets:images:icons' after 947 ms
Nates-iMac:shy nates$ gulp dist:client:assets:images:icons
[11:04:33] Requiring external module @babel/register
[11:04:35] Using gulpfile ~/dev/shy/gulpfile.babel.js
[11:04:35] Starting 'dist:client:assets:images:icons'...
[11:04:35] 'dist:client:assets:images:icons' errored after 9.51 ms
[11:04:35] Error: Input file has corrupt header: glib: SVG has no elements
(sharp:69328): GLib-CRITICAL **: 11:04:35.157: g_hash_table_lookup: assertion 'hash_table != NULL' failed
(sharp:69328): GLib-CRITICAL **: 11:04:35.157: g_hash_table_insert_internal: assertion 'hash_table != NULL' failed
(sharp:69328): GLib-CRITICAL **: 11:04:35.157: g_hash_table_lookup: assertion 'hash_table != NULL' failed
Segmentation fault: 11
Nates-iMac:shy nates$ date
Wed Mar 13 11:04:38 EDT 2019
3 successful executions followed by a failure on the 4th seconds apart.
My environment: node v10.15.2 gulp 4.0 macOS 10.14.3 @babel/register 7.0.0
Thanks for the updates. Given that you're only seeing this for SVG input I wonder if it's somehow related to #1572. Are you able to test with the uptake
branch that provides a newer librsvg?
npm install --build-from-source lovell/sharp#uptake
Hi @lovell,
Just tried with the uptake branch and ran into the problem on the first attempt to run the gulp task...
Nates-iMac:shy nates$ npm install --build-from-source lovell/sharp#uptake
> sharp@0.21.3 install /Users/nates/dev/shy/node_modules/sharp
> (node install/libvips && node install/dll-copy && prebuild-install) || (node-gyp rebuild && node install/dll-copy)
info sharp Downloading https://github.com/lovell/sharp-libvips/releases/download/v8.7.4/libvips-8.7.4-darwin-x64.tar.gz
TOUCH Release/obj.target/libvips-cpp.stamp
CXX(target) Release/obj.target/sharp/src/common.o
CXX(target) Release/obj.target/sharp/src/metadata.o
CXX(target) Release/obj.target/sharp/src/stats.o
CXX(target) Release/obj.target/sharp/src/operations.o
CXX(target) Release/obj.target/sharp/src/pipeline.o
CXX(target) Release/obj.target/sharp/src/sharp.o
CXX(target) Release/obj.target/sharp/src/utilities.o
SOLINK_MODULE(target) Release/sharp.node
+ sharp@0.21.3
added 1 package from 8 contributors and updated 3 packages in 33.21s
Nates-iMac:shy nates$ gulp dist:client:assets:images:icons
[12:32:46] Requiring external module @babel/register
[12:32:48] Using gulpfile ~/dev/shy/gulpfile.babel.js
[12:32:48] Starting 'dist:client:assets:images:icons'...
[12:32:48] 'dist:client:assets:images:icons' errored after 7.88 ms
[12:32:48] Error: Input file has corrupt header: glib: SVG has no elements
glib: SVG has no elements
(sharp:19282): GLib-CRITICAL **: 12:32:48.545: g_hash_table_lookup: assertion 'hash_table != NULL' failed
(sharp:19282): GLib-CRITICAL **: 12:32:48.545: g_hash_table_lookup: assertion 'hash_table != NULL' failed
(sharp:19282): GLib-CRITICAL **: 12:32:48.545: g_hash_table_lookup: assertion 'hash_table != NULL' failed
(sharp:19282): GLib-CRITICAL **: 12:32:48.545: g_hash_table_lookup: assertion 'hash_table != NULL' failed
(sharp:19282): GLib-CRITICAL **: 12:32:48.545: g_hash_table_lookup: assertion 'hash_table != NULL' failed
(sharp:19282): GLib-CRITICAL **: 12:32:48.545: g_hash_table_insert_internal: assertion 'hash_table != NULL' failed
(sharp:19282): GLib-CRITICAL **: 12:32:48.545: g_hash_table_lookup: assertion 'hash_table != NULL' failed
Segmentation fault: 11
Above, I sent a link to my SVG and the code for the gulp 4 task. Hope that helps.
Best, Nate
Thanks for checking, this still looks like a race condition in one of the (prior) gulp tasks. Perhaps try removing all the gulp tasks but this one, or make them all series, and add them back one at a time. Could an output be trampling an input? Are the paths all absolute rather than relative?
Hi @lovell,
Just updated the gulp task to use an absolute path and upgraded to sharp 0.22.0:
gulp.task('dist:client:assets:images:icons', async() => {
const render = renderConfig => {
//const image = sharp(paths.client.svgIcon);
const image = sharp('/Users/nates/dev/shy/client/assets/images/logo.svg');
const { width } = renderConfig;
if(!width) throw new Error('Gulp error in \'dist:client:assets:images:icons\': Width is a required parameter.');
let { height, name, scale, background } = renderConfig;
scale = scale || 100;
height = height || width;
name = name ? `./${paths.dist}/${clientPath}/${name}` : `./${paths.dist}/${clientPath}/assets/images/logo-${width}x${height}.png`;
const smallerLength = Math.min(width, height);
const logoLength = Math.round(smallerLength * scale / 100);
const top = Math.floor((height - logoLength) / 2);
const bottom = Math.ceil((height - logoLength) / 2);
const left = Math.floor((width - logoLength) / 2);
const right = Math.ceil((width - logoLength) / 2);
image
.resize(logoLength)
.extend({
top,
bottom,
left,
right,
background: background ? background : { r: 0, g: 0, b: 0, alpha: 0 }
});
if(background) image.flatten({ background });
return image.toFile(name);
};
const themeBackground = { background: '#5f4884' };
const android = { }; // Android devices use the defaults
const iOS = { ...themeBackground, scale: 95 };
const edge = { ...themeBackground, scale: 70 };
const startup = { background: '#fff', scale: 75 };
const schema = { background: '#fff' };
return await Promise.all([
render({ width: 128, ...edge }), // Edge 70x70
render({ width: 180, name: 'apple-touch-icon.png', ...iOS }), // iOS
render({ width: 192, ...android }), // Android
render({ width: 270, ...edge }), // Edge 150x150
render({ width: 512, ...android }), // Android
render({ width: 558, height: 270, ...edge }), // Edge 310x150
render({ width: 558, ...edge }), // Edge 310x310
render({ width: 1024, ...schema }), // Schema.org logo
render({ width: 1536, height: 2048, ...startup }), // iOS startup logo - iPad Air A1475 portrait
render({ width: 2048, height: 1536, ...startup }), // iOS startup logo - iPad Air A1475 portrait
render({ width: 828, height: 1792, ...startup }), // iOS startup logo - iPhone XR portrait
render({ width: 1792, height: 828, ...startup }), // iOS startup logo - iPhone XR landscape
render({ width: 1125, height: 2436, ...startup }), // iOS startup logo - iPhone X/XS portrait
render({ width: 2436, height: 1125, ...startup }), // iOS startup logo - iPhone X/XS landscape
render({ width: 1668, height: 2224, ...startup }), // iOS startup logo - 10.5 iPad Pro portrait
render({ width: 2224, height: 1668, ...startup }), // iOS startup logo - 10.5 iPad Pro landscape
render({ width: 2048, height: 2732, ...startup }), // iOS startup logo - 12.9 iPad Pro portrait
render({ width: 2732, height: 2048, ...startup }), // iOS startup logo - 12.9 iPad Pro landscape
render({ width: 1242, height: 2688, ...startup }), // iOS startup logo - iPhone XS Max portrait
render({ width: 2688, height: 1242, ...startup }) // iOS startup logo - iPhone XS Max landscape
]);
});
Also, in order to not contend with other gulp tasks, I'm running just this one task like this:
$ gulp dist:client:assets:images:icons
[09:46:18] Requiring external module @babel/register
[09:46:20] Using gulpfile ~/dev/shy/gulpfile.babel.js
[09:46:20] Starting 'dist:client:assets:images:icons'...
[09:46:20] 'dist:client:assets:images:icons' errored after 8.04 ms
[09:46:20] Error: Input file has corrupt header: glib: SVG has no elements
(sharp:25717): GLib-CRITICAL **: 09:46:20.144: g_hash_table_lookup: assertion 'hash_table != NULL' failed
(sharp:25717): GLib-CRITICAL **: 09:46:20.144: g_hash_table_lookup: assertion 'hash_table != NULL' failed
(sharp:25717): GLib-CRITICAL **: 09:46:20.144: g_hash_table_lookup: assertion 'hash_table != NULL' failed
(sharp:25717): GLib-CRITICAL **: 09:46:20.144: g_hash_table_lookup: assertion 'hash_table != NULL' failed
(sharp:25717): GLib-CRITICAL **: 09:46:20.144: g_hash_table_insert_internal: assertion 'hash_table != NULL' failed
(sharp:25717): GLib-CRITICAL **: 09:46:20.144: g_hash_table_lookup: assertion 'hash_table != NULL' failed
Segmentation fault: 11
If you were to copy my SVG, gulp ES6/7 code and run it through @babel/register, wondering if this would happen on your computer. Anything else you'd like me to try?
Best, Nate
Thanks for the extra info, this one has me a bit stumped.
Are you able to reproduce this on a Linux machine, perhaps inside a Docker container?
I'll try to reproduce locally - is there a public repo with all this in I can clone and run?
Hi @lovell,
Created a tiny repo (no babel or gulp) that reproduces the issue faithfully on macOS 10.14.3 / node 10.15.2 using sharp 0.22.0 - https://github.com/nstuyvesant/sharp-test.
On Ubuntu Server 18.10 with node 10.15.3, I have been unable to reproduce the issue.
Not sure if you have access to a system running macOS. Please let me know if there's anything you'd like me to try.
Best, Nate
Just tried a few steps on macOS 10.14.3 that appear to have resolved the intermittent issue (more testing is needed)...
$ xcode-select --install
$ brew install vips
$ export PKG_CONFIG_PATH="/usr/local/opt/libffi/lib/pkgconfig"
$ npm install sharp
> sharp@0.22.0 install /Users/nates/dev/sharp-test/node_modules/sharp
> (node install/libvips && node install/dll-copy && prebuild-install) || (node-gyp rebuild && node install/dll-copy)
info sharp Detected globally-installed libvips v8.7.4
info sharp Building from source via node-gyp
TOUCH Release/obj.target/libvips-cpp.stamp
CXX(target) Release/obj.target/sharp/src/common.o
CXX(target) Release/obj.target/sharp/src/metadata.o
CXX(target) Release/obj.target/sharp/src/stats.o
CXX(target) Release/obj.target/sharp/src/operations.o
CXX(target) Release/obj.target/sharp/src/pipeline.o
CXX(target) Release/obj.target/sharp/src/sharp.o
CXX(target) Release/obj.target/sharp/src/utilities.o
SOLINK_MODULE(target) Release/sharp.node
+ sharp@0.22.0
added 1 package from 55 contributors and audited 181 packages in 14.76s
found 0 vulnerabilities
In looking over https://github.com/lovell/sharp-libvips/releases/download/v8.7.4/libvips-8.7.4-darwin-x64.tar.gz, one of the dependencies is xml 2.9.4. Installing libvips via homebrew installs libxml2-2.9.9. As the SVG is really XML, wondering if that might be the reason installing libvips via homebrew works and sharp's install using https://github.com/lovell/sharp-libvips/releases/download/v8.7.4/libvips-8.7.4-darwin-x64.tar.gz doesn't?
Great detective work, the libxml version could well explain this. XML parsing is one of the few bits of librsvg that isn't written in Rust and still relies on libxml.
On closer inspection it turns out the OS X tarball is missing libxml so anything that depends on it will fall back to the OS X provided v2.9.4. I've created https://github.com/lovell/package-libvips-darwin/issues/4 to improve this situation.
Fantastic - thanks for the help @lovell. Since making the changes, I've probably had at least 50 trouble-free builds.
Marvellous, thanks for confirming. Let's track the libxml "upgrade" at https://github.com/lovell/package-libvips-darwin/issues/4
Is there a way to make it easier to install sharp for macOS users (so the dependencies all get installed via npm install sharp)?
@nstuyvesant https://sharp.pixelplumbing.com/en/stable/install/#mac-os (if you've installed vips via brew then that will take priority)
Gotcha. Perhaps update the macOS docs to indicate doing a brew install vips
is important in order to avoid the error we were getting previously?
I'm having similar problems, and was unfortunately unable to install brew dependencies on our build servers. I managed to fix the issue by "warming up" the library by running something like this before performing any actual SVG image operations
function warmupSharp(sharp) {
return sharp(
Buffer.from(
`<svg xmlns="http://www.w3.org/2000/svg"><rect width="1" height="1" /></svg>`,
'utf-8'
)
)
.metadata()
.then(() => sharp, () => sharp);
}
Apparently the error is only thrown on the first run of the library, regardless of if it fails. So ignoring any first error with a throwaway operation like this seems to make all subsequent run nicely.
Getting these errors periodically (~10% of the time) when I do a gulp build to produce several pngs from an SVG. The parameters and input file are exactly the same every time. Not sure how to track this one down. Here's a copy of the SVG. It appears to be OK.
Here's the code (didn't get around to adding the error handling but none of the parameters are changing either).