Skip to content

Commit

Permalink
fix #781: add a "--preserve-symlinks" flag
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Feb 11, 2021
1 parent e0bc08d commit f7d01de
Show file tree
Hide file tree
Showing 10 changed files with 57 additions and 12 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@

Having a logo for esbuild should make it easier to include esbuild in lists of other tools since the other tools often all have logos.

* Add support for node's `--preserve-symlinks` flag ([#781](https://github.com/evanw/esbuild/issues/781))

This release adds the `--preserve-symlinks` flag which behaves like [the corresponding flag in node](https://nodejs.org/api/cli.html#cli_preserve_symlinks). Without the flag, esbuild and node will use the real path (after resolving symlinks) as the identity of a file. This means that a given file can only be instantiated once. With the flag, esbuild and node will use the original path (without resolving symlinks) as the identity of a file. This means that a given file can be instantiated multiple times, once for every symlink pointing to it. Each copy will have its own identity so the resulting bundle may contain duplicate files. This option is useful if your code relies on this flag in node (or the [`resolve.symlinks` setting in Webpack](https://webpack.js.org/configuration/resolve/#resolvesymlinks)).

* Ignore a leading byte order mark (BOM) in CSS files ([#776](https://github.com/evanw/esbuild/issues/776))

Some text editors insert a U+FEFF code point at the start of text files. This is a zero-width non-breaking space character. Using one at the start of a file is a convention which is meant to indicate that the contents of the file are UTF-8 encoded. When this is done, the character is called a [byte order mark](https://en.wikipedia.org/wiki/Byte_order_mark).
Expand Down
1 change: 1 addition & 0 deletions cmd/esbuild/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ var helpText = func(colors logger.Colors) string {
--out-extension:.js=.mjs Use a custom output extension instead of ".js"
--outbase=... The base path used to determine entry point output
paths (for multiple entry points)
--preserve-symlinks Disable symlink resolution for module lookup
--public-path=... Set the base URL for the "file" loader
--pure:N Mark the name N as a pure function for tree shaking
--resolve-extensions=... A comma-separated list of implicit extensions
Expand Down
1 change: 1 addition & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ const (

type Options struct {
Mode Mode
PreserveSymlinks bool
RemoveWhitespace bool
MinifyIdentifiers bool
MangleSyntax bool
Expand Down
28 changes: 16 additions & 12 deletions internal/resolver/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,13 +336,15 @@ func (r *resolver) finalizeResolve(result ResolveResult) *ResolveResult {
result.PreserveUnusedImportsTS = dirInfo.tsConfigJSON.PreserveImportsNotUsedAsValues
}

if entry, ok := dirInfo.entries[base]; ok {
if symlink := entry.Symlink(r.fs); symlink != "" {
// Is this entry itself a symlink?
path.Text = symlink
} else if dirInfo.absRealPath != "" {
// Is there at least one parent directory with a symlink?
path.Text = r.fs.Join(dirInfo.absRealPath, base)
if !r.options.PreserveSymlinks {
if entry, ok := dirInfo.entries[base]; ok {
if symlink := entry.Symlink(r.fs); symlink != "" {
// Is this entry itself a symlink?
path.Text = symlink
} else if dirInfo.absRealPath != "" {
// Is there at least one parent directory with a symlink?
path.Text = r.fs.Join(dirInfo.absRealPath, base)
}
}
}
}
Expand Down Expand Up @@ -768,11 +770,13 @@ func (r *resolver) dirInfoUncached(path string) *dirInfo {
info.enclosingBrowserScope = parentInfo.enclosingBrowserScope

// Make sure "absRealPath" is the real path of the directory (resolving any symlinks)
if entry, ok := parentInfo.entries[base]; ok {
if symlink := entry.Symlink(r.fs); symlink != "" {
info.absRealPath = symlink
} else if parentInfo.absRealPath != "" {
info.absRealPath = r.fs.Join(parentInfo.absRealPath, base)
if !r.options.PreserveSymlinks {
if entry, ok := parentInfo.entries[base]; ok {
if symlink := entry.Symlink(r.fs); symlink != "" {
info.absRealPath = symlink
} else if parentInfo.absRealPath != "" {
info.absRealPath = r.fs.Join(parentInfo.absRealPath, base)
}
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions lib/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ function flagsForBuildOptions(
let bundle = getFlag(options, keys, 'bundle', mustBeBoolean);
let watch = getFlag(options, keys, 'watch', mustBeBooleanOrObject);
let splitting = getFlag(options, keys, 'splitting', mustBeBoolean);
let preserveSymlinks = getFlag(options, keys, 'preserveSymlinks', mustBeBoolean);
let metafile = getFlag(options, keys, 'metafile', mustBeString);
let outfile = getFlag(options, keys, 'outfile', mustBeString);
let outdir = getFlag(options, keys, 'outdir', mustBeString);
Expand Down Expand Up @@ -209,6 +210,7 @@ function flagsForBuildOptions(
}
}
if (splitting) flags.push('--splitting');
if (preserveSymlinks) flags.push('--preserve-symlinks');
if (metafile) flags.push(`--metafile=${metafile}`);
if (outfile) flags.push(`--outfile=${outfile}`);
if (outdir) flags.push(`--outdir=${outdir}`);
Expand Down
1 change: 1 addition & 0 deletions lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ interface CommonOptions {
export interface BuildOptions extends CommonOptions {
bundle?: boolean;
splitting?: boolean;
preserveSymlinks?: boolean;
outfile?: string;
metafile?: string;
outdir?: string;
Expand Down
1 change: 1 addition & 0 deletions pkg/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ type BuildOptions struct {

GlobalName string
Bundle bool
PreserveSymlinks bool
Splitting bool
Outfile string
Metafile string
Expand Down
1 change: 1 addition & 0 deletions pkg/api/api_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,7 @@ func rebuildImpl(
AbsNodePaths: make([]string, len(buildOpts.NodePaths)),
Banner: buildOpts.Banner,
Footer: buildOpts.Footer,
PreserveSymlinks: buildOpts.PreserveSymlinks,
WatchMode: buildOpts.Watch != nil,
Plugins: plugins,
}
Expand Down
3 changes: 3 additions & 0 deletions pkg/cli/cli_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ func parseOptionsImpl(osArgs []string, buildOpts *api.BuildOptions, transformOpt
case arg == "--bundle" && buildOpts != nil:
buildOpts.Bundle = true

case arg == "--preserve-symlinks" && buildOpts != nil:
buildOpts.PreserveSymlinks = true

case arg == "--splitting" && buildOpts != nil:
buildOpts.Splitting = true

Expand Down
27 changes: 27 additions & 0 deletions scripts/end-to-end-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
// my Windows VM (Windows 10 in VirtualBox on macOS).
if (process.platform !== 'win32') {
tests.push(
// Without preserve symlinks
test(['--bundle', 'in.js', '--outfile=node.js'], {
'in.js': `import {foo} from 'foo'; if (foo !== 123) throw 'fail'`,
'registry/node_modules/foo/index.js': `export {bar as foo} from 'bar'`,
Expand All @@ -87,6 +88,32 @@
'node_modules/foo/index.js': { symlink: `TEST_DIR_ABS_PATH/registry/node_modules/foo/index.js` },
}),

// With preserve symlinks
test(['--bundle', 'src/in.js', '--outfile=node.js', '--preserve-symlinks'], {
'src/in.js': `import {foo} from 'foo'; if (foo !== 123) throw 'fail'`,
'registry/node_modules/foo/index.js': `export {bar as foo} from 'bar'`,
'src/node_modules/bar/index.js': `export const bar = 123`,
'src/node_modules/foo': { symlink: `../../registry/node_modules/foo` },
}),
test(['--bundle', 'src/in.js', '--outfile=node.js', '--preserve-symlinks'], {
'src/in.js': `import {foo} from 'foo'; if (foo !== 123) throw 'fail'`,
'registry/node_modules/foo/index.js': `export {bar as foo} from 'bar'`,
'src/node_modules/bar/index.js': `export const bar = 123`,
'src/node_modules/foo/index.js': { symlink: `../../../registry/node_modules/foo/index.js` },
}),
test(['--bundle', 'src/in.js', '--outfile=node.js', '--preserve-symlinks'], {
'src/in.js': `import {foo} from 'foo'; if (foo !== 123) throw 'fail'`,
'registry/node_modules/foo/index.js': `export {bar as foo} from 'bar'`,
'src/node_modules/bar/index.js': `export const bar = 123`,
'src/node_modules/foo': { symlink: `TEST_DIR_ABS_PATH/registry/node_modules/foo` },
}),
test(['--bundle', 'src/in.js', '--outfile=node.js', '--preserve-symlinks'], {
'src/in.js': `import {foo} from 'foo'; if (foo !== 123) throw 'fail'`,
'registry/node_modules/foo/index.js': `export {bar as foo} from 'bar'`,
'src/node_modules/bar/index.js': `export const bar = 123`,
'src/node_modules/foo/index.js': { symlink: `TEST_DIR_ABS_PATH/registry/node_modules/foo/index.js` },
}),

// This is a test for https://github.com/evanw/esbuild/issues/222
test(['--bundle', 'src/in.js', '--outfile=out/node.js', '--metafile=out/meta.json', '--platform=node', '--format=cjs'], {
'a/b/src/in.js': `
Expand Down

0 comments on commit f7d01de

Please sign in to comment.