mirror of
https://github.com/zhigang1992/esbuild.git
synced 2026-01-12 22:46:54 +08:00
fix #1152: add the "--allow-overwrite" flag
This commit is contained in:
@@ -18,6 +18,10 @@
|
||||
|
||||
[The TC39 proposal for this feature](https://github.com/tc39/proposal-private-fields-in-in) is currently at stage 3 but has already been shipped in Chrome 91 and has also landed in Firefox. It seems reasonably inevitable given that it's already shipping and that it's a very simple feature, so it seems appropriate to add this feature to esbuild.
|
||||
|
||||
* Add the `--allow-overwrite` flag ([#1152](https://github.com/evanw/esbuild/issues/1152))
|
||||
|
||||
This is a new flag that allows output files to overwrite input files. It's not enabled by default because doing so means overwriting your source code, which can lead to data loss if your code is not checked in. But supporting this makes certain workflows easier by avoiding the need for a temporary directory so doing this is now supported.
|
||||
|
||||
## 0.11.12
|
||||
|
||||
* Fix a bug where `-0` and `0` were collapsed to the same value ([#1159](https://github.com/evanw/esbuild/issues/1159))
|
||||
|
||||
@@ -46,6 +46,7 @@ var helpText = func(colors logger.Colors) string {
|
||||
--watch Watch mode: rebuild on file system changes
|
||||
|
||||
` + colors.Bold + `Advanced options:` + colors.Reset + `
|
||||
--allow-overwrite Allow output files to overwrite input files
|
||||
--asset-names=... Path template to use for "file" loader files
|
||||
(default "[name]-[hash]")
|
||||
--banner:T=... Text to be prepended to each output file of type T
|
||||
|
||||
@@ -1900,18 +1900,22 @@ func (b *Bundle) Compile(log logger.Log, options config.Options, timer *helpers.
|
||||
|
||||
if !options.WriteToStdout {
|
||||
// Make sure an output file never overwrites an input file
|
||||
sourceAbsPaths := make(map[string]uint32)
|
||||
for _, sourceIndex := range allReachableFiles {
|
||||
keyPath := b.files[sourceIndex].inputFile.Source.KeyPath
|
||||
if keyPath.Namespace == "file" {
|
||||
lowerAbsPath := lowerCaseAbsPathForWindows(keyPath.Text)
|
||||
sourceAbsPaths[lowerAbsPath] = sourceIndex
|
||||
if !options.AllowOverwrite {
|
||||
sourceAbsPaths := make(map[string]uint32)
|
||||
for _, sourceIndex := range allReachableFiles {
|
||||
keyPath := b.files[sourceIndex].inputFile.Source.KeyPath
|
||||
if keyPath.Namespace == "file" {
|
||||
lowerAbsPath := lowerCaseAbsPathForWindows(keyPath.Text)
|
||||
sourceAbsPaths[lowerAbsPath] = sourceIndex
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, outputFile := range outputFiles {
|
||||
lowerAbsPath := lowerCaseAbsPathForWindows(outputFile.AbsPath)
|
||||
if sourceIndex, ok := sourceAbsPaths[lowerAbsPath]; ok {
|
||||
log.AddError(nil, logger.Loc{}, "Refusing to overwrite input file: "+b.files[sourceIndex].inputFile.Source.PrettyPath)
|
||||
for _, outputFile := range outputFiles {
|
||||
lowerAbsPath := lowerCaseAbsPathForWindows(outputFile.AbsPath)
|
||||
if sourceIndex, ok := sourceAbsPaths[lowerAbsPath]; ok {
|
||||
log.AddError(nil, logger.Loc{},
|
||||
fmt.Sprintf("Refusing to overwrite input file %q without permission (enable \"allow overwrite\" to proceed)",
|
||||
b.files[sourceIndex].inputFile.Source.PrettyPath))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -185,6 +185,7 @@ type Options struct {
|
||||
MangleSyntax bool
|
||||
CodeSplitting bool
|
||||
WatchMode bool
|
||||
AllowOverwrite bool
|
||||
|
||||
// Setting this to true disables warnings about code that is very likely to
|
||||
// be a bug. This is used to ignore issues inside "node_modules" directories.
|
||||
|
||||
@@ -197,12 +197,14 @@ function flagsForBuildOptions(
|
||||
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
|
||||
let allowOverwrite = getFlag(options, keys, 'allowOverwrite', mustBeBoolean);
|
||||
let incremental = getFlag(options, keys, 'incremental', mustBeBoolean) === true;
|
||||
keys.plugins = true; // "plugins" has already been read earlier
|
||||
checkForInvalidFlags(options, keys, `in ${callName}() call`);
|
||||
|
||||
if (sourcemap) flags.push(`--sourcemap${sourcemap === true ? '' : `=${sourcemap}`}`);
|
||||
if (bundle) flags.push('--bundle');
|
||||
if (allowOverwrite) flags.push('--allow-overwrite');
|
||||
if (watch) {
|
||||
flags.push('--watch');
|
||||
if (typeof watch === 'boolean') {
|
||||
|
||||
@@ -47,6 +47,7 @@ export interface BuildOptions extends CommonOptions {
|
||||
mainFields?: string[];
|
||||
conditions?: string[];
|
||||
write?: boolean;
|
||||
allowOverwrite?: boolean;
|
||||
tsconfig?: string;
|
||||
outExtension?: { [ext: string]: string };
|
||||
publicPath?: string;
|
||||
|
||||
@@ -276,10 +276,11 @@ type BuildOptions struct {
|
||||
EntryPoints []string
|
||||
EntryPointsAdvanced []EntryPoint
|
||||
|
||||
Stdin *StdinOptions
|
||||
Write bool
|
||||
Incremental bool
|
||||
Plugins []Plugin
|
||||
Stdin *StdinOptions
|
||||
Write bool
|
||||
AllowOverwrite bool
|
||||
Incremental bool
|
||||
Plugins []Plugin
|
||||
|
||||
Watch *WatchMode
|
||||
}
|
||||
|
||||
@@ -787,6 +787,7 @@ func rebuildImpl(
|
||||
MangleSyntax: buildOpts.MinifySyntax,
|
||||
RemoveWhitespace: buildOpts.MinifyWhitespace,
|
||||
MinifyIdentifiers: buildOpts.MinifyIdentifiers,
|
||||
AllowOverwrite: buildOpts.AllowOverwrite,
|
||||
ASCIIOnly: validateASCIIOnly(buildOpts.Charset),
|
||||
IgnoreDCEAnnotations: validateIgnoreDCEAnnotations(buildOpts.TreeShaking),
|
||||
GlobalName: validateGlobalName(log, buildOpts.GlobalName),
|
||||
|
||||
@@ -57,6 +57,9 @@ func parseOptionsImpl(
|
||||
case arg == "--splitting" && buildOpts != nil:
|
||||
buildOpts.Splitting = true
|
||||
|
||||
case arg == "--allow-overwrite" && buildOpts != nil:
|
||||
buildOpts.AllowOverwrite = true
|
||||
|
||||
case arg == "--watch" && buildOpts != nil:
|
||||
buildOpts.Watch = &api.WatchMode{}
|
||||
|
||||
|
||||
@@ -1285,6 +1285,35 @@ body {
|
||||
assert.strictEqual(meta.outputs[makePath(output + '.map')].bytes, value.outputFiles[0].contents.length)
|
||||
},
|
||||
|
||||
async allowOverwrite({ esbuild, testDir }) {
|
||||
const input = path.join(testDir, 'in.mjs')
|
||||
await writeFileAsync(input, `export default FOO`)
|
||||
|
||||
// Fail without "allowOverwrite"
|
||||
try {
|
||||
await esbuild.build({
|
||||
entryPoints: [input],
|
||||
outfile: input,
|
||||
logLevel: 'silent',
|
||||
})
|
||||
throw new Error('Expected build failure');
|
||||
} catch (e) {
|
||||
if (!e || !e.errors || !e.errors.length || !e.errors[0].text.includes('Refusing to overwrite input file'))
|
||||
throw e
|
||||
}
|
||||
|
||||
// Succeed with "allowOverwrite"
|
||||
await esbuild.build({
|
||||
entryPoints: [input],
|
||||
outfile: input,
|
||||
allowOverwrite: true,
|
||||
define: { FOO: '123' },
|
||||
})
|
||||
|
||||
const result = await import(input)
|
||||
assert.strictEqual(result.default, 123)
|
||||
},
|
||||
|
||||
async splittingRelativeSameDir({ esbuild, testDir }) {
|
||||
const inputA = path.join(testDir, 'a.js')
|
||||
const inputB = path.join(testDir, 'b.js')
|
||||
|
||||
Reference in New Issue
Block a user