@@ -31,8 +31,8 @@ function getCopyrightHeader() {
3131const cleanTasks = [ ] ;
3232
3333
34- // TODO(jakebailey): This is really gross. Waiting on https://github.com/microsoft/TypeScript/issues/25613,
35- // or at least control over noEmit / emitDeclarationOnly in build mode.
34+ // TODO(jakebailey): This is really gross. If the build is cancelled (i.e. Ctrl+C), the modification will persist.
35+ // Waiting on: https://github.com/microsoft/TypeScript/issues/51164
3636let currentlyBuilding = 0 ;
3737let oldTsconfigBase ;
3838
@@ -180,18 +180,18 @@ async function runDtsBundler(entrypoint, output) {
180180}
181181
182182/**
183+ * @typedef {{
184+ external?: string[];
185+ exportIsTsObject?: boolean;
186+ setDynamicImport?: boolean;
187+ }} ESBuildTaskOptions
183188 * @param {string } entrypoint
184189 * @param {string } outfile
185- * @param {boolean } exportIsTsObject True if this file exports the TS object and should have relevant code injected.
190+ * @param {ESBuildTaskOptions | undefined } [taskOptions]
186191 */
187- function esbuildTask ( entrypoint , outfile , exportIsTsObject = false ) {
192+ function esbuildTask ( entrypoint , outfile , taskOptions = { } ) {
188193 return {
189194 build : async ( ) => {
190- // Note: we do not use --minify, as that would hide function names from user backtraces
191- // (we don't ship our sourcemaps), and would break consumers like monaco which modify
192- // typescript.js for their own needs. Also, using --sourcesContent=false doesn't help,
193- // as even though it's a smaller source map that could be shipped to users for better
194- // stack traces via names, the maps are bigger than the actual source files themselves.
195195 /** @type {esbuild.BuildOptions } */
196196 const options = {
197197 entryPoints : [ entrypoint ] ,
@@ -202,10 +202,33 @@ async function runDtsBundler(entrypoint, output) {
202202 target : "es2018" , // Covers Node 10.
203203 format : "cjs" ,
204204 sourcemap : "linked" ,
205- external : [ "./node_modules/*" ] ,
206- conditions : [ "require" ] ,
205+ sourcesContent : false ,
206+ external : [
207+ ...( taskOptions . external ?? [ ] ) ,
208+ "source-map-support" ,
209+ ] ,
210+ logLevel : "warning" ,
207211 // legalComments: "none", // If we add copyright headers to the source files, uncomment.
208212 plugins : [
213+ {
214+ name : "no-node-modules" ,
215+ setup : ( build ) => {
216+ build . onLoad ( { filter : / [ \\ / ] n o d e _ m o d u l e s [ \\ / ] / } , ( ) => {
217+ // Ideally, we'd use "--external:./node_modules/*" here, but that doesn't work; we
218+ // will instead end up with paths to node_modules rather than the package names.
219+ // Instead, we'll return a load error when we see that we're trying to bundle from
220+ // node_modules, then explicitly declare which external dependencies we rely on, which
221+ // ensures that the correct module specifier is kept in the output (the non-wildcard
222+ // form works properly). It also helps us keep tabs on what external dependencies we
223+ // may be importing, which is handy.
224+ //
225+ // See: https://github.com/evanw/esbuild/issues/1958
226+ return {
227+ errors : [ { text : 'Attempted to bundle from node_modules; ensure "external" is set correctly.' } ]
228+ } ;
229+ } ) ;
230+ }
231+ } ,
209232 {
210233 name : "fix-require" ,
211234 setup : ( build ) => {
@@ -216,36 +239,36 @@ async function runDtsBundler(entrypoint, output) {
216239 // to be consumable by other bundlers, we need to convert these calls back to
217240 // require so our imports are visible again.
218241 //
219- // Note that this step breaks source maps, but only for lines that reference
220- // "__require", which is an okay tradeoff for the performance of not running
221- // the output through transpileModule/babel/etc.
242+ // The leading spaces are to keep the offsets the same within the files to keep
243+ // source maps working (though this only really matters for the line the require is on).
222244 //
223245 // See: https://github.com/evanw/esbuild/issues/1905
224246 let contents = await fs . promises . readFile ( outfile , "utf-8" ) ;
225- contents = contents . replace ( / _ _ r e q u i r e \( / g, "require(" ) ;
247+ contents = contents . replace ( / _ _ r e q u i r e \( / g, " require(" ) ;
226248 await fs . promises . writeFile ( outfile , contents ) ;
227249 } ) ;
228250 } ,
229251 }
230252 ]
231253 } ;
232254
233- if ( exportIsTsObject ) {
234- options . format = "iife" ; // We use an IIFE so we can inject the code below.
255+ if ( taskOptions . exportIsTsObject ) {
256+ // These snippets cannot appear in the actual source files, otherwise they will be rewritten
257+ // to things like exports or requires.
258+
259+ // If we are in a CJS context, export the ts namespace.
260+ let footer = `\nif (typeof module !== "undefined" && module.exports) { module.exports = ts; }` ;
261+
262+ if ( taskOptions . setDynamicImport ) {
263+ // If we are in a server bundle, inject the dynamicImport function.
264+ // This only works because the web server's "start" function returns;
265+ // the node server does not, but we don't use this there.
266+ footer += `\nif (ts.server && ts.server.setDynamicImport) { ts.server.setDynamicImport(id => import(id)); }` ;
267+ }
268+
269+ options . format = "iife" ; // We use an IIFE so we can inject the footer, and so that "ts" is global if not loaded as a module.
235270 options . globalName = "ts" ; // Name the variable ts, matching our old big bundle and so we can use the code below.
236- options . footer = {
237- // These snippets cannot appear in the actual source files, otherwise they will be rewritten
238- // to things like exports or requires.
239- js : `
240- if (typeof module !== "undefined" && module.exports) {
241- // If we are in a CJS context, export the ts namespace.
242- module.exports = ts;
243- }
244- if (ts.server) {
245- // If we are in a server bundle, inject the dynamicImport function.
246- ts.server.dynamicImport = id => import(id);
247- }`
248- } ;
271+ options . footer = { js : footer } ;
249272 }
250273
251274 await esbuild . build ( options ) ;
@@ -282,7 +305,7 @@ const cleanDebugTools = task({
282305cleanTasks . push ( cleanDebugTools ) ;
283306
284307
285- const esbuildTsc = esbuildTask ( "./src/tsc/tsc.ts" , "./built/local/tsc.js" , /* exportIsTsObject */ true ) ;
308+ const esbuildTsc = esbuildTask ( "./src/tsc/tsc.ts" , "./built/local/tsc.js" ) ;
286309
287310export const buildTsc = task ( {
288311 name : "tsc" ,
@@ -311,7 +334,7 @@ const buildServicesWithTsc = task({
311334
312335// TODO(jakebailey): rename this; no longer "services".
313336
314- const esbuildServices = esbuildTask ( "./src/typescript/typescript.ts" , "./built/local/typescript.js" , /* exportIsTsObject */ true ) ;
337+ const esbuildServices = esbuildTask ( "./src/typescript/typescript.ts" , "./built/local/typescript.js" , { exportIsTsObject : true } ) ;
315338
316339export const buildServices = task ( {
317340 name : "services" ,
@@ -339,7 +362,7 @@ export const dtsServices = task({
339362 run : ( ) => runDtsBundler ( "./built/local/typescript/typescript.d.ts" , "./built/local/typescript.d.ts" ) ,
340363} ) ;
341364
342- const esbuildServer = esbuildTask ( "./src/tsserver/server.ts" , "./built/local/tsserver.js" , /* exportIsTsObject */ true ) ;
365+ const esbuildServer = esbuildTask ( "./src/tsserver/server.ts" , "./built/local/tsserver.js" , { exportIsTsObject : true , setDynamicImport : true } ) ;
343366
344367export const buildServer = task ( {
345368 name : "tsserver" ,
@@ -380,7 +403,7 @@ const buildLsslWithTsc = task({
380403 run : ( ) => buildProject ( "src/tsserverlibrary" ) ,
381404} ) ;
382405
383- const esbuildLssl = esbuildTask ( "./src/tsserverlibrary/tsserverlibrary.ts" , "./built/local/tsserverlibrary.js" , /* exportIsTsObject */ true ) ;
406+ const esbuildLssl = esbuildTask ( "./src/tsserverlibrary/tsserverlibrary.ts" , "./built/local/tsserverlibrary.js" , { exportIsTsObject : true } ) ;
384407
385408export const buildLssl = task ( {
386409 name : "lssl" ,
@@ -414,7 +437,15 @@ export const dts = task({
414437
415438
416439const testRunner = "./built/local/run.js" ;
417- const esbuildTests = esbuildTask ( "./src/testRunner/_namespaces/Harness.ts" , testRunner ) ;
440+ const esbuildTests = esbuildTask ( "./src/testRunner/_namespaces/Harness.ts" , testRunner , {
441+ external : [
442+ "chai" ,
443+ "del" ,
444+ "diff" ,
445+ "mocha" ,
446+ "ms" ,
447+ ] ,
448+ } ) ;
418449
419450export const buildTests = task ( {
420451 name : "tests" ,
0 commit comments