11import esbuild from 'esbuild' ;
22import { getConfig } from '../utilities/getConfig' ;
3- import { resolve } from 'node:path' ;
3+ import p from 'node:path' ;
44import { glob } from 'glob' ;
55import { configDotenv } from 'dotenv' ;
66import assert from 'node:assert' ;
77import defaultEsbuild from '../utilities/defaultEsbuildConfig' ;
88import { require } from '../utilities/require' ;
99import { pathExists , pathExistsSync } from 'find-up' ;
10- import { mkdir , writeFile } from 'fs/promises' ;
10+ import { mkdir , writeFile , readFile } from 'fs/promises' ;
1111import * as Preprocessor from '../utilities/preprocessor' ;
1212import { bold , magentaBright } from 'colorette' ;
13- const validExtensions = [ '.ts' , '.js' , '.json' , '.png' , '.jpg' , '.jpeg' , '.webp' ] ;
1413
14+ const VALID_EXTENSIONS = [ '.ts' , '.js' ] ;
1515
1616type BuildOptions = {
1717 /**
@@ -24,10 +24,6 @@ type BuildOptions = {
2424 * default = esm
2525 */
2626 format ?: 'cjs' | 'esm' ;
27- /**
28- * extra esbuild plugins to build with sern.
29- */
30- esbuildPlugins ?: esbuild . Plugin [ ] ;
3127 /**
3228 * https://esbuild.github.io/api/#drop-labels
3329 **/
@@ -49,77 +45,72 @@ type BuildOptions = {
4945 env ?: string ;
5046} ;
5147
48+ const CommandHandlerPlugin = ( buildConfig : Partial < BuildOptions > , ambientFilePath : string , sernTsConfigPath : string ) => {
49+ return {
50+ name : "commandhandler" ,
51+ setup ( build ) {
52+
53+ const options = build . initialOptions
54+ const defVersion = ( ) => JSON . stringify ( require ( p . resolve ( 'package.json' ) ) . version ) ;
55+ options . define = {
56+ ...buildConfig . define ?? { } ,
57+ __DEV__ : `${ buildConfig . mode === 'development' } ` ,
58+ __PROD__ : `${ buildConfig . mode === 'production' } ` ,
59+ __VERSION__ : `${ buildConfig . defineVersion ? `${ defVersion ( ) } ` : 'undefined' } `
60+ } ?? { }
61+ Preprocessor . writeTsConfig ( buildConfig . format ! , sernTsConfigPath , writeFile ) ;
62+ Preprocessor . writeAmbientFile ( ambientFilePath , options . define ! , writeFile ) ;
63+
64+ }
65+ } as esbuild . Plugin
66+ }
67+ const resolveBuildConfig = ( path : string | undefined , language : string ) => {
68+ if ( language === 'javascript' ) {
69+ return path ?? 'jsconfig.json'
70+ }
71+ return path ?? 'tsconfig.json'
72+ }
73+
5274export async function build ( options : Record < string , any > ) {
5375 if ( ! options . supressWarnings ) {
5476 console . info ( `${ magentaBright ( 'EXPERIMENTAL' ) } : This API has not been stabilized. add -W or --suppress-warnings flag to suppress` ) ;
5577 }
5678 const sernConfig = await getConfig ( ) ;
57- let buildConfig : Partial < BuildOptions > = { } ;
58-
59- const entryPoints = await glob ( `./src/**/*{${ validExtensions . join ( ',' ) } }` , {
60- //for some reason, my ignore glob wasn't registering correctly'
61- ignore : {
62- ignored : ( p ) => p . name . endsWith ( '.d.ts' ) ,
63- } ,
64- } ) ;
65-
66- const buildConfigPath = resolve ( options . project ?? 'sern.build.js' ) ;
67-
68- const resolveBuildConfig = ( path : string | undefined , language : string ) => {
69- if ( language === 'javascript' ) {
70- return path ?? resolve ( 'jsconfig.json' )
71- }
72- return path ?? resolve ( 'tsconfig.json' )
73- }
79+ let buildConfig : BuildOptions ;
80+ const buildConfigPath = p . resolve ( options . project ?? 'sern.build.js' ) ;
7481
7582 const defaultBuildConfig = {
7683 defineVersion : true ,
7784 format : options . format ?? 'esm' ,
7885 mode : options . mode ?? 'development' ,
7986 dropLabels : [ ] ,
8087 tsconfig : resolveBuildConfig ( options . tsconfig , sernConfig . language ) ,
81- env : options . env ?? resolve ( '.env' ) ,
88+ env : options . env ?? '.env' ,
89+ include : [ ]
8290 } ;
8391 if ( pathExistsSync ( buildConfigPath ) ) {
8492 //throwable, buildConfigPath may not exist
85- buildConfig = {
86- ...defaultBuildConfig ,
87- ...( await import ( 'file:///' + buildConfigPath ) ) . default ,
88- } ;
93+ buildConfig = { ...defaultBuildConfig , ...( await import ( 'file:///' + buildConfigPath ) ) . default } ;
8994 } else {
9095 buildConfig = defaultBuildConfig ;
9196 console . log ( 'No build config found, defaulting' ) ;
9297 }
93-
94- let env = { } as Record < string , string > ;
95- configDotenv ( { path : buildConfig . env , processEnv : env } ) ;
96- const modeButNotNodeEnvExists = env . MODE && ! env . NODE_ENV ;
97- if ( modeButNotNodeEnvExists ) {
98- console . warn ( 'Use NODE_ENV instead of MODE' ) ;
99- console . warn ( 'MODE has no effect.' ) ;
100- console . warn ( `https://nodejs.org/en/learn/getting-started/nodejs-the-difference-between-development-and-production` ) ;
101- }
102-
103- if ( env . NODE_ENV ) {
104- buildConfig . mode = env . NODE_ENV as 'production' | 'development' ;
98+ configDotenv ( { path : buildConfig . env } ) ;
99+
100+ if ( process . env . NODE_ENV ) {
101+ buildConfig . mode = process . env . NODE_ENV as 'production' | 'development' ;
105102 console . log ( magentaBright ( 'NODE_ENV:' ) , 'Found NODE_ENV variable, setting `mode` to this.' ) ;
106103 }
107-
108104 assert ( buildConfig . mode === 'development' || buildConfig . mode === 'production' , 'Mode is not `production` or `development`' ) ;
109-
110-
111105 try {
112- let config = require ( buildConfig . tsconfig ! ) ;
106+ let config = JSON . parse ( await readFile ( buildConfig . tsconfig ! , 'utf8' ) ) ;
113107 config . extends && console . warn ( "Extend the generated tsconfig" )
114108 } catch ( e ) {
115- console . warn ( "no tsconfig / jsconfig found" ) ;
116- console . warn ( `Please create a ${ sernConfig . language === 'javascript' ? 'jsconfig.json' : 'tsconfig.json' } ` ) ;
117- console . warn ( "It should have at least extend the generated one sern makes." )
118- console . warn ( `
119- {
120- "extends": "./.sern/tsconfig.json",
121- }` . trim ( ) )
122- throw e ;
109+ console . error ( "no tsconfig / jsconfig found" ) ;
110+ console . error ( `Please create a ${ sernConfig . language === 'javascript' ? 'jsconfig.json' : 'tsconfig.json' } ` ) ;
111+ console . error ( 'It should have at least extend the generated one sern makes.\n \
112+ { "extends": "./.sern/tsconfig.json" }' ) ;
113+ throw e ;
123114 }
124115
125116 console . log ( bold ( 'Building with:' ) ) ;
@@ -129,41 +120,32 @@ export async function build(options: Record<string, any>) {
129120 console . log ( ' ' , magentaBright ( 'tsconfig' ) , buildConfig . tsconfig ) ;
130121 console . log ( ' ' , magentaBright ( 'env' ) , buildConfig . env ) ;
131122
132- const sernDir = resolve ( '.sern' ) ,
133- genDir = resolve ( sernDir , 'generated' ) ,
134- ambientFilePath = resolve ( sernDir , 'ambient.d.ts' ) ,
135- packageJsonPath = resolve ( 'package.json' ) ,
136- sernTsConfigPath = resolve ( sernDir , 'tsconfig.json' ) ,
137- packageJson = ( ) => require ( packageJsonPath ) ;
123+ const sernDir = p . resolve ( '.sern' ) ,
124+ [ ambientFilePath , sernTsConfigPath , genDir ] =
125+ [ 'ambient.d.ts' , 'tsconfig.json' , 'generated' ] . map ( f => p . resolve ( sernDir , f ) ) ;
138126
139127 if ( ! ( await pathExists ( genDir ) ) ) {
140128 console . log ( 'Making .sern/generated dir, does not exist' ) ;
141129 await mkdir ( genDir , { recursive : true } ) ;
142130 }
131+
132+ const entryPoints = await glob ( `src/**/*{${ VALID_EXTENSIONS . join ( ',' ) } }` , {
133+ ignore : {
134+ ignored : ( p ) => p . name . endsWith ( '.d.ts' ) ,
135+ }
136+ } ) ;
137+ //https://esbuild.github.io/content-types/#tsconfig-json
138+ const ctx = await esbuild . context ( {
139+ entryPoints,
140+ plugins : [ CommandHandlerPlugin ( buildConfig , ambientFilePath , sernTsConfigPath ) ] ,
141+ ...defaultEsbuild ( buildConfig . format ! , buildConfig . tsconfig ) ,
142+ dropLabels : [ buildConfig . mode === 'production' ? '__DEV__' : '__PROD__' , ...buildConfig . dropLabels ! ] ,
143+ } ) ;
143144
144- try {
145- const defVersion = ( ) => JSON . stringify ( packageJson ( ) . version ) ;
146- const define = {
147- ...( buildConfig . define ?? { } ) ,
148- __DEV__ : `${ buildConfig . mode === 'development' } ` ,
149- __PROD__ : `${ buildConfig . mode === 'production' } ` ,
150- } satisfies Record < string , string > ;
151-
152- buildConfig . defineVersion && Object . assign ( define , { __VERSION__ : defVersion ( ) } ) ;
153-
154- await Preprocessor . writeTsConfig ( buildConfig . format ! , sernTsConfigPath , writeFile ) ;
155- await Preprocessor . writeAmbientFile ( ambientFilePath , define , writeFile ) ;
156-
157- //https://esbuild.github.io/content-types/#tsconfig-json
158- await esbuild . build ( {
159- entryPoints,
160- plugins : [ ...( buildConfig . esbuildPlugins ?? [ ] ) ] ,
161- ...defaultEsbuild ( buildConfig . format ! , buildConfig . tsconfig ) ,
162- define,
163- dropLabels : [ buildConfig . mode === 'production' ? '__DEV__' : '__PROD__' , ...buildConfig . dropLabels ! ] ,
164- } ) ;
165- } catch ( e ) {
166- console . error ( e ) ;
167- process . exit ( 1 ) ;
145+ await ctx . rebuild ( )
146+ if ( options . watch ) {
147+ await ctx . watch ( )
148+ } else {
149+ await ctx . dispose ( )
168150 }
169151}
0 commit comments