UNPKG

5.51 kBJavaScriptView Raw
1///@ts-check
2"use strict";
3const path = require('path');
4const chalk = require('ansi-colors');
5const through = require('through2');
6// const applySourceMap = require('vinyl-sourcemaps-apply');
7const PluginError = require('./error');
8
9const EXT_NAME = ".wxss";
10/**
11 * 替换后缀名
12 * @param {string} file
13 * @param {string} ext
14 */
15function replaceExtension(file, ext) {
16 return path.join(path.dirname(file), path.basename(file, path.extname(file)) + ext);
17}
18const PLUGIN_NAME = 'sass';
19
20//////////////////////////////
21// Main Gulp Sass function
22//////////////////////////////
23const gulpSass = (options, sync) => through.obj((file, enc, cb) => { // eslint-disable-line consistent-return
24 if (file.isNull()) {
25 return cb(null, file);
26 }
27
28 if (file.isStream()) {
29 return cb(new PluginError(PLUGIN_NAME, 'Streaming not supported'));
30 }
31
32 if (path.basename(file.path).indexOf('_') === 0) {
33 return cb();
34 }
35
36 if (!file.contents.length) {
37 file.path = replaceExtension(file.path, EXT_NAME); // eslint-disable-line no-param-reassign
38 return cb(null, file);
39 }
40
41 const opts = Object.assign({}, options || {});
42 opts.data = file.contents.toString();
43
44 // we set the file path here so that libsass can correctly resolve import paths
45 opts.file = file.path;
46
47 // Ensure `indentedSyntax` is true if a `.sass` file
48 if (path.extname(file.path) === '.sass') {
49 opts.indentedSyntax = true;
50 }
51
52 // Ensure file's parent directory in the include path
53 if (opts.includePaths) {
54 if (typeof opts.includePaths === 'string') {
55 opts.includePaths = [opts.includePaths];
56 } else {
57 opts.includePaths = opts.includePaths.map(e => e)
58 }
59 } else {
60 opts.includePaths = [];
61 }
62
63 opts.includePaths.unshift(path.dirname(file.path));
64
65 // Generate Source Maps if plugin source-map present
66 if (file.sourceMap) {
67 opts.sourceMap = true;
68 opts.omitSourceMapUrl = true;
69 opts.sourceMapContents = true;
70 }
71
72 //////////////////////////////
73 // Handles returning the file to the stream
74 //////////////////////////////
75 const filePush = (sassObj) => {
76 let sassMap;
77 let sassMapFile;
78 let sassFileSrc;
79 let sassFileSrcPath;
80 let sourceFileIndex;
81
82 // Build Source Maps!
83 if (sassObj.map) {
84 // Transform map into JSON
85 sassMap = JSON.parse(sassObj.map.toString());
86 // Grab the stdout and transform it into stdin
87 sassMapFile = sassMap.file.replace(/^stdout$/, 'stdin');
88 // Grab the base file name that's being worked on
89 sassFileSrc = file.relative;
90 // Grab the path portion of the file that's being worked on
91 sassFileSrcPath = path.dirname(sassFileSrc);
92 if (sassFileSrcPath) {
93 // Prepend the path to all files in the sources array except the file that's being worked on
94 sourceFileIndex = sassMap.sources.indexOf(sassMapFile);
95 sassMap.sources = sassMap.sources.map((source, index) => { // eslint-disable-line arrow-body-style
96 return index === sourceFileIndex ? source : path.join(sassFileSrcPath, source);
97 });
98 }
99
100 // Remove 'stdin' from souces and replace with filenames!
101 sassMap.sources = sassMap.sources.filter(src => src !== 'stdin' && src);
102
103 // Replace the map file with the original file name (but new extension)
104 sassMap.file = replaceExtension(sassFileSrc, EXT_NAME);
105 // Apply the map
106 // applySourceMap(file, sassMap);
107 }
108
109 file.contents = sassObj.css; // eslint-disable-line no-param-reassign
110 file.path = replaceExtension(file.path, EXT_NAME); // eslint-disable-line no-param-reassign
111
112 cb(null, file);
113 };
114
115 //////////////////////////////
116 // Handles error message
117 //////////////////////////////
118 const errorM = (error) => {
119 const filePath = (error.file === 'stdin' ? file.path : error.file) || file.path;
120 const relativePath = path.relative(process.cwd(), filePath);
121 const message = [chalk.underline(relativePath), error.formatted].join('\n');
122
123 error.messageFormatted = message; // eslint-disable-line no-param-reassign
124 error.messageOriginal = error.message; // eslint-disable-line no-param-reassign
125 error.message = chalk.unstyle(message); // eslint-disable-line no-param-reassign
126 error.relativePath = relativePath; // eslint-disable-line no-param-reassign
127
128 return cb(new PluginError(PLUGIN_NAME, error));
129 };
130
131 if (sync !== true) {
132 //////////////////////////////
133 // Async Sass render
134 //////////////////////////////
135 const callback = (error, obj) => { // eslint-disable-line consistent-return
136 if (error) {
137 return errorM(error);
138 }
139 filePush(obj);
140 };
141
142 gulpSass.compiler.render(opts, callback);
143 } else {
144 //////////////////////////////
145 // Sync Sass render
146 //////////////////////////////
147 try {
148 filePush(gulpSass.compiler.renderSync(opts));
149 } catch (error) {
150 return errorM(error);
151 }
152 }
153});
154
155//////////////////////////////
156// Sync Sass render
157//////////////////////////////
158gulpSass.sync = options => gulpSass(options, true);
159
160//////////////////////////////
161// Log errors nicely
162//////////////////////////////
163gulpSass.logError = function logError(error) {
164 const message = new PluginError('sass', error.messageFormatted).toString();
165 process.stderr.write(`${message}\n`);
166 //@ts-ignore
167 this.emit('end');
168};
169
170//////////////////////////////
171// Store compiler in a prop
172//////////////////////////////
173gulpSass.compiler = require('sass');
174
175module.exports = gulpSass;