-
Notifications
You must be signed in to change notification settings - Fork 93
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Jordan Gensler
committed
Sep 19, 2016
1 parent
15e011a
commit fea1021
Showing
13 changed files
with
288 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"presets": ["airbnb"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"extends": "airbnb", | ||
"root": true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
node_modules | ||
lib |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,5 @@ | ||
# babel-plugin-inline-react-svg | ||
|
||
Inlines requires to SVG files so that they can be used seamlessly in your components. | ||
|
||
Inspired by and code foundation provided by [react-svg-loader](https://github.com/boopathi/react-svg-loader). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
{ | ||
"name": "babel-plugin-inline-react-svg", | ||
"version": "0.1.0", | ||
"description": "A babel plugin that optimizes and inlines SVGs for your react components.", | ||
"main": "lib/index.js", | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1", | ||
"sanity": "babel-node test/sanity.js", | ||
"build": "babel src --out-dir lib", | ||
"lint": "eslint src/", | ||
"prepublish": "npm run build" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/kesne/babel-plugin-inline-react-svg.git" | ||
}, | ||
"keywords": [ | ||
"babel", | ||
"plugin", | ||
"react", | ||
"svg", | ||
"inline" | ||
], | ||
"author": "Jordan Gensler <[email protected]>", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/kesne/babel-plugin-inline-react-svg/issues" | ||
}, | ||
"homepage": "https://github.com/kesne/babel-plugin-inline-react-svg#readme", | ||
"devDependencies": { | ||
"babel-cli": "^6.14.0", | ||
"babel-core": "^6.14.0", | ||
"babel-preset-airbnb": "^2.0.0", | ||
"eslint": "^3.5.0", | ||
"eslint-config-airbnb": "^11.1.0", | ||
"eslint-plugin-import": "^1.15.0", | ||
"eslint-plugin-jsx-a11y": "^2.2.2", | ||
"eslint-plugin-react": "^6.2.2", | ||
"react": "^15.3.1" | ||
}, | ||
"dependencies": { | ||
"babel-template": "^6.15.0", | ||
"babel-traverse": "^6.15.0", | ||
"babylon": "^6.10.0", | ||
"lodash.isplainobject": "^4.0.6", | ||
"svgo": "^0.7.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
export function hyphenToCamel(name) { | ||
return name.replace(/-([a-z])/g, g => g[1].toUpperCase()); | ||
} | ||
|
||
export function namespaceToCamel(namespace, name) { | ||
return namespace + name.charAt(0).toUpperCase() + name.slice(1); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
export default function cssToObj(css) { | ||
const o = {}; | ||
css.split(';') | ||
.filter(el => !!el) | ||
.forEach((el) => { | ||
const s = el.split(':'); | ||
const key = s.shift().trim(); | ||
const value = s.join(':').trim(); | ||
o[key] = value; | ||
}); | ||
|
||
return o; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import { extname, dirname, join } from 'path'; | ||
import { readFileSync } from 'fs'; | ||
import template from 'babel-template'; | ||
import traverse from 'babel-traverse'; | ||
import { parse } from 'babylon'; | ||
import optimize from './optimize'; | ||
import transformSvg from './transformSvg'; | ||
|
||
const buildSvg = template(` | ||
var SVG_NAME = function SVG_NAME(props) { return SVG_CODE; }; | ||
`); | ||
|
||
export default ({ types: t }) => ({ | ||
visitor: { | ||
ImportDeclaration(path, state) { | ||
// This plugin only applies for SVGs: | ||
if (extname(path.node.source.value) === '.svg') { | ||
// We only support the import default specifier, so let's use that identifier: | ||
const importIdentifier = path.node.specifiers[0].local; | ||
const iconPath = state.file.opts.filename; | ||
const absoluteIconPath = join(__dirname, '..', iconPath); | ||
const svgPath = join(dirname(absoluteIconPath), path.node.source.value); | ||
const svgSource = readFileSync(svgPath, 'utf8'); | ||
const optimizedSvgSource = optimize(svgSource); | ||
|
||
const parsedSvgAst = parse(optimizedSvgSource, { | ||
sourceType: 'module', | ||
plugins: ['jsx'], | ||
}); | ||
|
||
traverse(parsedSvgAst, transformSvg(t)); | ||
|
||
const svgCode = traverse.removeProperties(parsedSvgAst.program.body[0].expression); | ||
|
||
const svgReplacement = buildSvg({ | ||
SVG_NAME: importIdentifier, | ||
SVG_CODE: svgCode, | ||
}); | ||
|
||
path.replaceWith(svgReplacement); | ||
} | ||
}, | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
// validates svgo opts | ||
// to contain minimal set of plugins that will strip some stuff | ||
// for the babylon JSX parser to work | ||
import Svgo from 'svgo'; | ||
import isPlainObject from 'lodash.isplainobject'; | ||
|
||
const SVGO_OPTIONS = {}; | ||
|
||
const essentialPlugins = ['removeDoctype', 'removeComments']; | ||
|
||
function isEssentialPlugin(p) { | ||
return essentialPlugins.indexOf(p) !== -1; | ||
} | ||
|
||
function validateAndFix(opts) { | ||
if (!isPlainObject(opts)) return; | ||
|
||
if (opts.full) { | ||
if ( | ||
typeof opts.plugins === 'undefined' || | ||
(Array.isArray(opts.plugins) && opts.plugins.length === 0) | ||
) { | ||
opts.plugins = [...essentialPlugins]; | ||
return; | ||
} | ||
} | ||
|
||
// opts.full is false, plugins can be empty | ||
if (typeof opts.plugins === 'undefined') return; | ||
if (Array.isArray(opts.plugins) && opts.plugins.length === 0) return; | ||
|
||
// track whether its defined in opts.plugins | ||
var state = essentialPlugins.reduce((p, c) => Object.assign(p, {[c]: false}), {}); | ||
|
||
opts.plugins.map(p => { | ||
if (typeof p === 'string' && isEssentialPlugin(p)) { | ||
state[p] = true; | ||
} else if (typeof p === 'object') { | ||
Object.keys(p).forEach(k => { | ||
if (isEssentialPlugin(k)) { | ||
// make it essential | ||
if (!p[k]) p[k] = true; | ||
// and update state | ||
state[k] = true; | ||
} | ||
}); | ||
} | ||
}); | ||
|
||
Object.keys(state) | ||
.filter(key => !state[key]) | ||
.forEach(key => opts.plugins.push(key)); | ||
} | ||
|
||
module.exports = function optimize(content) { | ||
validateAndFix(SVGO_OPTIONS); | ||
const svgo = new Svgo(SVGO_OPTIONS); | ||
|
||
// Babel needs to be sync, so we fake it: | ||
var returnValue; | ||
svgo.optimize(content, (response) => { | ||
if (response.error) { | ||
returnValue = response.error; | ||
} else { | ||
returnValue = response.data; | ||
} | ||
}); | ||
|
||
|
||
while (!returnValue) {} | ||
return returnValue; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
/* eslint-disable no-param-reassign */ | ||
// | ||
// These visitors normalize the SVG into something React understands: | ||
// | ||
|
||
import { namespaceToCamel, hyphenToCamel } from './camelize'; | ||
import cssToObj from './cssToObj'; | ||
|
||
export default t => ({ | ||
JSXAttribute(path) { | ||
if (t.isJSXNamespacedName(path.node.name)) { | ||
// converts | ||
// <svg xmlns:xlink="asdf"> | ||
// to | ||
// <svg xmlnsXlink="asdf"> | ||
path.node.name = t.jSXIdentifier( | ||
namespaceToCamel(path.node.name.namespace.name, path.node.name.name.name) | ||
); | ||
} else if (t.isJSXIdentifier(path.node.name)) { | ||
// converts | ||
// <tag class="blah blah1"/> | ||
// to | ||
// <tag className="blah blah1"/> | ||
if (path.node.name.name === 'class') { | ||
path.node.name.name = 'className'; | ||
} | ||
|
||
// converts | ||
// <tag style="text-align: center; width: 50px"> | ||
// to | ||
// <tag style={{textAlign: 'center', width: '50px'}}> | ||
if (path.node.name.name === 'style') { | ||
const csso = cssToObj(path.node.value.value); | ||
const properties = Object.keys(csso).map(prop => t.objectProperty( | ||
t.identifier(hyphenToCamel(prop)), | ||
t.stringLiteral(csso[prop]) | ||
)); | ||
path.node.value = t.jSXExpressionContainer( | ||
t.objectExpression(properties) | ||
); | ||
} | ||
|
||
// converts | ||
// <svg stroke-width="5"> | ||
// to | ||
// <svg strokeWidth="5"> | ||
path.node.name.name = hyphenToCamel(path.node.name.name); | ||
} | ||
}, | ||
|
||
// converts | ||
// <svg> | ||
// to | ||
// <svg {...props}> | ||
// after passing through attributes visitors | ||
JSXOpeningElement(path) { | ||
if (path.node.name.name.toLowerCase() === 'svg') { | ||
// add spread props | ||
path.node.attributes.push( | ||
t.jSXSpreadAttribute( | ||
t.identifier('props') | ||
) | ||
); | ||
} | ||
}, | ||
}); |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import React from 'react'; | ||
import MySvg from './close.svg'; | ||
|
||
export function MyFunctionIcon() { | ||
return <MySvg />; | ||
} | ||
|
||
export class MyClassIcon extends React.Component { | ||
render() { | ||
return <MySvg />; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { transformFile } from 'babel-core'; | ||
|
||
transformFile('test/fixtures/test.jsx', { | ||
presets: ['airbnb'], | ||
plugins: [ | ||
'../../src/index', | ||
], | ||
}, (err, result) => { | ||
if (err) throw err; | ||
console.log(result.code); | ||
}); |