Skip to content

Commit

Permalink
fix #2776: assume extensionless files are js
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Dec 28, 2022
1 parent f42ca4a commit 466473b
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 3 deletions.
30 changes: 30 additions & 0 deletions CHANGELOG.md
@@ -1,5 +1,35 @@
# Changelog

## Unreleased

* Loader defaults to `js` for extensionless files ([#2776](https://github.com/evanw/esbuild/issues/2776))

Certain packages contain files without an extension. For example, the `yargs` package contains the file `yargs/yargs` which has no extension. Node, Webpack, and Parcel can all understand code that imports `yargs/yargs` because they assume that the file is JavaScript. However, esbuild was previously unable to understand this code because it relies on the file extension to tell it how to interpret the file. With this release, esbuild will now assume files without an extension are JavaScript files. This can be customized by setting the loader for `""` (the empty string, representing files without an extension) to another loader. For example, if you want files without an extension to be treated as CSS instead, you can do that like this:

* CLI:

```
esbuild --bundle --loader:=css
```

* JS:

```js
esbuild.build({
bundle: true,
loader: { '': 'css' },
})
```

* Go:

```go
api.Build(api.BuildOptions{
Bundle: true,
Loader: map[string]api.Loader{"": api.LoaderCSS},
})
```

## 0.16.11

* Avoid a syntax error in the presence of direct `eval` ([#2761](https://github.com/evanw/esbuild/issues/2761))
Expand Down
1 change: 1 addition & 0 deletions internal/bundler/bundler.go
Expand Up @@ -2216,6 +2216,7 @@ func (s *scanner) validateTLA(sourceIndex uint32) tlaCheck {

func DefaultExtensionToLoaderMap() map[string]config.Loader {
return map[string]config.Loader{
"": config.LoaderJS, // This represents files without an extension
".js": config.LoaderJS,
".mjs": config.LoaderJS,
".cjs": config.LoaderJS,
Expand Down
6 changes: 3 additions & 3 deletions internal/bundler_tests/bundler_default_test.go
Expand Up @@ -1122,16 +1122,16 @@ func TestRequireBadExtension(t *testing.T) {
default_suite.expectBundled(t, bundled{
files: map[string]string{
"/entry.js": `
console.log(require('./test'))
console.log(require('./test.bad'))
`,
"/test": `This is a test.`,
"/test.bad": `This is a test.`,
},
entryPaths: []string{"/entry.js"},
options: config.Options{
Mode: config.ModeBundle,
AbsOutputFile: "/out.js",
},
expectedScanLog: `entry.js: ERROR: Do not know how to load path: test
expectedScanLog: `entry.js: ERROR: No loader is configured for ".bad" files: test.bad
`,
})
}
Expand Down
30 changes: 30 additions & 0 deletions scripts/js-api-tests.js
Expand Up @@ -63,6 +63,36 @@ let buildTests = {
}
},

// Verify that it's possible to disable a loader by setting it to "default".
// In particular, verify that it's possible to disable the special loader ""
// for extensionless files.
async errorIfExtensionlessLoaderIsDisabled({ esbuild, testDir }) {
let entry = path.join(testDir, 'entry.js');
let what = path.join(testDir, 'what');
await writeFileAsync(entry, 'import "./what"')
await writeFileAsync(what, 'foo()')
await esbuild.build({
entryPoints: [entry],
bundle: true,
write: false,
})
try {
await esbuild.build({
entryPoints: [entry],
bundle: true,
write: false,
logLevel: 'silent',
loader: { '': 'default' },
})
throw new Error('Expected build failure');
} catch (e) {
const relPath = path.relative(process.cwd(), what).split(path.sep).join('/')
if (!e.errors || !e.errors[0] || e.errors[0].text !== 'Do not know how to load path: ' + relPath) {
throw e;
}
}
},

async mangleCacheBuild({ esbuild }) {
var result = await esbuild.build({
stdin: {
Expand Down

0 comments on commit 466473b

Please sign in to comment.