@@ -31,6 +31,13 @@ enum MediaType {
31
31
Unknown = 5
32
32
}
33
33
34
+ // Warning! The values in this enum are duplicated in cli/msg.rs
35
+ // Update carefully!
36
+ enum CompilerRequestType {
37
+ Compile = 0 ,
38
+ Bundle = 1
39
+ }
40
+
34
41
// Startup boilerplate. This is necessary because the compiler has its own
35
42
// snapshot. (It would be great if we could remove these things or centralize
36
43
// them somewhere else.)
@@ -44,16 +51,23 @@ window["denoMain"] = denoMain;
44
51
45
52
const ASSETS = "$asset$" ;
46
53
const OUT_DIR = "$deno$" ;
54
+ const BUNDLE_LOADER = "bundle_loader.js" ;
47
55
48
56
/** The format of the work message payload coming from the privileged side */
49
- interface CompilerReq {
57
+ type CompilerRequest = {
50
58
rootNames : string [ ] ;
51
- bundle ?: string ;
52
59
// TODO(ry) add compiler config to this interface.
53
60
// options: ts.CompilerOptions;
54
61
configPath ?: string ;
55
62
config ?: string ;
56
- }
63
+ } & (
64
+ | {
65
+ type : CompilerRequestType . Compile ;
66
+ }
67
+ | {
68
+ type : CompilerRequestType . Bundle ;
69
+ outFile ?: string ;
70
+ } ) ;
57
71
58
72
interface ConfigureResponse {
59
73
ignoredOptions ?: string [ ] ;
@@ -271,7 +285,7 @@ function fetchSourceFiles(
271
285
async function processImports (
272
286
specifiers : Array < [ string , string ] > ,
273
287
referrer = ""
274
- ) : Promise < void > {
288
+ ) : Promise < SourceFileJson [ ] > {
275
289
if ( ! specifiers . length ) {
276
290
return ;
277
291
}
@@ -287,6 +301,7 @@ async function processImports(
287
301
await processImports ( sourceFile . imports ( ) , sourceFile . url ) ;
288
302
}
289
303
}
304
+ return sourceFiles ;
290
305
}
291
306
292
307
/** Utility function to turn the number of bytes into a human readable
@@ -314,16 +329,36 @@ function cache(extension: string, moduleId: string, contents: string): void {
314
329
const encoder = new TextEncoder ( ) ;
315
330
316
331
/** Given a fileName and the data, emit the file to the file system. */
317
- function emitBundle ( fileName : string , data : string ) : void {
332
+ function emitBundle (
333
+ rootNames : string [ ] ,
334
+ fileName : string | undefined ,
335
+ data : string ,
336
+ sourceFiles : readonly ts . SourceFile [ ]
337
+ ) : void {
318
338
// For internal purposes, when trying to emit to `$deno$` just no-op
319
- if ( fileName . startsWith ( "$deno$" ) ) {
339
+ if ( fileName && fileName . startsWith ( "$deno$" ) ) {
320
340
console . warn ( "skipping emitBundle" , fileName ) ;
321
341
return ;
322
342
}
323
- const encodedData = encoder . encode ( data ) ;
324
- console . log ( `Emitting bundle to "${ fileName } "` ) ;
325
- writeFileSync ( fileName , encodedData ) ;
326
- console . log ( `${ humanFileSize ( encodedData . length ) } emitted.` ) ;
343
+ const loader = fetchAsset ( BUNDLE_LOADER ) ;
344
+ // when outputting to AMD and a single outfile, TypeScript makes up the module
345
+ // specifiers which are used to define the modules, and doesn't expose them
346
+ // publicly, so we have to try to replicate
347
+ const sources = sourceFiles . map ( sf => sf . fileName ) ;
348
+ const sharedPath = util . commonPath ( sources ) ;
349
+ rootNames = rootNames . map ( id =>
350
+ id . replace ( sharedPath , "" ) . replace ( / \. \w + $ / i, "" )
351
+ ) ;
352
+ const instantiate = `instantiate(${ JSON . stringify ( rootNames ) } );\n` ;
353
+ const bundle = `${ loader } \n${ data } \n${ instantiate } ` ;
354
+ if ( fileName ) {
355
+ const encodedData = encoder . encode ( bundle ) ;
356
+ console . warn ( `Emitting bundle to "${ fileName } "` ) ;
357
+ writeFileSync ( fileName , encodedData ) ;
358
+ console . warn ( `${ humanFileSize ( encodedData . length ) } emitted.` ) ;
359
+ } else {
360
+ console . log ( bundle ) ;
361
+ }
327
362
}
328
363
329
364
/** Returns the TypeScript Extension enum for a given media type. */
@@ -380,17 +415,23 @@ class Host implements ts.CompilerHost {
380
415
381
416
/** Provides the `ts.HostCompiler` interface for Deno.
382
417
*
418
+ * @param _rootNames A set of modules that are the ones that should be
419
+ * instantiated first. Used when generating a bundle.
383
420
* @param _bundle Set to a string value to configure the host to write out a
384
421
* bundle instead of caching individual files.
385
422
*/
386
- constructor ( private _bundle ?: string ) {
387
- if ( this . _bundle ) {
423
+ constructor (
424
+ private _requestType : CompilerRequestType ,
425
+ private _rootNames : string [ ] ,
426
+ private _outFile ?: string
427
+ ) {
428
+ if ( this . _requestType === CompilerRequestType . Bundle ) {
388
429
// options we need to change when we are generating a bundle
389
430
const bundlerOptions : ts . CompilerOptions = {
390
431
module : ts . ModuleKind . AMD ,
391
- inlineSourceMap : true ,
392
432
outDir : undefined ,
393
433
outFile : `${ OUT_DIR } /bundle.js` ,
434
+ // disabled until we have effective way to modify source maps
394
435
sourceMap : false
395
436
} ;
396
437
Object . assign ( this . _options , bundlerOptions ) ;
@@ -531,10 +572,11 @@ class Host implements ts.CompilerHost {
531
572
) : void {
532
573
util . log ( "compiler::host.writeFile" , fileName ) ;
533
574
try {
534
- if ( this . _bundle ) {
535
- emitBundle ( this . _bundle , data ) ;
575
+ assert ( sourceFiles != null ) ;
576
+ if ( this . _requestType === CompilerRequestType . Bundle ) {
577
+ emitBundle ( this . _rootNames , this . _outFile , data , sourceFiles ! ) ;
536
578
} else {
537
- assert ( sourceFiles != null && sourceFiles . length == 1 ) ;
579
+ assert ( sourceFiles . length == 1 ) ;
538
580
const url = sourceFiles ! [ 0 ] . fileName ;
539
581
const sourceFile = SourceFile . get ( url ) ;
540
582
@@ -579,16 +621,29 @@ class Host implements ts.CompilerHost {
579
621
// lazy instantiating the compiler web worker
580
622
window . compilerMain = function compilerMain ( ) : void {
581
623
// workerMain should have already been called since a compiler is a worker.
582
- window . onmessage = async ( { data } : { data : CompilerReq } ) : Promise < void > => {
583
- const { rootNames, configPath, config, bundle } = data ;
584
- util . log ( ">>> compile start" , { rootNames, bundle } ) ;
624
+ window . onmessage = async ( {
625
+ data : request
626
+ } : {
627
+ data : CompilerRequest ;
628
+ } ) : Promise < void > => {
629
+ const { rootNames, configPath, config } = request ;
630
+ util . log ( ">>> compile start" , {
631
+ rootNames,
632
+ type : CompilerRequestType [ request . type ]
633
+ } ) ;
585
634
586
635
// This will recursively analyse all the code for other imports, requesting
587
636
// those from the privileged side, populating the in memory cache which
588
637
// will be used by the host, before resolving.
589
- await processImports ( rootNames . map ( rootName => [ rootName , rootName ] ) ) ;
590
-
591
- const host = new Host ( bundle ) ;
638
+ const resolvedRootModules = ( await processImports (
639
+ rootNames . map ( rootName => [ rootName , rootName ] )
640
+ ) ) . map ( info => info . url ) ;
641
+
642
+ const host = new Host (
643
+ request . type ,
644
+ resolvedRootModules ,
645
+ request . type === CompilerRequestType . Bundle ? request . outFile : undefined
646
+ ) ;
592
647
let emitSkipped = true ;
593
648
let diagnostics : ts . Diagnostic [ ] | undefined ;
594
649
@@ -642,8 +697,9 @@ window.compilerMain = function compilerMain(): void {
642
697
643
698
// We will only proceed with the emit if there are no diagnostics.
644
699
if ( diagnostics && diagnostics . length === 0 ) {
645
- if ( bundle ) {
646
- console . log ( `Bundling "${ bundle } "` ) ;
700
+ if ( request . type === CompilerRequestType . Bundle ) {
701
+ // warning so it goes to stderr instead of stdout
702
+ console . warn ( `Bundling "${ resolvedRootModules . join ( `", "` ) } "` ) ;
647
703
}
648
704
const emitResult = program . emit ( ) ;
649
705
emitSkipped = emitResult . emitSkipped ;
@@ -662,7 +718,10 @@ window.compilerMain = function compilerMain(): void {
662
718
663
719
postMessage ( result ) ;
664
720
665
- util . log ( "<<< compile end" , { rootNames, bundle } ) ;
721
+ util . log ( "<<< compile end" , {
722
+ rootNames,
723
+ type : CompilerRequestType [ request . type ]
724
+ } ) ;
666
725
667
726
// The compiler isolate exits after a single message.
668
727
workerClose ( ) ;
0 commit comments