1 | ;
|
2 | /**
|
3 | * scss编译为css
|
4 | *
|
5 | * @class Pug2html
|
6 | * {
|
7 | * src:'', <string> scss文件路径
|
8 | * dist:'', <string> css输出路径
|
9 | * debug:true [boolean] 默认:true,debug模式将格式化样式并生成有调试信息
|
10 | * }
|
11 | */
|
12 | class Sass2css{
|
13 | constructor(option){
|
14 | const _ts = this;
|
15 |
|
16 | option = option || {};
|
17 |
|
18 | let m = _ts.m = {
|
19 | fs:require('fs-extra'),
|
20 | path:require('path'),
|
21 | sass:require('node-sass'),
|
22 | pathInfo:require('./getPathInfo'),
|
23 | replaceGlobal:require('./replaceGlobal')
|
24 | },
|
25 | config = _ts.config = {};
|
26 |
|
27 | //配置写入到_ts.config
|
28 | for(let i in option){
|
29 | config[i] = option[i];
|
30 | };
|
31 |
|
32 | //默认开启debug模式
|
33 | config.debug = config.debug === undefined ? true : config.debug;
|
34 | return new Promise((resolve,reject)=>{
|
35 | let fileType = m.pathInfo(config.src).extension;
|
36 | if(fileType === '.scss' || fileType === '.sass'){
|
37 | try {
|
38 | _ts.init().then(v => {
|
39 | resolve(v);
|
40 | }).catch(e => {
|
41 | reject(e);
|
42 | });
|
43 | } catch (error) {
|
44 | reject({
|
45 | status:'error',
|
46 | msg:`初始化失败 ${m.path.join(fwsPath,'lib','sass2css.js')}`,
|
47 | info:error
|
48 | });
|
49 | };
|
50 | }else{
|
51 | reject({
|
52 | status:'error',
|
53 | msg:typeof config.src === 'string' ? `${config.src} 不是有效的Sass文件` : `参数传入错误`
|
54 | });
|
55 | };
|
56 | });
|
57 | }
|
58 | init(){
|
59 | const _ts = this,
|
60 | m = _ts.m,
|
61 | config = _ts.config;
|
62 |
|
63 | //处理编译选项
|
64 | let option = {
|
65 | file:config.src
|
66 | };
|
67 |
|
68 | if(config.debug){
|
69 | option.sourceComments = true;
|
70 | option.outputStyle = 'expanded';
|
71 | option.sourceMapContents = true;
|
72 | option.sourceMapEmbed = true;
|
73 | }else{
|
74 | option.sourceComments = false;
|
75 | option.outputStyle = 'compressed';
|
76 | };
|
77 |
|
78 | // //如果出错会进行多次尝试的
|
79 | // let sassRender = (resolve,reject)=>{
|
80 | // //定义编译方法
|
81 | // let run = (errBlack)=>{
|
82 | // try {
|
83 | // let result,
|
84 | // sassContent = m.fs.readFileSync(config.src).toString();
|
85 | // sassContent = sassContent.replace(/[^\x00-\xff]/g,(k)=>{
|
86 | // let u = parseInt(k.charCodeAt(0),10).toString(16);
|
87 | // return `\\`+u;
|
88 | // });
|
89 | // try{
|
90 | // option.data = sassContent;
|
91 | // option.includePaths = [
|
92 | // m.path.join(config.src,'..')
|
93 | // ];
|
94 | // option.omitSourceMapUrl = false;
|
95 | // result = m.sass.renderSync(option);
|
96 | // }catch(e){
|
97 | // if(typeof errBlack === 'function'){
|
98 | // errBlack(e);
|
99 | // };
|
100 | // };
|
101 |
|
102 | // if(result && result.css){
|
103 | // //创建目录并写入文件
|
104 | // let distDir = m.path.dirname(config.dist);
|
105 | // m.fs.ensureDir(distDir,err => {
|
106 | // if(err){
|
107 | // reject({
|
108 | // status:'error',
|
109 | // msg:`创建失败 ${distDir}`,
|
110 | // info:err
|
111 | // });
|
112 | // };
|
113 |
|
114 | // //写入css文件
|
115 | // try {
|
116 | // m.fs.writeFileSync(config.dist,result.css);
|
117 | // resolve({
|
118 | // status:'success',
|
119 | // msg:`写入 ${config.dist}`,
|
120 | // distPath:config.dist,
|
121 | // data:result.css,
|
122 | // });
|
123 | // } catch (err) {
|
124 | // reject({
|
125 | // status:'error',
|
126 | // msg:`写入失败 ${config.dist}`,
|
127 | // distPath:config.dist,
|
128 | // info:err
|
129 | // });
|
130 | // };
|
131 | // });
|
132 | // };
|
133 | // } catch (error) {
|
134 | // reject({
|
135 | // status:'error',
|
136 | // msg:`编译出错 ${config.src}`,
|
137 | // info:error
|
138 | // });
|
139 | // };
|
140 | // };
|
141 |
|
142 | // //部分IDE在保存文件时即时编译会出错,如果出错,那每50ms会重新试一次,最多尝试100次
|
143 | // let tryNumber = 0,
|
144 | // tryRun;
|
145 | // (tryRun = ()=>{
|
146 | // run((errInfo)=>{
|
147 | // setTimeout(()=>{
|
148 | // if(tryNumber < 50){
|
149 | // tryRun();
|
150 | // }else{
|
151 | // reject({
|
152 | // status:'error',
|
153 | // msg:`编译出错 ${config.src}`,
|
154 | // info:errInfo
|
155 | // });
|
156 | // };
|
157 | // tryNumber++;
|
158 | // },30);
|
159 | // });
|
160 | // })();
|
161 |
|
162 | // };
|
163 |
|
164 | let sassRender = (resolve,reject)=>{
|
165 | //定义编译方法
|
166 | try {
|
167 | let result,
|
168 | sassContent = m.fs.readFileSync(config.src).toString()
|
169 |
|
170 | sassContent = sassContent.replace(/[^\x00-\xff]/g,(k)=>{
|
171 | let u = parseInt(k.charCodeAt(0),10).toString(16);
|
172 | return `\\`+u;
|
173 | });
|
174 |
|
175 | option.data = sassContent;
|
176 | option.includePaths = [m.path.join(config.src,'..')];
|
177 | result = m.sass.renderSync(option);
|
178 |
|
179 | if(result && result.css){
|
180 | result.css = m.replaceGlobal(result.css.toString());
|
181 | result.css = '@charset "UTF-8";\r\n'+result.css.replace(/@charset "UTF-8";/g,'');
|
182 |
|
183 | //创建目录并写入文件
|
184 | let distDir = m.path.dirname(config.dist);
|
185 | m.fs.ensureDir(distDir,err => {
|
186 | if(err){
|
187 | reject({
|
188 | status:'error',
|
189 | msg:`创建失败 ${distDir}`,
|
190 | info:err
|
191 | });
|
192 | };
|
193 |
|
194 | //写入css文件
|
195 | try {
|
196 | m.fs.writeFileSync(config.dist,result.css);
|
197 | resolve({
|
198 | status:'success',
|
199 | msg:`写入 ${config.dist}`,
|
200 | distPath:config.dist,
|
201 | data:result.css,
|
202 | });
|
203 | } catch (err) {
|
204 | reject({
|
205 | status:'error',
|
206 | msg:`写入失败 ${config.dist}`,
|
207 | distPath:config.dist,
|
208 | info:err
|
209 | });
|
210 | };
|
211 | });
|
212 | };
|
213 | } catch (error) {
|
214 | reject({
|
215 | status:'error',
|
216 | msg:`编译出错 ${config.src}`,
|
217 | info:error
|
218 | });
|
219 | };
|
220 |
|
221 | };
|
222 |
|
223 | return new Promise(sassRender);
|
224 | }
|
225 | }
|
226 | module.exports = Sass2css;
|