UNPKG

11.7 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3const tslib_1 = require("tslib");
4const url = require("url");
5const path = require("path");
6const less = require("less");
7const postcss = require("postcss");
8const class_1 = require("../class");
9const declare_1 = require("../declare");
10const util_1 = require("../util");
11const plugin_1 = require("../plugin");
12/* precss-start */
13// const precss = require('precss')
14// import 插件有wxc工具提供
15// const postcssPartialImport = require('postcss-partial-import')
16const postcssMixins = require('postcss-mixins');
17const postcssAdvancedVariables = require('postcss-advanced-variables');
18const postcssCustomMedia = require('postcss-custom-media');
19const postcssCustomProperties = require('postcss-custom-properties');
20const postcssMediaMinmax = require('postcss-media-minmax');
21const postcssColorFunction = require('postcss-color-function');
22const postcssNesting = require('postcss-nesting');
23const postcssNested = require('postcss-nested');
24const postcssCustomSelectors = require('postcss-custom-selectors');
25const postcssAtroot = require('postcss-atroot');
26const postcssPropertyLookup = require('postcss-property-lookup');
27const postcssExtend = require('postcss-extend');
28const postcssSelectorMatches = require('postcss-selector-matches');
29const postcssSelectorNot = require('postcss-selector-not');
30/* precss-end */
31const postcssBem = require('postcss-bem');
32const postcssCalc = require('postcss-calc');
33// bem 选项
34const postcssBemOptions = {
35 defaultNamespace: undefined,
36 style: 'suit',
37 separators: {
38 descendent: '__',
39 modifier: '--'
40 },
41 shortcuts: {
42 utility: 'u',
43 component: 'b',
44 descendent: 'e',
45 modifier: 'm',
46 when: 'is'
47 }
48};
49// postcss 处理器
50const processor = postcss([
51 postcssBem(postcssBemOptions),
52 postcssMixins,
53 postcssAdvancedVariables,
54 postcssCustomMedia,
55 postcssCustomProperties,
56 postcssMediaMinmax,
57 postcssColorFunction,
58 postcssNesting,
59 postcssNested,
60 postcssCustomSelectors,
61 postcssAtroot,
62 postcssPropertyLookup,
63 postcssExtend,
64 postcssSelectorMatches,
65 postcssSelectorNot,
66 postcssCalc,
67 plugin_1.postcssUnit2rpx
68]);
69/**
70 * STYLE 模块类
71 *
72 * @export
73 * @class WxSFMStyle
74 * @extends {WxSFM}
75 */
76class WxSFMStyle extends class_1.WxSFM {
77 /**
78 * Creates an instance of WxSFMStyle.
79 * @param {string} source
80 * @param {Request} request
81 * @param {CompileType} compileType
82 * @memberof WxSFMStyle
83 */
84 constructor(source, request, options) {
85 super(source, request, {
86 destExt: util_1.config.ext.wxss
87 });
88 this.options = options;
89 /**
90 * 依赖列表
91 *
92 * @private
93 * @type {Depend[]}
94 * @memberof WxSFMStyle
95 */
96 this.depends = [];
97 this.initDepends();
98 }
99 /**
100 * style 基础编译
101 *
102 * @returns
103 * @memberof WxSFMStyle
104 */
105 compileStyle() {
106 return tslib_1.__awaiter(this, void 0, void 0, function* () {
107 if (!this.result)
108 return '';
109 // 更新依赖路径后,重新编译
110 return yield postcss([
111 plugin_1.postcssUnit2rpx
112 ]).process(this.result).then(result => result.css);
113 });
114 }
115 /**
116 * style less 编译
117 *
118 * @returns
119 * @memberof WxSFMStyle
120 */
121 compileLess() {
122 return tslib_1.__awaiter(this, void 0, void 0, function* () {
123 if (!this.source)
124 return '';
125 // 1.0.5 版本以前,less 编译不支持 @import 外部文件
126 // 1.0.5 版本开始,less 编译会将所有 @import 外部文件打包在一个入口文件
127 // 将来的某个版本可能会调整 @import 外部文件分离编译
128 let source = '';
129 let options = {
130 filename: this.request.src
131 };
132 source = this.source;
133 // 全局 style 样式
134 source = util_1.Global.config.style.lessCode + '\n' + source;
135 // less 编译
136 source = yield less.render(source, options).then(result => result.css);
137 // 经 postcss 编译 unit2px 转换
138 source = yield postcss([
139 plugin_1.postcssUnit2rpx
140 ]).process(source).then(result => result.css);
141 return source;
142 });
143 }
144 /**
145 * style postcss 编译
146 *
147 * @returns
148 * @memberof WxSFMStyle
149 */
150 compilePcss() {
151 return tslib_1.__awaiter(this, void 0, void 0, function* () {
152 if (!this.result)
153 return '';
154 // TODO 由于使用style样式全局变量,编译后的代码会存在多个 换行问题
155 let source = '';
156 // 从 result 中提取文件内容(依赖已更新)
157 source = yield postcss().process(this.result).then(result => result.css);
158 // 全局 style 样式
159 source = util_1.Global.config.style.pcssCode + '\n' + source;
160 // postcss 编译(bem、precss集合插件中排除import插件、unit2rpx)
161 source = yield processor.process(source).then(result => result.css);
162 return source;
163 });
164 }
165 /**
166 * 生成代码
167 *
168 * @returns {Promise<string>}
169 * @memberof WxSFMStyle
170 */
171 generator() {
172 return tslib_1.__awaiter(this, void 0, void 0, function* () {
173 switch (this.options.compileType) {
174 case declare_1.CompileType.LESS:
175 return yield this.compileLess();
176 case declare_1.CompileType.PCSS:
177 return yield this.compilePcss();
178 default:
179 return yield this.compileStyle();
180 }
181 });
182 }
183 /**
184 * 保存文件
185 *
186 * @memberof WxSFMStyle
187 */
188 save() {
189 super.save();
190 }
191 /**
192 * 移除文件
193 *
194 * @memberof WxSFMStyle
195 */
196 remove() {
197 super.remove();
198 }
199 /**
200 * 获取依赖列表
201 *
202 * @returns {Depend[]}
203 * @memberof WxSFMStyle
204 */
205 getDepends() {
206 return this.depends;
207 }
208 /**
209 * 更新依赖列表
210 *
211 * @param {Request.Core[]} useRequests 可用的请求列表
212 * @memberof WxSFMStyle
213 */
214 updateDepends(useRequests) {
215 let depends = this.getDepends();
216 if (!depends.length)
217 return;
218 useRequests.forEach(useRequest => {
219 depends
220 .filter(depend => {
221 return depend.requestType === useRequest.requestType && depend.request === useRequest.request;
222 })
223 .forEach(depend => {
224 let request = '';
225 request = path.relative(path.dirname(this.dest), path.dirname(useRequest.dest));
226 request = path.join(request, path.basename(useRequest.dest, useRequest.ext));
227 request = request.charAt(0) !== '.' ? `./${request}` : request;
228 request = request.split(path.sep).join('/');
229 switch (depend.requestType) {
230 case declare_1.RequestType.STYLE:
231 // ② 更新依赖引用路径,将所有的扩展名统一改成 .wxss
232 depend.$atRule.params = `'${request}${util_1.config.ext.wxss}'`;
233 break;
234 case declare_1.RequestType.ICONFONT:
235 let requestURL = url.parse(depend.request);
236 // depend.request => ./iconfont.eot?t=1515059114217
237 // depend.$decl.value => url('./iconfont.eot?t=1515059114217')
238 depend.$decl.value = depend.$decl.value.replace(depend.request, `${request}${useRequest.ext}${requestURL.search}`);
239 break;
240 }
241 });
242 });
243 }
244 /**
245 * 初始化 depends 依赖列表
246 *
247 * @private
248 * @memberof WxSFMStyle
249 */
250 initDepends() {
251 if (!this.source)
252 return;
253 if (this.options.compileType === declare_1.CompileType.LESS)
254 return;
255 let transformer = root => {
256 // @import
257 root.walkAtRules((rule, index) => {
258 if (rule.name !== 'import') {
259 return;
260 }
261 // ① 收集所有的依赖,用于后续的依赖加载和路径更新
262 this.depends.push({
263 request: rule.params.replace(/^('|")(.*)('|")$/g, (match, quotn, filename) => filename),
264 requestType: declare_1.RequestType.STYLE,
265 $atRule: rule
266 });
267 });
268 // background background-image
269 root.walkDecls((decl, index) => {
270 // WXSS 里不用本地资源
271 // background background-image => IMAGE
272 // decl.prop !== 'background' && decl.prop !== 'background-image'
273 // src => ICONFONT
274 if (decl.prop !== 'src') {
275 return;
276 }
277 // src: url('./iconfont.eot?t=1515059114217');
278 if (decl.value.indexOf('url') === -1) {
279 return;
280 }
281 // src: url('./iconfont.eot?t') format('embedded-opentype'), /* IE6-IE8 */
282 // url('./iconfont.ttf?t=1515059114217') format('truetype')
283 let urls = decl.value.split(/format\([\'\"][a-z-]+[\'\"]\),/);
284 urls.forEach(url => {
285 let matchs = url.match(util_1.ICONFONT_PATTERN);
286 if (!matchs) {
287 return;
288 }
289 // url('./iconfont.eot?t=1515059114217#iefix')
290 url = matchs[1];
291 // Check local file
292 if (!util_1.default.checkLocalFile(url)) {
293 return;
294 }
295 this.depends.push({
296 request: url,
297 requestType: declare_1.RequestType.ICONFONT,
298 $decl: decl
299 });
300 });
301 });
302 };
303 let lazyResult = postcss([transformer]).process(this.source);
304 lazyResult.toString();
305 this.result = lazyResult['result'];
306 }
307}
308exports.WxSFMStyle = WxSFMStyle;
309// import wxss 保留引用,不被插件编译
310// class ImportWxssPlugin {
311// pick: postcss.Plugin<any>
312// revert: postcss.Plugin<any>
313// private atRules: postcss.AtRule[] = []
314// constructor () {
315// this._pick()
316// this._revert()
317// }
318// /**
319// * 摘取 @import *.wxss 扩展的路径引用
320// *
321// * @private
322// * @memberof ImportWxssPlugin
323// */
324// private _pick() {
325// this.pick = postcss.plugin('postcss-plugin-pick-import-wxss', () => {
326// return root => {
327// root.walkAtRules((rule, index) => {
328// if (rule.name === 'import' && /\.wxss('|")$/.test(rule.params)) {
329// root.removeChild(rule)
330// this.atRules.push(rule)
331// }
332// })
333// }
334// })
335// }
336// /**
337// * 归还 @import *.wxss 扩展的路径引用
338// *
339// * @private
340// * @memberof ImportWxssPlugin
341// */
342// private _revert() {
343// this.revert = postcss.plugin('postcss-plugin-revert-import-wxss', () => {
344// return root => {
345// if (root.nodes && this.atRules.length > 0) {
346// root.prepend(this.atRules)
347// }
348// }
349// })
350// }
351// }