fuse-box
Version:
Fuse-Box a bundler that does it right
120 lines (100 loc) • 3.64 kB
text/typescript
import { File } from "../../core/File";
import { WorkFlowContext, Plugin } from "../../core/WorkflowContext";
import * as path from "path";
import { Config } from "../../Config";
export interface SassPluginOptions {
includePaths?: string[];
macros?: { [key: string]: string };
importer?: boolean | ImporterFunc;
cache?: boolean;
functions?: { [key: string]: (...args: any[]) => any }
}
export interface ImporterFunc {
(url: string, prev: string, done: (opts: { url?: string; file?: string; }) => any): any;
}
let sass;
/**
* @export
* @class SassPlugin
* @implements {Plugin}
*/
export class SassPluginClass implements Plugin {
public test: RegExp = /\.(scss|sass)$/;
public context: WorkFlowContext;
constructor(public options: SassPluginOptions = {}) { }
public init(context: WorkFlowContext) {
context.allowExtension(".scss");
context.allowExtension(".sass");
this.context = context;
}
public transform(file: File): Promise<any> {
file.addStringDependency("fuse-box-css");
const context = file.context;
if (context.useCache && this.options.cache) {
let cached = context.cache.getStaticCache(file);
if (cached) {
if (cached.sourceMap) {
file.sourceMap = cached.sourceMap;
}
file.isLoaded = true;
file.contents = cached.contents;
return;
}
}
file.loadContents();
if (!file.contents) {
return;
}
if (!sass) { sass = require("node-sass"); }
const defaultMacro = {
"$homeDir": file.context.homeDir,
"$appRoot": context.appRoot,
"~": Config.NODE_MODULES_DIR + "/",
};
const options = Object.assign({
data: file.contents,
sourceMap: true,
outFile: file.info.fuseBoxPath,
sourceMapContents: true
}, this.options);
options.includePaths = [];
if (typeof this.options.includePaths !== "undefined") {
this.options.includePaths.forEach((path) => {
options.includePaths.push(path);
});
}
options.macros = Object.assign(defaultMacro, this.options.macros || {}, );
if (this.options.importer === true) {
options.importer = (url, prev, done) => {
if (/https?:/.test(url)) {
return done({ url });
}
for (let key in options.macros) {
if (options.macros.hasOwnProperty(key)) {
url = url.replace(key, options.macros[key]);
}
}
done({ file: path.normalize(url) });
};
}
options.includePaths.push(file.info.absDir);
return new Promise((resolve, reject) => {
return sass.render(options, (err, result) => {
if (err) {
file.contents = "";
console.log(err.stack || err)
return resolve();
}
file.sourceMap = result.map && result.map.toString();
file.contents = result.css.toString();
if (context.useCache && this.options.cache) {
context.cache.writeStaticCache(file, file.sourceMap);
}
return resolve();
});
});
}
}
export const SassPlugin = (options?: SassPluginOptions) => {
return new SassPluginClass(options);
};