1
0
mirror of https://github.com/locomotivemtl/locomotive-boilerplate.git synced 2026-01-15 00:55:08 +08:00
Files
locomotive-boilerplate/build/tasks/concats.js
Chauncey McAskill c9056b27d8 Add support for removing duplicates in concats.js
Added:
- Argument `concatOptions` to `concatFiles()` function to customize concatenation.
- Option 'removeDuplicates' to `concatOptions` to remove duplicate paths from the array of globbed paths. Defaults to `true`.

The 'removeDuplicates' is useful for customizing the order of files to concatenate, in which globbing will usually sort paths alphabetically.

This option is convenient when the installed glob library does not support removing duplicates on their own (feature supported in 'fast-glob' and 'glob').

Example:

```
/assets/scripts/vendors/a.js
/assets/scripts/vendors/b.js
/assets/scripts/vendors/c.js
/assets/scripts/vendors/d.js
```

```json
"concats": [
    {
        "includes": [
            "{% paths.scripts.src %}/vendors/c.js",
            "{% paths.scripts.src %}/vendors/*.js"
        ],
        "outfile": "{% paths.scripts.dest %}/vendors.js"
    }
]
```
2022-02-08 14:46:34 -05:00

125 lines
4.1 KiB
JavaScript

import loconfig from '../../loconfig.json';
import glob from '../utils/glob.js';
import message from '../utils/message.js';
import notification from '../utils/notification.js';
import template from '../utils/template.js';
import concat from 'concat';
import {
basename,
normalize,
} from 'node:path';
/**
* @const {object} defaultGlobOptions - The default shared glob options.
* @const {object} developmentGlobOptions - The predefined glob options for development.
* @const {object} productionGlobOptions - The predefined glob options for production.
*/
export const defaultGlobOptions = {
};
export const developmentGlobOptions = Object.assign({}, defaultGlobOptions);
export const productionGlobOptions = Object.assign({}, defaultGlobOptions);
/**
* @typedef {object} ConcatOptions
* @property {boolean} removeDuplicates - Removes duplicate paths from
* the array of matching files and folders.
* Only the first occurrence of each path is kept.
*/
/**
* @const {ConcatOptions} defaultConcatOptions - The default shared concatenation options.
* @const {ConcatOptions} developmentConcatOptions - The predefined concatenation options for development.
* @const {ConcatOptions} productionConcatOptions - The predefined concatenation options for production.
*/
export const defaultConcatOptions = {
removeDuplicates: true,
};
export const developmentConcatOptions = Object.assign({}, defaultConcatOptions);
export const productionConcatOptions = Object.assign({}, defaultConcatOptions);
/**
* @const {object} developmentConcatFilesArgs - The predefined `concatFiles()` options for development.
* @const {object} productionConcatFilesArgs - The predefined `concatFiles()` options for production.
*/
export const developmentConcatFilesArgs = [
developmentGlobOptions,
developmentConcatOptions,
];
export const productionConcatFilesArgs = [
productionGlobOptions,
productionConcatOptions,
];
/**
* Concatenates groups of files.
*
* @todo Add support for minification.
*
* @async
* @param {object} [globOptions=null] - Customize the glob options.
* If `null`, default production options are used.
* @param {object} [concatOptions=null] - Customize the concatenation options.
* If `null`, default production options are used.
* @return {Promise}
*/
export default async function concatFiles(globOptions = null, concatOptions = null) {
if (globOptions == null) {
globOptions = productionGlobOptions;
} else if (
globOptions !== developmentGlobOptions &&
globOptions !== productionGlobOptions
) {
globOptions = Object.assign({}, defaultGlobOptions, globOptions);
}
if (concatOptions == null) {
concatOptions = productionConcatOptions;
} else if (
concatOptions !== developmentConcatOptions &&
concatOptions !== productionConcatOptions
) {
concatOptions = Object.assign({}, defaultConcatOptions, concatOptions);
}
loconfig.tasks.concats.forEach(async ({
includes,
outfile,
label = null
}) => {
if (!label) {
label = basename(outfile || 'undefined');
}
const timeLabel = `${label} concatenated in`;
console.time(timeLabel);
try {
includes = includes.map((path) => template(path));
outfile = template(outfile);
let files = await glob(includes, globOptions);
if (concatOptions.removeDuplicates) {
files = files.map((path) => normalize(path));
files = [ ...new Set(files) ];
}
await concat(files, outfile);
if (files.length) {
message(`${label} concatenated`, 'success', timeLabel);
} else {
message(`${label} is empty`, 'notice', timeLabel);
}
} catch (err) {
message(`Error concatenating ${label}`, 'error');
message(err);
notification({
title: `${label} concatenation failed 🚨`,
message: `${err.name}: ${err.message}`
});
}
});
};