dc09.ru-old/dc09.js

300 lines
7.4 KiB
JavaScript

const fs = require('fs')
const path = require('path')
const cp = require('child_process')
const process = require('process')
/* Debug option */
const debug = false
/* ************ */
const exec = (cmd) => {
if (debug)
console.log(`Exec: ${cmd}`)
return cp.execSync(cmd)
}
const cwd = process.cwd()
const CleanCSS = require('clean-css')
const Handlebars = require('handlebars')
const html = require('html-minifier')
const red = '\033[1;31m'
const green = '\033[1;32m'
const yellow = '\033[1;33m'
const blue = '\033[1;34m'
const purple = '\033[1;35m'
const bold = '\033[1m'
const reset = '\033[0m'
const minjs = 'script.min.js'
const mincss = 'style.min.css'
main()
function main() {
switch (process.argv[2]) {
case 'watch':
fs.watch(cwd, {recursive: true}, (_ev, file) => {
const rel = path.relative(cwd, file)
if (rel.includes('dist/'))
return
print(`Changed: ${file}`, true, '#', yellow)
const dirs = rel.split(path.sep)
const dir = (dirs.length > 1) ? dirs[0] : '.'
buildOne(dir)
})
break
case 'build':
const dir = process.argv[3]
if (dir)
buildOne(dir)
else
buildAll()
break
case 'archive':
archive()
break
case 'clean':
clean()
break
default:
print('Available actions:', true)
printList([
'watch',
'build',
'build <dir>',
'archive',
'clean',
])
break
}
}
function buildAll() {
const dirs = fs.readdirSync('.', {
withFileTypes: true
})
.filter(file => file.isDirectory())
.map(file => file.name)
const pages = [
'.',
...dirs,
]
for (let page of pages)
buildOne(page)
print('Completed', true, 'V', green)
}
function buildOne(dir) {
print(
`${bold}Building:${reset} ${dir}`,
false, '>', purple,
)
const config = `${dir}/webpage.json`
if (!fs.existsSync(config)) {
print(
'Unable to find webpage.json, skipping',
false, '!', yellow,
)
return
}
const files = JSON.parse(fs.readFileSync(config))
fs.mkdirSync(`dist/${dir}`, {
recursive: true
})
print('Minifying JS')
minifyJs(dir, files)
print('Rendering LESS')
renderLess(dir, files)
print('Minifying CSS')
minifyCss(dir, files)
print('Compiling Handlebars HTML')
compileHbHtml(dir, files)
print('Converting paths in HTML')
convertPathsHtml(dir, files)
print('Minifying HTML')
minifyHtml(dir, files)
print('Copying other files')
copyOther(dir, files)
}
function minifyJs(dir, files) {
files.js = files.js || []
if (files.js.length == 0) return;
exec(
'node_modules/.bin/terser --compress --mangle ' +
`-o "dist/${dir}/${minjs}" ` +
files.js.map(js => `"${dir}/${js}"`).join(' ')
)
}
function renderLess(dir, files) {
files.less = files.less || []
if (files.less.length == 0) return;
const rendered = path.resolve(`dist/${dir}/${mincss}`)
exec(
'node_modules/.bin/lessc ' +
files.less.map(less => `"${dir}/${less}"`).join(' ') +
` "${rendered}"`
)
files.css = [
...(files.css || []),
rendered,
]
}
function minifyCss(dir, files) {
files.css = files.css || []
if (files.css.length == 0) return;
const content = new CleanCSS().minify(files.css).styles
fs.writeFileSync(`dist/${dir}/${mincss}`, content)
}
function compileHbHtml(dir, files) {
files.hb = files.hb || []
const compiled = []
for (let file of files.hb) {
const parts = file.split('.')
const base = parts.slice(0, -1).join('.') || ''
const name = path.resolve(`${dir}/${file}`)
const conf = path.resolve(`${dir}/${base}.json`)
const built = path.resolve(`dist/${dir}/${base}.html`)
if (!fs.existsSync(conf)) {
print(
`Unable to find ${conf} \n` +
' for the template, skipping',
false, '!', yellow,
)
continue
}
const ctx = JSON.parse(fs.readFileSync(conf))
const template = Handlebars.compile(
fs.readFileSync(name).toString()
)
fs.writeFileSync(built, template(ctx))
compiled.push(built)
}
files.html = [
...(files.html || []),
...compiled,
]
}
function convertPathsHtml(dir, files) {
const scriptRegex = /(?:<script src=['"]?js\/\w+\.js['"]?><\/script>[\s\r\n]*)+/gm
const converted = []
files.html = files.html || []
for (let file of files.html) {
const isAbs = path.isAbsolute(file)
const name = path.resolve(isAbs ? file : `${dir}/${file}`)
const built = path.resolve(isAbs ? file : `dist/${dir}/${file}`)
const content = fs.readFileSync(name)
.toString()
.replace(
'<script src="https://cdn.jsdelivr.net/npm/less"></script>',
''
)
.replace(
'<link rel="stylesheet/less" type="text/css" href="styles.less" />',
`<link rel="stylesheet" href="${mincss}" />`
)
.replace(
scriptRegex,
`<script src="${minjs}"></script>`
)
fs.writeFileSync(built, content)
converted.push(built)
}
files.html = converted
}
function minifyHtml(dir, files) {
files.html = files.html || []
for (let file of files.html) {
const isAbs = path.isAbsolute(file)
const name = (isAbs ? file : `${dir}/${file}`)
const built = (isAbs ? file : `dist/${dir}/${file}`)
const content = html.minify(
fs.readFileSync(name).toString(),
{
collapseBooleanAttributes: true,
collapseInlineTagWhitespace: true,
collapseWhitespace: true,
removeAttributeQuotes: true,
removeComments: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
useShortDoctype: true,
keepClosingSlash: false,
minifyCSS: true,
minifyJS: true,
}
)
fs.writeFileSync(built, content)
}
}
function copyOther(dir, files) {
files.other = files.other || []
for (let file of files.other) {
const isAbs = path.isAbsolute(file)
const name = (isAbs ? file : `${dir}/${file}`)
const built = (isAbs ? file : `dist/${dir}/${file}`)
fs.cpSync(name, built, {
recursive: true,
errorOnExist: false,
})
}
}
function archive() {
exec('7z a dist.zip dist/*')
}
function clean() {
fs.rmSync('dist/', {
recursive: true,
force: true,
})
fs.rmSync('dist.zip', {
force: true,
})
}
function print(
str,
title = false,
symbol = '*',
color = blue,
) {
console.log(
`${color}[${symbol}]${reset} ` +
`${title ? bold : ""}${str}${reset}`
)
}
function printList(arr) {
for (let item of arr)
console.log(` ${item}`)
}