Merge pull request #96 from locomotivemtl/mcaskill-refactor-build-options
This commit is contained in:
@@ -9,6 +9,8 @@ import { basename } from 'node:path';
|
||||
/**
|
||||
* Concatenates groups of files.
|
||||
*
|
||||
* @todo Add support for minification.
|
||||
*
|
||||
* @async
|
||||
* @return {Promise}
|
||||
*/
|
||||
|
||||
@@ -5,13 +5,54 @@ import template from '../utils/template.js';
|
||||
import esbuild from 'esbuild';
|
||||
import { basename } from 'node:path';
|
||||
|
||||
/**
|
||||
* @const {object} defaultESBuildOptions - The default shared ESBuild options.
|
||||
* @const {object} developmentESBuildOptions - The predefined ESBuild options for development.
|
||||
* @const {object} productionESBuildOptions - The predefined ESBuild options for production.
|
||||
*/
|
||||
export const defaultESBuildOptions = {
|
||||
bundle: true,
|
||||
color: true,
|
||||
sourcemap: true,
|
||||
target: [
|
||||
'es2015',
|
||||
],
|
||||
};
|
||||
export const developmentESBuildOptions = Object.assign({}, defaultESBuildOptions);
|
||||
export const productionESBuildOptions = Object.assign({}, defaultESBuildOptions, {
|
||||
logLevel: 'warning',
|
||||
minify: true,
|
||||
});
|
||||
|
||||
/**
|
||||
* @const {object} developmentScriptsArgs - The predefined `compileScripts()` options for development.
|
||||
* @const {object} productionScriptsArgs - The predefined `compileScripts()` options for production.
|
||||
*/
|
||||
export const developmentScriptsArgs = [
|
||||
developmentESBuildOptions,
|
||||
];
|
||||
export const productionScriptsArgs = [
|
||||
productionESBuildOptions,
|
||||
];
|
||||
|
||||
/**
|
||||
* Bundles and minifies main JavaScript files.
|
||||
*
|
||||
* @async
|
||||
* @param {object} [esBuildOptions=null] - Customize the ESBuild build API options.
|
||||
* If `null`, default production options are used.
|
||||
* @return {Promise}
|
||||
*/
|
||||
export default async function compileScripts() {
|
||||
export default async function compileScripts(esBuildOptions = null) {
|
||||
if (esBuildOptions == null) {
|
||||
esBuildOptions = productionESBuildOptions;
|
||||
} else if (
|
||||
esBuildOptions !== developmentESBuildOptions &&
|
||||
esBuildOptions !== productionESBuildOptions
|
||||
) {
|
||||
esBuildOptions = Object.assign({}, defaultESBuildOptions, esBuildOptions);
|
||||
}
|
||||
|
||||
loconfig.tasks.scripts.forEach(async ({
|
||||
includes,
|
||||
outdir = '',
|
||||
@@ -35,19 +76,11 @@ export default async function compileScripts() {
|
||||
);
|
||||
}
|
||||
|
||||
await esbuild.build({
|
||||
await esbuild.build(Object.assign({}, esBuildOptions, {
|
||||
entryPoints: includes,
|
||||
bundle: true,
|
||||
minify: true,
|
||||
sourcemap: true,
|
||||
color: true,
|
||||
logLevel: 'error',
|
||||
target: [
|
||||
'es2015',
|
||||
],
|
||||
outdir,
|
||||
outfile
|
||||
});
|
||||
outfile,
|
||||
}));
|
||||
|
||||
message(`${filename} compiled`, 'success', timeLabel);
|
||||
} catch (err) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import loconfig from '../../loconfig.json';
|
||||
import message from '../utils/message.js';
|
||||
import notification from '../utils/notification.js';
|
||||
import postcss from '../utils/postcss.js';
|
||||
import postcss, { pluginsMap as postcssPluginsMap } from '../utils/postcss.js';
|
||||
import template from '../utils/template.js';
|
||||
import { writeFile } from 'node:fs/promises';
|
||||
import { basename } from 'node:path';
|
||||
@@ -10,13 +10,91 @@ import sass from 'node-sass';
|
||||
|
||||
const sassRender = promisify(sass.render);
|
||||
|
||||
let postcssProcessor;
|
||||
|
||||
/**
|
||||
* @const {object} defaultSassOptions - The default shared Sass options.
|
||||
* @const {object} developmentSassOptions - The predefined Sass options for development.
|
||||
* @const {object} productionSassOptions - The predefined Sass options for production.
|
||||
*/
|
||||
export const defaultSassOptions = {
|
||||
omitSourceMapUrl: true,
|
||||
sourceMap: true,
|
||||
sourceMapContents: true,
|
||||
};
|
||||
export const developmentSassOptions = Object.assign({}, defaultSassOptions, {
|
||||
outputStyle: 'expanded',
|
||||
});
|
||||
export const productionSassOptions = Object.assign({}, defaultSassOptions, {
|
||||
outputStyle: 'compressed',
|
||||
});
|
||||
|
||||
/**
|
||||
* @const {object} defaultPostCSSOptions - The default shared PostCSS options.
|
||||
* @const {object} developmentPostCSSOptions - The predefined PostCSS options for development.
|
||||
* @const {object} productionPostCSSOptions - The predefined PostCSS options for production.
|
||||
*/
|
||||
export const defaultPostCSSOptions = {
|
||||
processor: {
|
||||
map: {
|
||||
annotation: false,
|
||||
inline: false,
|
||||
sourcesContent: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
export const developmentPostCSSOptions = Object.assign({}, defaultPostCSSOptions);
|
||||
export const productionPostCSSOptions = Object.assign({}, defaultPostCSSOptions);
|
||||
|
||||
/**
|
||||
* @const {object} developmentStylesArgs - The predefined `compileStyles()` options for development.
|
||||
* @const {object} productionStylesArgs - The predefined `compileStyles()` options for production.
|
||||
*/
|
||||
export const developmentStylesArgs = [
|
||||
developmentSassOptions,
|
||||
developmentPostCSSOptions,
|
||||
];
|
||||
export const productionStylesArgs = [
|
||||
productionSassOptions,
|
||||
productionPostCSSOptions,
|
||||
];
|
||||
|
||||
/**
|
||||
* Compiles and minifies main Sass files to CSS.
|
||||
*
|
||||
* @todo Add deep merge of `postcssOptions` to better support customization
|
||||
* of default processor options.
|
||||
*
|
||||
* @async
|
||||
* @param {object} [sassOptions=null] - Customize the Sass render API options.
|
||||
* If `null`, default production options are used.
|
||||
* @param {object|boolean} [postcssOptions=null] - Customize the PostCSS processor API options.
|
||||
* If `null`, default production options are used.
|
||||
* If `false`, PostCSS processing will be ignored.
|
||||
* @return {Promise}
|
||||
*/
|
||||
export default async function compileStyles() {
|
||||
export default async function compileStyles(sassOptions = null, postcssOptions = null) {
|
||||
if (sassOptions == null) {
|
||||
sassOptions = productionSassOptions;
|
||||
} else if (
|
||||
sassOptions !== developmentSassOptions &&
|
||||
sassOptions !== productionSassOptions
|
||||
) {
|
||||
sassOptions = Object.assign({}, defaultSassOptions, sassOptions);
|
||||
}
|
||||
|
||||
if (postcss) {
|
||||
if (postcssOptions == null) {
|
||||
postcssOptions = productionPostCSSOptions;
|
||||
} else if (
|
||||
postcssOptions !== false &&
|
||||
postcssOptions !== developmentSassOptions &&
|
||||
postcssOptions !== productionSassOptions
|
||||
) {
|
||||
postcssOptions = Object.assign({}, defaultPostCSSOptions, postcssOptions);
|
||||
}
|
||||
}
|
||||
|
||||
loconfig.tasks.styles.forEach(async ({
|
||||
infile,
|
||||
outfile
|
||||
@@ -30,25 +108,26 @@ export default async function compileStyles() {
|
||||
infile = template(infile);
|
||||
outfile = template(outfile);
|
||||
|
||||
let result = await sassRender({
|
||||
let result = await sassRender(Object.assign({}, sassOptions, {
|
||||
file: infile,
|
||||
omitSourceMapUrl: true,
|
||||
outFile: outfile,
|
||||
outputStyle: 'compressed',
|
||||
sourceMap: true,
|
||||
sourceMapContents: true
|
||||
});
|
||||
}));
|
||||
|
||||
if (postcss) {
|
||||
result = await postcss.process(result.css, {
|
||||
if (postcss && postcssOptions) {
|
||||
if (typeof postcssProcessor === 'undefined') {
|
||||
postcssProcessor = createPostCSSProcessor(
|
||||
postcssPluginsMap,
|
||||
postcssOptions
|
||||
);
|
||||
}
|
||||
|
||||
result = await postcssProcessor.process(
|
||||
result.css,
|
||||
Object.assign({}, postcssOptions.processor, {
|
||||
from: outfile,
|
||||
to: outfile,
|
||||
map: {
|
||||
annotation: false,
|
||||
inline: false,
|
||||
sourcesContent: true
|
||||
}
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
if (result.warnings) {
|
||||
const warnings = result.warnings();
|
||||
@@ -103,3 +182,32 @@ export default async function compileStyles() {
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a PostCSS Processor with the given plugins and options.
|
||||
*
|
||||
* @param {array<(function|object)>|object<string, (function|object)>} pluginsListOrMap -
|
||||
* A list or map of plugins.
|
||||
* If a map of plugins, the plugin name looks up `options`.
|
||||
* @param {object} options - The PostCSS options.
|
||||
*/
|
||||
function createPostCSSProcessor(pluginsListOrMap, options)
|
||||
{
|
||||
let plugins;
|
||||
|
||||
if (Array.isArray(pluginsListOrMap)) {
|
||||
plugins = pluginsListOrMap;
|
||||
} else {
|
||||
plugins = [];
|
||||
|
||||
for (let [ name, plugin ] of Object.entries(pluginsListOrMap)) {
|
||||
if (name in options) {
|
||||
plugin = plugin[name](options[name]);
|
||||
}
|
||||
|
||||
plugins.push(plugin);
|
||||
}
|
||||
}
|
||||
|
||||
return postcss(plugins);
|
||||
}
|
||||
|
||||
@@ -5,13 +5,48 @@ import template from '../utils/template.js';
|
||||
import { basename } from 'node:path';
|
||||
import mixer from 'svg-mixer';
|
||||
|
||||
/**
|
||||
* @const {object} defaultMixerOptions - The default shared Mixer options.
|
||||
* @const {object} developmentMixerOptions - The predefined Mixer options for development.
|
||||
* @const {object} productionMixerOptions - The predefined Mixer options for production.
|
||||
*/
|
||||
export const defaultMixerOptions = {
|
||||
spriteConfig: {
|
||||
usages: false,
|
||||
},
|
||||
};
|
||||
export const developmentMixerOptions = Object.assign({}, defaultMixerOptions);
|
||||
export const productionMixerOptions = Object.assign({}, defaultMixerOptions);
|
||||
|
||||
/**
|
||||
* @const {object} developmentSVGsArgs - The predefined `compileSVGs()` options for development.
|
||||
* @const {object} productionSVGsArgs - The predefined `compileSVGs()` options for production.
|
||||
*/
|
||||
export const developmentSVGsArgs = [
|
||||
developmentMixerOptions,
|
||||
];
|
||||
export const productionSVGsArgs = [
|
||||
productionMixerOptions,
|
||||
];
|
||||
|
||||
/**
|
||||
* Generates and transforms SVG spritesheets.
|
||||
*
|
||||
* @async
|
||||
* @param {object} [mixerOptions=null] - Customize the Mixer API options.
|
||||
* If `null`, default production options are used.
|
||||
* @return {Promise}
|
||||
*/
|
||||
export default async function compileSVGs() {
|
||||
export default async function compileSVGs(mixerOptions = null) {
|
||||
if (mixerOptions == null) {
|
||||
mixerOptions = productionMixerOptions;
|
||||
} else if (
|
||||
mixerOptions !== developmentMixerOptions &&
|
||||
mixerOptions !== productionMixerOptions
|
||||
) {
|
||||
mixerOptions = Object.assign({}, defaultMixerOptions, mixerOptions);
|
||||
}
|
||||
|
||||
loconfig.tasks.svgs.forEach(async ({
|
||||
includes,
|
||||
outfile
|
||||
@@ -25,11 +60,7 @@ export default async function compileSVGs() {
|
||||
includes = includes.map((path) => template(path));
|
||||
outfile = template(outfile);
|
||||
|
||||
const result = await mixer(includes, {
|
||||
spriteConfig: {
|
||||
usages: false
|
||||
}
|
||||
});
|
||||
const result = await mixer(includes, mixerOptions);
|
||||
|
||||
await result.write(outfile);
|
||||
|
||||
|
||||
@@ -1,14 +1,28 @@
|
||||
/**
|
||||
* @file If available, returns the PostCSS processor with any plugins.
|
||||
* @file If available, returns the PostCSS Processor creator and
|
||||
* any the Autoprefixer PostCSS plugin.
|
||||
*/
|
||||
|
||||
try {
|
||||
var { default: postcss } = await import('postcss');
|
||||
let { default: autoprefixer } = await import('autoprefixer');
|
||||
let postcss, autoprefixer;
|
||||
|
||||
postcss = postcss([ autoprefixer ]);
|
||||
try {
|
||||
postcss = await import('postcss');
|
||||
postcss = postcss.default;
|
||||
|
||||
autoprefixer = await import('autoprefixer');
|
||||
autoprefixer = autoprefixer.default;
|
||||
} catch (err) {
|
||||
postcss = null;
|
||||
autoprefixer = null;
|
||||
}
|
||||
|
||||
export default postcss;
|
||||
export const pluginsList = [
|
||||
autoprefixer,
|
||||
];
|
||||
export const pluginsMap = {
|
||||
'autoprefixer': autoprefixer,
|
||||
};
|
||||
export {
|
||||
autoprefixer
|
||||
};
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import loconfig from '../loconfig.json';
|
||||
import concatFiles from './tasks/concats.js';
|
||||
import compileScripts from './tasks/scripts.js';
|
||||
import compileStyles from './tasks/styles.js' ;
|
||||
import compileSVGs from './tasks/svgs.js';
|
||||
import compileScripts, { developmentScriptsArgs } from './tasks/scripts.js';
|
||||
import compileStyles, { developmentStylesArgs } from './tasks/styles.js' ;
|
||||
import compileSVGs, { developmentSVGsArgs } from './tasks/svgs.js';
|
||||
import template from './utils/template.js';
|
||||
import server from 'browser-sync';
|
||||
import { join } from 'node:path';
|
||||
@@ -30,9 +30,9 @@ server.init(serverConfig);
|
||||
// Build scripts, compile styles, concat files,
|
||||
// and generate spritesheets on first hit
|
||||
concatFiles();
|
||||
compileScripts();
|
||||
compileStyles();
|
||||
compileSVGs();
|
||||
compileScripts(...developmentScriptsArgs);
|
||||
compileStyles(...developmentStylesArgs);
|
||||
compileSVGs(...developmentSVGsArgs);
|
||||
|
||||
// and call any methods on it.
|
||||
server.watch(
|
||||
@@ -50,7 +50,7 @@ server.watch(
|
||||
join(paths.scripts.src, '**/*.js'),
|
||||
]
|
||||
).on('change', () => {
|
||||
compileScripts();
|
||||
compileScripts(...developmentScriptsArgs);
|
||||
});
|
||||
|
||||
// Watch concats
|
||||
@@ -69,7 +69,7 @@ server.watch(
|
||||
join(paths.styles.src, '**/*.scss'),
|
||||
]
|
||||
).on('change', () => {
|
||||
compileStyles();
|
||||
compileStyles(...developmentStylesArgs);
|
||||
});
|
||||
|
||||
// Watch svgs
|
||||
@@ -78,5 +78,5 @@ server.watch(
|
||||
join(paths.svgs.src, '*.svg'),
|
||||
]
|
||||
).on('change', () => {
|
||||
compileSVGs();
|
||||
compileSVGs(...developmentSVGsArgs);
|
||||
});
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user