2
2
import {
3
3
CancelToken ,
4
4
} from "@esfx/canceltoken" ;
5
+ import assert from "assert" ;
5
6
import chalk from "chalk" ;
6
7
import chokidar from "chokidar" ;
7
8
import esbuild from "esbuild" ;
@@ -46,7 +47,7 @@ import {
46
47
void 0 ;
47
48
48
49
const copyrightFilename = "./scripts/CopyrightNotice.txt" ;
49
- const copyright = memoize ( async ( ) => {
50
+ const getCopyrightHeader = memoize ( async ( ) => {
50
51
const contents = await fs . promises . readFile ( copyrightFilename , "utf-8" ) ;
51
52
return contents . replace ( / \r \n / g, "\n" ) ;
52
53
} ) ;
@@ -76,7 +77,7 @@ export const generateLibs = task({
76
77
run : async ( ) => {
77
78
await fs . promises . mkdir ( "./built/local" , { recursive : true } ) ;
78
79
for ( const lib of libs ( ) ) {
79
- let output = await copyright ( ) ;
80
+ let output = await getCopyrightHeader ( ) ;
80
81
81
82
for ( const source of lib . sources ) {
82
83
const contents = await fs . promises . readFile ( source , "utf-8" ) ;
@@ -187,10 +188,13 @@ async function runDtsBundler(entrypoint, output) {
187
188
*/
188
189
function createBundler ( entrypoint , outfile , taskOptions = { } ) {
189
190
const getOptions = memoize ( async ( ) => {
191
+ const copyright = await getCopyrightHeader ( ) ;
192
+ const banner = taskOptions . exportIsTsObject ? "var ts = {}; ((module) => {" : "" ;
193
+
190
194
/** @type {esbuild.BuildOptions } */
191
195
const options = {
192
196
entryPoints : [ entrypoint ] ,
193
- banner : { js : await copyright ( ) } ,
197
+ banner : { js : copyright + banner } ,
194
198
bundle : true ,
195
199
outfile,
196
200
platform : "node" ,
@@ -205,12 +209,10 @@ function createBundler(entrypoint, outfile, taskOptions = {}) {
205
209
} ;
206
210
207
211
if ( taskOptions . exportIsTsObject ) {
208
- // We use an IIFE so we can inject the footer, and so that "ts" is global if not loaded as a module.
209
- options . format = "iife" ;
210
- // Name the variable ts, matching our old big bundle and so we can use the code below.
211
- options . globalName = "ts" ;
212
- // If we are in a CJS context, export the ts namespace.
213
- options . footer = { js : `\nif (typeof module !== "undefined" && module.exports) { module.exports = ts; }` } ;
212
+ // Monaco bundles us as ESM by wrapping our code with something that defines module.exports
213
+ // but then does not use it, instead using the `ts` variable. Ensure that if we think we're CJS
214
+ // that we still set `ts` to the module.exports object.
215
+ options . footer = { js : `})(typeof module !== "undefined" && module.exports ? module : { exports: ts });\nif (typeof module !== "undefined" && module.exports) { ts = module.exports; }` } ;
214
216
215
217
// esbuild converts calls to "require" to "__require"; this function
216
218
// calls the real require if it exists, or throws if it does not (rather than
@@ -227,13 +229,25 @@ function createBundler(entrypoint, outfile, taskOptions = {}) {
227
229
const fakeName = "Q" . repeat ( require . length ) ;
228
230
const fakeNameRegExp = new RegExp ( fakeName , "g" ) ;
229
231
options . define = { [ require ] : fakeName } ;
232
+
233
+ // For historical reasons, TypeScript does not set __esModule. Hack esbuild's __toCommonJS to be a noop.
234
+ // We reference `__copyProps` to ensure the final bundle doesn't have any unreferenced code.
235
+ const toCommonJsRegExp = / v a r _ _ t o C o m m o n J S .* / ;
236
+ const toCommonJsRegExpReplacement = "var __toCommonJS = (mod) => (__copyProps, mod); // Modified helper to skip setting __esModule." ;
237
+
230
238
options . plugins = [
231
239
{
232
- name : "fix-require " ,
240
+ name : "post-process " ,
233
241
setup : build => {
234
242
build . onEnd ( async ( ) => {
235
243
let contents = await fs . promises . readFile ( outfile , "utf-8" ) ;
236
244
contents = contents . replace ( fakeNameRegExp , require ) ;
245
+ let matches = 0 ;
246
+ contents = contents . replace ( toCommonJsRegExp , ( ) => {
247
+ matches ++ ;
248
+ return toCommonJsRegExpReplacement ;
249
+ } ) ;
250
+ assert ( matches === 1 , "Expected exactly one match for __toCommonJS" ) ;
237
251
await fs . promises . writeFile ( outfile , contents ) ;
238
252
} ) ;
239
253
} ,
@@ -450,7 +464,7 @@ export = ts;
450
464
* @param {string } contents
451
465
*/
452
466
async function fileContentsWithCopyright ( contents ) {
453
- return await copyright ( ) + contents . trim ( ) . replace ( / \r \n / g, "\n" ) + "\n" ;
467
+ return await getCopyrightHeader ( ) + contents . trim ( ) . replace ( / \r \n / g, "\n" ) + "\n" ;
454
468
}
455
469
456
470
const lssl = task ( {
0 commit comments