The communications platform that puts data protection first.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
Rocket.Chat/packages/rocketchat-postcss/plugin/minify-css.js

202 lines
4.7 KiB

/* global CssTools */
import appModulePath from 'app-module-path';
import Future from 'fibers/future';
import fs from 'fs';
import path from 'path';
import postCSS from 'postcss';
import sourcemap from 'source-map';
appModulePath.addPath(`${ process.cwd() }/node_modules/`);
const postCSSConfigFile = path.resolve(process.cwd(), '.postcssrc');
const postCSSConfig = JSON.parse(fs.readFileSync(postCSSConfigFile));
const getPostCSSPlugins = () => {
const plugins = [];
if (postCSSConfig.plugins) {
Object.keys(postCSSConfig.plugins).forEach((pluginName) => {
const postCSSPlugin = require(pluginName);
if (postCSSPlugin && postCSSPlugin().postcssPlugin) {
plugins.push(postCSSPlugin(postCSSConfig.plugins ? postCSSConfig.plugins[pluginName] : {}));
}
});
}
return plugins;
};
const getExcludedPackages = () => {
if (postCSSConfig.excludedPackages && postCSSConfig.excludedPackages instanceof Array) {
return postCSSConfig.excludedPackages;
}
return false;
};
const isNotInExcludedPackages = (excludedPackages, pathInBundle) => {
let exclArr = [];
if (excludedPackages && excludedPackages instanceof Array) {
exclArr = excludedPackages.map(packageName => {
return pathInBundle && pathInBundle.indexOf(`packages/${ packageName.replace(':', '_') }`) > -1;
});
}
return exclArr.indexOf(true) === -1;
};
const isNotImport = inputFileUrl => !(/\.import\.css$/.test(inputFileUrl) || /(?:^|\/)imports\//.test(inputFileUrl));
const mergeCss = css => {
const originals = {};
const excludedPackagesArr = getExcludedPackages();
const cssAsts = css.map(file => {
const filename = file.getPathInBundle();
originals[filename] = file;
const f = new Future;
let css;
let postres;
const isFileForPostCSS = isNotInExcludedPackages(excludedPackagesArr, file.getPathInBundle());
postCSS(isFileForPostCSS ? getPostCSSPlugins() : [])
.process(file.getContentsAsString(), {
from: process.cwd() + file._source.url.replace('_', '-')
})
.then(result => {
result.warnings().forEach(warn => {
process.stderr.write(warn.toString());
});
f.return(result);
})
.catch(error => {
if (error.name === 'CssSyntaxError') {
error.message = `${ error.message }\n\nCss Syntax Error.\n\n${ error.message }${ error.showSourceCode() }`;
}
f.return(error);
});
try {
const parseOptions = {
source: filename,
position: true
};
postres = f.wait();
if (postres.name === 'CssSyntaxError') {
throw postres;
}
css = postres.css;
const ast = CssTools.parseCss(css, parseOptions);
ast.filename = filename;
return ast;
} catch (e) {
if (e.name === 'CssSyntaxError') {
file.error({
message: e.message,
line: e.line,
column: e.column
});
} else if (e.reason) {
file.error({
message: e.reason,
line: e.line,
column: e.column
});
} else {
file.error({
message: e.message
});
}
return {
type: 'stylesheet',
stylesheet: { rules: [] },
filename
};
}
});
const mergedCssAst = CssTools.mergeCssAsts(cssAsts, (filename, msg) => {
console.log(`${ filename }: warn: ${ msg }`);
});
const stringifiedCss = CssTools.stringifyCss(mergedCssAst, {
sourcemap: true,
inputSourcemaps: false
});
if (!stringifiedCss.code) {
return { code: '' };
}
stringifiedCss.map.sourcesContent =
stringifiedCss.map.sources.map(filename => {
return originals[filename].getContentsAsString();
});
const newMap = sourcemap.SourceMapGenerator.fromSourceMap(new sourcemap.SourceMapConsumer(stringifiedCss.map));
Object.keys(originals).forEach(name => {
const file = originals[name];
if (!file.getSourceMap()) {
return false;
}
try {
newMap.applySourceMap(new sourcemap.SourceMapConsumer(file.getSourceMap()), name);
} catch (err) {
// If can't apply the source map, silently drop it.
}
});
return {
code: stringifiedCss.code,
sourceMap: newMap.toString()
};
};
class CssToolsMinifier {
processFilesForBundle(files, options) {
const mode = options.minifyMode;
if (!files.length) {
return false;
}
const filesToMerge = [];
files.forEach(file => {
if (isNotImport(file._source.url)) {
filesToMerge.push(file);
}
});
const merged = mergeCss(filesToMerge);
if (mode === 'development') {
files[0].addStylesheet({
data: merged.code,
sourceMap: merged.sourceMap,
path: 'merged-stylesheets.css'
});
return false;
}
const minifiedFiles = CssTools.minifyCss(merged.code);
if (files.length) {
minifiedFiles.forEach(minified => {
files[0].addStylesheet({
data: minified
});
});
}
}
}
Plugin.registerMinifier({extensions: ['css']}, () => new CssToolsMinifier);