22import {
33 CancelToken ,
44} from "@esfx/canceltoken" ;
5+ import assert from "assert" ;
56import chalk from "chalk" ;
67import chokidar from "chokidar" ;
78import esbuild from "esbuild" ;
@@ -46,7 +47,7 @@ import {
4647void 0 ;
4748
4849const copyrightFilename = "./scripts/CopyrightNotice.txt" ;
49- const copyright = memoize ( async ( ) => {
50+ const getCopyrightHeader = memoize ( async ( ) => {
5051 const contents = await fs . promises . readFile ( copyrightFilename , "utf-8" ) ;
5152 return contents . replace ( / \r \n / g, "\n" ) ;
5253} ) ;
@@ -76,7 +77,7 @@ export const generateLibs = task({
7677 run : async ( ) => {
7778 await fs . promises . mkdir ( "./built/local" , { recursive : true } ) ;
7879 for ( const lib of libs ( ) ) {
79- let output = await copyright ( ) ;
80+ let output = await getCopyrightHeader ( ) ;
8081
8182 for ( const source of lib . sources ) {
8283 const contents = await fs . promises . readFile ( source , "utf-8" ) ;
@@ -187,10 +188,13 @@ async function runDtsBundler(entrypoint, output) {
187188 */
188189function createBundler ( entrypoint , outfile , taskOptions = { } ) {
189190 const getOptions = memoize ( async ( ) => {
191+ const copyright = await getCopyrightHeader ( ) ;
192+ const banner = taskOptions . exportIsTsObject ? "var ts = {}; ((module) => {" : "" ;
193+
190194 /** @type {esbuild.BuildOptions } */
191195 const options = {
192196 entryPoints : [ entrypoint ] ,
193- banner : { js : await copyright ( ) } ,
197+ banner : { js : copyright + banner } ,
194198 bundle : true ,
195199 outfile,
196200 platform : "node" ,
@@ -205,12 +209,10 @@ function createBundler(entrypoint, outfile, taskOptions = {}) {
205209 } ;
206210
207211 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; }` } ;
214216
215217 // esbuild converts calls to "require" to "__require"; this function
216218 // calls the real require if it exists, or throws if it does not (rather than
@@ -227,13 +229,25 @@ function createBundler(entrypoint, outfile, taskOptions = {}) {
227229 const fakeName = "Q" . repeat ( require . length ) ;
228230 const fakeNameRegExp = new RegExp ( fakeName , "g" ) ;
229231 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+
230238 options . plugins = [
231239 {
232- name : "fix-require " ,
240+ name : "post-process " ,
233241 setup : build => {
234242 build . onEnd ( async ( ) => {
235243 let contents = await fs . promises . readFile ( outfile , "utf-8" ) ;
236244 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" ) ;
237251 await fs . promises . writeFile ( outfile , contents ) ;
238252 } ) ;
239253 } ,
@@ -450,7 +464,7 @@ export = ts;
450464 * @param {string } contents
451465 */
452466async 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" ;
454468}
455469
456470const lssl = task ( {
0 commit comments