|
const fs = require('fs') |
|
const util = require('util') |
|
const autoprefixer = require('autoprefixer') |
|
const browserSync = require('browser-sync').create() |
|
const postcss = require('postcss') |
|
const sass = require('sass') |
|
const uglifyjs = require('uglify-js') |
|
const localenv = require('./build.env') |
|
|
|
const writeFile = util.promisify(fs.writeFile) |
|
|
|
// paths |
|
const path = { |
|
styles: { |
|
src: 'scss/styles.scss', |
|
srcDir: 'scss', |
|
dest: 'css/styles.css', |
|
watch: 'scss/**/*.scss' |
|
}, |
|
scripts: { |
|
src: 'js/scripts.js', |
|
srcFile: 'scripts.js', |
|
dest: 'js/min/scripts.js', |
|
watch: 'js/scripts.js' |
|
} |
|
} |
|
|
|
// BrowserSync settings |
|
function bsync () { |
|
browserSync.init({ |
|
port: localenv.port, |
|
proxy: localenv.proxy, |
|
open: localenv.open, |
|
browser: localenv.browser, |
|
ui: localenv.iu, |
|
ghostMode: localenv.ghostMode, |
|
notify: localenv.notify, |
|
reloadOnRestart: localenv.reloadOnRestart, |
|
files: [path.styles.dest, path.scripts.dest], |
|
snippetOptions: { |
|
// Load Browsersync inject code before the closing body tag |
|
// in-order to avoid issues with D10's admin toolbar. |
|
rule: { |
|
match: /<\/body>/i, |
|
fn: function (snippet, match) { |
|
return snippet + match |
|
} |
|
} |
|
} |
|
}) |
|
} |
|
|
|
// Function to compile Sass to CSS |
|
function compileSass () { |
|
const result = sass.compile(path.styles.src, { |
|
style: 'expanded', |
|
sourceMap: true, |
|
sourceMapIncludeSources: true |
|
}) |
|
|
|
return result |
|
} |
|
|
|
// Function to add vendor prefixes to CSS using PostCSS Autoprefixer |
|
async function processCSS (css) { |
|
const result = await postcss([autoprefixer]).process(css, { |
|
from: path.styles.dest, |
|
to: path.styles.dest, |
|
map: { |
|
inline: false, // Generate external sourcemap file |
|
sourcesContent: true |
|
} |
|
}) |
|
|
|
return result |
|
} |
|
|
|
// Main function to compile Sass, add vendor prefixes |
|
async function buildCSS () { |
|
try { |
|
// Compile Sass to CSS |
|
const sassResult = compileSass() |
|
|
|
// create embedded sass sourcemap. |
|
const sassMap = JSON.stringify(sassResult.sourceMap) |
|
// convert sources to relative paths. |
|
const mapSources = JSON.parse(sassMap) |
|
const updatedSources = mapSources.sources.map(source => { |
|
const segments = source.split('/') |
|
const srcIndex = segments.indexOf(path.styles.srcDir) // looks for 'src' directory. |
|
|
|
if (srcIndex !== -1) { |
|
const remainingSegments = segments.slice(srcIndex) |
|
return remainingSegments.join('/').replace(/^/, '../') |
|
} else { |
|
return source |
|
} |
|
}) |
|
mapSources.sources = updatedSources |
|
const updatedSassMap = JSON.stringify(mapSources) |
|
// complete embedded sass sourcemap after resource paths replacement. |
|
const sassMapBase64 = (Buffer.from(updatedSassMap, 'utf8') || '').toString('base64') |
|
const sassMapComment = '/*# sourceMappingURL=data:application/json;charset=utf-8;base64,' + sassMapBase64 + ' */' |
|
const finalResult = sassResult.css.toString() + '\n'.repeat(2) + sassMapComment |
|
|
|
// Add vendor prefixes to the CSS using PostCSS Autoprefixer |
|
const processedCss = await processCSS(finalResult) |
|
|
|
// Write the processed CSS and sourcemap to files |
|
await writeFile(path.styles.dest, processedCss.css) |
|
await writeFile(path.styles.dest + '.map', processedCss.map.toString()) |
|
|
|
console.log('Sass build complete!') |
|
} catch (error) { |
|
console.error('Sass build error:', error) |
|
} |
|
} |
|
|
|
// Function to compress JavaScript |
|
function compressJS () { |
|
const jsCode = fs.readFileSync(path.scripts.src, 'utf8') |
|
const options = { |
|
compress: true, |
|
mangle: false, |
|
sourceMap: { |
|
filename: path.scripts.srcFile, |
|
url: path.scripts.srcFile + '.map' |
|
} |
|
} |
|
const result = uglifyjs.minify(jsCode, options) |
|
return { |
|
code: result.code, |
|
map: result.map |
|
} |
|
} |
|
|
|
function minifyJS () { |
|
try { |
|
// Compress JavaScript using UglifyJS |
|
const jsResult = compressJS() |
|
|
|
// Replace "sources" value with file name. |
|
const jsResultMap = JSON.parse(jsResult.map) |
|
const emptySourceValue = '0' |
|
const fileSourceValue = '../' + path.scripts.srcFile |
|
// Find the index of the old value in the sources array |
|
const sourceIndex = jsResultMap.sources.indexOf(emptySourceValue) |
|
// If the old value is found, replace it with the new value |
|
if (sourceIndex !== -1) { |
|
jsResultMap.sources[sourceIndex] = fileSourceValue |
|
} |
|
|
|
// Write the compressed JavaScript and sourcemap to files |
|
writeFile(path.scripts.dest, jsResult.code) |
|
writeFile(path.scripts.dest + '.map', JSON.stringify(jsResultMap)) |
|
|
|
console.log('UglifyJS complete!') |
|
} catch (error) { |
|
console.error('UglifyJS error:', error) |
|
} |
|
} |
|
|
|
// ---------------------------------------------------------------------------- |
|
|
|
// Run BrowserSync |
|
function watchFiles () { |
|
bsync() |
|
|
|
browserSync.watch(path.styles.watch).on('change', function () { |
|
buildCSS() |
|
}) |
|
|
|
browserSync.watch(path.scripts.watch).on('change', function () { |
|
minifyJS() |
|
}) |
|
} |
|
|
|
module.exports = { |
|
buildCSS, |
|
minifyJS, |
|
watchFiles |
|
} |