Skip to content

Instantly share code, notes, and snippets.

@flaki
Created October 21, 2020 11:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save flaki/88e9d453304dc0f2e8d5390588b28ac7 to your computer and use it in GitHub Desktop.
Save flaki/88e9d453304dc0f2e8d5390588b28ac7 to your computer and use it in GitHub Desktop.
Generate minified, source-mapped PostCSS output
const postcss = require('postcss');
const sourcemapConcat = require('concat-with-sourcemaps');
const fs = require('fs-extra');
const { dirname, basename } = require('path');
let CONFIG;
try {
// Throws if no config file
let configFile = require('./postcss.config');
// Function callback
if (typeof configFile === 'function') {
CONFIG = configFile.call(null, {
options: {}
});
// Config obejct
} else if (typeof configFile === 'object') {
CONFIG = configFile;
// Invalid config file
} else {
throw(new Error('Invalid config file!'));
}
}
catch(e) {
console.error(e);
console.error('Make sure you configure postcss-generate first!');
console.error('Hint: use the "generate" property of postcss.config.js!');
process.exit(1);
}
function mkProcessOpts(src) {
return ({
map: {
// Disable inline source maps to ensure .map is populated
inline: false,
// Turn off annotations (not needed since we're concating)
annotation: false
},
from: src,
to: `${CONFIG.generate.outdir}${src}`
});
}
async function transform(processor, src) {
let pOpts = mkProcessOpts(src);
let sourceCss = await fs.readFile(pOpts.from);
// Make sure output dir exists
await fs.ensureDir(dirname(pOpts.to));
// Transform source
let result = await processor.process(sourceCss, pOpts);
// Only write resulting files of not concatenating (no outfile specified)
if (!CONFIG.generate.outfile) {
await fs.writeFile(pOpts.to, result.css);
if (result.map) {
await fs.writeFile(`${pOpts.to}.map`, result.map.toString());
}
}
// Return full processing results for further processing
return result;
}
async function concat(results, outfile) {
let out = new sourcemapConcat(true, outfile, '\n');
// Add a header
out.add(null, "/* (c) RustFest Global 2020 | Brand by URA Design */");
for (const { opts, css, map } of results) {
// NOTE: for some inputs stripping the entire file path
// might not be desirable
// TODO: make this optional/configurable?
const filename = basename(opts.from);
// Original source filename (with full path)
// TODO: this isn't strictly neccessary - maybe make it optional?
out.add(null, `/* ${opts.from} */`);
out.add(filename, css.toString(), map.toString());
}
// Link generated source map
out.add(null, `/*# sourceMappingURL=${basename(outfile)}.map */`);
const concatenated = {
css: out.content, // note: is a buffer
map: out.sourceMap // note: is a string
}
// Make sure output dir exists
await fs.ensureDir(dirname(outfile));
// Transform source and write resulting CSS
await fs.writeFile(outfile, concatenated.css);
await fs.writeFile(`${outfile}.map`, concatenated.map);
return concatenated;
}
async function run() {
// Create a processor by using the plugins from the config file
const processor = postcss(CONFIG.plugins);
// Process source files
let results = await Promise.all(
CONFIG.generate.from.map(
sourceFile => transform(processor, sourceFile)
)
);
// Concatenate all sources into a single source-mapped outfile
let concatresult = await concat(results, CONFIG.generate.outfile);
console.log(`Updated CSS build in ${CONFIG.generate.outfile}`);
}
if (require.main === module) {
run().catch(e => console.error(e));
} else {
module.exports = run
}
module.exports = (ctx) => ({
map: ctx.options.map,
plugins: [
require('postcss-nested'),
require('autoprefixer'),
require('cssnano')({
preset: 'default',
}),
],
//TODO: check for the canonical postcss.config.js properties
//TODO: figure out how list sources by paty (in a way that accounts for ordering)
generate: {
from: [
// Fonts
'assets/fonts/inter/inter.css',
'assets/fonts/quicksand.css',
// Defaults
'assets/css/brand-colors.css',
'assets/css/brand-fonts.css',
'assets/css/brand-base.css',
'assets/css/brand-translations.css',
// Skeleton
'assets/css/brand-header.css',
'assets/css/brand-footer.css',
// Homepage
'assets/css/pg-home-twinkles.css',
'assets/css/pg-home-hero.css',
'assets/css/pg-home-boxes.css',
'assets/css/pg-home-intouch.css',
'assets/css/pg-home-sponsors.css',
// Information page
'assets/css/pg-info.css',
'assets/css/pg-info-team.css',
// Registration
'assets/css/pg-registration.css',
],
outdir: '_site/',
// If no outfile don't concat into single file
outfile: '_site/css/style.css',
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment