diff --git a/package.json b/package.json index e2bf09bb725..2b55f213cb2 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "babylon-walk": "^1.0.2", "browser-resolve": "^1.11.2", "chalk": "^2.1.0", + "child-process-promise": "^2.2.1", "chokidar": "^1.7.0", "commander": "^2.11.0", "cross-spawn": "^5.1.0", diff --git a/src/Bundler.js b/src/Bundler.js index 8398545e33e..5abf2552a8d 100644 --- a/src/Bundler.js +++ b/src/Bundler.js @@ -252,13 +252,17 @@ class Bundler extends EventEmitter { return bundle; } - async resolveAsset(name, parent) { + async resolveAsset(name, parent, options = {}) { let {path, pkg} = await this.resolver.resolve(name, parent); if (this.loadedAssets.has(path)) { return this.loadedAssets.get(path); } - let asset = this.parser.getAsset(path, pkg, this.options); + let asset = this.parser.getAsset( + path, + pkg, + Object.assign({}, this.options, options) + ); this.loadedAssets.set(path, asset); if (this.watcher) { @@ -270,7 +274,7 @@ class Bundler extends EventEmitter { async resolveDep(asset, dep) { try { - return await this.resolveAsset(dep.name, asset.name); + return await this.resolveAsset(dep.name, asset.name, dep); } catch (err) { let thrown = err; diff --git a/src/Parser.js b/src/Parser.js index 92365e2299f..d6508d52aec 100644 --- a/src/Parser.js +++ b/src/Parser.js @@ -29,6 +29,8 @@ class Parser { this.registerExtension('scss', './assets/SASSAsset'); this.registerExtension('html', './assets/HTMLAsset'); + this.registerExtension('rs', './assets/RustAsset'); + this.registerExtension('wasm', './assets/WasmAsset'); let extensions = options.extensions || {}; for (let ext in extensions) { diff --git a/src/assets/HTMLAsset.js b/src/assets/HTMLAsset.js index 3e4c613cea8..db8d050c73c 100644 --- a/src/assets/HTMLAsset.js +++ b/src/assets/HTMLAsset.js @@ -43,7 +43,9 @@ class HTMLAsset extends Asset { for (let attr in node.attrs) { let elements = ATTRS[attr]; if (elements && elements.includes(node.tag)) { - let assetPath = this.addURLDependency(node.attrs[attr]); + let assetPath = this.addURLDependency(node.attrs[attr], { + from: 'html' + }); if (!isURL(assetPath)) { assetPath = urlJoin(this.options.publicURL, assetPath); } diff --git a/src/assets/RustAsset.js b/src/assets/RustAsset.js new file mode 100644 index 00000000000..fecb4c999d7 --- /dev/null +++ b/src/assets/RustAsset.js @@ -0,0 +1,35 @@ +const path = require('path'); +const {exec} = require('child-process-promise'); + +const md5 = require('../utils/md5'); +const JSAsset = require('./JSAsset'); + +const rustTarget = `wasm32-unknown-unknown`; + +class RustAsset extends JSAsset { + collectDependencies() { + // Do nothing. Dependencies are collected by cargo :). + } + + async parse() { + const release = process.env.NODE_ENV === 'production'; + const {dir, base} = path.parse(this.name); + const wasmPath = path.join( + this.options.publicURL, + md5(this.name) + '.wasm' + ); + const cmd = `rustc +nightly --target ${rustTarget} -O --crate-type=cdylib ${base} -o .${wasmPath} ${ + release ? ' --release' : '' + }`; + + await exec(cmd, {cwd: dir}); + + const pathToWasm = JSON.stringify(wasmPath); + + this.contents = `module.exports=${pathToWasm};`; + + return await super.parse(this.contents); + } +} + +module.exports = RustAsset; diff --git a/src/assets/WasmAsset.js b/src/assets/WasmAsset.js new file mode 100644 index 00000000000..1e667fc5b61 --- /dev/null +++ b/src/assets/WasmAsset.js @@ -0,0 +1,20 @@ +const RawAsset = require('./RawAsset'); +const path = require('path'); + +class WasmAsset extends RawAsset { + // Don't load raw assets. They will be copied by the RawPackager directly. + load() {} + + generate(pathToAsset) { + pathToAsset = + pathToAsset || + JSON.stringify( + path.join(this.options.publicURL, this.generateBundleName()) + ); + return { + js: `module.exports=${pathToAsset};` + }; + } +} + +module.exports = WasmAsset; diff --git a/src/utils/fs.js b/src/utils/fs.js index f71707664b8..8b01c80680b 100644 --- a/src/utils/fs.js +++ b/src/utils/fs.js @@ -5,6 +5,7 @@ const mkdirp = require('mkdirp'); exports.readFile = promisify(fs.readFile); exports.writeFile = promisify(fs.writeFile); exports.stat = promisify(fs.stat); +exports.readdir = promisify(fs.readdir); exports.exists = function(filename) { return new Promise(resolve => {