mirror of
https://github.com/locomotivemtl/locomotive-boilerplate.git
synced 2026-01-15 00:55:08 +08:00
Refactor build tasks
Decouple static "main" keys in mconfig.json and refactor tasks to support many output files. Added: - scripts.js: Array of output files (such as 'app.js') to iterate over to bundle JS files. - styles.js: Array of input files (such as 'main.css' and 'critical.css') to iterate over to compile Sass files. - svgs.js: Array of output files (such as 'sprite.svg') to iterate over to compile SVG spritesheets. Changed: - mconfig.json: Decouple entry points to individual tasks to allow for more flexibility in projects. - concat.js: Refactor function to use promises to build list of JS files to concatenate. - message.js: Replace if statements with switch for improved readability. - message.js: If timerID provided with "waiting" type, log time. - watch.js: Change CSS and JS reload watch paths to include all files. - Sorted imports by path.
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
import { buildScripts } from './scripts.js';
|
||||
import { concatVendors } from './concat.js';
|
||||
import { compileScripts } from './scripts.js';
|
||||
import { compileStyles } from './styles.js' ;
|
||||
import { generateSpriteSVG } from './svgs.js' ;
|
||||
import { compileSVGs } from './svgs.js' ;
|
||||
|
||||
buildScripts();
|
||||
concatVendors();
|
||||
compileScripts();
|
||||
compileStyles();
|
||||
generateSpriteSVG();
|
||||
compileSVGs();
|
||||
|
||||
@@ -1,27 +1,57 @@
|
||||
import paths from '../mconfig.json';
|
||||
import notification from './notification.js';
|
||||
import message from './utils/message.js';
|
||||
import fs from 'fs';
|
||||
import concat from 'concat';
|
||||
import fs from 'fs';
|
||||
|
||||
/**
|
||||
* Concatenates third-party JavaScript files.
|
||||
*/
|
||||
export function concatVendors() {
|
||||
console.time('Concat in');
|
||||
const filename = 'vendors.js';
|
||||
const outfile = paths.scripts.dest + filename;
|
||||
const external = [
|
||||
// Add files in node_modules example:
|
||||
// 'node_modules/gsap/dist/gsap.min.js',
|
||||
];
|
||||
|
||||
// Get all files in scripts/vendors/
|
||||
const files = fs.readdirSync(paths.scripts.vendors.src);
|
||||
const timeLabel = `${filename} concatenated in`;
|
||||
console.time(timeLabel);
|
||||
|
||||
// Exclude files that are not JavaScript
|
||||
var jsFiles = files.filter((file) => {
|
||||
return file.includes('.js');
|
||||
// Get all files in `scripts/vendors/`
|
||||
fs.readdir(paths.scripts.vendors.src, (err, files) => {
|
||||
if (err) {
|
||||
message(`Error preparing ${filename}`, 'error');
|
||||
message(err);
|
||||
|
||||
notification({
|
||||
title: `${filename} concatenation failed 🚨`,
|
||||
message: `${err.name}: ${e.message}`
|
||||
});
|
||||
}
|
||||
|
||||
if (files.length) {
|
||||
// Exclude files that are not JavaScript
|
||||
files = files.filter((file) => file.includes('.js'));
|
||||
|
||||
// Prepend absolute path
|
||||
files = files.map((file) => paths.scripts.vendors.src + file);
|
||||
}
|
||||
|
||||
if (external.length) {
|
||||
files = files.concat(external);
|
||||
}
|
||||
|
||||
concat(files, outfile).then(() => {
|
||||
message(`${filename} concatenated'`, 'success', timeLabel);
|
||||
}).catch((err) => {
|
||||
message(`Error concatenating ${filename}`, 'error');
|
||||
message(err);
|
||||
|
||||
notification({
|
||||
title: `${filename} concatenation failed 🚨`,
|
||||
message: `${err.name}: ${err.message}`
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Prepend absolute path
|
||||
jsFiles = jsFiles.map((file) => {
|
||||
return `${paths.scripts.vendors.src + file}`;
|
||||
});
|
||||
// add files in node_modules example:
|
||||
// jsFiles.push('node_modules/gsap/dist/gsap.min.js');
|
||||
|
||||
concat(jsFiles, paths.scripts.dest + paths.scripts.vendors.main + '.js').then(() => {
|
||||
message('Vendors concatenated', 'success', 'Concat in');
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ import notifier from 'node-notifier';
|
||||
|
||||
export default function notification({ title, message }) {
|
||||
notifier.notify({
|
||||
title: title,
|
||||
message: message,
|
||||
title,
|
||||
message,
|
||||
icon: 'https://user-images.githubusercontent.com/4596862/54868065-c2aea200-4d5e-11e9-9ce3-e0013c15f48c.png'
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,29 +1,40 @@
|
||||
import esbuild from 'esbuild';
|
||||
import paths from '../mconfig.json';
|
||||
import message from './utils/message.js';
|
||||
import notification from './notification.js';
|
||||
import message from './utils/message.js';
|
||||
import esbuild from 'esbuild';
|
||||
|
||||
export function buildScripts() {
|
||||
console.time('JS built in');
|
||||
/**
|
||||
* Bundles and minifies main JavaScript files.
|
||||
*/
|
||||
export function compileScripts() {
|
||||
[
|
||||
'app.js',
|
||||
].forEach((filename) => {
|
||||
const includes = [ paths.scripts.src + filename ];
|
||||
const outfile = paths.scripts.dest + filename;
|
||||
|
||||
esbuild.build({
|
||||
entryPoints: [ paths.scripts.src + paths.scripts.main + '.js' ],
|
||||
bundle: true,
|
||||
minify: true,
|
||||
sourcemap: true,
|
||||
color: true,
|
||||
logLevel: 'error',
|
||||
target: [ 'es2015' ],
|
||||
outfile: paths.scripts.dest + paths.scripts.main + '.js'
|
||||
}).catch((e) => {
|
||||
// errors managments (already done in esbuild)
|
||||
const timeLabel = `${filename} compiled in`;
|
||||
console.time(timeLabel);
|
||||
|
||||
notification({
|
||||
title: 'Javascript built failed 🚨',
|
||||
message: `${e.errors[0].text} in ${e.errors[0].location.file} line ${e.errors[0].location.line}`
|
||||
esbuild.build({
|
||||
entryPoints: includes,
|
||||
bundle: true,
|
||||
minify: true,
|
||||
sourcemap: true,
|
||||
color: true,
|
||||
logLevel: 'error',
|
||||
target: [
|
||||
'es2015',
|
||||
],
|
||||
outfile
|
||||
}).catch((err) => {
|
||||
// errors managments (already done in esbuild)
|
||||
notification({
|
||||
title: `${filename} compilation failed 🚨`,
|
||||
message: `${err.errors[0].text} in ${err.errors[0].location.file} line ${err.errors[0].location.line}`
|
||||
});
|
||||
}).then(() => {
|
||||
message(`${filename} compiled`, 'success', timeLabel);
|
||||
});
|
||||
|
||||
}).then(() => {
|
||||
message('Javascript built','success', 'JS built in')
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,56 +1,54 @@
|
||||
import fs from 'fs';
|
||||
import sass from 'node-sass';
|
||||
import paths from '../mconfig.json';
|
||||
import fs from 'fs';
|
||||
import message from './utils/message.js';
|
||||
import notification from './notification.js';
|
||||
|
||||
/**
|
||||
* Compiles and minifies main Sass files to CSS.
|
||||
*/
|
||||
export function compileStyles() {
|
||||
console.time('Styles built in');
|
||||
[
|
||||
'critical',
|
||||
'main',
|
||||
].forEach((name) => {
|
||||
const infile = paths.styles.src + name + '.scss';
|
||||
const outfile = paths.styles.dest + name + '.css';
|
||||
|
||||
// Compile main scss
|
||||
sass.render({
|
||||
file: paths.styles.src + paths.styles.main + '.scss',
|
||||
outFile: paths.styles.dest + paths.styles.main + '.css',
|
||||
outputStyle: 'compressed',
|
||||
sourceMap: true
|
||||
}, (error, result) => {
|
||||
if (error) {
|
||||
message('Error compiling main.scss', 'error');
|
||||
console.log(error.formatted);
|
||||
const timeLabel = `${name}.css compiled in`;
|
||||
console.time(timeLabel);
|
||||
|
||||
notification({
|
||||
title: 'main.scss compilation failed 🚨',
|
||||
message: `${error.formatted}`
|
||||
sass.render({
|
||||
file: infile,
|
||||
outFile: outfile,
|
||||
outputStyle: 'compressed',
|
||||
sourceMap: true
|
||||
}, (err, result) => {
|
||||
if (err) {
|
||||
message(`Error compiling ${name}.scss`, 'error');
|
||||
message(err.formatted);
|
||||
|
||||
notification({
|
||||
title: `${name}.scss compilation failed 🚨`,
|
||||
message: err.formatted
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
fs.writeFile(outfile, result.css, (err) => {
|
||||
if (err) {
|
||||
message(`Error compiling ${name}.scss`, 'error');
|
||||
message(err.formatted);
|
||||
|
||||
notification({
|
||||
title: `${name}.scss compilation failed 🚨`,
|
||||
message: `Could not save stylesheet to ${name}.css`
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
message(`${name}.css compiled`, 'success', timeLabel);
|
||||
});
|
||||
} else {
|
||||
message('Styles built', 'success', 'Styles built in');
|
||||
}
|
||||
|
||||
if (!error){
|
||||
// No errors during the compilation, write this result on the disk
|
||||
fs.writeFile(paths.styles.dest + paths.styles.main + '.css', result.css, (err) => {});
|
||||
}
|
||||
});
|
||||
|
||||
console.time('Critical style built in');
|
||||
|
||||
// Compile critical scss
|
||||
sass.render({
|
||||
file: paths.styles.src + paths.styles.critical + '.scss',
|
||||
outFile: paths.styles.dest + paths.styles.critical + '.css',
|
||||
outputStyle: 'compressed',
|
||||
sourceMap: true
|
||||
}, (error, result) => {
|
||||
if (error) {
|
||||
message('Error compiling critical.scss', 'error');
|
||||
console.log(error);
|
||||
} else {
|
||||
message('Critical style built', 'success', 'Critical style built in');
|
||||
}
|
||||
|
||||
if (!error){
|
||||
// No errors during the compilation, write this result on the disk
|
||||
fs.writeFile(paths.styles.dest + paths.styles.critical + '.css', result.css, (err) => {});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,19 +1,42 @@
|
||||
import mixer from 'svg-mixer';
|
||||
import paths from '../mconfig.json';
|
||||
import notification from './notification.js';
|
||||
import message from './utils/message.js';
|
||||
import mixer from 'svg-mixer';
|
||||
|
||||
export function generateSpriteSVG() {
|
||||
console.time('Sprite generated in');
|
||||
/**
|
||||
* Generates and transforms SVG spritesheets.
|
||||
*/
|
||||
export function compileSVGs() {
|
||||
[
|
||||
{
|
||||
includes: [ paths.svgs.src + '*.svg' ],
|
||||
filename: 'sprite.svg'
|
||||
},
|
||||
].forEach(({
|
||||
includes,
|
||||
filename
|
||||
}) => {
|
||||
const outfile = paths.scripts.dest + filename;
|
||||
|
||||
// Write sprite content on disk
|
||||
mixer([
|
||||
paths.svgs.src + '*.svg'
|
||||
], {
|
||||
spriteConfig: {
|
||||
usages: false
|
||||
}
|
||||
}).then((result) => {
|
||||
result.write(paths.svgs.dest + 'sprite.svg');
|
||||
message('SVG Sprite generated', 'success', 'Sprite generated in');
|
||||
const timeLabel = `${filename} compiled in`;
|
||||
console.time(timeLabel);
|
||||
|
||||
mixer(includes, {
|
||||
spriteConfig: {
|
||||
usages: false
|
||||
}
|
||||
}).then((result) => {
|
||||
result.write(outfile).then(() => {
|
||||
message(`${filename} compiled`, 'success', timeLabel);
|
||||
});
|
||||
}).catch((err) => {
|
||||
message(`Error compiling ${filename}`, 'error');
|
||||
message(err);
|
||||
|
||||
notification({
|
||||
title: `${filename} compilation failed 🚨`,
|
||||
message: `${err.name}: ${err.message}`
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,19 +1,31 @@
|
||||
import kleur from 'kleur';
|
||||
|
||||
export default function message(text, type, timerId) {
|
||||
if (type === 'success') {
|
||||
console.log(kleur.bgGreen().black(`${text} ✅`));
|
||||
export default function message(text, type, timerID) {
|
||||
switch (type) {
|
||||
case 'success':
|
||||
console.log(kleur.bgGreen().black(`✅ ${text}`));
|
||||
|
||||
if (timerId !== undefined) {
|
||||
console.timeEnd(timerId)
|
||||
}
|
||||
} else if (type === 'error') {
|
||||
console.log(kleur.red().underline(`${text} ❌`));
|
||||
} else if (type === 'waiting') {
|
||||
console.log(kleur.blue().italic(`${text} ⏱`));
|
||||
} else {
|
||||
console.log(text);
|
||||
if (timerID !== undefined) {
|
||||
console.timeEnd(timerID);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'error':
|
||||
console.log(kleur.red().underline(`❌ ${text}`));
|
||||
break;
|
||||
|
||||
case 'waiting':
|
||||
console.log(kleur.blue().italic(`⏱ ${text}`));
|
||||
|
||||
if (timerID !== undefined) {
|
||||
console.timeLog(timerID);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
console.log(text);
|
||||
break;
|
||||
}
|
||||
|
||||
console.log('');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { buildScripts } from './scripts.js';
|
||||
import { concatVendors } from './concat.js';
|
||||
import { compileStyles } from './styles.js' ;
|
||||
import { generateSpriteSVG } from './svgs.js';
|
||||
import paths from '../mconfig.json';
|
||||
import { concatVendors } from './concat.js';
|
||||
import { compileScripts } from './scripts.js';
|
||||
import { compileStyles } from './styles.js' ;
|
||||
import { compileSVGs } from './svgs.js';
|
||||
import server from 'browser-sync';
|
||||
|
||||
const serverConfig = {
|
||||
@@ -24,35 +24,34 @@ if (typeof paths.url === 'string' && paths.url.length > 0) {
|
||||
server.init(serverConfig);
|
||||
|
||||
// Build scripts, compile styles, concat vendors and generate the svgs sprite on first hit
|
||||
buildScripts();
|
||||
concatVendors();
|
||||
compileScripts();
|
||||
compileStyles();
|
||||
generateSpriteSVG();
|
||||
compileSVGs();
|
||||
|
||||
// and call any methods on it.
|
||||
server.watch(
|
||||
[
|
||||
paths.views.src,
|
||||
paths.scripts.dest + paths.scripts.main + '.js',
|
||||
paths.scripts.dest + paths.scripts.vendors.main + '.js',
|
||||
paths.styles.dest + paths.styles.main + '.css',
|
||||
paths.svgs.dest + 'sprite.svg'
|
||||
paths.scripts.dest + '*.js',
|
||||
paths.styles.dest + '*.css',
|
||||
paths.svgs.dest + '*.svg',
|
||||
]
|
||||
).on('change', server.reload);
|
||||
|
||||
// Watch scripts
|
||||
server.watch(
|
||||
[
|
||||
paths.scripts.src + '**/*.js'
|
||||
paths.scripts.src + '**/*.js',
|
||||
]
|
||||
).on('change', () => {
|
||||
buildScripts();
|
||||
compileScripts();
|
||||
});
|
||||
|
||||
// Watch scripts vendors
|
||||
server.watch(
|
||||
[
|
||||
paths.scripts.vendors.src + '*.js'
|
||||
paths.scripts.vendors.src + '*.js',
|
||||
]
|
||||
).on('change', () => {
|
||||
concatVendors();
|
||||
@@ -61,7 +60,7 @@ server.watch(
|
||||
// Watch styles
|
||||
server.watch(
|
||||
[
|
||||
paths.styles.src + '**/*.scss'
|
||||
paths.styles.src + '**/*.scss',
|
||||
]
|
||||
).on('change', () => {
|
||||
compileStyles();
|
||||
@@ -70,8 +69,8 @@ server.watch(
|
||||
// Watch svgs
|
||||
server.watch(
|
||||
[
|
||||
paths.svgs.src + '*.svg'
|
||||
paths.svgs.src + '*.svg',
|
||||
]
|
||||
).on('change', () => {
|
||||
generateSpriteSVG();
|
||||
compileSVGs();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user