Skip to content

Commit

Permalink
feat(postcss-plugin): Add support for postcss-loader 2.x
Browse files Browse the repository at this point in the history
  • Loading branch information
jantimon committed Jul 31, 2017
1 parent af73c81 commit c832df9
Show file tree
Hide file tree
Showing 14 changed files with 248 additions and 251 deletions.
55 changes: 37 additions & 18 deletions README.md
Expand Up @@ -5,6 +5,12 @@ This plugin tries to keep the usage and maintenance of icon fonts as simple as p

Browser Support: IE9 - IE11 and all modern browsers

# Requirements

This plugin requires webpack 2+ and postcss-loader 2+

Please use the iconfont-webpack-plugin 0.0.12 for older webpack / postcss-loader versions.

## Installation

```
Expand All @@ -14,44 +20,57 @@ npm i --save-dev iconfont-webpack-plugin
## Configuration

```js
var IconfontWebpackPlugin = require('iconfont-webpack-plugin');
const IconfontWebpackPlugin = require('iconfont-webpack-plugin');

// make sure you use the postcss loader:
module: {
loaders: [
rules: [
{
test: /\.css$/,
loader: 'css-loader!postcss-loader'
use: [
'css-loader',
{
loader: 'postcss-loader',
options: {
plugins: (loader) => [
// Add the plugin
new IconfontWebpackPlugin(loader)
]
}
}
]
}
]
},
// add the plugin
plugins: [
new IconfontWebpackPlugin()
]
```

## Advanced Configuration


```js
var IconfontWebpackPlugin = require('iconfont-webpack-plugin');
vconst IconfontWebpackPlugin = require('iconfont-webpack-plugin');

// make sure you use the postcss loader:
module: {
loaders: [
rules: [
{
test: /\.css$/,
loader: 'css-loader!postcss-loader'
use: [
'css-loader',
{
loader: 'postcss-loader',
options: {
plugins: (loader) => [
// Add the plugin
new IconfontWebpackPlugin({
resolve: loader.resolve,
fontNamePrefix: 'custom-',
})
]
}
}
]
}
]
},
// add the plugin
plugins: [
new IconfontWebpackPlugin({
fontNamePrefix: 'custom-'
})
]
```

## Usage
Expand Down
61 changes: 42 additions & 19 deletions example/default/dist/bundle.js
@@ -1,57 +1,80 @@
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};

/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {

/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;

/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };

/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);

/******/
/******/ // Flag the module as loaded
/******/ module.loaded = true;

/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }


/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;

/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;

/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";

/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {

__webpack_require__(1);
__webpack_require__(1);


/***/ }),
/* 1 */
/***/ (function(module, exports) {

// removed by extract-text-webpack-plugin
// removed by extract-text-webpack-plugin

/***/ })
/******/ ]);
7 changes: 1 addition & 6 deletions example/default/dist/styles.css
@@ -1,9 +1,4 @@
@font-face {
font-family: u84c0f;
src: url("data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAAAAAQwAAsAAAAABkwAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABCAAAADsAAABUIIwleU9TLzIAAAFEAAAAPwAAAFYvsjszY21hcAAAAYQAAABKAAABcOEoo6pnbHlmAAAB0AAAAJcAAACkBXkxZWhlYWQAAAJoAAAALgAAADYLpPaZaGhlYQAAApgAAAAeAAAAJAPxAe9obXR4AAACuAAAAAgAAAAIAe7//2xvY2EAAALAAAAABgAAAAYAUgAAbWF4cAAAAsgAAAAeAAAAIAENAEBuYW1lAAAC6AAAASkAAAIWm5e+CnBvc3QAAAQUAAAAGwAAACxqPAEEeJxjYGRgYOBiMGCwY2DKSSzJY+BzcfMJYZBiYGGAAJA8MpsxJzM9kYEDxgPKsYBpDiBmg4gCAClZBUgAeJxjYGT4zjiBgZWBgdGSMY2BgcEdSn9lkGRoYWBgYmBlZsAKAtJcUxgcHjA8AKoBAj0mZgZGIA3CDACcLwhKAHic7ZCxDYAwEAPPykOBGIEqNbNQsb/YJPkY2CKWzpJPXz2wACU5kwDdiJErrewLm31QfRPDP7T2d+5wo5WZ3X18y796QR0aJglRAAB4nB2IQQrCMBAAs5s0mzZpY6KmkoNFkYoiSik04KHe/IGf8PX+QIMzMIdh8M3ABzkbGRumlH3AP2O6QRrT1Oc3Qxs6sNCStCBzeIehDVQIY7xbrrV7d1bUxAkRqGz85RC3m6KUCIILqUpnzb1QlSDh3Xl3DU2DiMfZ9j5GZX3tSavGvCKqirRRGobF/nmqjF0F9gOdHRIIAHicY2BkYGAA4v0iIbrx/DZfGbiZGEDgqnfUWRj9HwgYPzAxA7kcDGBpAD0mDI0AAHicY2BkYGBiAAHGd//////H+IGBkQEVMAEAg2cF4gAAAAAAAAHu//8AAAAAAFIAAHicY2BkYGBgYjBhANEgFgMDFxAyMPwH8xkADasBTgAAeJxlkD1uwkAUhMdgSAJSghQpKbNVCiKZn5IDQE9Bl8KYtTGyvdZ6QaLLCXKEHCGniHKCHChj82hgLT9/M2/e7soABviFh3p5uG1qvVq4oTpxm/Qg7JOfhTvo40W4S38o3MMbpsJ9POKdO3j+HZ0BSuEW7vEh3Kb/KeyTv4Q7eMK3cJf+j3APK/wJ9/HqDdPIFLEp3FIn+yy0Z3n+rrStUlOoSTA+WwtdaBs6vVHro6oOydS5WMXW5GrOrs4yo0prdjpywda5cjYaxeIHkcmRIoJBgbipDktoJNgjQwh71b3UK6YtKvq1VpggwPgqtWCqaJIhlcaGyTWOrBUOPG1K1zGt+FrO5KS5zGreJCMr/u+6t6MT0Q+wbaZKzDDiE1/kg+YO+T89EV6oAAAAeJxjYGKAAFYG7ICJkYmRmYEp04CBAQADvgCsAA==") format('woff');
font-weight: normal;
font-style: normal;
}
@font-face { font-family: u84c0f; src:url("data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAAAAAQwAAsAAAAABkwAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABCAAAADsAAABUIIslek9TLzIAAAFEAAAAPwAAAFYvsjszY21hcAAAAYQAAABKAAABcOEoo6pnbHlmAAAB0AAAAJcAAACkBXkxZWhlYWQAAAJoAAAALwAAADYMV/uxaGhlYQAAApgAAAAeAAAAJAPxAe9obXR4AAACuAAAAAgAAAAIAe7//2xvY2EAAALAAAAABgAAAAYAUgAAbWF4cAAAAsgAAAAeAAAAIAENAEBuYW1lAAAC6AAAASkAAAIWm5e+CnBvc3QAAAQUAAAAGwAAACxqPAEEeJxjYGRgYOBiMGCwY2BycfMJYeDLSSzJY5BiYGGAAJA8MpsxJzM9kYEDxgPKsYBpDiBmg4gCACY7BUgAeJxjYGT4zjiBgZWBgdGSMY2BgcEdSn9lkGRoYWBgYmBlZsAKAtJcUxgcHjA8AKoBAj0mZgZGIA3CDACcLwhKAHic7ZCxDYAwEAPPykOBGIEqNbNQsb/YJPkY2CKWzpJPXz2wACU5kwDdiJErrewLm31QfRPDP7T2d+5wo5WZ3X18y796QR0aJglRAAB4nB2IQQrCMBAAs5s0mzZpY6KmkoNFkYoiSik04KHe/IGf8PX+QIMzMIdh8M3ABzkbGRumlH3AP2O6QRrT1Oc3Qxs6sNCStCBzeIehDVQIY7xbrrV7d1bUxAkRqGz85RC3m6KUCIILqUpnzb1QlSDh3Xl3DU2DiMfZ9j5GZX3tSavGvCKqirRRGobF/nmqjF0F9gOdHRIIAHicY2BkYGAA4r0bPH/H89t8ZeBmYgCBq0vuRsLo/0DA+IGJGcjlYABLAwCOBg66AHicY2BkYGBiAAHGd//////H+IGBkQEVMAEAg2cF4gAAAAAAAAHu//8AAAAAAFIAAHicY2BkYGBgYjBhANEgFgMDFxAyMPwH8xkADasBTgAAeJxlkD1uwkAUhMdgSAJSghQpKbNVCiKZn5IDQE9Bl8KYtTGyvdZ6QaLLCXKEHCGniHKCHChj82hgLT9/M2/e7soABviFh3p5uG1qvVq4oTpxm/Qg7JOfhTvo40W4S38o3MMbpsJ9POKdO3j+HZ0BSuEW7vEh3Kb/KeyTv4Q7eMK3cJf+j3APK/wJ9/HqDdPIFLEp3FIn+yy0Z3n+rrStUlOoSTA+WwtdaBs6vVHro6oOydS5WMXW5GrOrs4yo0prdjpywda5cjYaxeIHkcmRIoJBgbipDktoJNgjQwh71b3UK6YtKvq1VpggwPgqtWCqaJIhlcaGyTWOrBUOPG1K1zGt+FrO5KS5zGreJCMr/u+6t6MT0Q+wbaZKzDDiE1/kg+YO+T89EV6oAAAAeJxjYGKAAFYG7ICJkYmRmYEp04CBAQADvgCsAA==") format('woff');font-weight: normal;font-style: normal;}

a:before {
text-rendering: auto;
Expand Down
18 changes: 15 additions & 3 deletions example/default/webpack.config.js
Expand Up @@ -10,14 +10,26 @@ module.exports = {
filename: 'bundle.js'
},
module: {
loaders: [
rules: [
{ test: /\.css$/,
loader: ExtractTextPlugin.extract('style-loader', 'css-loader!postcss-loader')
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
'css-loader',
{
loader: 'postcss-loader',
options: {
plugins: (loader) => [
new IconfontWebpackPlugin(loader)
]
}
}
]
})
}
]
},
plugins: [
new IconfontWebpackPlugin(),
new ExtractTextPlugin('styles.css')
]
};
Expand Down
45 changes: 27 additions & 18 deletions index.js
@@ -1,24 +1,33 @@
'use strict';
var _ = require('lodash');
let _ = require('lodash');
let assert = require('assert');

function IconfontWebpackPlugin (options) {
module.exports = function IconfontWebpackPlugin (userOptions) {
// Default options
this.options = _.extend({
fontNamePrefix: ''
}, options);
}
const options = _.extend({

IconfontWebpackPlugin.prototype.apply = function (compiler) {
compiler.plugin('compilation', (compilation) =>
compilation.plugin('postcss-loader-before-processing',
(plugins) => (plugins || []).concat(
require('./lib/postcss-plugin')({
compiler: compiler,
pluginOptions: this.options
})
)
)
// allows to prefix the font name to prevent collisions
fontNamePrefix: '',

// resolve function to translate webpack urls into absolute filepaths
// e.g. url('demo.svg') -> '/Users/me/project-x/demo.svg'
// usually you should pass on the postcss loader
// https://webpack.js.org/api/loaders/#this-resolve
resolve: undefined

}, userOptions);

// Verify resolve function
assert(typeof options.resolve === 'function',
'Please pass a resolve function to the IconFontWebpackPlugin.\n' +
'For example: \n' +
'{\n' +
' loader: \'postcss-loader\',\n' +
' options: {\n' +
' plugins: (loader) => [\n' +
' require(\'iconfont-webpack-plugin\')({ resolve: loader.resolve }), \n\n'
);
};

module.exports = IconfontWebpackPlugin;
// Call postcss plugin
return require('./lib/postcss-plugin')(options);
};
28 changes: 14 additions & 14 deletions lib/icons-to-woff.js
@@ -1,9 +1,9 @@
var assert = require('assert');
var path = require('path');
var svgicons2svgfont = require('svgicons2svgfont');
var svg2ttf = require('svg2ttf');
var ttf2woff = require('ttf2woff');
var Readable = require('stream').Readable;
const assert = require('assert');
const path = require('path');
const svgicons2svgfont = require('svgicons2svgfont');
const svg2ttf = require('svg2ttf');
const ttf2woff = require('ttf2woff');
const Readable = require('stream').Readable;

/**
* @param {InputFileSystem} fs An input file system
Expand All @@ -15,16 +15,16 @@ module.exports = function createIconFont (fs, icons, options) {
assert(typeof options === 'object', 'Options are mandatory.');
icons = icons.map((iconPath) => path.resolve('.', iconPath));
return new Promise((resolve, reject) => {
var fontStream = svgicons2svgfont({
const fontStream = svgicons2svgfont({
name: options.name,
normalize: true,
log: function () {},
error: function (err) {
reject(err);
}
});
var fontIconHeight;
var svgFont = '';
let fontIconHeight;
let svgFont = '';
fontStream
.on('finish', function () {
resolve(svgFont);
Expand All @@ -36,7 +36,7 @@ module.exports = function createIconFont (fs, icons, options) {
reject(err);
});
icons.forEach((filename, i) => {
var glyph = new Readable();
const glyph = new Readable();
glyph._read = function noop () {};
glyph.metadata = {
unicode: [String.fromCodePoint('\ue000'.charCodeAt(0) + i)],
Expand All @@ -48,10 +48,10 @@ module.exports = function createIconFont (fs, icons, options) {
return reject(err);
}
result = result.toString();
var iconHeight = getSvgHeight(result, filename);
const iconHeight = getSvgHeight(result, filename);
if (fontIconHeight && fontIconHeight !== iconHeight) {
return reject(`SVG font generation failed as not all icons have the same height. ` +
`Found: "${fontIconHeight}" and "${iconHeight}".`);
return reject(new Error(`SVG font generation failed as not all icons have the same height. ` +
`Found: "${fontIconHeight}" and "${iconHeight}".`));
}
fontIconHeight = iconHeight;
// prevent svgs with fill="none" from beeing translated into an empty symbol
Expand All @@ -64,7 +64,7 @@ module.exports = function createIconFont (fs, icons, options) {
})
.then((svgFont) => svg2ttf(svgFont, {}).buffer)
.then((ttfFont) => ttf2woff(ttfFont).buffer)
.then((woffFont) => new Buffer(woffFont).toString('base64'));
.then((woffFont) => Buffer.from(woffFont).toString('base64'));
};

/**
Expand Down
14 changes: 7 additions & 7 deletions lib/loader.js
Expand Up @@ -5,28 +5,28 @@
* Parses the query parameters and returns a base64 font:
* 'module.exports="data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAAAAAQwAA..";
*/
var createIconFont = require('./icons-to-woff.js');
var loaderUtils = require('loader-utils');
var path = require('path');
const createIconFont = require('./icons-to-woff.js');
const loaderUtils = require('loader-utils');
const path = require('path');

module.exports = function () {
// Don't regenerate as long as the svgs don't change
if (this.cacheable) {
this.cacheable();
}
var callback = this.async();
var query = loaderUtils.parseQuery(this.query);
const callback = this.async();
const query = loaderUtils.parseQuery(this.query);
// Add svgs to webpack file watching:
query.svgs.forEach((svg) => this.addDependency(path.resolve(svg)));
// Generate the fonts
createIconFont(this._compiler.inputFileSystem, query.svgs, query)
.then((result) => {
// Return the font to webpack
var url = '"data:application/x-font-woff;charset=utf-8;base64,' + result + '"';
const url = '"data:application/x-font-woff;charset=utf-8;base64,' + result + '"';
callback(null, 'module.exports=' + JSON.stringify(url) + ';');
}, function (err) {
// In case of an svg generation error return an invalid font and throw an error
var url = '"data:application/x-font-woff;charset=utf-8;base64,"';
const url = '"data:application/x-font-woff;charset=utf-8;base64,"';
if (typeof err === 'string') {
err = new Error(err);
}
Expand Down

0 comments on commit c832df9

Please sign in to comment.