mirror of
https://github.com/locomotivemtl/locomotive-boilerplate.git
synced 2026-01-15 00:55:08 +08:00
Compare commits
6 Commits
mcaskill/j
...
mcaskill/b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f4087b7859 | ||
|
|
b19c18b18c | ||
|
|
db85740a18 | ||
|
|
5c24fabaa2 | ||
|
|
9e3d304654 | ||
|
|
6ded72bc79 |
@@ -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,9 @@
|
||||
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 +12,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 +110,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, {
|
||||
from: outfile,
|
||||
to: outfile,
|
||||
map: {
|
||||
annotation: false,
|
||||
inline: false,
|
||||
sourcesContent: true
|
||||
}
|
||||
});
|
||||
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,
|
||||
})
|
||||
);
|
||||
|
||||
if (result.warnings) {
|
||||
const warnings = result.warnings();
|
||||
@@ -103,3 +184,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);
|
||||
}
|
||||
|
||||
@@ -1,17 +1,100 @@
|
||||
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 { basename } from 'node:path';
|
||||
import mixer from 'svg-mixer';
|
||||
import {
|
||||
mkdir,
|
||||
readFile,
|
||||
writeFile
|
||||
} from 'node:fs/promises';
|
||||
import {
|
||||
basename,
|
||||
dirname,
|
||||
join,
|
||||
resolve
|
||||
} from 'node:path';
|
||||
import SVGSpriter from 'svg-sprite';
|
||||
import Vinyl from 'vinyl';
|
||||
|
||||
/**
|
||||
* @const {object} defaultSVOOptions - The default shared SVO options.
|
||||
* @const {object} developmentSVOOptions - The predefined SVO options for development.
|
||||
* @const {object} productionSVOOptions - The predefined SVO options for production.
|
||||
*/
|
||||
export const defaultSVOOptions = {
|
||||
};
|
||||
export const developmentSVOOptions = Object.assign({}, defaultSVOOptions);
|
||||
export const productionSVOOptions = Object.assign({}, defaultSVOOptions);
|
||||
|
||||
/**
|
||||
* @const {object} defaultSVGSpriterOptions - The default shared SVGSpriter options.
|
||||
* @const {object} developmentSVGSpriterOptions - The predefined SVGSpriter options for development.
|
||||
* @const {object} productionSVGSpriterOptions - The predefined SVGSpriter options for production.
|
||||
*/
|
||||
export const defaultSVGSpriterOptions = {
|
||||
mode: {},
|
||||
shape: {
|
||||
transform: [],
|
||||
},
|
||||
svg: {
|
||||
doctypeDeclaration: false,
|
||||
xmlDeclaration: false,
|
||||
},
|
||||
};
|
||||
export const developmentSVGSpriterOptions = Object.assign({}, defaultSVGSpriterOptions);
|
||||
export const productionSVGSpriterOptions = Object.assign({}, defaultSVGSpriterOptions);
|
||||
|
||||
/**
|
||||
* @const {object} developmentSVGsArgs - The predefined `compileSVGs()` options for development.
|
||||
* @const {object} productionSVGsArgs - The predefined `compileSVGs()` options for production.
|
||||
*/
|
||||
export const developmentSVGsArgs = [
|
||||
developmentSVGSpriterOptions,
|
||||
developmentSVOOptions,
|
||||
];
|
||||
export const productionSVGsArgs = [
|
||||
productionSVGSpriterOptions,
|
||||
productionSVOOptions,
|
||||
];
|
||||
|
||||
/**
|
||||
* Generates and transforms SVG spritesheets.
|
||||
*
|
||||
* @async
|
||||
* @param {object} [spriterOptions=null] - Customize the SVGSpriter API options.
|
||||
* If `null`, default production options are used.
|
||||
* @param {object} [svgoOptions=null] - Customize the SVGO API options.
|
||||
* If `null`, default production options are used.
|
||||
* @return {Promise}
|
||||
*/
|
||||
export default async function compileSVGs() {
|
||||
export default async function compileSVGs(spriterOptions = null, svgoOptions = null) {
|
||||
if (spriterOptions == null) {
|
||||
spriterOptions = productionSVGSpriterOptions;
|
||||
} else if (
|
||||
spriterOptions !== developmentSVGSpriterOptions &&
|
||||
spriterOptions !== productionSVGSpriterOptions
|
||||
) {
|
||||
spriterOptions = Object.assign({}, defaultSVGSpriterOptions, spriterOptions);
|
||||
}
|
||||
|
||||
if (svgoOptions == null) {
|
||||
svgoOptions = productionSVOOptions;
|
||||
} else if (
|
||||
svgoOptions !== developmentSVOOptions &&
|
||||
svgoOptions !== productionSVOOptions
|
||||
) {
|
||||
svgoOptions = Object.assign({}, defaultSVOOptions, svgoOptions);
|
||||
}
|
||||
|
||||
if (svgoOptions) {
|
||||
spriterOptions.shape.transform.push({
|
||||
svgo: svgoOptions,
|
||||
});
|
||||
}
|
||||
|
||||
const svgSpriter = new SVGSpriter(spriterOptions);
|
||||
|
||||
loconfig.tasks.svgs.forEach(async ({
|
||||
includes,
|
||||
outfile
|
||||
@@ -25,14 +108,22 @@ export default async function compileSVGs() {
|
||||
includes = includes.map((path) => template(path));
|
||||
outfile = template(outfile);
|
||||
|
||||
const result = await mixer(includes, {
|
||||
spriteConfig: {
|
||||
usages: false
|
||||
svgSpriter.compile({
|
||||
symbol: {
|
||||
dest: dirname(outfile),
|
||||
sprite: filename,
|
||||
},
|
||||
}, (error, result) => {
|
||||
for (const mode in result) {
|
||||
for (const resource in result[mode]) {
|
||||
await mkdir(path.dirname(result[mode][resource].path), {
|
||||
recursive: true
|
||||
});
|
||||
await writeFile(result[mode][resource].path, result[mode][resource].contents);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await result.write(outfile);
|
||||
|
||||
message(`${filename} compiled`, 'success', timeLabel);
|
||||
} catch (err) {
|
||||
message(`Error compiling ${filename}`, 'error');
|
||||
|
||||
@@ -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;
|
||||
postcss = null;
|
||||
autoprefixer = null;
|
||||
}
|
||||
|
||||
export default postcss;
|
||||
export const pluginsList = [
|
||||
autoprefixer,
|
||||
];
|
||||
export const pluginsMap = {
|
||||
'autoprefixer': autoprefixer,
|
||||
};
|
||||
export {
|
||||
autoprefixer
|
||||
};
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
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 +36,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 +56,7 @@ server.watch(
|
||||
join(paths.scripts.src, '**/*.js'),
|
||||
]
|
||||
).on('change', () => {
|
||||
compileScripts();
|
||||
compileScripts(...developmentScriptsArgs);
|
||||
});
|
||||
|
||||
// Watch concats
|
||||
@@ -69,14 +75,14 @@ server.watch(
|
||||
join(paths.styles.src, '**/*.scss'),
|
||||
]
|
||||
).on('change', () => {
|
||||
compileStyles();
|
||||
compileStyles(...developmentStylesArgs);
|
||||
});
|
||||
|
||||
// Watch svgs
|
||||
server.watch(
|
||||
[
|
||||
join(paths.svgs.src, '*.svg'),
|
||||
join(paths.svgs.src, '**/*.svg'),
|
||||
]
|
||||
).on('change', () => {
|
||||
compileSVGs();
|
||||
compileSVGs(...developmentSVGsArgs);
|
||||
});
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
"svgs": [
|
||||
{
|
||||
"includes": [
|
||||
"{% paths.svgs.src %}/*.svg"
|
||||
"{% paths.svgs.src %}/**/*.svg"
|
||||
],
|
||||
"outfile": "{% paths.svgs.dest %}/sprite.svg"
|
||||
}
|
||||
|
||||
6684
package-lock.json
generated
6684
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
10
package.json
10
package.json
@@ -21,15 +21,15 @@
|
||||
"svg4everybody": "^2.1.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^10.3.7",
|
||||
"browser-sync": "^2.26.13",
|
||||
"autoprefixer": "^10.4.0",
|
||||
"browser-sync": "^2.27.7",
|
||||
"concat": "^1.0.3",
|
||||
"esbuild": "^0.13.4",
|
||||
"esbuild": "^0.13.12",
|
||||
"kleur": "^4.1.4",
|
||||
"node-notifier": "^10.0.0",
|
||||
"node-sass": "^6.0.1",
|
||||
"postcss": "^8.3.9",
|
||||
"svg-mixer": "^2.3.14",
|
||||
"postcss": "^8.3.11",
|
||||
"svg-sprite": "^1.5.3",
|
||||
"tiny-glob": "^0.2.9"
|
||||
}
|
||||
}
|
||||
|
||||
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