Skip to content

Commit

Permalink
follow-up to #2828: duplicate custom output paths
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Jan 16, 2023
1 parent 5a586ab commit 01efc05
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 8 deletions.
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,29 @@

Entry points can optionally provide custom output paths to change the path of the generated output file. For example, `esbuild foo=abc.js bar=xyz.js --outdir=out` generates the files `out/foo.js` and `out/bar.js`. However, this previously didn't work when using the `copy` loader due to an oversight. This bug has been fixed. For example, you can now do `esbuild foo=abc.html bar=xyz.html --outdir=out --loader:.html=copy` to generate the files `out/foo.html` and `out/bar.html`.

* The JS API can now take an array of objects ([#2828](https://github.com/evanw/esbuild/issues/2828))

Previously it was not possible to specify two entry points with the same custom output path using the JS API, although it was possible to do this with the Go API and the CLI. This will not cause a collision if both entry points use different extensions (e.g. if one uses `.js` and the other uses `.css`). You can now pass the JS API an array of objects to work around this API limitation:

```js
// The previous API didn't let you specify duplicate output paths
let result = await esbuild.build({
entryPoints: {
// This object literal contains a duplicate key, so one is ignored
'dist': 'foo.js',
'dist': 'bar.css',
},
})

// You can now specify duplicate output paths as an array of objects
let result = await esbuild.build({
entryPoints: [
{ in: 'foo.js', out: 'dist' },
{ in: 'bar.css', out: 'dist' },
],
})
```

## 0.17.0

**This release deliberately contains backwards-incompatible changes.** To avoid automatically picking up releases like this, you should either be pinning the exact version of `esbuild` in your `package.json` file (recommended) or be using a version range syntax that only accepts patch upgrades such as `^0.16.0` or `~0.16.0`. See npm's documentation about [semver](https://docs.npmjs.com/cli/v6/using-npm/semver/) for more information.
Expand Down
25 changes: 18 additions & 7 deletions lib/shared/common.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as types from "./types"
import type * as types from "./types"
import * as protocol from "./stdio_protocol"

declare const ESBUILD_VERSION: string
Expand Down Expand Up @@ -37,12 +37,12 @@ let mustBeArray = <T>(value: T[] | undefined): string | null =>
let mustBeObject = (value: Object | undefined): string | null =>
typeof value === 'object' && value !== null && !Array.isArray(value) ? null : 'an object'

let mustBeEntryPoints = (value: types.BuildOptions['entryPoints']): string | null =>
typeof value === 'object' && value !== null ? null : 'an array or an object'

let mustBeWebAssemblyModule = (value: WebAssembly.Module | undefined): string | null =>
value instanceof WebAssembly.Module ? null : 'a WebAssembly.Module'

let mustBeArrayOrRecord = <T extends string>(value: T[] | Record<T, T> | undefined): string | null =>
typeof value === 'object' && value !== null ? null : 'an array or an object'

let mustBeObjectOrNull = (value: Object | null | undefined): string | null =>
typeof value === 'object' && !Array.isArray(value) ? null : 'an object or null'

Expand Down Expand Up @@ -265,7 +265,7 @@ function flagsForBuildOptions(
let inject = getFlag(options, keys, 'inject', mustBeArray)
let banner = getFlag(options, keys, 'banner', mustBeObject)
let footer = getFlag(options, keys, 'footer', mustBeObject)
let entryPoints = getFlag(options, keys, 'entryPoints', mustBeArrayOrRecord)
let entryPoints = getFlag(options, keys, 'entryPoints', mustBeEntryPoints)
let absWorkingDir = getFlag(options, keys, 'absWorkingDir', mustBeString)
let stdin = getFlag(options, keys, 'stdin', mustBeObject)
let write = getFlag(options, keys, 'write', mustBeBoolean) ?? writeDefault; // Default to true if not specified
Expand Down Expand Up @@ -351,8 +351,19 @@ function flagsForBuildOptions(

if (entryPoints) {
if (Array.isArray(entryPoints)) {
for (let entryPoint of entryPoints) {
entries.push(['', validateStringValue(entryPoint, 'entry point')])
for (let i = 0, n = entryPoints.length; i < n; i++) {
let entryPoint = entryPoints[i]
if (typeof entryPoint === 'object' && entryPoint !== null) {
let entryPointKeys: OptionKeys = Object.create(null)
let input = getFlag(entryPoint, entryPointKeys, 'in', mustBeString)
let output = getFlag(entryPoint, entryPointKeys, 'out', mustBeString)
checkForInvalidFlags(entryPoint, entryPointKeys, 'in entry point at index ' + i)
if (input === undefined) throw new Error('Missing property "in" for entry point at index ' + i)
if (output === undefined) throw new Error('Missing property "out" for entry point at index ' + i)
entries.push([output, input])
} else {
entries.push(['', validateStringValue(entryPoint, 'entry point at index ' + i)])
}
}
} else {
for (let key in entryPoints) {
Expand Down
2 changes: 1 addition & 1 deletion lib/shared/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ export interface BuildOptions extends CommonOptions {
/** Documentation: https://esbuild.github.io/api/#footer */
footer?: { [type: string]: string }
/** Documentation: https://esbuild.github.io/api/#entry-points */
entryPoints?: string[] | Record<string, string>
entryPoints?: string[] | Record<string, string> | { in: string, out: string }[]
/** Documentation: https://esbuild.github.io/api/#stdin */
stdin?: StdinOptions
/** Documentation: https://esbuild.github.io/plugins/ */
Expand Down
18 changes: 18 additions & 0 deletions scripts/js-api-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -2788,6 +2788,24 @@ import "after/alias";
assert.strictEqual(outputFiles[1].path, path.join(testDir, 'entry', 'out', '3KY7NOSR-2.js'))
},

async customEntryPointOutputPathsDuplicates({ esbuild, testDir }) {
const input1 = path.join(testDir, 'foo.js')
const input2 = path.join(testDir, 'bar.css')
await writeFileAsync(input1, `foo()`)
await writeFileAsync(input2, `.bar {}`)
var { outputFiles } = await esbuild.build({
entryPoints: [
{ in: input1, out: 'abc' },
{ in: input2, out: 'abc' },
],
outdir: testDir,
write: false,
})
assert.strictEqual(outputFiles.length, 2)
assert.strictEqual(outputFiles[0].path, path.join(testDir, 'abc.js'))
assert.strictEqual(outputFiles[1].path, path.join(testDir, 'abc.css'))
},

async nodeColonPrefixImport({ esbuild }) {
const tryTargetESM = async target => {
const result = await esbuild.build({
Expand Down

0 comments on commit 01efc05

Please sign in to comment.