@poppinss/ts-exec 1.4.1 → 1.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,43 +1,279 @@
1
- # @poppinss/ts-exec
1
+ <div align="center">
2
2
 
3
- TypeScript JIT compiler built for correctness and supports legacy/experimental decorators.
3
+ # 🚀 @poppinss/ts-exec
4
4
 
5
- <br />
5
+ A JIT compiler for running TypeScript and JavaScript code in Node.js without compilation, built on top of SWC with full ESM support for Node.js 24 and above.
6
6
 
7
7
  [![gh-workflow-image]][gh-workflow-url] [![npm-image]][npm-url] ![][typescript-image] [![license-image]][license-url]
8
8
 
9
- > [!IMPORTANT]
10
- > The `@poppinss/ts-exec` package requires `Node.js >= 24` and works with only ES modules.
9
+ </div>
10
+
11
+ <br />
12
+
13
+ ---
14
+
15
+ ## ðŸŽŊ Overview
16
+
17
+ `ts-exec` is a TypeScript execution engine that lets you run `.ts` and `.tsx` files directly in Node.js without a build step. **Unlike other popular solutions, ts-exec prioritizes compatibility with Node.js module resolution, ensuring that code running with ts-exec will work identically after compilation to JavaScript**.
18
+
19
+ <br />
20
+
21
+ ## ðŸ’Ą Why ts-exec exists
22
+
23
+ Existing solutions like `ts-node` and `tsx` have served the community well, but they come with significant tradeoffs that can lead to production issues.
24
+
25
+ `ts-node` is no longer actively maintained and has become bloated over time. While `tsx` offers a modern alternative, it makes a critical compromise: it allows extension-less imports and directory imports during development. This creates a dangerous disconnect. Your code runs perfectly in development but breaks in production when compiled to JavaScript, because Node.js strictly requires explicit file extensions and cannot resolve directory imports.
26
+
27
+ `ts-exec` takes a different approach. It provides the complete TypeScript feature set (including enums, legacy decorators, and JSX syntax) while strictly following Node.js file resolution rules. This means every import that works with ts-exec will work after compilation, eliminating an entire class of production deployment failures.
28
+
29
+ <br />
30
+
31
+ ## âœĻ Features
32
+
33
+ <table>
34
+ <tr>
35
+ <td>
36
+
37
+ ðŸŽĻ **Full TypeScript support**
38
+ Enums, legacy decorators, namespace imports, and JSX syntax
39
+
40
+ </td>
41
+ <td>
42
+
43
+ ðŸ›Ąïļ **Production-safe imports**
44
+ Enforces Node.js module resolution
45
+
46
+ </td>
47
+ </tr>
48
+ <tr>
49
+ <td>
50
+
51
+ ðŸ“Ķ **Built for ESM**
52
+ First-class support for ECMAScript modules
53
+
54
+ </td>
55
+ <td>
56
+
57
+ ⚡ **Modern foundation**
58
+ Built on SWC for fast compilation
59
+
60
+ </td>
61
+ </tr>
62
+ <tr>
63
+ <td>
64
+
65
+ ðŸŠķ **Lightweight**
66
+ Less than 200 lines, inspired by [Amaro](https://github.com/nodejs/amaro)
11
67
 
12
- ## Usage
68
+ </td>
69
+ <td>
13
70
 
14
- Install the package from the npm packages registry.
71
+ ⚙ïļ **Zero configuration**
72
+ No custom config files needed, parses tsconfig.json automatically
15
73
 
16
- ```sh
74
+ </td>
75
+ </tr>
76
+ <tr>
77
+ <td>
78
+
79
+ ✅ **Development confidence**
80
+ Code that runs with ts-exec will run after compilation
81
+
82
+ </td>
83
+ </tr>
84
+ </table>
85
+
86
+ <br />
87
+
88
+ ## ðŸ“Ķ Installation
89
+
90
+ ```bash
17
91
  npm i -D @poppinss/ts-exec
18
92
  ```
19
93
 
20
- Once installed you can use it via the `--import` flag to execute the TypeScript source code.
94
+ <br />
21
95
 
22
- ```sh
23
- node --import=@poppinss/ts-exec some-script.ts
96
+ ## ðŸšĶ Usage
97
+
98
+ ### Basic execution
99
+
100
+ Run any TypeScript file directly.
101
+
102
+ ```bash
103
+ node --import=@poppinss/ts-exec ./src/index.ts
24
104
  ```
25
105
 
26
- ## Why another package?
106
+ ### Programmatic usage
107
+
108
+ Use ts-exec within your Node.js application.
109
+
110
+ ```ts
111
+ import '@poppinss/ts-exec'
112
+
113
+ // Now you can import TypeScript files
114
+ const module = await import('./my-typescript-file.ts')
115
+ ```
116
+
117
+ <br />
118
+
119
+ ## 📝 Imports with `.ts` file extension
120
+
121
+ TypeScript originally made a deliberate decision to keep import paths unchanged during compilation. When you write an import in TypeScript, it stays exactly the same in the compiled JavaScript output. This design choice means you must reference the file extension that will exist after compilation, not the current TypeScript extension.
122
+
123
+ For example, when importing a TypeScript file, you write the import with a `.js` extension because that's what will exist after compilation.
124
+
125
+ ```ts
126
+ export class UserService {
127
+ // implementation
128
+ }
129
+ ```
130
+
131
+ ```ts
132
+ // Reference with .js even though the file is user_service.ts
133
+ import { UserService } from '../services/user_service.js'
134
+ ```
135
+
136
+ After compilation, both files become `.js` files, and the import path works seamlessly with Node.js without any modifications.
137
+
138
+ Recently, the TypeScript team introduced the `rewriteRelativeImportExtensions` compiler option, which allows you to use `.ts` extensions in your imports. When this option is enabled, TypeScript will rewrite `.ts` extensions to `.js` during compilation.
27
139
 
28
- ## Contributing
140
+ If you prefer to use `.ts` extensions in your imports, enable this option in your `tsconfig.json`.
141
+
142
+ ```json
143
+ {
144
+ "compilerOptions": {
145
+ "rewriteRelativeImportExtensions": true
146
+ }
147
+ }
148
+ ```
149
+
150
+ With this configuration, you can write imports using `.ts` extensions.
151
+
152
+ ```ts
153
+ // Now you can use .ts extension
154
+ import { UserService } from '../services/user_service.ts'
155
+ ```
156
+
157
+ TypeScript will automatically rewrite this to `.js` during compilation, and `ts-exec` will handle it correctly during development.
158
+
159
+ <br />
160
+
161
+ ### Subpath import aliases
162
+
163
+ Subpath import aliases are defined in your `package.json` file, which remains unchanged during the TypeScript compilation process. Since `package.json` is used directly by Node.js at runtime and is never rewritten by the TypeScript compiler, the paths you define in your aliases must reference the compiled output extensions.
164
+
165
+ This means your subpath aliases should always use `.js` extensions, even when the source files are `.ts`. The `package.json` file will be the same in both development (with ts-exec) and production (with compiled JavaScript), so the paths need to work for the compiled output.
166
+
167
+ ```json
168
+ {
169
+ "name": "my-app",
170
+ "imports": {
171
+ "#controllers/*": "./build/controllers/*.js",
172
+ "#services/*": "./build/services/*.js",
173
+ "#models/*": "./build/models/*.js"
174
+ }
175
+ }
176
+ ```
177
+
178
+ With these aliases defined, you can use them in your TypeScript source files.
179
+
180
+ ```ts
181
+ import { UsersController } from '#controllers/users_controller'
182
+ import { UserService } from '#services/user_service'
183
+ import { User } from '#models/user'
184
+ ```
185
+
186
+ This approach works seamlessly with both `ts-exec` during development and Node.js after compilation. The aliases resolve correctly in both environments because `package.json` remains unchanged and Node.js uses it directly for module resolution.
187
+
188
+ If you have `rewriteRelativeImportExtensions` enabled in your TypeScript configuration, it will not affect subpath import aliases. The rewriting only applies to relative imports (those starting with `./` or `../`), not to bare specifiers or subpath imports.
189
+
190
+ <br />
191
+
192
+ ## ðŸĪ” Why not tsx?
193
+
194
+ If you're currently using `tsx`, you might wonder why to switch. The answer depends on your priorities.
195
+
196
+ `tsx` is excellent and fast, but it allows patterns that will fail in production. Consider this common scenario:
197
+
198
+ <table>
199
+ <tr>
200
+ <th>❌ Works with tsx (breaks after compilation)</th>
201
+ <th>✅ Works with ts-exec (works after compilation)</th>
202
+ </tr>
203
+ <tr>
204
+ <td>
205
+
206
+ ```ts
207
+ // Extension-less import
208
+ import { User } from './models/user'
209
+
210
+ // Directory import
211
+ import config from './config'
212
+
213
+ // After compilation:
214
+ // Error: Cannot find module
215
+ ```
216
+
217
+ </td>
218
+ <td>
219
+
220
+ ```ts
221
+ // Explicit extension
222
+ import { User } from './models/user.ts'
223
+
224
+ // Explicit file
225
+ import config from './config/index.ts'
226
+
227
+ // After compilation:
228
+ // Works identically âœĻ
229
+ ```
230
+
231
+ </td>
232
+ </tr>
233
+ </table>
234
+
235
+ Additionally, `tsx` doesn't support legacy decorators, which many projects still rely on. `ts-exec` provides full decorator support, making it compatible with frameworks and libraries that haven't migrated to the new decorator specification.
236
+
237
+ <br />
238
+
239
+ ## 📊 Comparison
240
+
241
+ | Feature | ts-exec | tsx | ts-node | Node.js (native) |
242
+ | ----------------------------- | :-----: | :-: | :-----: | :--------------: |
243
+ | **Active maintenance** | ✅ | ✅ | ❌ | ✅ |
244
+ | **Built on SWC** | ✅ | ❌ | ⚠ïļ | ✅ |
245
+ | **Legacy decorators** | ✅ | ❌ | ✅ | ❌ |
246
+ | **Node.js-compliant imports** | ✅ | ❌ | ✅ | ✅ |
247
+ | **ESM-first** | ✅ | ✅ | ⚠ïļ | ✅ |
248
+ | **Full TypeScript features** | ✅ | ⚠ïļ | ✅ | ❌ |
249
+ | **Respects tsconfig.json** | ✅ | ✅ | ✅ | ❌ |
250
+ | **Lightweight** | ✅ | ✅ | ❌ | ✅ |
251
+
252
+ <br />
253
+
254
+ ---
255
+
256
+ <div align="center">
257
+
258
+ ## ðŸĪ Contributing
29
259
 
30
260
  One of the primary goals of Poppinss is to have a vibrant community of users and contributors who believes in the principles of the framework.
31
261
 
32
262
  We encourage you to read the [contribution guide](https://github.com/poppinss/.github/blob/main/docs/CONTRIBUTING.md) before contributing to the framework.
33
263
 
34
- ## Code of Conduct
264
+ <br />
265
+
266
+ ## 📜 Code of Conduct
35
267
 
36
268
  In order to ensure that the poppinss community is welcoming to all, please review and abide by the [Code of Conduct](https://github.com/poppinss/.github/blob/main/docs/CODE_OF_CONDUCT.md).
37
269
 
38
- ## License
270
+ <br />
271
+
272
+ ## 📄 License
273
+
274
+ @poppinss/ts-exec is open-sourced software licensed under the [MIT license](LICENSE.md).
39
275
 
40
- <pkg-name> is open-sourced software licensed under the [MIT license](LICENSE.md).
276
+ </div>
41
277
 
42
278
  [gh-workflow-image]: https://img.shields.io/github/actions/workflow/status/poppinss/ts-exec/checks.yml?style=for-the-badge
43
279
  [gh-workflow-url]: https://github.com/poppinss/ts-exec/actions/workflows/checks.yml 'Github action'
package/build/index.js CHANGED
@@ -1,3 +1,4 @@
1
1
  // index.ts
2
2
  import { register } from "module";
3
+ process.setSourceMapsEnabled(true);
3
4
  register("./src/loader.js", import.meta.url);
@@ -32,6 +32,9 @@ var DEFAULT_CONFIG = {
32
32
  runtime: "automatic"
33
33
  }
34
34
  },
35
+ experimental: {
36
+ keepImportAttributes: true
37
+ },
35
38
  keepClassNames: true
36
39
  }
37
40
  };
@@ -76,6 +79,9 @@ function tsConfigToSwcConfig(tsConfig2) {
76
79
  } : {}
77
80
  }
78
81
  },
82
+ experimental: {
83
+ keepImportAttributes: true
84
+ },
79
85
  keepClassNames: true
80
86
  }
81
87
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@poppinss/ts-exec",
3
3
  "description": "TypeScript JIT compiler built for correctness and supports legacy/experimental decorators",
4
- "version": "1.4.1",
4
+ "version": "1.4.3",
5
5
  "engines": {
6
6
  "node": ">=24.0.0"
7
7
  },
@@ -39,21 +39,21 @@
39
39
  "@japa/file-system": "^2.3.2",
40
40
  "@japa/runner": "^4.4.0",
41
41
  "@japa/snapshot": "^2.0.9",
42
- "@release-it/conventional-changelog": "^10.0.1",
43
- "@types/node": "^24.2.1",
42
+ "@release-it/conventional-changelog": "^10.0.2",
43
+ "@types/node": "^24.10.1",
44
44
  "c8": "^10.1.3",
45
- "eslint": "^9.33.0",
46
- "ipaddr.js": "^2.2.0",
47
- "preact": "^10.27.0",
48
- "preact-render-to-string": "^6.5.13",
49
- "prettier": "^3.6.2",
50
- "release-it": "^19.0.4",
51
- "tsup": "^8.5.0",
52
- "typescript": "^5.9.2"
45
+ "eslint": "^9.39.1",
46
+ "ipaddr.js": "^2.3.0",
47
+ "preact": "^10.28.0",
48
+ "preact-render-to-string": "^6.6.3",
49
+ "prettier": "^3.7.4",
50
+ "release-it": "^19.0.6",
51
+ "tsup": "^8.5.1",
52
+ "typescript": "^5.9.3"
53
53
  },
54
54
  "dependencies": {
55
- "@swc/core": "1.13.3",
56
- "get-tsconfig": "^4.10.1"
55
+ "@swc/core": "1.15.3",
56
+ "get-tsconfig": "^4.13.0"
57
57
  },
58
58
  "homepage": "https://github.com/poppinss/ts-exec#readme",
59
59
  "repository": {