Skip to content

Commit c2e50f5

Browse files
committed
Add an es2015 module. Don't append Icon to the icons. Enable importing single icons. Add tests.
1 parent d379667 commit c2e50f5

8 files changed

+5218
-5137
lines changed

.gitignore

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
1-
node_modules
2-
icons
3-
lib
1+
node_modules/
2+
package/

.gitmodules

-3
This file was deleted.

README.md

+25-12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
# Material Design Icons for Material-UI
2-
32
[![npm](https://img.shields.io/npm/v/mdi-material-ui.svg)](https://www.npmjs.com/package/mdi-material-ui)
43
[![Material Design Icons version](https://img.shields.io/badge/mdi-v2.0.46-blue.svg)](https://github.com/Templarian/MaterialDesign-SVG/)
54

@@ -20,29 +19,43 @@ npm install mdi-material-ui --save
2019
```
2120

2221
## Usage
22+
Every icon is exported with its original name in PascalCase. So `coffee` becomes `Coffee`,
23+
`cloud-print-outline` is exported as `CloudPrintOutline` and so on.
2324

24-
Every icon is exported with its original name in PascalCase, plus _Icon_. So `coffee` becomes `CoffeeIcon`,
25-
`cloud-print-outline` is exported as `CloudPrintOutlineIcon` and so on.
25+
### With tree-shaking
26+
If your environment supports tree-shaking and you are sure that it works fine in your setup, you can simply import the icons as follows:
2627

2728
```js
28-
import { CoffeeIcon } from 'mdi-material-ui'
29+
import { Coffee, Food } from 'mdi-material-ui'
30+
```
2931

30-
// ...
32+
### Without tree-shaking
33+
If your environment doesn't support tree-shaking, you should only import the icons that you actually need in order to ensure that you don't end up bundling _all_ icons.
34+
35+
```js
36+
import Coffee from 'mdi-material-ui/Coffee'
37+
import Food from 'mdi-material-ui/Food'
38+
```
3139

32-
render() {
33-
return (
34-
<div>
35-
Enjoy your coffee! <CoffeeIcon />
36-
</div>
37-
)
40+
If you think that this is far too verbose (I agree!), consider using [babel-plugin-direct-import](https://github.com/umidbekkarimov/babel-plugin-direct-import). Install it and adjust your `.babelrc` by adding the following snippet to the plugins section:
41+
42+
```js
43+
{
44+
// ...
45+
plugins: [
46+
// ...
47+
["direct-import", [{
48+
name: "mdi-material-ui",
49+
indexFile: "mdi-material-ui/index.es"
50+
}]]
51+
]
3852
}
3953
```
4054

4155
## Related projects
4256
Feel more like using a webfont instead of inline svg? We've [got your back][materialdesign-webfont-material-ui]!
4357

4458
## License
45-
4659
The scripts included in this repository are licensed under the WTFPL.
4760
The icons are licensed under the MIT license (see [Material Design Icons](https://github.com/Templarian/MaterialDesign-SVG) and the [NOTICE][] file).
4861

__tests__/testIcons.js

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/* eslint-env jest */
2+
import React from 'react'
3+
import renderer from 'react-test-renderer'
4+
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'
5+
import * as commonjsIcons from '../package/index'
6+
import * as es2015Icons from '../package/index.es'
7+
8+
console.log('hi')
9+
10+
describe('the generated commonjs module', () => {
11+
it('should export icons that render to SVGs', () => {
12+
for (const iconName of Object.keys(commonjsIcons)) {
13+
const Icon = commonjsIcons[iconName]
14+
const renderedIcon = renderer.create((
15+
<MuiThemeProvider>
16+
<Icon />
17+
</MuiThemeProvider>
18+
)).toJSON()
19+
expect(renderedIcon.type).toBe('svg')
20+
}
21+
})
22+
})
23+
24+
describe('the generated es2015 module', () => {
25+
it('should export icons that render to SVGs', () => {
26+
for (const iconName of Object.keys(es2015Icons)) {
27+
const Icon = es2015Icons[iconName]
28+
const renderedIcon = renderer.create((
29+
<MuiThemeProvider>
30+
<Icon />
31+
</MuiThemeProvider>
32+
)).toJSON()
33+
expect(renderedIcon.type).toBe('svg')
34+
}
35+
})
36+
37+
it('should include the same icons as the CommonJS module', () => {
38+
expect(Object.keys(es2015Icons)).toEqual(expect.arrayContaining(Object.keys(commonjsIcons)))
39+
expect(Object.keys(es2015Icons).length).toBe(Object.keys(commonjsIcons).length)
40+
})
41+
})

generate-module.js

+51-16
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
#!/usr/bin/env node
2-
const fs = require('fs')
2+
const fse = require('fs-extra')
33
const path = require('path')
4-
const mkdirp = require('mkdirp')
5-
const rimraf = require('rimraf')
64
const pascalCase = require('pascal-case')
75
const babel = require('babel-core')
86
const libxmljs = require('libxmljs')
7+
const pick = require('lodash.pick')
98

109
function tryRemoveAttr (element, attributeName, matcher) {
1110
const attribute = element.attr(attributeName)
@@ -41,7 +40,7 @@ function transformForReact (element) {
4140
const mdiSvgPath = path.join(path.dirname(require.resolve('mdi-svg/meta.json')), 'svg')
4241
const icons = require('mdi-svg/meta.json')
4342
.map((icon) => {
44-
const xml = libxmljs.parseXml(fs.readFileSync(path.join(mdiSvgPath, `${icon.name}.svg`), 'utf8'))
43+
const xml = libxmljs.parseXml(fse.readFileSync(path.join(mdiSvgPath, `${icon.name}.svg`), 'utf8'))
4544
const svg = xml.root().childNodes().map((child) => {
4645
if (child.type() === 'text') return
4746
transformForReact(child)
@@ -54,22 +53,58 @@ const icons = require('mdi-svg/meta.json')
5453
throw Error(`Unexpected number of paths (${xml.svg.path.length}) for ${icon.name}`)
5554
}
5655
return {
57-
name: `${pascalCase(icon.name)}Icon`,
56+
name: pascalCase(icon.name),
5857
svg
5958
}
6059
})
6160

62-
rimraf.sync(path.join(__dirname, 'lib'))
63-
mkdirp.sync(path.join(__dirname, 'lib'))
61+
fse.removeSync(path.join(__dirname, 'package'))
62+
fse.mkdirpSync(path.join(__dirname, 'package'))
6463

65-
// there is an 'svg' icon, so we can't call the SvgIcon component SvgIcon
66-
const code = `
67-
import React from 'react'
68-
import Icon from 'material-ui/SvgIcon'
69-
70-
${icons.map(({ name, svg }) => `export const ${name} = (props) => <Icon {...props}>${svg}</Icon>`).join('\n')}
64+
for (const { name, svg } of icons) {
65+
const code = `import React from 'react'
66+
import SvgIcon from 'material-ui/SvgIcon'
67+
export default (props) => <SvgIcon {...props}>${svg}</SvgIcon>
7168
`
72-
fs.writeFileSync(path.join(__dirname, 'lib', 'index.js'), babel.transform(code, {
73-
presets: ['es2015', 'react', 'stage-0'],
74-
compact: true
69+
70+
// commonjs module syntax
71+
fse.writeFileSync(path.join(__dirname, 'package', `${name}.js`), babel.transform(code, {
72+
presets: ['es2015', 'react', 'stage-0'],
73+
compact: process.env.NODE_ENV === 'production'
74+
}).code)
75+
}
76+
77+
// es2015 module syntax
78+
const allExports = icons.map(({ name }) => `export { default as ${name} } from './${name}'`).join('\n')
79+
fse.writeFileSync(path.join(__dirname, 'package', 'index.es.js'), allExports)
80+
81+
// commonjs module
82+
fse.writeFileSync(path.join(__dirname, 'package', 'index.js'), babel.transform(allExports, {
83+
plugins: ['transform-es2015-modules-commonjs'],
84+
compact: process.env.NODE_ENV === 'production'
7585
}).code)
86+
87+
// copy other files
88+
;[
89+
'README.md',
90+
'NOTICE',
91+
'LICENSE',
92+
'.npmignore'
93+
].forEach((file) => fse.copySync(path.join(__dirname, file), path.join(__dirname, 'package', file)))
94+
95+
const packageJson = require('./package.json')
96+
fse.writeFileSync(path.join(__dirname, 'package', 'package.json'), JSON.stringify(pick(packageJson, [
97+
'name',
98+
'version',
99+
'description',
100+
'main',
101+
'module',
102+
'jsnext:main',
103+
'repository',
104+
'keywords',
105+
'author',
106+
'license',
107+
'bugs',
108+
'homepage',
109+
'peerDependencies'
110+
])), 'utf-8')

0 commit comments

Comments
 (0)