Skip to content

Commit

Permalink
fix #3003, fix #3238: --packages= and tsconfig
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Aug 8, 2023
1 parent 727e5ff commit cb46459
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 31 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@

Note that using this feature means esbuild will potentially do a lot of file system I/O to find all possible files that might match the pattern. This is by design, and is not a bug. If this is a concern, I recommend either avoiding the `/**/` pattern (e.g. by not putting a `/` before a wildcard) or using this feature only in directory subtrees which do not have many files that don't match the pattern (e.g. making a subdirectory for your JSON files and explicitly including that subdirectory in the pattern).

* Path aliases in `tsconfig.json` no longer count as packages ([#2792](https://github.com/evanw/esbuild/issues/2792), [#3003](https://github.com/evanw/esbuild/issues/3003), [#3160](https://github.com/evanw/esbuild/issues/3160), [#3238](https://github.com/evanw/esbuild/issues/3238))

Setting `--packages=external` tells esbuild to make all import paths external when they look like a package path. For example, an import of `./foo/bar` is not a package path and won't be external while an import of `foo/bar` is a package path and will be external. However, the [`paths` field](https://www.typescriptlang.org/tsconfig#paths) in `tsconfig.json` allows you to create import paths that look like package paths but that do not resolve to packages. People do not want these paths to count as package paths. So with this release, the behavior of `--packages=external` has been changed to happen after the `tsconfig.json` path remapping step.

* Use the `local-css` loader for `.module.css` files by default ([#20](https://github.com/evanw/esbuild/issues/20))

With this release the `css` loader is still used for `.css` files except that `.module.css` files now use the `local-css` loader. This is a common convention in the web development community. If you need `.module.css` files to use the `css` loader instead, then you can override this behavior with `--loader:.module.css=css`.
Expand Down
31 changes: 31 additions & 0 deletions internal/bundler_tests/bundler_tsconfig_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2457,3 +2457,34 @@ func TestTsconfigIgnoreInsideNodeModules(t *testing.T) {
},
})
}

func TestTsconfigJsonPackagesExternal(t *testing.T) {
tsconfig_suite.expectBundled(t, bundled{
files: map[string]string{
"/Users/user/project/src/entry.js": `
import truePkg from 'pkg1'
import falsePkg from 'internal/pkg2'
truePkg()
falsePkg()
`,
"/Users/user/project/src/tsconfig.json": `
{
"compilerOptions": {
"paths": {
"internal/*": ["./stuff/*"]
}
}
}
`,
"/Users/user/project/src/stuff/pkg2.js": `
export default success
`,
},
entryPaths: []string{"/Users/user/project/src/entry.js"},
options: config.Options{
Mode: config.ModeBundle,
AbsOutputFile: "/Users/user/project/out.js",
ExternalPackages: true,
},
})
}
13 changes: 13 additions & 0 deletions internal/bundler_tests/snapshots/snapshots_tsconfig.txt
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,19 @@ TestTsconfigJsonOverrideNodeModules
// Users/user/project/other/foo-good.ts
console.log("good");

================================================================================
TestTsconfigJsonPackagesExternal
---------- /Users/user/project/out.js ----------
// Users/user/project/src/entry.js
import truePkg from "pkg1";

// Users/user/project/src/stuff/pkg2.js
var pkg2_default = success;

// Users/user/project/src/entry.js
truePkg();
pkg2_default();

================================================================================
TestTsconfigJsonTrailingCommaAllowed
---------- /Users/user/project/out.js ----------
Expand Down
67 changes: 36 additions & 31 deletions internal/resolver/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -436,19 +436,6 @@ func (res *Resolver) Resolve(sourceDir string, importPath string, kind ast.Impor
}, debugMeta
}

// "import 'pkg'" when all packages are external (vs. "import './pkg'")
if r.options.ExternalPackages && IsPackagePath(importPath) && !r.fs.IsAbs(importPath) && !strings.HasPrefix(importPath, "#") {
if r.debugLogs != nil {
r.debugLogs.addNote("Marking this path as external because it's a package path")
}

r.flushDebugLogs(flushDueToSuccess)
return &ResolveResult{
PathPair: PathPair{Primary: logger.Path{Text: importPath}},
IsExternal: true,
}, debugMeta
}

// "import fs from 'fs'"
if r.options.Platform == config.PlatformNode && BuiltInNodeModules[importPath] {
if r.debugLogs != nil {
Expand Down Expand Up @@ -1010,12 +997,48 @@ func (r resolverQuery) resolveWithoutSymlinks(sourceDir string, sourceDirInfo *d
}
}

// First, check path overrides from the nearest enclosing TypeScript "tsconfig.json" file
if sourceDirInfo != nil {
if tsConfigJSON := r.tsConfigForDir(sourceDirInfo); tsConfigJSON != nil {
// Try path substitutions first
if tsConfigJSON.Paths != nil {
if absolute, ok, diffCase := r.matchTSConfigPaths(tsConfigJSON, importPath); ok {
return &ResolveResult{PathPair: absolute, DifferentCase: diffCase}
}
}

// Try looking up the path relative to the base URL
if tsConfigJSON.BaseURL != nil {
basePath := r.fs.Join(*tsConfigJSON.BaseURL, importPath)
if absolute, ok, diffCase := r.loadAsFileOrDirectory(basePath); ok {
return &ResolveResult{PathPair: absolute, DifferentCase: diffCase}
}
}
}
}

// Check both relative and package paths for CSS URL tokens, with relative
// paths taking precedence over package paths to match Webpack behavior.
isPackagePath := IsPackagePath(importPath)
checkRelative := !isPackagePath || r.kind.IsFromCSS()
checkPackage := isPackagePath

// "import 'pkg'" when all packages are external (vs. "import './pkg'"). This
// is deliberately done after we check for "tsconfig.json" aliases because
// people want to be able to make things look like packages but have them not
// be packages.
if r.options.ExternalPackages && isPackagePath && !strings.HasPrefix(importPath, "#") {
if r.debugLogs != nil {
r.debugLogs.addNote("Marking this path as external because it's a package path")
}

r.flushDebugLogs(flushDueToSuccess)
return &ResolveResult{
PathPair: PathPair{Primary: logger.Path{Text: importPath}},
IsExternal: true,
}
}

if checkRelative {
absPath := r.fs.Join(sourceDir, importPath)

Expand Down Expand Up @@ -2295,24 +2318,6 @@ func (r resolverQuery) loadNodeModules(importPath string, dirInfo *dirInfo, forb
defer r.debugLogs.decreaseIndent()
}

// First, check path overrides from the nearest enclosing TypeScript "tsconfig.json" file
if tsConfigJSON := r.tsConfigForDir(dirInfo); tsConfigJSON != nil {
// Try path substitutions first
if tsConfigJSON.Paths != nil {
if absolute, ok, diffCase := r.matchTSConfigPaths(tsConfigJSON, importPath); ok {
return absolute, true, diffCase
}
}

// Try looking up the path relative to the base URL
if tsConfigJSON.BaseURL != nil {
basePath := r.fs.Join(*tsConfigJSON.BaseURL, importPath)
if absolute, ok, diffCase := r.loadAsFileOrDirectory(basePath); ok {
return absolute, true, diffCase
}
}
}

// Find the parent directory with the "package.json" file
dirInfoPackageJSON := dirInfo
for dirInfoPackageJSON != nil && dirInfoPackageJSON.packageJSON == nil {
Expand Down

0 comments on commit cb46459

Please sign in to comment.