UNPKG

8.54 kBJavaScriptView Raw
1/*
2 * iconfont fis3
3 * 依赖具体的项目目录结构
4 * 字体生成到modules/common/fonts目录下面
5 * 对应的css直接插入到了页面中
6 * 目前的目录结构
7 * -src
8 * -----|lego_modules
9 * -----|modules
10 * -----|pages
11 * ----------|index
12 * ---------------|main.js
13 * ----------|test
14 * ---------------|main.js
15 * -----partials
16 * -----index.html
17 * -----test.html
18 * -----fis-conf.js
19 * -----package.json
20 */
21
22
23/*
24 * 1. 遍历项目下所有的html, tpl, js 文件中的icon
25 * 2. 生成字体文件
26 * 3. 生成css文件,
27 * 4. 所有项目根目录下的html以inline或者link方式引入样式
28 *
29 * 每个html文件都引入了项目下的所有icon相关的样式,非按需加载方式
30 * cdn 编译
31 */
32'use strict';
33
34var path = require('path'),
35 fs = require('fs'),
36 _ = fis.util,
37 icon = require('./iconfont.js');
38
39var iconfontTag = new RegExp('<!--ICONFONT_PLACEHOLDER-->');
40
41var fisVersion = fis.version.split('.')[0],
42 isFis3 = fisVersion === 3;
43
44
45
46var DEF_CONF = {
47 classPrefix: 'i-',
48 svgPath: '../svgs',
49 output: 'fonts/iconfont',
50 cssInline: false,
51 pseClass: 'before',
52 base64: false,
53 recursive: 0,
54 ignoreSrc: []
55};
56
57// 处理glob表达式
58function getIncludeAndExclude(conf) {
59 var ret = {
60 include: [],
61 exclude: []
62 };
63
64 conf.forEach(function(glob) {
65 if (/^!/.test(glob)) {
66 ret.exclude.push(glob.replace(/^!/, ''));
67 } else {
68 ret.include.push(glob);
69 }
70 });
71 return ret;
72}
73
74// 数组去重
75function uniqList(arr) {
76 var ret = [],
77 tmpl = {},
78 item;
79 for (var k = 0, len = arr.length; k < len; k++) {
80 item = arr[k];
81 if (item && !tmpl[item]) {
82 tmpl[item] = 1;
83 ret.push(item);
84 }
85 }
86 return ret;
87}
88
89/*
90 * 匹配文本中的icon
91 */
92function getIconMatches(content, iconReg, cleanIconReg) {
93 var matches = content.match(iconReg);
94 if (matches) {
95 for (var i = 0; i < matches.length; i++) {
96 matches[i] = matches[i].replace(cleanIconReg, '');
97 }
98 }
99 return matches || [];
100}
101
102function isMatchPath(source, parentPath, recursive) {
103
104 if (!recursive) {
105 return source === parentPath;
106 }
107
108 //recursive 支持iconfont资源写入src/xxx下的html文件
109 var index = source.lastIndexOf('/');
110 if (index > -1) {
111 if (source.substring(0, index) === parentPath) {
112 return true;
113 }
114 }
115 return false;
116}
117
118// ret.pkg生成虚拟文件,产出由fis本身处理
119module.exports = function(ret, conf, settings, opt) {
120
121 var files = ret.src,
122 res = ret.map.res;
123
124 settings = _.assign({}, DEF_CONF, settings);
125
126 var projectPath = fis.project.getProjectPath(),
127 iconPrefix = settings.classPrefix || 'i-',
128 iconReg = new RegExp('icon-font\\\s' + iconPrefix + '([a-zA-Z0-9\\\-_]*)', 'mg'),
129 cleanIconReg = new RegExp('icon-font\\\s' + iconPrefix, 'g');
130
131 // svg在插件目录下,安装插件时,就installsvg
132 // var defaultSvgPath = path.join(path.dirname(__dirname), 'svgs');
133 var configSvgPath = settings.svgPath ? path.join(projectPath, settings.svgPath) : '';
134
135 var recursive = parseInt(settings.recursive, 10);
136
137 settings._svgPath = configSvgPath;
138
139
140 if (!fs.existsSync(configSvgPath)) {
141 fis.log.error('目录 --' + configSvgPath + '-- 不存在, 请配置正确的 fis-postpackager-iconfont 插件的 "svgPath" 属性');
142 }
143
144
145 var ignoreLibList = settings.ignore || ['zepto', 'badjs', 'mod', 'bj-report', 'tools', 'db'];
146
147 var pages = [],
148 ext,
149 content,
150 eachFileIconList = [],
151 allIconList = [];
152
153 var inAndEx = getIncludeAndExclude(settings.ignoreSrc);
154 // whole project icon list
155 _.map(files, function(subpath, file) {
156 ext = _.ext(file.toString());
157 content = file.getContent();
158
159 // 配置中有ignore,部分文件不检查是否有icon,直接忽略
160 if (settings.ignoreSrc.length > 0 && !_.filter(file.subpath, '**', inAndEx.exclude)) {
161 return;
162 }
163
164
165 // src 目录下的 html文件
166 // ~['.html', '.js', '.tpl']
167 // if(~['.html', '.tpl'].indexOf(ext.ext)) {
168 if (file.isHtmlLike || ext.ext === '.tpl') {
169 // html, tpl, vm
170 eachFileIconList = getIconMatches(content, iconReg, cleanIconReg);
171 if (eachFileIconList.length > 0) {
172 allIconList = allIconList.concat(eachFileIconList);
173 }
174
175 // 需要添加css的页面
176 // 项目根目录下面的html文件,认定为是业务页面,需要添加字体文件
177
178 if (isMatchPath(ext.dirname, projectPath, recursive)) {
179 pages.push(file);
180 }
181
182
183
184 } else if (file.isJsLike && ~~ignoreLibList.indexOf(ext.filename)) {
185 // 基础库忽略查找
186 // js 中iconfont查找方式不同 addClass('i-xxx');
187 var matches = content.match(/addClass\([\'\"]([^\'\"\s]*\s)?i-([^\'\"\s]*)/mg);
188 if (matches) {
189 // iconfont 无法覆盖
190 // 场景 html 标签上已经有 i-a
191 // 依赖的js中有addClass('i-b'),这里没法确保覆盖
192 matches.forEach(function(match, i) {
193 matches[i] = matches[i].replace(/addClass\([\'\"]([^\'\"\s]*\s)?i-/, '');
194 });
195 allIconList = allIconList.concat(matches);
196 }
197
198 }
199 });
200
201
202
203 /*
204 * 整个项目中的icon
205 * font和css中的content都是根据这个数组生成出来的,
206 * 数组里面即便有多余的icon(实际不是icon),也能确保css和font对应上
207 * css中的content和font中svg对应的key值都是用数据的index生成的,是一致的。
208 */
209 allIconList = uniqList(allIconList);
210
211 if (isFis3) {
212 fis.emit('iconfont:allIcons', allIconList);
213 }
214
215 /*
216 * 按需生成字体文件
217 */
218 // var fontsFile = icon.genarateFonts(settings, allIconList);
219
220 var fontObj = icon.genarateFonts(settings, allIconList),
221 outFontsContent = fontObj.content;
222
223
224 if (!settings.base64) {
225 settings._fontCdn = {};
226 // 这种pkg的处理方式有兼容问题,fis2中getUrl没有返回domain
227
228 for (var type in outFontsContent) {
229 if (outFontsContent.hasOwnProperty(type)) {
230 var fontPkg = fis.file(projectPath, fontObj.subpath + '.' + type);
231 fontPkg.setContent(outFontsContent[type]);
232 if (!isFis3 && opt.dest === 'dev') {
233 // dev 模式下 useHash = false
234 fontPkg.useHash = false;
235 }
236 ret.pkg[fontPkg.subpath] = fontPkg;
237 // getUrl 参数为了兼容fis2
238 settings._fontCdn[type] = fontPkg.getUrl(fontPkg.useHash, fontPkg.useDomain);
239 }
240 }
241 }
242
243
244 var cssContent;
245 cssContent = settings.base64 ? icon.generateBase64Css(settings, allIconList, outFontsContent.ttf) : icon.generateCss(settings, allIconList);
246
247 var cssFileHash = 'font.css';
248
249 cssFileHash = path.join(settings.output, cssFileHash);
250
251 // 这种方式 fis2有问题,dev模式下,useHash 都是true,导致 getUrl有问题
252 var cssFile = fis.file(projectPath, cssFileHash);
253 cssFile.setContent(cssContent);
254 if (!isFis3 && opt.dest === 'dev') {
255 // dev 模式下 useHash = false
256 cssFile.useHash = false;
257 }
258 ret.pkg[cssFile.subpath] = cssFile;
259
260 // 外链方式引入
261 var inlineCss = '<link rel="stylesheet" type="text/css" href="' + cssFile.getUrl(cssFile.useHash, cssFile.useDomain) + '" />\r\n';
262
263 if (settings.cssInline) {
264 // inline 方式引入
265 inlineCss = '<style>\r\n' + cssContent + '\r\n</style>';
266 }
267
268
269 /*
270 * 页面页面引入css
271 */
272 pages.forEach(function(page) {
273 var content = page.getContent();
274 if (iconfontTag.test(content)) {
275 content = content.replace(iconfontTag, inlineCss);
276 } else {
277 content = content.replace('</head>', '\t' + inlineCss + '$&');
278 }
279 page.setContent(content);
280 });
281};