@@ -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,14 +202,37 @@ 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+ ] ,
207210 supported : {
208211 // "const-and-let": false, // https://github.com/evanw/esbuild/issues/297
209212 "object-rest-spread" : false , // Performance enhancement, see: https://github.com/evanw/esbuild/releases/tag/v0.14.46
210213 } ,
214+ logLevel : "warning" ,
211215 // legalComments: "none", // If we add copyright headers to the source files, uncomment.
212216 plugins : [
217+ {
218+ name : "no-node-modules" ,
219+ setup : ( build ) => {
220+ build . onLoad ( { filter : / [ \\ / ] n o d e _ m o d u l e s [ \\ / ] / } , ( ) => {
221+ // Ideally, we'd use "--external:./node_modules/*" here, but that doesn't work; we
222+ // will instead end up with paths to node_modules rather than the package names.
223+ // Instead, we'll return a load error when we see that we're trying to bundle from
224+ // node_modules, then explicitly declare which external dependencies we rely on, which
225+ // ensures that the correct module specifier is kept in the output (the non-wildcard
226+ // form works properly). It also helps us keep tabs on what external dependencies we
227+ // may be importing, which is handy.
228+ //
229+ // See: https://github.com/evanw/esbuild/issues/1958
230+ return {
231+ errors : [ { text : 'Attempted to bundle from node_modules; ensure "external" is set correctly.' } ]
232+ } ;
233+ } ) ;
234+ }
235+ } ,
213236 {
214237 name : "fix-require" ,
215238 setup : ( build ) => {
@@ -220,36 +243,36 @@ async function runDtsBundler(entrypoint, output) {
220243 // to be consumable by other bundlers, we need to convert these calls back to
221244 // require so our imports are visible again.
222245 //
223- // Note that this step breaks source maps, but only for lines that reference
224- // "__require", which is an okay tradeoff for the performance of not running
225- // the output through transpileModule/babel/etc.
246+ // The leading spaces are to keep the offsets the same within the files to keep
247+ // source maps working (though this only really matters for the line the require is on).
226248 //
227249 // See: https://github.com/evanw/esbuild/issues/1905
228250 let contents = await fs . promises . readFile ( outfile , "utf-8" ) ;
229- contents = contents . replace ( / _ _ r e q u i r e \( / g, "require(" ) ;
251+ contents = contents . replace ( / _ _ r e q u i r e \( / g, " require(" ) ;
230252 await fs . promises . writeFile ( outfile , contents ) ;
231253 } ) ;
232254 } ,
233255 }
234256 ]
235257 } ;
236258
237- if ( exportIsTsObject ) {
238- options . format = "iife" ; // We use an IIFE so we can inject the code below.
259+ if ( taskOptions . exportIsTsObject ) {
260+ // These snippets cannot appear in the actual source files, otherwise they will be rewritten
261+ // to things like exports or requires.
262+
263+ // If we are in a CJS context, export the ts namespace.
264+ let footer = `\nif (typeof module !== "undefined" && module.exports) { module.exports = ts; }` ;
265+
266+ if ( taskOptions . setDynamicImport ) {
267+ // If we are in a server bundle, inject the dynamicImport function.
268+ // This only works because the web server's "start" function returns;
269+ // the node server does not, but we don't use this there.
270+ footer += `\nif (ts.server && ts.server.setDynamicImport) { ts.server.setDynamicImport(id => import(id)); }` ;
271+ }
272+
273+ 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.
239274 options . globalName = "ts" ; // Name the variable ts, matching our old big bundle and so we can use the code below.
240- options . footer = {
241- // These snippets cannot appear in the actual source files, otherwise they will be rewritten
242- // to things like exports or requires.
243- js : `
244- if (typeof module !== "undefined" && module.exports) {
245- // If we are in a CJS context, export the ts namespace.
246- module.exports = ts;
247- }
248- if (ts.server) {
249- // If we are in a server bundle, inject the dynamicImport function.
250- ts.server.dynamicImport = id => import(id);
251- }`
252- } ;
275+ options . footer = { js : footer } ;
253276 }
254277
255278 await esbuild . build ( options ) ;
@@ -286,7 +309,7 @@ const cleanDebugTools = task({
286309cleanTasks . push ( cleanDebugTools ) ;
287310
288311
289- const esbuildTsc = esbuildTask ( "./src/tsc/tsc.ts" , "./built/local/tsc.js" , /* exportIsTsObject */ true ) ;
312+ const esbuildTsc = esbuildTask ( "./src/tsc/tsc.ts" , "./built/local/tsc.js" ) ;
290313
291314export const buildTsc = task ( {
292315 name : "tsc" ,
@@ -315,7 +338,7 @@ const buildServicesWithTsc = task({
315338
316339// TODO(jakebailey): rename this; no longer "services".
317340
318- const esbuildServices = esbuildTask ( "./src/typescript/typescript.ts" , "./built/local/typescript.js" , /* exportIsTsObject */ true ) ;
341+ const esbuildServices = esbuildTask ( "./src/typescript/typescript.ts" , "./built/local/typescript.js" , { exportIsTsObject : true } ) ;
319342
320343export const buildServices = task ( {
321344 name : "services" ,
@@ -343,7 +366,7 @@ export const dtsServices = task({
343366 run : ( ) => runDtsBundler ( "./built/local/typescript/typescript.d.ts" , "./built/local/typescript.d.ts" ) ,
344367} ) ;
345368
346- const esbuildServer = esbuildTask ( "./src/tsserver/server.ts" , "./built/local/tsserver.js" , /* exportIsTsObject */ true ) ;
369+ const esbuildServer = esbuildTask ( "./src/tsserver/server.ts" , "./built/local/tsserver.js" , { exportIsTsObject : true , setDynamicImport : true } ) ;
347370
348371export const buildServer = task ( {
349372 name : "tsserver" ,
@@ -384,7 +407,7 @@ const buildLsslWithTsc = task({
384407 run : ( ) => buildProject ( "src/tsserverlibrary" ) ,
385408} ) ;
386409
387- const esbuildLssl = esbuildTask ( "./src/tsserverlibrary/tsserverlibrary.ts" , "./built/local/tsserverlibrary.js" , /* exportIsTsObject */ true ) ;
410+ const esbuildLssl = esbuildTask ( "./src/tsserverlibrary/tsserverlibrary.ts" , "./built/local/tsserverlibrary.js" , { exportIsTsObject : true } ) ;
388411
389412export const buildLssl = task ( {
390413 name : "lssl" ,
@@ -418,7 +441,15 @@ export const dts = task({
418441
419442
420443const testRunner = "./built/local/run.js" ;
421- const esbuildTests = esbuildTask ( "./src/testRunner/_namespaces/Harness.ts" , testRunner ) ;
444+ const esbuildTests = esbuildTask ( "./src/testRunner/_namespaces/Harness.ts" , testRunner , {
445+ external : [
446+ "chai" ,
447+ "del" ,
448+ "diff" ,
449+ "mocha" ,
450+ "ms" ,
451+ ] ,
452+ } ) ;
422453
423454export const buildTests = task ( {
424455 name : "tests" ,
0 commit comments