Skip to content

Commit

Permalink
Load svgo version from project (#9969)
Browse files Browse the repository at this point in the history
  • Loading branch information
devongovett authored Nov 4, 2024
1 parent f304cf5 commit f53f450
Show file tree
Hide file tree
Showing 10 changed files with 492 additions and 70 deletions.
87 changes: 85 additions & 2 deletions packages/core/integration-tests/test/html.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import {
fsFixture,
} from '@parcel/test-utils';
import path from 'path';
import Logger from '@parcel/logger';
import {md} from '@parcel/diagnostic';

describe('html', function () {
beforeEach(async () => {
Expand Down Expand Up @@ -679,6 +681,83 @@ describe('html', function () {
);
});

it('should detect the version of SVGO to use', async function () {
// Test is outside parcel so that svgo is not already installed.
await fsFixture(overlayFS, '/')`
htmlnano-svgo-version
index.html:
<!DOCTYPE html>
<html>
<body>
<svg><rect id="test" /></svg>
</body>
</html>
.htmlnanorc:
{
"minifySvg": {
"full": true
}
}
yarn.lock:
`;

let messages = [];
let loggerDisposable = Logger.onLog(message => {
if (message.level !== 'verbose') {
messages.push(message);
}
});

try {
await bundle(path.join('/htmlnano-svgo-version/index.html'), {
inputFS: overlayFS,
defaultTargetOptions: {
shouldOptimize: true,
},
shouldAutoinstall: false,
});
} catch (err) {
// autoinstall is disabled
assert.equal(
err.diagnostics[0].message,
md`Could not resolve module "svgo" from "${path.resolve(
overlayFS.cwd(),
'/htmlnano-svgo-version/index',
)}"`,
);
}

loggerDisposable.dispose();
assert(
messages[0].diagnostics[0].message.startsWith(
'Detected deprecated SVGO v2 options in',
),
);
assert.deepEqual(messages[0].diagnostics[0].codeFrames, [
{
filePath: path.resolve(
overlayFS.cwd(),
'/htmlnano-svgo-version/.htmlnanorc',
),
codeHighlights: [
{
message: undefined,
start: {
line: 3,
column: 5,
},
end: {
line: 3,
column: 16,
},
},
],
},
]);
});

it('should not minify default values inside HTML in production mode', async function () {
let inputFile = path.join(
__dirname,
Expand Down Expand Up @@ -1001,7 +1080,7 @@ describe('html', function () {
let contents = await outputFS.readFile(b.getBundles()[0].filePath, 'utf8');
assert(
contents.includes(
'<svg><symbol id="all"><rect width="100" height="100"/></symbol></svg><svg><use xlink:href="#all" href="#all"/></svg>',
'<svg><symbol id="all"><rect width="100" height="100"/></symbol></svg><svg><use href="#all"/></svg>',
),
);
});
Expand Down Expand Up @@ -2928,7 +3007,11 @@ describe('html', function () {

let output = await outputFS.readFile(b.getBundles()[0].filePath, 'utf8');
assert(output.includes('<x-custom stddeviation="0.5"'));
assert(output.includes('<svg role="img" viewBox='));
assert(
output.includes(
'<svg preserveAspectRatio="xMinYMin meet" role="img" viewBox=',
),
);
assert(output.includes('<filter'));
assert(output.includes('<feGaussianBlur in="SourceGraphic" stdDeviation='));
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
const { extendDefaultPlugins } = require('svgo');

module.exports = {
plugins: extendDefaultPlugins([
plugins: [
{
name: 'removeComments',
active: false
name: 'preset-default',
params: {
overrides: {
removeComments: false
}
}
}
])
]
}
86 changes: 84 additions & 2 deletions packages/core/integration-tests/test/svg.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
import assert from 'assert';
import {assertBundles, bundle, distDir, outputFS} from '@parcel/test-utils';
import {
assertBundles,
bundle,
distDir,
outputFS,
overlayFS,
fsFixture,
} from '@parcel/test-utils';
import path from 'path';
import Logger from '@parcel/logger';
import {md} from '@parcel/diagnostic';

describe('svg', function () {
it('should support bundling SVG', async () => {
Expand Down Expand Up @@ -126,6 +135,79 @@ describe('svg', function () {
assert(file.includes('comment'));
});

it('should detect the version of SVGO to use', async function () {
// Test is outside parcel so that svgo is not already installed.
await fsFixture(overlayFS, '/')`
svgo-version
icon.svg:
<svg></svg>
index.html:
<img src="icon.svg" />
svgo.config.json:
{
"full": true
}
yarn.lock:
`;

let messages = [];
let loggerDisposable = Logger.onLog(message => {
if (message.level !== 'verbose') {
messages.push(message);
}
});

try {
await bundle(path.join('/svgo-version/index.html'), {
inputFS: overlayFS,
defaultTargetOptions: {
shouldOptimize: true,
},
shouldAutoinstall: false,
});
} catch (err) {
// autoinstall is disabled
assert.equal(
err.diagnostics[0].message,
md`Could not resolve module "svgo" from "${path.resolve(
overlayFS.cwd(),
'/svgo-version/index',
)}"`,
);
}

loggerDisposable.dispose();
assert(
messages[0].diagnostics[0].message.startsWith(
'Detected deprecated SVGO v2 options in',
),
);
assert.deepEqual(messages[0].diagnostics[0].codeFrames, [
{
filePath: path.resolve(
overlayFS.cwd(),
'/svgo-version/svgo.config.json',
),
codeHighlights: [
{
message: undefined,
start: {
line: 2,
column: 3,
},
end: {
line: 2,
column: 14,
},
},
],
},
]);
});

it('should detect xml-stylesheet processing instructions', async function () {
let b = await bundle(
path.join(__dirname, '/integration/svg-xml-stylesheet/img.svg'),
Expand Down Expand Up @@ -222,7 +304,7 @@ describe('svg', function () {

const svg = await outputFS.readFile(path.join(distDir, 'img.svg'), 'utf8');

assert(svg.includes('<style>:root{fill:red}</style>'));
assert(svg.includes('style="fill:red"'));
});

it('should be in separate bundles', async function () {
Expand Down
1 change: 1 addition & 0 deletions packages/core/utils/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,4 @@ export {
remapSourceLocation,
} from './sourcemap';
export {default as stripAnsi} from 'strip-ansi';
export {detectSVGOVersion} from './svgo';
50 changes: 50 additions & 0 deletions packages/core/utils/src/svgo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// @flow
export function detectSVGOVersion(
config: any,
): {|version: 3|} | {|version: 2, path: string|} {
if (!config) {
return {version: 3};
}

// These options were removed in v2.
if (config.full != null || config.svg2js != null) {
return {version: 2, path: config.full != null ? '/full' : '/svg2js'};
}

if (Array.isArray(config.plugins)) {
// Custom plugins in v2 had additional (required) fields that don't exist anymore.
let v2Plugin = config.plugins.findIndex(
p => p?.type != null || (p?.fn && p?.params != null),
);
if (v2Plugin !== -1) {
let field = config.plugins[v2Plugin].type != null ? 'type' : 'params';
return {version: 2, path: `/plugins/${v2Plugin}/${field}`};
}

// the cleanupIDs plugin lost the prefix option in v3.
let cleanupIdsIndex = config.plugins.findIndex(
p => p?.name === 'cleanupIDs',
);
let cleanupIDs =
cleanupIdsIndex !== -1 ? config.plugins[cleanupIdsIndex] : null;
if (cleanupIDs?.params?.prefix != null) {
return {version: 2, path: `/plugins/${cleanupIdsIndex}/params/prefix`};
}

// Automatically migrate some options from SVGO 2 config files.
config.plugins = config.plugins.filter(p => p?.active !== false);

for (let i = 0; i < config.plugins.length; i++) {
let p = config.plugins[i];
if (p === 'cleanupIDs') {
config.plugins[i] = 'cleanupIds';
}

if (p?.name === 'cleanupIDs') {
config.plugins[i].name = 'cleanupIds';
}
}
}

return {version: 3};
}
8 changes: 6 additions & 2 deletions packages/optimizers/htmlnano/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,14 @@
"parcel": "^2.12.0"
},
"dependencies": {
"@parcel/diagnostic": "2.12.0",
"@parcel/plugin": "2.12.0",
"@parcel/utils": "2.12.0",
"htmlnano": "^2.0.0",
"nullthrows": "^1.1.1",
"posthtml": "^0.16.5",
"svgo": "^2.4.0"
"posthtml": "^0.16.5"
},
"devDependencies": {
"svgo": "^3.3.2"
}
}
Loading

0 comments on commit f53f450

Please sign in to comment.