Skip to content

Conversation

@Borewit
Copy link
Collaborator

@Borewit Borewit commented May 9, 2025

Introduces an optional option, to disable XML validation.

Disabling the XML validation makes SVG recognition a lot faster, at the cost the SVG XML is not validated.

Difference in processing time:

With XML validation:
  Parsed small SVGs, 255 SVG strings in 124.32 milliseconds.
  Parsed large SVG, 1 SVG strings in 636.30 milliseconds.
Without XML validation:
  Parsed small SVGs, 255 SVG strings in 9.79 milliseconds.
  Parsed large SVG, 1 SVG strings in 11.00 milliseconds.

Resulting in about ~12× to ~60× times short processing time.

ToDo:

  • Needs a unit test covering use cases with validation disabled

Code I used to measure performance:

import fs from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import isSvg from 'is-svg';
import { performance } from 'node:perf_hooks';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// Small SVG files, using https://github.com/hampusborgos/country-flags/tree/main/svg
const smallSvgFiles = path.resolve(__dirname, '..', 'country-flags', 'svg'); // Small SVG files
// Large SVG file, using https://upload.wikimedia.org/wikipedia/commons/c/c1/Propane_flame_contours-en.svg
const largeSvgFiles = path.resolve(__dirname, 'svg'); // Large SVG file

async function checkSvgFiles(dir, name, options) {
    try {

        const files = await fs.readdir(dir, { withFileTypes: true });
        let svgFiles = 0;

        const svgStrings = [];

        for (const file of files) {
            if (file.isFile()) {
                const filePath = path.join(dir, file.name);
                const content = await fs.readFile(filePath, 'utf8');
                svgStrings.push(content);


            }
        }

        const start = performance.now();

        for(let svgString of svgStrings) {
            if (isSvg(svgString, options)) {
                ++svgFiles;
            }
        }

        const end = performance.now();
        console.log(`  Parsed ${name}, ${svgFiles} SVG strings in ${(end - start).toFixed(2)} milliseconds.`);
    } catch (err) {
        console.error('Error reading directory:', err);
    }
}

async function runTestSuite(options) {
    await checkSvgFiles(smallSvgFiles, 'small SVGs', options);
    await checkSvgFiles(largeSvgFiles, 'large SVG', options);
}

async function runTests() {
    console.log(`With XML validation:`);
    await runTestSuite();
    console.log(`Without XML validation:`);
    await runTestSuite({xmlValidation: false});
}

runTests();

Resolves #42 (with the note that the actual degradation in performance as described in that issue, I could not reproduce, yet this is significantly reduce parsing time)

@Borewit Borewit self-assigned this May 9, 2025
@Borewit Borewit force-pushed the make-xml-validation-optional branch 2 times, most recently from b0c5430 to ff2ab4b Compare May 9, 2025 11:23
@Borewit Borewit marked this pull request as draft May 9, 2025 11:35
@Borewit Borewit force-pushed the make-xml-validation-optional branch from ff2ab4b to 377d7e1 Compare June 20, 2025 08:27
@Borewit Borewit marked this pull request as ready for review June 20, 2025 08:28
@Borewit Borewit requested a review from sindresorhus June 20, 2025 08:29
@sindresorhus
Copy link
Owner

Why do we need an option for this? The previous version was fast enough without an option to disable validation. Not clear whether it did validation or not, but it worked fine, so I would prefer to keep it simple if possible.

@Borewit
Copy link
Collaborator Author

Borewit commented Jun 22, 2025

Why do we need an option for this? The previous version was fast enough without an option to disable validation. Not clear whether it did validation or not, but it worked fine, so I would prefer to keep it simple if possible.

The previous implementation actually did perform basic XML validation. I had to explicitly enable that in @file-type/xml to maintain backward compatibility with is-svg. For reference, file-type itself does not apply XML validation.

The current implementation, even with validation enabled, is slightly faster than the previous one.

In most use cases, I believe users aren’t concerned with basic XML validation—they just want to check whether the input looks like an SVG. For large SVG files, skipping validation can make a significant difference in performance. The first issue raised since the change, was about performance, so apparently there are users who care. Well, at least one user.

index.d.ts Outdated
Comment on lines 4 to 9
export type IsSvgOptions = {
/**
Enable or disable XML validation, enabled by default
*/
xmlValidation?: boolean;
};
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
export type IsSvgOptions = {
/**
Enable or disable XML validation, enabled by default
*/
xmlValidation?: boolean;
};
export type Options = {
/**
Whether to validate the SVG as proper XML.
Turning this off can improve performance.
@default true
*/
validate?: boolean;
};

index.js Outdated
import {XmlTextDetector} from '@file-type/xml';

export default function isSvg(string) {
export default function isSvg(string, options) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
export default function isSvg(string, options) {
export default function isSvg(string, {validate} = {}) {

- Rename `xmValidate` to `validate`
- Use inline constructor to initialize empty options object
- Renamed TypeScript `type` `IsSvgOptions` to `Options`
@Borewit Borewit force-pushed the make-xml-validation-optional branch from cd4b960 to 3b9ca9b Compare July 7, 2025 13:20
@Borewit Borewit requested a review from sindresorhus July 7, 2025 13:21
@sindresorhus sindresorhus merged commit e164d6a into main Jul 8, 2025
4 checks passed
@sindresorhus sindresorhus deleted the make-xml-validation-optional branch July 8, 2025 11:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Performance Degradation in is-svg v6.0 Compared to v5.x with Base64 Strings

2 participants