22
33import { Transformer } from '@parcel/plugin' ;
44
5- import svgoPlugin from '@svgr/plugin-svgo' ;
65import jsxPlugin from '@svgr/plugin-jsx' ;
76import { transform } from '@svgr/core' ;
7+ import { detectSVGOVersion } from '@parcel/utils' ;
8+ import path from 'path' ;
9+ import { md , generateJSONCodeHighlights } from '@parcel/diagnostic' ;
810
911export default ( new Transformer ( {
10- async loadConfig ( { config} ) {
12+ async loadConfig ( { config, logger , options } ) {
1113 let svgrResult = await config . getConfig ( [
1214 '.svgrrc' ,
1315 '.svgrrc.json' ,
@@ -19,25 +21,102 @@ export default (new Transformer({
1921 'svgr.config.cjs' ,
2022 'svgr.config.mjs' ,
2123 ] ) ;
22- let svgoResult = await config . getConfig ( [
24+ let svgoResult : any = await config . getConfig ( [
2325 'svgo.config.js' ,
2426 'svgo.config.cjs' ,
2527 'svgo.config.mjs' ,
2628 'svgo.config.json' ,
2729 ] ) ;
28- return { svgr : svgrResult ?. contents , svgo : svgoResult ?. contents } ;
30+
31+ let svgoConfig = svgrResult ?. contents ?. svgoConfig ?? svgoResult ?. contents ;
32+ let svgoConfigPath = svgrResult ?. contents ?. svgoConfig
33+ ? svgrResult . filePath
34+ : svgoResult ?. filePath ;
35+
36+ // See if svgo is already installed.
37+ let resolved ;
38+ try {
39+ resolved = await options . packageManager . resolve (
40+ 'svgo' ,
41+ path . join ( options . projectRoot , 'index' ) ,
42+ { shouldAutoInstall : false } ,
43+ ) ;
44+ } catch ( err ) {
45+ // ignore.
46+ }
47+
48+ // If so, use the existing installed version.
49+ let svgoVersion = 3 ;
50+ if ( resolved ) {
51+ if ( resolved . pkg ?. version ) {
52+ svgoVersion = parseInt ( resolved . pkg . version ) ;
53+ }
54+ } else if ( svgoConfig ) {
55+ // Otherwise try to detect the version based on the config file.
56+ let v = detectSVGOVersion ( svgoConfig ) ;
57+ if ( svgoConfig != null && v . version === 2 ) {
58+ logger . warn ( {
59+ message : md `Detected deprecated SVGO v2 options in ${ path . relative (
60+ process . cwd ( ) ,
61+ svgoConfigPath ,
62+ ) } `,
63+ codeFrames : [
64+ {
65+ filePath : svgoConfigPath ,
66+ codeHighlights :
67+ path . basename ( svgoConfigPath ) === '.svgrrc' ||
68+ path . extname ( svgoConfigPath ) === '.json'
69+ ? generateJSONCodeHighlights (
70+ await options . inputFS . readFile ( svgoConfigPath , 'utf8' ) ,
71+ [
72+ {
73+ key : `${
74+ svgrResult ?. contents ?. svgoConfig
75+ ? '/svgoConfig'
76+ : ''
77+ } ${ v . path } `,
78+ } ,
79+ ] ,
80+ )
81+ : [ ] ,
82+ } ,
83+ ] ,
84+ } ) ;
85+ }
86+
87+ svgoVersion = v . version ;
88+ }
89+
90+ return { svgr : svgrResult ?. contents , svgo : svgoConfig , svgoVersion} ;
2991 } ,
3092
31- async transform ( { asset, config} ) {
93+ async transform ( { asset, config, options } ) {
3294 let code = await asset . getCode ( ) ;
3395
96+ let plugins = [ ] ;
97+ if ( config . svgr ?. svgo !== false ) {
98+ let svgo = await options . packageManager . require (
99+ 'svgo' ,
100+ path . join ( options . projectRoot , 'index' ) ,
101+ {
102+ range : `^${ config . svgoVersion } ` ,
103+ saveDev : true ,
104+ shouldAutoInstall : options . shouldAutoInstall ,
105+ } ,
106+ ) ;
107+
108+ plugins . push ( createSvgoPlugin ( svgo ) ) ;
109+ }
110+
111+ plugins . push ( jsxPlugin ) ;
112+
34113 const jsx = await transform (
35114 code ,
36115 { svgoConfig : config . svgo , ...config . svgr , runtimeConfig : false } ,
37116 {
38117 caller : {
39118 name : '@parcel/transformer-svg-react' ,
40- defaultPlugins : [ svgoPlugin , jsxPlugin ] ,
119+ defaultPlugins : plugins ,
41120 } ,
42121 filePath : asset . filePath ,
43122 } ,
@@ -50,3 +129,48 @@ export default (new Transformer({
50129 return [ asset ] ;
51130 } ,
52131} ) : Transformer ) ;
132+
133+ // Below is copied from @svgr /plugin-svgo. MIT license.
134+ // https://github.com/gregberge/svgr/tree/180eb6d503215fc782dfece351ff751194a0dfed/packages/plugin-svgo
135+
136+ function getSvgoConfigFromSvgrConfig ( config ) {
137+ const params = { overrides : { } } ;
138+ if ( config . icon || config . dimensions === false ) {
139+ params . overrides . removeViewBox = false ;
140+ }
141+ if ( config . native ) {
142+ params . overrides . inlineStyles = {
143+ onlyMatchedOnce : false ,
144+ } ;
145+ }
146+
147+ return {
148+ plugins : [
149+ {
150+ name : 'preset-default' ,
151+ params,
152+ } ,
153+ 'prefixIds' ,
154+ ] ,
155+ } ;
156+ }
157+
158+ function getSvgoConfig ( config ) {
159+ if ( config . svgoConfig ) return config . svgoConfig ;
160+ return getSvgoConfigFromSvgrConfig ( config ) ;
161+ }
162+
163+ function createSvgoPlugin ( svgo ) {
164+ return ( code , config , state ) => {
165+ const svgoConfig = getSvgoConfig ( config ) ;
166+ const result = svgo . optimize ( code , { ...svgoConfig , path : state . filePath } ) ;
167+
168+ // @ts -ignore
169+ if ( result . modernError ) {
170+ // @ts -ignore
171+ throw result . modernError ;
172+ }
173+
174+ return result . data ;
175+ } ;
176+ }
0 commit comments