scss-to-css/index.js

210 lines
4.2 KiB
JavaScript
Raw Permalink Normal View History

2018-12-03 10:00:21 +08:00
/**
*
* @author yutent<yutent@doui.cc>
* @date 2018/11/01 09:37:55
*/
'use strict'
const vsc = require('vscode')
const path = require('path')
2019-08-05 16:02:59 +08:00
const exec = require('child_process').exec
2018-12-03 10:57:30 +08:00
const fs = require('iofs')
2018-12-03 10:00:21 +08:00
const postcss = require('postcss')
const autoprefixer = require('autoprefixer')
2018-12-03 14:08:33 +08:00
let prefixer
2018-12-03 10:00:21 +08:00
const log = console.log
2019-06-10 16:18:57 +08:00
const std = vsc.window.createOutputChannel('scss-to-css')
std.out = function(msg) {
std.appendLine(msg)
}
2018-12-03 10:00:21 +08:00
2019-08-05 16:02:59 +08:00
function run(cmd) {
return new Promise((yes, no) => {
exec(cmd, (err, res) => {
if (err) {
std.out(err)
no(err)
2018-12-03 10:57:30 +08:00
} else {
2019-08-05 16:02:59 +08:00
yes(res)
2018-12-03 10:57:30 +08:00
}
})
})
}
2019-08-05 16:02:59 +08:00
const render = function(style, file) {
return run(`node-sass --output-style ${style} ${file}`)
}
2018-12-03 10:57:30 +08:00
let options = {
2018-12-03 10:00:21 +08:00
compileOnSave: true,
autoPrefixer: true,
output: 'compressed',
exclude: ''
}
2019-08-05 16:02:59 +08:00
const compileScss = (style, entry, output) => {
2019-02-14 13:38:11 +08:00
if (options.outdir) {
let tmp = output.replace(options.workspace, '.')
output = path.join(options.outdir, tmp)
}
2019-06-10 16:18:57 +08:00
return render(style, entry)
.then(css => {
if (options.autoPrefixer) {
return prefixer.process(css, { from: '', to: '' }).then(result => {
return { css: result.css, output }
})
} else {
return { css, output }
}
})
.catch(err => {
std.out(err)
})
2018-12-03 10:00:21 +08:00
}
const Compiler = {
compile(doc) {
let origin = doc.fileName || ''
2019-02-14 13:38:11 +08:00
let target = origin.replace(/\.scss$/, '')
2018-12-03 10:00:21 +08:00
let task = []
// 说明不是scss文件
if (origin === target) {
return
}
2018-12-03 10:57:30 +08:00
task = options.output.map(style => {
2019-02-14 13:38:11 +08:00
let ext = '.css'
2018-12-03 10:00:21 +08:00
2018-12-03 10:57:30 +08:00
switch (style) {
2018-12-03 10:00:21 +08:00
case 'compressed':
2019-02-14 13:38:11 +08:00
ext = '.min' + ext
2018-12-03 10:00:21 +08:00
break
default:
2019-02-14 13:38:11 +08:00
ext = style.slice(0, 1) + ext
2018-12-03 10:00:21 +08:00
}
2018-12-03 10:57:30 +08:00
return { style, output: target + ext }
2018-12-03 10:00:21 +08:00
})
// 编译单一类型, 则去掉文件名微调
if (task.length === 1) {
2019-02-14 13:38:11 +08:00
task[0].output = target + '.css'
2018-12-03 10:00:21 +08:00
}
task = task.map(item => {
2019-08-05 16:02:59 +08:00
return compileScss(item.style, origin, item.output)
2018-12-03 10:00:21 +08:00
})
Promise.all(task)
.then(list => {
2018-12-03 10:57:30 +08:00
list.forEach(it => {
fs.echo(it.css, it.output)
})
2018-12-03 10:00:21 +08:00
})
.catch(err => {
vsc.window.showInformationMessage(err)
2018-12-03 10:00:21 +08:00
})
},
/**
* 条件过滤
* 用于保存时编译的动作, 右键编译时, 不过滤这2项
*/
filter(doc) {
// 未开启保存时编译
2018-12-03 10:57:30 +08:00
if (!options.compileOnSave) {
2018-12-03 10:00:21 +08:00
return
}
let origin = doc.fileName || ''
// var.scss文件默认不编译
if (/\/var\.scss$/.test(origin)) {
return
}
// 过滤不编译的文件
2018-12-03 10:57:30 +08:00
if (options.exclude) {
let exp = new RegExp(options.exclude, 'i')
2018-12-03 10:00:21 +08:00
if (exp.test(origin)) {
return
}
}
this.compile(doc)
}
}
2019-01-05 04:24:17 +08:00
function __init__() {
let conf = vsc.workspace.getConfiguration('Scss2css')
2019-02-14 13:38:11 +08:00
let folders = vsc.workspace.workspaceFolders
let wsDir = ''
let configFile = ''
2019-01-05 04:24:17 +08:00
Object.assign(options, conf)
2019-02-14 13:38:11 +08:00
conf = null
2019-01-05 04:24:17 +08:00
options.output = options.output.split('|').map(it => it.trim())
2018-12-03 14:08:33 +08:00
if (folders && folders.length) {
2019-02-14 13:38:11 +08:00
wsDir = folders[0].uri.path
2018-12-03 14:08:33 +08:00
}
2019-02-14 13:38:11 +08:00
if (wsDir) {
configFile = path.join(wsDir, '.scssrc')
} else {
let editor = vsc.window.activeTextEditor
if (editor) {
2019-02-14 13:38:11 +08:00
wsDir = path.dirname(editor.document.fileName)
configFile = path.join(wsDir, '.scssrc')
}
2018-12-03 14:08:33 +08:00
}
2019-02-14 13:38:11 +08:00
// 以配置文件所在目录为根目录(workspace)
if (fs.exists(configFile)) {
options.workspace = path.dirname(configFile)
let tmp = JSON.parse(fs.cat(configFile).toString())
Object.assign(options, tmp)
tmp = null
if (options.outdir) {
options.outdir = path.join(options.workspace, options.outdir)
}
2018-12-03 14:08:33 +08:00
}
2019-02-14 13:38:11 +08:00
2018-12-03 14:08:33 +08:00
prefixer = postcss().use(
autoprefixer({
browsers: options.browsers
})
)
2019-02-14 13:38:11 +08:00
}
2018-12-03 14:08:33 +08:00
2019-06-10 16:18:57 +08:00
function deactivate() {}
exports.activate = function(ctx) {
2019-01-05 04:24:17 +08:00
__init__()
vsc.workspace.onDidChangeConfiguration(__init__)
2018-12-03 10:00:21 +08:00
vsc.workspace.onDidSaveTextDocument(doc => {
2019-06-10 16:18:57 +08:00
std.clear()
2018-12-03 10:00:21 +08:00
Compiler.filter(doc)
})
let cmd = vsc.commands.registerCommand('Scss2css.compile', _ => {
let editor = vsc.window.activeTextEditor
if (editor) {
Compiler.compile(editor.document)
}
})
ctx.subscriptions.push(cmd)
2018-12-03 10:00:21 +08:00
}
exports.deactivate = deactivate