1
1
// @ts -check
2
2
import { CancelToken } from "@esfx/canceltoken" ;
3
- import assert from "assert" ;
4
3
import chalk from "chalk" ;
5
4
import chokidar from "chokidar" ;
6
5
import esbuild from "esbuild" ;
@@ -172,25 +171,22 @@ async function runDtsBundler(entrypoint, output) {
172
171
* @param {BundlerTaskOptions } [taskOptions]
173
172
*
174
173
* @typedef BundlerTaskOptions
175
- * @property {boolean } [exportIsTsObject]
176
174
* @property {boolean } [treeShaking]
177
175
* @property {boolean } [usePublicAPI]
178
176
* @property {() => void } [onWatchRebuild]
179
177
*/
180
178
function createBundler ( entrypoint , outfile , taskOptions = { } ) {
181
179
const getOptions = memoize ( async ( ) => {
182
180
const copyright = await getCopyrightHeader ( ) ;
183
- const banner = taskOptions . exportIsTsObject ? "var ts = {}; ((module) => {" : "" ;
184
-
185
181
/** @type {esbuild.BuildOptions } */
186
182
const options = {
187
183
entryPoints : [ entrypoint ] ,
188
- banner : { js : copyright + banner } ,
184
+ banner : { js : copyright } ,
189
185
bundle : true ,
190
186
outfile,
191
187
platform : "node" ,
192
188
target : [ "es2020" , "node14.17" ] ,
193
- format : "cjs " ,
189
+ format : "esm " ,
194
190
sourcemap : "linked" ,
195
191
sourcesContent : false ,
196
192
treeShaking : taskOptions . treeShaking ,
@@ -200,66 +196,17 @@ function createBundler(entrypoint, outfile, taskOptions = {}) {
200
196
} ;
201
197
202
198
if ( taskOptions . usePublicAPI ) {
203
- options . external = [ "./typescript.js" ] ;
204
199
options . plugins = options . plugins || [ ] ;
205
200
options . plugins . push ( {
206
- name : "remap-typescript-to-require " ,
201
+ name : "remap-typescript-to-public-api " ,
207
202
setup ( build ) {
208
- build . onLoad ( { filter : / s r c [ \\ / ] t y p e s c r i p t [ \\ / ] t y p e s c r i p t \. t s $ / } , ( ) => {
209
- return { contents : `export * from "./typescript.js"` } ;
203
+ build . onResolve ( { filter : / ^ (?: \. \. [ \\ / ] ) * t y p e s c r i p t [ \\ / ] t y p e s c r i p t \. j s $ / } , ( ) => {
204
+ return { path : "./typescript.js" , external : true } ;
210
205
} ) ;
211
206
} ,
212
207
} ) ;
213
208
}
214
209
215
- if ( taskOptions . exportIsTsObject ) {
216
- // Monaco bundles us as ESM by wrapping our code with something that defines module.exports
217
- // but then does not use it, instead using the `ts` variable. Ensure that if we think we're CJS
218
- // that we still set `ts` to the module.exports object.
219
- options . footer = { js : `})({ get exports() { return ts; }, set exports(v) { ts = v; if (typeof module !== "undefined" && module.exports) { module.exports = v; } } })` } ;
220
-
221
- // esbuild converts calls to "require" to "__require"; this function
222
- // calls the real require if it exists, or throws if it does not (rather than
223
- // throwing an error like "require not defined"). But, since we want typescript
224
- // to be consumable by other bundlers, we need to convert these calls back to
225
- // require so our imports are visible again.
226
- //
227
- // To fix this, we redefine "require" to a name we're unlikely to use with the
228
- // same length as "require", then replace it back to "require" after bundling,
229
- // ensuring that source maps still work.
230
- //
231
- // See: https://github.com/evanw/esbuild/issues/1905
232
- const require = "require" ;
233
- const fakeName = "Q" . repeat ( require . length ) ;
234
- const fakeNameRegExp = new RegExp ( fakeName , "g" ) ;
235
- options . define = { [ require ] : fakeName } ;
236
-
237
- // For historical reasons, TypeScript does not set __esModule. Hack esbuild's __toCommonJS to be a noop.
238
- // We reference `__copyProps` to ensure the final bundle doesn't have any unreferenced code.
239
- const toCommonJsRegExp = / v a r _ _ t o C o m m o n J S .* / ;
240
- const toCommonJsRegExpReplacement = "var __toCommonJS = (mod) => (__copyProps, mod); // Modified helper to skip setting __esModule." ;
241
-
242
- options . plugins = options . plugins || [ ] ;
243
- options . plugins . push (
244
- {
245
- name : "post-process" ,
246
- setup : build => {
247
- build . onEnd ( async ( ) => {
248
- let contents = await fs . promises . readFile ( outfile , "utf-8" ) ;
249
- contents = contents . replace ( fakeNameRegExp , require ) ;
250
- let matches = 0 ;
251
- contents = contents . replace ( toCommonJsRegExp , ( ) => {
252
- matches ++ ;
253
- return toCommonJsRegExpReplacement ;
254
- } ) ;
255
- assert ( matches === 1 , "Expected exactly one match for __toCommonJS" ) ;
256
- await fs . promises . writeFile ( outfile , contents ) ;
257
- } ) ;
258
- } ,
259
- } ,
260
- ) ;
261
- }
262
-
263
210
return options ;
264
211
} ) ;
265
212
@@ -305,6 +252,7 @@ let printedWatchWarning = false;
305
252
* @param {string } options.output
306
253
* @param {boolean } [options.enableCompileCache]
307
254
* @param {Task[] } [options.mainDeps]
255
+ * @param {boolean } [options.reexportDefault]
308
256
* @param {BundlerTaskOptions } [options.bundlerOptions]
309
257
*/
310
258
function entrypointBuildTask ( options ) {
@@ -329,13 +277,13 @@ function entrypointBuildTask(options) {
329
277
const moduleSpecifier = path . relative ( outDir , output ) ;
330
278
const lines = [
331
279
`// This file is a shim which defers loading the real module until the compile cache is enabled.` ,
332
- `try { ` ,
333
- ` const { enableCompileCache } = require("node:module"); ` ,
334
- ` if ( enableCompileCache) { ` ,
335
- ` enableCompileCache(); ` ,
336
- ` } ` ,
337
- `} catch {} ` ,
338
- `module.exports = require("./${ moduleSpecifier . replace ( / [ \\ / ] / g, "/" ) } ");` ,
280
+ `import mod from "node:module"; ` ,
281
+ `if (mod.enableCompileCache) { ` ,
282
+ ` mod. enableCompileCache(); ` ,
283
+ `} ` ,
284
+ `// Keep this synchronous so downstream people who required this file do not see TLA. ` ,
285
+ `const require = mod.createRequire(import.meta.url); ` ,
286
+ `require("./${ moduleSpecifier . replace ( / [ \\ / ] / g, "/" ) } ");` ,
339
287
] ;
340
288
await fs . promises . writeFile ( originalOutput , lines . join ( "\n" ) + "\n" ) ;
341
289
} ,
@@ -355,22 +303,33 @@ function entrypointBuildTask(options) {
355
303
} ) ;
356
304
357
305
/**
358
- * Writes a CJS module that reexports another CJS file. E.g. given
306
+ * Writes a module that reexports another file. E.g. given
359
307
* `options.builtEntrypoint = "./built/local/tsc/tsc.js"` and
360
308
* `options.output = "./built/local/tsc.js"`, this will create a file
361
309
* named "./built/local/tsc.js" containing:
362
310
*
363
311
* ```
364
- * module.exports = require( "./tsc/tsc.js")
312
+ * export * from "./tsc/tsc.js";
365
313
* ```
366
314
*/
367
315
const shim = task ( {
368
316
name : `shim-${ options . name } ` ,
369
317
run : async ( ) => {
370
318
const outDir = path . dirname ( output ) ;
371
319
await fs . promises . mkdir ( outDir , { recursive : true } ) ;
372
- const moduleSpecifier = path . relative ( outDir , options . builtEntrypoint ) ;
373
- await fs . promises . writeFile ( output , `module.exports = require("./${ moduleSpecifier . replace ( / [ \\ / ] / g, "/" ) } ")` ) ;
320
+ const moduleSpecifier = path . relative ( outDir , options . builtEntrypoint ) . replace ( / [ \\ / ] / g, "/" ) ;
321
+ const lines = [
322
+ `export * from "./${ moduleSpecifier } ";` ,
323
+ ] ;
324
+
325
+ if ( options . reexportDefault ) {
326
+ lines . push (
327
+ `import _default from "./${ moduleSpecifier } ";` ,
328
+ `export default _default;` ,
329
+ ) ;
330
+ }
331
+
332
+ await fs . promises . writeFile ( output , lines . join ( "\n" ) + "\n" ) ;
374
333
} ,
375
334
} ) ;
376
335
@@ -435,7 +394,7 @@ const { main: services, build: buildServices, watch: watchServices } = entrypoin
435
394
builtEntrypoint : "./built/local/typescript/typescript.js" ,
436
395
output : "./built/local/typescript.js" ,
437
396
mainDeps : [ generateLibs ] ,
438
- bundlerOptions : { exportIsTsObject : true } ,
397
+ reexportDefault : true ,
439
398
} ) ;
440
399
export { services , watchServices } ;
441
400
@@ -477,25 +436,22 @@ export const watchMin = task({
477
436
dependencies : [ watchTsc , watchTsserver ] ,
478
437
} ) ;
479
438
480
- // This is technically not enough to make tsserverlibrary loadable in the
481
- // browser, but it's unlikely that anyone has actually been doing that.
482
439
const lsslJs = `
483
- if (typeof module !== "undefined" && module.exports) {
484
- module.exports = require("./typescript.js");
485
- }
486
- else {
487
- throw new Error("tsserverlibrary requires CommonJS; use typescript.js instead");
488
- }
440
+ import ts from "./typescript.js";
441
+ export * from "./typescript.js";
442
+ export default ts;
489
443
` ;
490
444
491
445
const lsslDts = `
492
- import ts = require("./typescript.js");
493
- export = ts;
446
+ import ts from "./typescript.js";
447
+ export * from "./typescript.js";
448
+ export default ts;
494
449
` ;
495
450
496
451
const lsslDtsInternal = `
497
- import ts = require("./typescript.internal.js");
498
- export = ts;
452
+ import ts from "./typescript.internal.js";
453
+ export * from "./typescript.internal.js";
454
+ export default ts;
499
455
` ;
500
456
501
457
/**
@@ -536,7 +492,7 @@ const { main: tests, watch: watchTests } = entrypointBuildTask({
536
492
description : "Builds the test infrastructure" ,
537
493
buildDeps : [ generateDiagnostics ] ,
538
494
project : "src/testRunner" ,
539
- srcEntrypoint : "./src/testRunner/_namespaces/Harness .ts" ,
495
+ srcEntrypoint : "./src/testRunner/runner .ts" ,
540
496
builtEntrypoint : "./built/local/testRunner/runner.js" ,
541
497
output : testRunner ,
542
498
mainDeps : [ generateLibs ] ,
0 commit comments