/*
expansive.es - Configuration for exp-js
Transform by minifying.
*/
Expansive.load({
services: {
name: 'js',
compress: true,
dotmin: true,
extract: false,
files: [ 'lib/**.js*', '!lib**.map' ],
minify: false,
options: '--mangle --compress dead_code=true,conditionals=true,booleans=true,unused=true,if_return=true,join_vars=true,drop_console=true'
usemap: true,
usemin: true,
transforms: [{
mappings: {
'js',
'min.js',
'min.map',
'min.js.map'
},
init: function(transform) {
let service = transform.service
if (service.usemap) {
service.usemin ||= true
}
if (service.files) {
if (!(service.files is Array)) {
service.files = [ service.files ]
}
expansive.control.collections.scripts =
(expansive.control.collections.scripts + service.files).unique()
}
if (!service.extract) {
expansive.transforms['js-extract'].enable = false
}
},
resolve: function(path: Path, transform): Path? {
let service = transform.service
let vfile = directories.contents.join(path)
if (vfile.endsWith('.min.js')) {
let base = vfile.trimEnd('.min.js')
if (service.usemin && !(service.minify && base.joinExt('js', true).exists)) {
if (service.usemap) {
if (base.joinExt('min.map', true).exists || base.joinExt('min.js.map', true).exists) {
return terminal(path)
}
} else {
return terminal(path)
}
}
} else if (vfile.endsWith('.min.map') || vfile.endsWith('.min.js.map')) {
if (service.usemin) {
let base = vfile.trimEnd('.min.map').trimEnd('.min.js.map')
if (service.usemap && !(service.minify && base.joinExt('js', true).exists)) {
if (base.joinExt('min.js', true).exists) {
return terminal(path)
}
}
}
} else {
let minified = vfile.replaceExt('min.js')
/*
Minify if required, or a suitable minfied version does not exist or !usemin
*/
if (service.minify || !(minified.exists && service.usemin && (!service.usemap ||
(vfile.replaceExt('min.map').exists || vfile.replaceExt('min.js.map').exists)))) {
if (service.minify && service.dotmin) {
return terminal(path.trimExt().joinExt('min.js', true))
}
return terminal(path)
}
}
return null
},
}, {
name: 'minify',
mappings: 'js',
init: function(transform) {
let service = transform.service
let cmd = Cmd.locate('uglifyjs')
if (!cmd) {
trace('Warn', 'Cannot find uglifyjs')
transform.enable = false
} else if (!service.minify) {
transform.enable = false
} else {
if (service.options) {
cmd += ' ' + service.options
}
transform.cmd = cmd
}
},
render: function (contents, meta, transform) {
trace('Minify', meta.source)
let cmd = transform.cmd
if (transform.service.usemap) {
let mapFile = meta.dest.replaceExt('map')
mapFile.dirname.makeDir()
cmd += ' --source-map ' + mapFile
contents = runFile(cmd, contents, meta)
let map = mapFile.readJSON()
map.sources = [ meta.dest ]
mapFile.write(serialize(map))
} else {
contents = run(cmd, contents)
}
return contents
},
}, {
name: 'render',
/*
Default to only scripts from packages under contents/lib
Required scripts may vary on a page by page basis.
*/
mappings: {
'js',
'min.js'
},
init: function(transform) {
let service = transform.service
service.hash = {}
/*
Render Scripts is based on 'collections.scripts' which defaults to 'lib/**.js' and is modified
via expansive.json and addItems.
*/
global.renderScripts = function(filter = null, extras = []) {
let collections = expansive.collections
if (!collections.scripts) {
return
}
function buildScriptList(files: Array): Array {
let directories = expansive.directories
let service = expansive.services.js
let scripts = []
for each (script in files) {
let before = script
if ((script = expansive.getDestPath(script)) == null) {
continue
}
let vfile = directories.contents.join(script)
let base = vfile.trimEnd('.min.js').trimEnd('.js')
let map = base.joinExt('min.map', true).exists || base.joinExt('js.map', true).exists ||
base.joinExt('.min.js.map', true).exists
if (vfile.endsWith('min.js')) {
if ((service.minify || service.usemin) && (!service.usemap || map)) {
scripts.push(script)
}
} else {
let minified = vfile.replaceExt('min.js').exists
let map = vfile.replaceExt('min.map').exists || vfile.replaceExt('js.map').exists ||
vfile.replaceExt('.min.js.map').exists
if (service.minify || !minified || !(service.usemap && map)) {
if (service.minify && service.dotmin) {
scripts.push(script.replaceExt('min.js'))
} else {
scripts.push(script)
}
}
}
}
return scripts
}
/*
Pages have different scripts and so must compute script list per page.
This is hased and saved.
*/
let directories = expansive.directories
let service = expansive.services.js
if (!service.hash[collections.scripts]) {
let files = directories.contents.files(collections.scripts,
{ contents: true, directories: false, relative: true})
files = expansive.orderFiles(files, "js")
service.hash[collections.scripts] = buildScriptList(files).unique()
}
for each (script in service.hash[collections.scripts]) {
if (filter && !Path(script).glob(filter)) {
continue
}
let uri = meta.top.join(script).trimStart('./')
write('\n ')
}
if (extras && extras is String) {
extras = [extras]
}
if (service.states) {
let extracted = service.states[meta.destPath]
if (extracted && extracted.href) {
let jt = expansive.transforms.js
extras.push(jt.resolve(extracted.href, jt))
}
}
for each (script in extras) {
let uri = meta.top.join(script).trimStart('./')
write('\n ')
}
}
},
pre: function(transform) {
if (expansive.modified.everything) {
transform.service.hash = {}
}
},
}, {
name: 'extract',
mappings: 'html',
init: function(transform) {
transform.nextId = 0
transform.service.states = {}
},
render: function (contents, meta, transform) {
let service = transform.service
/*
Local function to extract inline script elements
*/
function handleScriptElements(contents, meta, state): String {
let service = expansive.services.js
let re = /