diff --git a/src/Asset.js b/src/Asset.js index e65ea177025..ee5d3e68ded 100644 --- a/src/Asset.js +++ b/src/Asset.js @@ -175,11 +175,23 @@ class Asset { generateBundleName() { // Resolve the main file of the package.json - let main = + const main = this.package && this.package.main ? path.resolve(path.dirname(this.package.pkgfile), this.package.main) : null; - let ext = '.' + this.type; + const ext = '.' + this.type; + + const isEntryPoint = this.name === this.options.mainFile; + + // If this is the entry point of the root bundle, use outFile filename if provided + if (isEntryPoint && this.options.outFile) { + return ( + path.basename( + this.options.outFile, + path.extname(this.options.outFile) + ) + ext + ); + } // If this asset is main file of the package, use the sanitized package name if (this.name === main) { @@ -190,7 +202,7 @@ class Asset { } // If this is the entry point of the root bundle, use the original filename - if (this.name === this.options.mainFile) { + if (isEntryPoint) { return path.basename(this.name, path.extname(this.name)) + ext; } diff --git a/src/Bundler.js b/src/Bundler.js index 6c26f70e1ea..a5c8889e438 100644 --- a/src/Bundler.js +++ b/src/Bundler.js @@ -70,6 +70,7 @@ class Bundler extends EventEmitter { const target = options.target || 'browser'; return { outDir: Path.resolve(options.outDir || 'dist'), + outFile: options.outFile || '', publicURL: publicURL, watch: watch, cache: typeof options.cache === 'boolean' ? options.cache : true, diff --git a/src/cli.js b/src/cli.js index e6ef1b0ddbe..a618da8a23c 100755 --- a/src/cli.js +++ b/src/cli.js @@ -23,11 +23,15 @@ program 'set the hostname of HMR websockets, defaults to location.hostname of current window' ) .option('--https', 'serves files over HTTPS') - .option('-o, --open', 'automatically open in default browser') + .option('--open', 'automatically open in default browser') .option( '-d, --out-dir ', 'set the output directory. defaults to "dist"' ) + .option( + '-o, --out-file ', + 'set the output filename for the application entry point.' + ) .option( '--public-url ', 'set the public URL to serve on. defaults to the same as the --out-dir option' @@ -50,6 +54,10 @@ program '-d, --out-dir ', 'set the output directory. defaults to "dist"' ) + .option( + '-o, --out-file ', + 'set the output filename for the application entry point.' + ) .option( '--public-url ', 'set the public URL to serve on. defaults to the same as the --out-dir option' @@ -71,6 +79,10 @@ program '-d, --out-dir ', 'set the output directory. defaults to "dist"' ) + .option( + '-o, --out-file ', + 'set the output filename for the application entry point.' + ) .option( '--public-url ', 'set the public URL to serve on. defaults to the same as the --out-dir option' diff --git a/test/asset.js b/test/asset.js index e1f13cd7eee..7555fd14151 100644 --- a/test/asset.js +++ b/test/asset.js @@ -1,5 +1,7 @@ const assert = require('assert'); +const fs = require('fs'); const Asset = require('../src/Asset'); +const {bundle} = require('./utils'); describe('Asset', () => { it('should include default implementations', async () => { @@ -19,6 +21,15 @@ describe('Asset', () => { assert.equal(a.generateErrorMessage(err), err); }); + it('should support overriding the filename of the root bundle', async function() { + const outFile = 'custom-out-file.html'; + await bundle(__dirname + '/integration/html/index.html', { + outFile + }); + + assert(fs.existsSync(__dirname, `/dist/${outFile}`)); + }); + describe('addURLDependency', () => { const bundleName = 'xyz'; const options = {