Skip to content

Instantly share code, notes, and snippets.

@christiannaths
Created July 3, 2017 20:00
Show Gist options
  • Save christiannaths/d165e17ef212a7a4146e51c82068ee47 to your computer and use it in GitHub Desktop.
Save christiannaths/d165e17ef212a7a4146e51c82068ee47 to your computer and use it in GitHub Desktop.
SVG file to JSX Component Script
"scripts": {
"build": "yarn icons:crush && yarn icons:to-jsx && yarn diagrams:crush && yarn diagrams:to-jsx",
"icons:crush": "svgo --pretty --indent=2 -f ./icons/assets",
"icons:to-jsx": "babel-node --presets=react,es2015 ./scripts/svg-to-jsx.js ./icons/assets ./icons",
"diagrams:crush": "svgo --pretty --indent=2 -f ./diagrams/assets",
"diagrams:to-jsx": "babel-node --presets=react,es2015 ./scripts/svg-to-jsx.js ./diagrams/assets ./diagrams"
}
import path from 'path';
import fs from 'fs';
import pascalCase from 'pascal-case';
import camelCase from 'camel-case';
(function() {
if (!process.argv[2] || !process.argv[3])
return console.warn(
'Please pass <path/to/input> and <path/to/output> as command-line arguments'
);
const assetDir = path.resolve(__dirname, '../', process.argv[2]);
const componentDir = path.resolve(__dirname, '../', process.argv[3]);
const componentWrapper = svg => `import React from 'react';
export default (props) => (\n${svg});`;
fs.readdir(assetDir, (err, files) => {
fs.writeFileSync(path.resolve(assetDir, 'index.js'), '');
fs.writeFileSync(path.resolve(componentDir, 'index.js'), '');
const svgFiles = files.filter(file => path.extname(file) === '.svg');
const components = svgFiles
.map(file => path.resolve(assetDir, file))
.map(file => fs.readFileSync(file, { encoding: 'utf8' }))
.map(svg => componentWrapper(svg))
.map(svg => svg.replace(/xmlns:xlink/g, camelCase('xmlns:xlink')))
.map(svg => svg.replace(/xlink:href/g, camelCase('xlink:href')))
.map(svg => svg.replace(/fill-rule/g, camelCase('fill-rule')))
.map(svg => svg.replace(/fill-opacity/g, camelCase('fill-opacity')))
.map(svg => svg.replace(/<svg\s/g, '<svg {...props} '));
const jsxFiles = svgFiles
.map(file => path.basename(file, '.svg'))
.map(file => path.resolve(componentDir, `${file}.jsx`))
.map((file, index) => {
fs.writeFileSync(file, components[index]);
return file;
});
jsxFiles
.map(file => path.basename(file, '.jsx'))
.map(file =>
fs.appendFileSync(
path.resolve(componentDir, 'index.js'),
`export { default as ${pascalCase(file)} } from './${file}';\n`
)
);
});
})();
@christiannaths
Copy link
Author

Essentially, this script operates on a directory full of .svg files, converting each one into its own React component. There's probably a few ways to improve this – it's something I wrote quickly because I was too lazy to look for an existing solution that exactly fit my needs. In the package.json file, I create a script-runner that sends the .svg files through svgo before hand so that my components stay nice and small.

SVGO will replace the contents of the original svg files, my script will create new files, leaving the .svg files alone entirely.

My workflow consists of exporting from IconJar into the appropriate folder, then running this script on that folder.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment