nodejs iconfont处理
做前端优化,iconfont可以替换掉很多图片,减少请求,并有很好的兼容性,颜色大小也有很好的自由度。现在网上已经有很多公开的iconfont供我们使用。但是每个项目有不同的应用场景,网上的并不能满足所有的需求。设计在出ps的有很多svg的图标。
在线的矢量图标库,我们熟知的,http://www.iconfont.cn/,国内功能很强大且图标内容很丰富的矢量图标库。
可是我们自己做项目,每次都要上传iconfont,再下载最新的,要操作好多。表示本人是个懒人,操作了几遍就感觉生命在浪费。
最近在整理,nodejs gulp相关的插件,编写符合业务活动开发的gulp脚本,加快开发,并且前端优化。
所以就想着nodejs有没网络字体处理
font-carrier https://github.com/purplebamboo/font-carrier
用起来很简单,首先定义好适合项目的文件目录格式
//api参数说明 icon({ isWatch: true, //是否启动watch,监控更改 template: __dirname + "/_fonts_demo.tmpl", //产生的预览html模版 path: './qnk/font', //项目的font目录 fontName: 'iconfont', //字体文字 beginNum: 0xe001 //字体开始的最小值 })
//基于 模块chokidar 进行文件监控 path+'/*.svg'文件
//在svg文件新增,修改,删除的,会调用font.setSvg,更新字体信息,并更新对应的json配置,用于下次的恢复svg与unicode关系
//会实时生成 {fontName}.html 进行字体效果预览,该文件通过template生成,使用的模版语言是handlebars
下面看主要代码,现在的代码没有封装模块,主要是功能还有些欠缺
现在的功能是实时发布 矢量图标库,开发的时候,还是需要通过查看{fontName}.html,进行html编写
后期进一步结合项目情况,生成项目可以用的html模版,iconfont配置变量,在html的时候只需要根据svg文件名,编写,如{{我的红包}}
var fontCarrier = require('font-carrier') var chokidar = require('chokidar'); var sysPath = require('path'); var Handlebars = require('handlebars'); var fs = require('fs'); var glob = require('glob') //makeWatch ready前会有add响应,所以增加参数进行屏蔽 var makeWatch = function (flies, done) { var files = []; var _isdone = -1; var watcher = chokidar.watch(flies, { ignored: /[\/\\]\./, persistent: true }); watcher.on('add', path => { if (_isdone == -1) { files.push(path); } else if (_isdone == 1) { done('add', path); } }).on('change', path => { if (_isdone == 1) { done('change', path); } }).on('unlink', path => { if (_isdone == 1) { done('remove', path); } }).on('ready', function() { _isdone = 1; done('ready', files); }) return watcher; }; //defaults默认数值 var defaults = { beginNum: 0xe001, template: '<style>@font-face {font-family: "{{fontName}}";src: url("{{fontName}}.eot?t={{now}}"); src: url("{{fontName}}.eot?t={{now}}#iefix") format("embedded-opentype"),url("{{fontName}}.woff?t={{now}}") format("woff"),url("{{fontName}}.ttf?t={{now}}") format("truetype"),url("{{fontName}}.svg?t={{now}}#{{fontName}}") format("svg");}/n\ .{{fontName}} {font-family:"{{fontName}}" !important;font-size:16px;font-style:normal;-webkit-font-smoothing: antialiased;-webkit-text-stroke-width: 0.2px;-moz-osx-font-smoothing: grayscale;\}</style>/n\ <ul class="icon_lists clear">{{#each data}}<li><i class="icon {{../fontName}}">&#x{{val}};</i><div class="name">{{name}}</div><div class="code">&#x{{val}};</div></li>{{/each}}</ul>', fontName: 'iconfont' }; //通过现有的json配置 和 文件夹实际的svg目录,进行数据修正,获取正确的beginNum var getExistsFontMap = function (map, dirPath, beginNum) { var files = glob.sync(dirPath + '/*.svg'); var fileMap = {}; var res = {}; files.forEach(function (f) { fileMap[sysPath.basename(f, '.svg')] = f; }) for (var key in map) { if (!fileMap[key]) delete map[key]; } var _bNum; for (var key in map) { _bNum = map[key]; break; } _bNum = _bNum || beginNum; for (var key in map) { if (map[key] >= _bNum) { _bNum = map[key] + 1; } } for (var key in fileMap) { res[key] = map[key] || _bNum++; } return { fontMap: res, beginNum: _bNum } } //模块主方法 var icon = function (opts) { var font = fontCarrier.create();//创建字体 var bNum = opts.beginNum || defaults.beginNum; var template; var fontMap = {}; if (opts.template) { template = Handlebars.compile(fs.readFileSync(opts.template).toString()); } else { template = Handlebars.compile(defaults.template); } var path = opts.path; if (!path) { throw new Error('must set path option.') } var fontPath = path; var fontName = opts.fontName || defaults.fontName; var dirPath = fontPath + '/svg'; var jsonPath = dirPath + '/' + fontName + '.json'; //字体信息保存 var save = function (action) { //字体保存 font.output({ path: fontPath + '/' + fontName }) //配置保存 fs.writeFileSync(jsonPath, JSON.stringify(fontMap)); var tab = []; for (var key in fontMap) { tab.push({name: key, val: fontMap[key].toString(16)}) } //预览文件保存 fs.writeFile(fontPath + '/' + fontName + '.html', template({data: tab, fontName: fontName, now: +new Date}), (err) => { if (err) throw err; }); }; var setSvg = function (flie, key) { fs.readFile(flie, (err, data) => { if (err) { throw err; } font.setSvg('&#x' + key.toString(16) + ';', data.toString()); save(); }); }; var fileExists = fs.existsSync(jsonPath); var map = {}; if (fileExists) { map = JSON.parse(fs.readFileSync(jsonPath).toString()); } var res = getExistsFontMap(map, dirPath, bNum); fontMap = res.fontMap; bNum = res.beginNum; for (var fileName in fontMap) { font.setSvg('&#x' + fontMap[fileName].toString(16) + ';', fs.readFileSync(dirPath + '/' + fileName + '.svg').toString()); } save(); //watch 文件修改逻辑 if (opts.isWatch) { return makeWatch(dirPath + '/*.svg', function (action, flie) { if (action == 'ready') { } else if (action == 'change' || action == 'add') { var fileName = sysPath.basename(flie, '.svg'); var n = fontMap[fileName] = fontMap[fileName] || bNum++; //**文件存在busy状态,延时1秒读取文件,不能解决根本问题 setTimeout(function () { setSvg(flie, n); }, 1000); } else if (action == 'remove') { var fileName = sysPath.basename(flie, '.svg'); font.setSvg('&#x' + fontMap[fileName].toString(16) + ';', ''); delete fontMap[fileName]; save(action); } }) } }; icon({ isWatch: true, template: __dirname + "/_fonts_demo.tmpl", path: './v3-mobile-snail-com/qnk/font' })