Last active
June 5, 2017 23:33
-
-
Save jasononeil/4decc74a0e0e83841f74d62a7a7bd5ec to your computer and use it in GitHub Desktop.
A webpack loader that compiles (and watches) a hxml file, including the resulting JS in the webpack bundle.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const fs = require('fs'); | |
const path = require('path'); | |
const loaderUtils = require('loader-utils'); | |
const exec = require('child_process').exec; | |
module.exports = function(hxmlContent) { | |
if (this.cacheable) { | |
this.cacheable(); | |
} | |
const cb = this.async(); | |
let jsOutputFile = null; | |
let haxeBuildInfoFile = '_tmp_haxe_build_info.json'; | |
let args = []; | |
// Add args that are specific to hxml-loader | |
if (this.debug) { | |
args.push('-debug'); | |
} | |
args.push('--macro'); | |
args.push(`"WebpackLoaderUtil.outputJson('${haxeBuildInfoFile}')"`); | |
// Add args from hxml file | |
for (let line of hxmlContent.split('\n')) { | |
line = line.trim(); | |
if (line === '' || line.substr(0, 1) === '#') { | |
continue; | |
} | |
let space = line.indexOf(' '); | |
let name = space > -1 ? line.substr(0, space) : line; | |
args.push(name); | |
if (name === '--next') { | |
var err = `${this | |
.resourcePath} included a "--next" line, hxml-loader only supports a single JS build per hxml file.`; | |
return cb(err); | |
} | |
if (space > -1) { | |
let value = line.substr(space + 1).trim(); | |
args.push(value); | |
if (name === '-js') { | |
jsOutputFile = value; | |
} | |
} | |
} | |
if (!jsOutputFile) { | |
var err = `${this | |
.resourcePath} did not include a "-js" line, hxml-loader only supports a single JS build per hxml file.`; | |
return cb(err); | |
} | |
// Execute the Haxe build. | |
exec(`haxe ${args.join(' ')}`, (err, stdout, stderr) => { | |
if (stdout) { | |
console.log(stdout); | |
} | |
if (stderr) { | |
console.error(stderr); | |
} | |
if (err) { | |
return cb(err); | |
} | |
// TODO: use promises here to avoid callback crazyness. | |
// Read the Haxe build info so we can register dependencies. | |
fs.readFile(haxeBuildInfoFile, (err, json) => { | |
if (err) return cb(err); | |
var data = JSON.parse(json); | |
for (let file of data.modules) { | |
var filePath = path.resolve(file); | |
this.addDependency(filePath); | |
} | |
// Delete the temporary build info file. | |
fs.unlink(haxeBuildInfoFile, err => { | |
if (err) return cb(err); | |
// Read the resulting JS file. | |
fs.readFile(jsOutputFile, (err, data) => { | |
if (err) return cb(err); | |
return cb(null, data); | |
}); | |
}); | |
}); | |
}); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import haxe.macro.Context; | |
import haxe.macro.Type; | |
import haxe.macro.Expr; | |
import sys.io.File; | |
class WebpackLoaderUtil { | |
public static function outputJson(outputFile:String) { | |
Context.onGenerate(function (types:Array<Type>) { | |
var allFilesUsed = []; | |
for (type in types) { | |
addFilesForType(type, allFilesUsed); | |
} | |
var data = { | |
modules: allFilesUsed | |
}; | |
var json = haxe.Json.stringify(data); | |
File.saveContent(outputFile, json); | |
}); | |
} | |
static function addFilesForType(type:Type, files:Array<String>) { | |
switch type { | |
case TMono(_.get() => t): | |
addFilesForType(t, files); | |
case TEnum(_.get() => et, params): | |
addFileFromPosition(et.pos, files); | |
case TInst(_.get() => ct, params): | |
addFileFromPosition(ct.pos, files); | |
case TType(_.get() => td, params): | |
addFileFromPosition(td.pos, files); | |
case TFun(args, ret): | |
// No files to add. | |
case TAnonymous(_.get() => a): | |
// No files to add. | |
case TDynamic(dynamicParam): | |
if (dynamicParam != null) { | |
addFilesForType(dynamicParam, files); | |
} | |
case TLazy(fn): | |
addFilesForType(fn(), files); | |
case TAbstract(_.get() => a, params): | |
addFileFromPosition(a.pos, files); | |
} | |
} | |
static function addFileFromPosition(p:Position, files:Array<String>) { | |
var info = Context.getPosInfos(p); | |
if (files.indexOf(info.file) < 0) { | |
files.push(info.file); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment