waveorb
Version:
Waveorb Javascript web app development framework
135 lines (114 loc) • 3.71 kB
JavaScript
const fs = require('fs')
const path = require('path')
const URL = require('url').URL
const stream = require('stream')
const { promisify } = require('util')
const lodash = require('lodash')
const { exist, mkdir, rmdir, read, write, copy, sleep } = require('extras')
const got = require('got')
const terser = require('terser')
const sass = require('sass')
const fport = require('fport')
const util = require('../lib/util.js')
const loader = require('../lib/loader.js')
const serve = require('../lib/serve.js')
const ROOT = process.cwd()
const APP_ROOT = process.env.WAVEORB_APP || 'app'
const DIST = path.join(ROOT, 'dist')
async function build() {
const app = await loader(APP_ROOT)
const builder = process.argv[3] || 'build.js'
const config = exist(builder) ? await read(builder)(app) : {}
let { urls } = config
// If urls not found, build from routes
if (!urls) {
urls = Object.keys(app.routes)
.filter((x) => x.startsWith('get#') && !x.includes('/_'))
.map((x) => x.replace(/^get#/, ''))
}
// No hostname means start localhost on random port
let { protocol, hostname, port } = new URL(config.host || 'http://localhost')
port = port || (await fport.port())
const host = `${protocol}//${hostname}:${port}`
const { server } = await serve({ port }, app)
// Wait for server start
await sleep(1)
rmdir(DIST)
if (!exist(DIST)) mkdir(DIST)
const pipeline = promisify(stream.pipeline)
for (const url of urls) {
let name = url
if (name.endsWith('/')) {
name += 'index.html'
}
const dir = path.dirname(name)
const file = path.basename(name)
mkdir(path.join(DIST, dir))
const address = `${host}${url}`
console.log(`Building ${name}`)
try {
const writer = fs.createWriteStream(path.join(DIST, dir, file))
await pipeline(got.stream(address), writer)
} catch (e) {
console.log(`Can't build ${name}, skipping...`)
}
}
console.log(`Build complete...\n`)
server.close()
await sleep(1)
// Copy assets
copy(path.join(APP_ROOT, 'assets', '*'), 'dist')
// Build assets
const assets = lodash.get(app, 'config.assets.bundle')
if (assets) {
for (const type of Object.keys(assets)) {
console.log(`Bundling ${type} files...`)
const files = assets[type] || []
const bundle = files
.map(function (file) {
const inpath = path.join(APP_ROOT, 'assets', file)
const content = read(inpath, 'utf8')
if (type == 'css') {
return util.rewriteCSSUrl(file, content)
}
return content
})
.join(type == 'js' ? ';' : '\n')
// Write bundle uncompressed to bundle path
const bundlePath = path.join(DIST, `bundle.${type}`)
write(bundlePath, bundle)
// Source map path
const mapPath = bundlePath + '.map'
// Compress Javascript bundle
if (type == 'js') {
const code = {}
files.forEach((file) => {
code[file] = read(path.join(DIST, file), 'utf8')
})
const result = await terser.minify(code, {
sourceMap: {
filename: 'bundle.js',
url: 'bundle.js.map'
}
})
write(bundlePath, result.code)
write(mapPath, result.map)
}
// Compress CSS bundle
if (type == 'css') {
const result = sass.renderSync({
file: bundlePath,
outFile: bundlePath,
outputStyle: 'compressed',
sourceMap: true
})
write(bundlePath, result.css)
write(mapPath, result.map)
}
}
}
console.log(`\nFiles written to '${DIST}'`)
process.exit(0)
}
build()