1- import { build as esbuild , BuildFailure , BuildResult , Platform , Plugin , Format } from 'esbuild' ;
1+ import * as esbuild from 'esbuild' ;
22import path from 'path' ;
33import fse from 'fs-extra' ;
44import gzipSize from 'gzip-size' ;
55import brotliSize from 'brotli-size' ;
66import prettyBytes from 'pretty-bytes' ;
7- import chalk from 'chalk' ;
87import execa from 'execa' ;
8+ import chalk from 'chalk' ;
99import { environment } from './environment' ;
1010import { existsAsync } from './exists-async' ;
1111
1212interface ESBuildOptions {
1313 watch ?: boolean ;
14- target ?: Platform ;
15- format ?: Format ;
14+ target ?: esbuild . Platform ;
15+ format ?: esbuild . Format ;
1616 output ?: string ;
1717 sourcemap ?: boolean ;
1818 name ?: string ;
@@ -22,42 +22,48 @@ interface ESBuildOptions {
2222
2323export async function build ( options : ESBuildOptions ) {
2424 if ( options . output ) {
25- try {
26- await esbuild ( {
27- bundle : true ,
28- minify : true ,
29- watch : options . watch ? { onRebuild : onRebuildFactory ( options ) } : undefined ,
30- legalComments : 'none' ,
31- platform : options . target ?? 'browser' ,
32- format : options . format ?? 'cjs' ,
33- globalName : options . format === 'iife' ? options . name : undefined ,
34- entryPoints : [ await getEntrypoint ( options . format ) ] ,
35- sourcemap : options . sourcemap ,
36- outfile : options . output ,
37- tsconfig : 'node_modules/.temp/tsconfig.build.json' ,
38- external : options . externals ,
39- loader : { '.ts' : 'ts' , '.tsx' : 'tsx' } ,
40- define : Object . fromEntries (
41- Object . entries ( environment ) . map ( ( [ key , value ] ) => [ `process.env.${ key } ` , JSON . stringify ( value ) ] ) ,
42- ) ,
43- plugins : [ ...globalsPlugin ( options . globals || { } ) ] ,
44-
45- // We need this footer because: https://github.com/evanw/esbuild/issues/1182
46- footer :
47- options . format === 'iife'
48- ? {
49- // This snippet replaces `window.{name}` with
50- // `window.{name}.default`, with any additional named exports
51- // assigned. Finally, it removes `window.{name}.default`.
52- js : `if (${ options . name } && ${ options . name } .default != null) { ${ options . name } = Object.assign(${ options . name } .default, ${ options . name } ); delete ${ options . name } .default; }` ,
53- }
54- : undefined ,
55- } ) ;
25+ const buildOptions : esbuild . BuildOptions = {
26+ bundle : true ,
27+ minify : true ,
28+ treeShaking : true ,
29+ drop : process . env . NODE_ENV === 'production' ? [ 'debugger' , 'console' ] : [ 'debugger' ] ,
30+ legalComments : 'none' ,
31+ platform : options . target ?? 'browser' ,
32+ format : options . format ?? 'cjs' ,
33+ globalName : options . format === 'iife' ? options . name : undefined ,
34+ entryPoints : [ await getEntrypoint ( options . format ) ] ,
35+ sourcemap : options . sourcemap ,
36+ outfile : options . output ,
37+ tsconfig : 'node_modules/.temp/tsconfig.build.json' ,
38+ external : options . externals ,
39+ loader : { '.ts' : 'ts' , '.tsx' : 'tsx' } ,
40+ define : Object . fromEntries (
41+ Object . entries ( environment ) . map ( ( [ key , value ] ) => [ `process.env.${ key } ` , JSON . stringify ( value ) ] ) ,
42+ ) ,
43+ plugins : [ ...globalsPlugin ( options . globals || { } ) ] ,
44+
45+ mangleProps : / ^ _ / ,
46+ ignoreAnnotations : false ,
47+ metafile : true , // Generate metafile for size analysis
48+
49+ // We need this footer because: https://github.com/evanw/esbuild/issues/1182
50+ footer :
51+ options . format === 'iife'
52+ ? {
53+ // This snippet replaces `window.{name}` with
54+ // `window.{name}.default`, with any additional named exports
55+ // assigned. Finally, it removes `window.{name}.default`.
56+ js : `if (${ options . name } && ${ options . name } .default != null) { ${ options . name } = Object.assign(${ options . name } .default, ${ options . name } ); delete ${ options . name } .default; }` ,
57+ }
58+ : undefined ,
59+ } ;
5660
61+ if ( options . watch ) {
62+ const ctx = await esbuild . context ( buildOptions ) ;
63+ await ctx . watch ( ) ;
64+ } else {
65+ await esbuild . build ( buildOptions ) ;
5766 await printOutputSizeInfo ( options ) ;
58- } catch ( e ) {
59- console . error ( e ) ;
60- throw e ;
6167 }
6268 }
6369}
@@ -75,40 +81,22 @@ async function printOutputSizeInfo(options: ESBuildOptions) {
7581 }
7682}
7783
78- /**
79- * Returns a function that can be used to handle rebuild events from ESBuild.
80- */
81- function onRebuildFactory ( options : ESBuildOptions ) {
82- return async ( error : BuildFailure | null , result : BuildResult | null ) => {
83- if ( error ) {
84- console . error ( error . message ) ;
85- } else {
86- await printOutputSizeInfo ( options ) ;
87- }
88- } ;
89- }
90-
9184/**
9285 * Emits TypeScript typings for the current package.
9386 */
9487export async function emitTypes ( watch ?: boolean ) {
95- try {
96- if ( watch ) {
97- await execa ( 'tsc' , [ '-w' , '-p' , 'node_modules/.temp/tsconfig.build.json' ] ) ;
98- } else {
99- await execa ( 'tsc' , [ '-p' , 'node_modules/.temp/tsconfig.build.json' ] ) ;
100- }
101- } catch ( e ) {
102- console . error ( e ) ;
103- throw e ;
88+ if ( watch ) {
89+ await execa ( 'tsc' , [ '-w' , '-p' , 'node_modules/.temp/tsconfig.build.json' ] ) ;
90+ } else {
91+ await execa ( 'tsc' , [ '-p' , 'node_modules/.temp/tsconfig.build.json' ] ) ;
10492 }
10593}
10694
10795/**
10896 * Resolves the entrypoint file for ESBuild,
10997 * based on the format and target platform.
11098 */
111- async function getEntrypoint ( format ?: Format ) {
99+ async function getEntrypoint ( format ?: esbuild . Format ) {
112100 const findEntrypoint = async ( indexTarget ?: string ) => {
113101 if ( format && ( await existsAsync ( path . resolve ( process . cwd ( ) , `./src/index.${ indexTarget } .ts` ) ) ) ) {
114102 return `src/index.${ indexTarget } .ts` ;
@@ -172,13 +160,13 @@ export async function createTemporaryTSConfigFile() {
172160 * Creates a list of plugins to replace
173161 * externalized packages with a global variable.
174162 */
175- function globalsPlugin ( globals : Record < string , string > ) : Plugin [ ] {
163+ function globalsPlugin ( globals : Record < string , string > ) : esbuild . Plugin [ ] {
176164 return Object . entries ( globals ) . map ( ( [ packageName , globalVar ] ) => {
177165 const namespace = `globals-plugin:${ packageName } ` ;
178166 return {
179167 name : namespace ,
180168 setup ( builder ) {
181- builder . onResolve ( { filter : new RegExp ( `^${ packageName } $` ) } , ( args ) => ( {
169+ builder . onResolve ( { filter : new RegExp ( `^${ packageName } $` ) } , args => ( {
182170 path : args . path ,
183171 namespace,
184172 } ) ) ;
@@ -200,7 +188,6 @@ export async function getSizeInfo(code: string, filename: string) {
200188
201189 const formatSize = ( size : number , type : 'gz' | 'br' ) => {
202190 const pretty = raw ? `${ size } B` : prettyBytes ( size ) ;
203-
204191 const color = size < 5000 ? chalk . green : size > 40000 ? chalk . red : chalk . yellow ;
205192 return `${ color ( pretty ) } : ${ chalk . white ( path . basename ( filename ) ) } .${ type } ` ;
206193 } ;
0 commit comments