folke / esbuild-runner Goto Github PK
View Code? Open in Web Editor NEW⚡️ Super-fast on-the-fly transpilation of modern JS, TypeScript and JSX using esbuild
Home Page: https://www.npmjs.com/package/esbuild-runner
License: Apache License 2.0
⚡️ Super-fast on-the-fly transpilation of modern JS, TypeScript and JSX using esbuild
Home Page: https://www.npmjs.com/package/esbuild-runner
License: Apache License 2.0
Hi,
in the same vein as #23, unless I'm mistaken, it seems that the --loader
esbuild option is not currently supported.
Similarly to the externals
issue, a merge of user provided loaders with the default stack could be considered.
My use case is testing modules that use static binary assets.
My esbuild-runner-config.js
:
module.exports = {
type: 'bundle',
esbuild: {
target: 'node14',
format: 'cjs',
loader: {
'.png': 'binary'
}
}
}
Result:
> lib/loader-issue.js:1:16: error: No loader is configured for ".png" files: assets/img/image.png
1 │ import pngImage from '../assets/img/image.png'
╵ ~~~~~~~~~~~~~~~~~~~~~~~~~
Thanks for a great tool!
I'm trying to switch from ts-node
to esbuild-runner
for my package https://github.com/Julien-Marcou/static-html
Here is the problematic file bin/static.ts :
#!/usr/bin/env -S npx ts-node-script
import * as fs from 'fs';
const usage = 'Usage : npx static <init|build|watch|serve|deploy|clean>\n';
// ...
The goal of this file is to expose npx static
commands to developers who install my package.
But when I replace #!/usr/bin/env -S npx ts-node-script
by #!/usr/bin/env -S npx esbuild-runner
, I then get this error when calling my npx static
command :
(node:1888) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
(Use `node --trace-warnings ...` to show where the warning was created)
/home/jmarcou/dev/my-project/node_modules/static-html/bin/static.ts:2
import * as fs from 'fs';
^^^^^^
SyntaxError: Cannot use import statement outside a module
As if esbuild
thinks I'm targeting ECMAScript Module
instead of CommonJS
.
I did create a esbuild-runner-config.js
file, and tried to put it inside the root folder of the static-html
package aswell as the bin folder, but nothing changed.
module.exports = {
type: 'bundle',
esbuild: {
target: 'node14',
format: 'cjs',
},
};
Am I doing something wrong ?
I’m curious if there are benchmarks between this and say native ESM loading. Just to get a rough idea of cost (cached/cold).
Thanks!
I'm executing a script like this: esr scripts/script
My environment requires the current working directory to be the root of my project. When executing a script inside the scripts
folder, the current working directory will not be the root.
Is there any way around this?
Thanks in advance!
Not sure what I'm doing wrong but...
node -r esbuild-runner/register helloworld.ts
TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for /Users/cjr/dev/packages/api/helloworld.ts
at new NodeError (node:internal/errors:363:5)
at Loader.defaultGetFormat [as _getFormat] (node:internal/modules/esm/get_format:71:15)
at Loader.getFormat (node:internal/modules/esm/loader:105:42)
at Loader.getModuleJob (node:internal/modules/esm/loader:243:31)
at Loader.import (node:internal/modules/esm/loader:177:17)
at Object.loadESM (node:internal/process/esm_loader:68:5)
helloworld.ts:
console.log("HELLO WORLD LITERALLY!");
export default {}
node -v
> v16.3.0
In a monorepo, importing from different files of a sibling workspace package leads to duplicate code in generated bundle.
Consider this monorepo:
packages/a/1.ts
imports ./shared
packages/a/2.ts
imports ./shared
packages/a/shared.ts
— this import gets duplicated in esbuild-runner bundlepackages/b/index.ts
— imports @test/a/1
and @test/a/2
then run:
cd packages/b
pnpm esr index.ts
The code in shared.ts
will execute twice.
Complete minimal reproduction: https://github.com/IlyaSemenov/esbuild-runner-monorepo-duplicate-import
I believe here:
Lines 35 to 38 in 6e5d00b
we can filter externals
with something like:
.filter(e => !(pkg.dependencies?.[e] || pkg.devDependencies?.[e]).startsWith("workspace:"))
When the package is configured with "type": "module"
all .js
files are interpreted as ESM by default, including esbuild-runner.config.js
. We would need to set the extension to .cjs
instead.
However the file name is hardcoded and always uses .js
maybe add support for passing esbuild options for 'install' functions? like this:
const { install } = require('esbuild-runner');
install({
type: 'transform',
debug: false,
esbuild: {
target: 'esnext',
plugins: [...]
}
});
I have a build.ts
which I run to compile my source files with esbuild
. To run it I have a npm-run-script:
"compile": "node -r esbuild-runner/register build.ts",
We do not have tslib
explicitly installed in our project. When running the above command we get the following error:
/Users/<project-folder>/node_modules/esbuild-runner/lib/esbuild.js:22
externals = (0, tslib_1.__spreadArray)((0, tslib_1.__spreadArray)([], Object.keys((_a = pkg.dependencies) !== null && _a !== void 0 ? _a : {}), true), Object.keys((_b = pkg.devDependencies) !== null && _b !== void 0 ? _b : {}), true);
TypeError: (0 , tslib_1.__spreadArray) is not a function
at Object.<anonymous> (/Users/<project-folder>/node_modules/esbuild-runner/lib/esbuild.js:22:70)
If I add tslib
explicitly to the project, the above command runs without any problems.
I believe esbuild.config.js
is too generic naming. It misleads the reader as if that were esbuild config, which it is not. It also 'squats' the place for the actual esbuild config, for example if developer wanted to keep and reuse esbuild settings between different components of the project (such as: esbuild-runner, estrella, vite, esbuild-loader, etc.)
I believe esbuild-runner.config.js
would be better naming, directly explaining the purpose of the file.
I created an issue/question for this in SST at sst/sst#1065. I'm wondering if I'm doing something wrong or if this just a shortcoming of esbuild-runner
. How come the jest.mock()
calls are not hoisted to the top in the generated JavaScript files of Jest tests written in TypeScript? Below is snippet of the resulting JavaScript, notice the jest.mock()
calls appear towards the middle, nowhere near the top as Jest babel-jest
transformer for example would do,
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const lambda = __importStar(require("../src/acme-lambda"));
jest.mock('ioredis');
jest.mock('@acme/common-util');
...
This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.
These updates are currently rate-limited. Click on a checkbox below to force their creation now.
These updates have all been created already. Click a checkbox below to force a retry/rebase of any.
@types/eslint
, @types/eslint-plugin-prettier
, @types/node
, @types/prettier
, @types/source-map-support
, @typescript-eslint/eslint-plugin
, @typescript-eslint/parser
, esbuild
, eslint
, eslint-config-prettier
, eslint-plugin-import
, eslint-plugin-jest
, husky
, jest
, prettier
, release-it
, tslib
, type-fest
, typescript
, typesync
)@types/node
, @types/prettier
, @types/rimraf
)@typescript-eslint/eslint-plugin
, @typescript-eslint/parser
, eslint
, eslint-config-prettier
, eslint-plugin-jest
, eslint-plugin-prettier
, eslint-plugin-unicorn
, prettier
).github/workflows/node.js.yml
actions/checkout v3
actions/setup-node v3
package.json
source-map-support 0.5.21
tslib 2.4.0
@release-it/conventional-changelog 5.1.1
@types/eslint 8.4.7
@types/eslint-plugin-prettier 3.1.0
@types/node 18.8.5
@types/prettier 2.7.1
@types/rimraf 3.0.2
@types/source-map-support 0.5.6
@typescript-eslint/eslint-plugin 5.40.1
@typescript-eslint/parser 5.40.1
devmoji 2.3.0
esbuild 0.15.12
eslint 8.25.0
eslint-config-prettier 8.5.0
eslint-plugin-eslint-comments 3.2.0
eslint-plugin-import 2.26.0
eslint-plugin-jest 27.1.3
eslint-plugin-node 11.1.0
eslint-plugin-prettier 4.2.1
eslint-plugin-promise 6.1.1
eslint-plugin-unicorn 44.0.2
husky 8.0.1
jest 29.2.1
prettier 2.7.1
release-it 15.5.0
rimraf 3.0.2
type-fest 3.1.0
typescript 4.8.4
typesync 0.9.2
esbuild *
If I import a function from one script into another then require.main === module
is true in both so they both fully run. This is different behavior from node and ts-node.
Hi,
I love esbuild-runner
, however I tried to replace my toolchain for testing with esbuild-runner
but I can't get the same result as ts-node
did.
I ran nyc
with mocha
like this,
nyc mocha -r ts-node/register './src/**/*.test.ts' --extension ts
and replace with
nyc mocha -r esbuild-runner/register './src/**/*.test.ts' --extension ts
But it seemed I didn't get the same result as ts-node
version
Thanks
config
// esbuild-runner.config.js
/* eslint-disable import/no-extraneous-dependencies */
const path = require('path');
const { esbuildDecorators } = require('@anatine/esbuild-decorators');
const tsconfig = path.resolve(__dirname, './tsconfig.json');
const getEsbuildOptions = async () => ({
// Any esbuild build or transform options go here
platform: 'node',
target: 'esnext',
sourcemap: false,
plugins: [esbuildDecorators({ tsconfig, cwd: process.cwd() })],
});
const getConfig = async () => ({
type: 'bundle', // bundle or transform (see description above)
esbuild: await getEsbuildOptions(),
});
module.exports = getConfig();
bin.js
if (typeof process.env.NODE_ENV === 'undefined') {
process.env.NODE_ENV = 'development';
}
require('esbuild-runner/register');
require('module-alias/register');
error
ColumnTypeUndefinedError: Column type for PostEntity#title is not defined and cannot be guessed. Make sure you have turned on an "emitDecoratorMetadata": true option in tsconfig.json. Also make sure you have imported "reflect-metadata" on top of the main entry file in your application (before any entity imported).If you are using JavaScript instead of TypeScript you must explicitly provide a column type.
at new Co
The documentation says:
Dependencies defined in
package.json
ornode_modules
will never be transpiled.
This is not entirely true. In a pnpm project with multiple workspaces, node_modules
coming from a sibling workspace module are transpiled. I believe they should not, similar to the module's own node_modules
.
In the example:
node -r esbuild-runner/register hello-world.ts
How does one pass options to esbuild, such as for example --external:nock
?
any plugin or way check type error before run?
I have wrong type in typescript but esbuild runner just run code without checking type.
I install npm i esbuild-plugin-ts-checker
and add to plugin but not work
I often use esbuild-runner CLI for running test code written in TypeScript. It's helpful to print esr version while sharing the test data and output for easy reproduction. However, esr does not have -v
or --version
option.
$ node -v
v16.18.1
$ esr -v
Usage: esr [options] <source-file> [file-options]
--cache Transform on a file per file basis and cache code
--clearCache Clear transform cache
--help|-h Display this help message
$ esr --version
Usage: esr [options] <source-file> [file-options]
--cache Transform on a file per file basis and cache code
--clearCache Clear transform cache
--help|-h Display this help message
Add -v
or --version
option which prints version of the esbuild-runner being used.
I use fnm for managing node versions. I can run grep on package.json file
$ grep '"version"' /run/user/267807/fnm_multishells/22654_1669997929042/lib/node_modules/esbuild-runner/package.json
"version": "2.2.2",
However, the package.json will be located on different path for nvm, or node installed directly.
It seems like the loader
I defined in my config is not being passed to Esbuild.
module.exports = {
debug: true,
esbuild: {
loader: { '.js': 'jsx' },
target: 'esnext',
},
type: 'transform', // I also tried bundle
};
Note: Dropped a
console.log
in this file, it is being loaded.
{
"transform": {
"^.+\\.(js|jsx|ts|tsx)$": "esbuild-runner/jest"
}
}
yarn run v1.22.17
$ jest spec/javascript/components/Accordion.test.js
RUNS spec/javascript/components/Accordion.test.js
✘ [ERROR] The JSX syntax extension is not currently enabled
/workspace/spec/javascript/components/Accordion.test.js:11:6:
11 │ <Accordion expanded={false}>
╵ ^
The esbuild loader for this file is currently set to "js" but it must be set to "jsx" to
FAIL spec/javascript/components/Accordion.test.js { '.js': 'jsx' }" to do that.
● Test suite failed to run
Transform failed with 1 error:
/workspace/spec/javascript/components/Accordion.test.js:11:6: ERROR: The JSX syntax extension is not currently enabled
at failureErrorWithLog (node_modules/esbuild/lib/main.js:1603:15)
at node_modules/esbuild/lib/main.js:1392:29
at node_modules/esbuild/lib/main.js:666:9
at handleIncomingPacket (node_modules/esbuild/lib/main.js:763:9)
at Socket.readFromStdout (node_modules/esbuild/lib/main.js:632:7)
Test Suites: 1 failed, 1 total
Tests: 0 total
Snapshots: 0 total
Time: 0.228 s
Ran all test suites matching /spec\/javascript\/components\/Accordion.test.js/i.
error Command failed with exit code 1.
Getting an error when trying to use esbuild-runner with the latest version of Jest. Config is simple:
transform: {
'\\.ts$': 'esbuild-runner/jest',
},
Versions:
jest: 27.0.4
esbuild-runner: 2.2.0
There is an error with this repository's Renovate configuration that needs to be fixed. As a precaution, Renovate will stop PRs until it is resolved.
Error type: undefined. Note: this is a nested preset so please contact the preset author if you are unable to fix it yourself.
Hello,
I tried defining pg-native
as an external dependency but it seems the option is ignored, i.e., not being merged with the computed externals here:
Line 94 in 5f005db
My esbuild-runner.config.js
:
module.exports = {
type: 'bundle',
esbuild: {
external: ['pg-native'],
},
}
and the error that is produced when running:
> ../../node_modules/pg/lib/native/client.js:4:21: error: Could not resolve "pg-native" (mark it as external to exclude it from the bundle, or surround it with try/catch to handle the failure at run-time)
4 │ var Native = require('pg-native')
╵ ~~~~~~~~~~~
/Users/vieira/Code/f1/node_modules/esbuild/lib/main.js:1466
let error = new Error(`${text}${summary}`);
^
Error: Build failed with 1 error:
../../node_modules/pg/lib/native/client.js:4:21: error: Could not resolve "pg-native" (mark it as external to exclude it from the bundle, or surround it with try/catch to handle the failure at run-time)
at failureErrorWithLog (/Users/vieira/Code/f1/node_modules/esbuild/lib/main.js:1466:15)
at /Users/vieira/Code/f1/node_modules/esbuild/lib/main.js:1148:28
at runOnEndCallbacks (/Users/vieira/Code/f1/node_modules/esbuild/lib/main.js:1066:65)
at buildResponseToResult (/Users/vieira/Code/f1/node_modules/esbuild/lib/main.js:1146:7)
at /Users/vieira/Code/f1/node_modules/esbuild/lib/main.js:1253:14
at /Users/vieira/Code/f1/node_modules/esbuild/lib/main.js:629:9
at handleIncomingPacket (/Users/vieira/Code/f1/node_modules/esbuild/lib/main.js:726:9)
at readFromStdout (/Users/vieira/Code/f1/node_modules/esbuild/lib/main.js:596:7)
at runServiceSync (/Users/vieira/Code/f1/node_modules/esbuild/lib/main.js:1831:3)
at Object.buildSync (/Users/vieira/Code/f1/node_modules/esbuild/lib/main.js:1651:3)
I should note that I am using npm7 workspaces and that pg-native
is a dependency of a dependency of another package in the workspace, if I add the dependency directly to the package.json
of the package I am trying to run it works (the externals
computation finds it).
I am guessing that many, like myself, would like to use esbuild-runner in their Typescript tool chain.
It would be very useful for people who want to try things out to have working examples with different links in the chain other than Jest. For examples might include how to use with:
I would be more than happy to help with this but my attempts to get it to work with node --test -r esbuild-runner/register
have failed...
Hi,
I noticed having type: 'bundle'
in my esbuild-runner config broke my test coverage, so swapped it out to "transform"
.
This, however, caused my loader
definition to be ignored.
Would it be possible to give type: 'transform'
the same love you gave to bundle
in #24 ?
Thanks!
Loving this tools. Makes using esbuild that bit easier.
One thing I would love, is a first class support for watching. I currently use nodemon to accomplish this, which works reasonably well, but wonder if this could be improved, by having esbuild runner do it all (and keeping it in memory):
yarn run nodemon --watch 'src/**/*' -e ts,tsx --exec 'dotenv -e=.env -- yarn run esr --cache src/main.ts'"
Hi,
trying to replace node with esr, here is the nodejs way in package.json:
"d": " node -r dotenv/config --inspect=0.0.0.0",
how can we achieve this? following not working:
"esr": " esr -r dotenv/config --inspect=0.0.0.0",
I'm trying to workaround #36 for .mts
files.
I tried switching from ts-node
to esbuild-runner
, as you can see here.
In this project, and I obtain paths from Error.stack
, very simply, as you can see here:
const location = new Error().stack!
.split("\n")[2]
.replace(/^\s+at /, "");
For some reason, the paths in stack-traces appear to... multiply?
For example, if you run npm run test
, you'll see test output like this:
× [equal] it produces the expected test results
└ /home/mindplay/workspace/funky-test/test/test/test.ts:76:10
That path is /home/mindplay/workspace/funky-test/test/test.ts:76:10
, so there's a /test
too many in there.
As there is test coverage for that fact, you will see failing tests as well:
× "location": "/home/mindplay/workspace/funky-test/test/test/cases.ts:9:6",
√ "location": "/home/mindplay/workspace/funky-test/test/cases.ts:9:6",
Something appears to be not right with the run-time path resolution of this loader?
In jest version 28 was changed transform return type
https://jestjs.io/docs/upgrading-to-jest28#transformer
I used this patch to bypass the problem
index df993a4..be2603e 100644
--- a/node_modules/esbuild-runner/lib/jest.js
+++ b/node_modules/esbuild-runner/lib/jest.js
@@ -3,7 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
var esbuild_1 = require("./esbuild");
require("./register");
function process(src, filename) {
- return (0, esbuild_1.transpile)(src, filename, { type: "transform" });
+ const code = (0, esbuild_1.transpile)(src, filename, { type: 'transform' })
+ return { code }
}
exports.default = { process: process };
//# sourceMappingURL=jest.js.map
Thanks for a great library!
Can we bother you for a new version release? It'd be nice to get Jest v28 support #65 out so we can upgrade our dependencies.
Hello! Thanks for this awesome project, it's really cool!
The only thing that blocks me from using it is esbuild version is hardcoded hence I cannot use the latest version.
Could we make it a peerDependencies? Thanks!
The esbuild-node-externals plugin allows you to specify an allowList
parameter for including dependencies into the bundle.
Why would you want this? For example:
"foo": "link:.src/some/path/foo"
in the package.json. These aren't really external dependencies and they should be bundled/transpiled, they're just a convenient way to make bits of the source appear as top-level packages for import
.In our case, the first bullet prevents us from using esbuild-runner for some of our tools: our source tree is pure ESM, esr transpiles to CJS for running under node except the internally linked entries defined in packages.json aren't being bundled, so the result doesn't run.
I would like to suggest one or two options:
allowList
or externalsAllowList
, specifying dependencies that should be transpiled/bundled.If this is something you'd consider, I could try to make a PR.
When I use node-tap
with esbuild-runner
, it fails to parse source code and show proper line numbers. When I replace esbuild-runner
with @swc-node/register
, everything works fine.
I am not exactly sure it's esbuild-runner
's problem, but I suspect so. I don't think node-tap
has some inner hacks specifically tailored to @swc-node/register
, it's more probable that esbuild-runner
fails to emit the source map in the generally assumable way.
Example source code:
import tap from "tap"
tap.same("a", "b")
@swc-node/register
Everything works as expected, it shows source code fully:
yarn tap --node-arg '-r' --node-arg '@swc-node/register' test.ts
emits:
FAIL test.ts
✖ should be equivalent
test.ts
1 | import tap from "tap"
2 |
> 3 | tap.same("a", "b")
| ----^
--- expected
+++ actual
@@ -1,1 +1,1 @@
-"b"
+"a"
esbuild-register
It fails to parse sourcemap and show source code with proper line numbers:
yarn tap --node-arg '-r' --node-arg 'esbuild-register' test.ts
emits:
FAIL test.ts
✖ should be equivalent
--- expected
+++ actual
@@ -1,1 +1,1 @@
-"b"
+"a"
test: test.ts
at:
line: 20
column: 20
file: test.ts
stack: |
Object.<anonymous> (test.ts:20:20)
Module.replacementCompile (node_modules/append-transform/index.js:60:13)
Module._compile (node_modules/esbuild-register/dist/node.js:2258:26)
module.exports (node_modules/default-require-extensions/js.js:7:9)
node_modules/append-transform/index.js:64:4
newLoader (node_modules/esbuild-register/dist/node.js:2262:9)
Object.<anonymous> (node_modules/append-transform/index.js:64:4)
See https://github.com/IlyaSemenov/esbuild-runner-node-tap-repro for the complete repro.
If we could use either esbuild or esbuild-wasm, that would be very helpful.
Thanks for the package, it performs well and is simple to set up. ❤️
I'm using it as a Jest transformer and trying to test a function written in Typescript to read a package JSON file:
import { createRequire } from 'module'
import { resolve } from 'path'
export const requirePackage = (path: string) =>
createRequire(import.meta.url)(resolve(path, 'package.json'))
I get an error from import.meta.url
being undefined.
Possibly related issue in TS-Jest? kulshekhar/ts-jest#1174
the plugins option must in async config
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.