"use strict;" directive sometimes not included when using a custom plugin
- Dominant language
- Go
- Stars
- 40.1k
- Forks
- 1.3k
- PR merge metrics
- No merged PRs in 30d
Description
## Issue
"use strict;" directive sometimes not included when using a custom plugin.
If the custom plugin resolves an`entry-point` into a javascript file which imports the `entry-point`, the "strict" flag seems to be dropped and "use strict" is not emitted.
Here's a walkthru of the issue: https://share.commandbar.com/CP3F2nMN
## Steps to reproduce
### Sample project
Here's a sample project that reproduces the issue (download and run "yarn && yarn node esbuild.js" then examine dist/bundle*.js): [esbuild-bug-onresolve-plugin.tgz](https://github.com/evanw/esbuild/files/12529869/esbuild-bug-onresolve-plugin.tgz)
### Summary
Consider this build file with a plugin:
```js
//// esbuild.js
const esbuild = require('esbuild');
const path = require("path");
function myPlugin() {
const pluginName = 'myPlugin';
return {
name: pluginName,
setup({ onLoad, onResolve, resolve }) {
onResolve({ filter: /.*/ }, async (args) => {
if (args.kind !== "entry-point") {
return;
} else {
return {
pluginName,
path: path.join(args.resolveDir, args.path), // note: unused but will show up in metafile.json,
namespace: '__my_plugin_namespace__',
pluginData: {
originalPath: args.path,
originalResolveDir: args.resolveDir,
},
// add a suffix; will cause esbuild to re-resolve the path when we reimport it below
suffix: "?__my_plugin_suffix__=true",
};
}
});
onLoad({ filter: /.*/, namespace: '__my_plugin_namespace__' }, (args) => {
const originalPath = args.pluginData.originalPath;
const originalResolveDir = args.pluginData.originalResolveDir;
return {
loader: "js",
pluginName,
contents: `import ${JSON.stringify(originalPath)};`,
resolveDir: originalResolveDir,
};
});
}
};
}
esbuild.build({
entryPoints: ['src/index.ts'],
bundle: true,
outfile: 'dist/bundle.js',
plugins: [
myPlugin(),
]
})
```
```js
///// src/index.ts
function fn() { console.log("`this` should be 'undefined'", this===undefined, this); }
fn();
export default "Hello World!";
```
```js
//// tsconfig.json
{
"compilerOptions": {
"target": "es2016",
"module": "commonjs",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
}
}
```
## Expected result:
Because the `tsconfig.json` file includes "strict: true", `esbuild` should include "use strict;" somewhere in the built file so that "fn" is executed in strict mode.
## Actual result:
With "myPlugin" installed, the emitted file looks like this:
```js
(() => {
// src/index.ts
function fn() {
console.log("`this` should be 'undefined'", this === void 0, this);
}
fn();
})();
```
Without "myPlugin" installed, we get the "use strict" directive at the top of the file as expected:
```js
"use strict";
(() => {
// src/index.ts
function fn() {
console.log("`this` should be 'undefined'", this === void 0, this);
}
fn();
var src_default = "Hello World!";
})();
```
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with the supplied esbuild.js plugin reproduction, run "yarn && yarn node esbuild.js", and compare dist/bundle*.js with and without the plugin. Trace how src/index.ts, tsconfig.json, and the plugin's re-resolved entry point affect strict-mode output; done means the bundled code preserves the expected "use strict" directive when the plugin is enabled.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go, javascript, typescript
- Domain
- build-system, compilers, tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100