1
1
import { dim } from 'https://deno.land/[email protected] /fmt/colors.ts'
2
- import * as path from 'https://deno.land/[email protected] /path/mod.ts'
2
+ import { dirname , join } from 'https://deno.land/[email protected] /path/mod.ts'
3
3
import { ensureDir } from 'https://deno.land/[email protected] /fs/ensure_dir.ts'
4
+ // @deno -types="https://deno.land/x/[email protected] /mod.d.ts"
5
+ import { build } from 'https://deno.land/x/[email protected] /mod.js'
4
6
import { parseExportNames , transform } from '../compiler/mod.ts'
5
7
import { trimModuleExt } from '../framework/core/module.ts'
6
8
import { ensureTextFile , existsFileSync , lazyRemove } from '../shared/fs.ts'
7
9
import log from '../shared/log.ts'
8
10
import util from '../shared/util.ts'
9
11
import { VERSION } from '../version.ts'
10
12
import type { Application , Module } from '../server/app.ts'
11
- import {
12
- clearCompilation ,
13
- computeHash ,
14
- getAlephPkgUri ,
15
- } from '../server/helper.ts'
13
+ import { computeHash , getAlephPkgUri } from '../server/helper.ts'
14
+ import { cache } from '../server/cache.ts'
16
15
17
16
export const bundlerRuntimeCode = ( `
18
17
window.__ALEPH = {
@@ -121,9 +120,9 @@ export class Bundler {
121
120
122
121
private async copyBundleFile ( jsFilename : string ) {
123
122
const { buildDir, outputDir } = this . #app
124
- const bundleFile = path . join ( buildDir , jsFilename )
125
- const saveAs = path . join ( outputDir , '_aleph' , jsFilename )
126
- await ensureDir ( path . dirname ( saveAs ) )
123
+ const bundleFile = join ( buildDir , jsFilename )
124
+ const saveAs = join ( outputDir , '_aleph' , jsFilename )
125
+ await ensureDir ( dirname ( saveAs ) )
127
126
await Deno . copyFile ( bundleFile , saveAs )
128
127
}
129
128
@@ -195,7 +194,7 @@ export class Bundler {
195
194
const mainJS = `__ALEPH.bundledFiles=${ JSON . stringify ( bundledFiles ) } ;` + this . #app. getMainJS ( true )
196
195
const hash = computeHash ( mainJS )
197
196
const bundleFilename = `main.bundle.${ hash . slice ( 0 , 8 ) } .js`
198
- const bundleFile = path . join ( this . #app. buildDir , bundleFilename )
197
+ const bundleFile = join ( this . #app. buildDir , bundleFilename )
199
198
await Deno . writeTextFile ( bundleFile , mainJS )
200
199
this . #bundledFiles. set ( 'main' , bundleFilename )
201
200
log . info ( ` {} main.js ${ dim ( '• ' + util . formatBytes ( mainJS . length ) ) } ` )
@@ -207,7 +206,7 @@ export class Bundler {
207
206
const { buildTarget } = this . #app. config
208
207
const hash = computeHash ( buildTarget + Deno . version . deno + VERSION )
209
208
const bundleFilename = `polyfill.bundle.${ hash . slice ( 0 , 8 ) } .js`
210
- const bundleFile = path . join ( this . #app. buildDir , bundleFilename )
209
+ const bundleFile = join ( this . #app. buildDir , bundleFilename )
211
210
if ( ! existsFileSync ( bundleFile ) ) {
212
211
const rawPolyfillFile = `${ alephPkgUri } /bundler/polyfills/${ buildTarget } /mod.ts`
213
212
await this . _bundle ( rawPolyfillFile , bundleFile )
@@ -238,8 +237,8 @@ export class Bundler {
238
237
} ) ) ) . flat ( ) . join ( '\n' )
239
238
const hash = computeHash ( entryCode + VERSION + Deno . version . deno )
240
239
const bundleFilename = `${ name } .bundle.${ hash . slice ( 0 , 8 ) } .js`
241
- const bundleEntryFile = path . join ( this . #app. buildDir , `${ name } .bundle.entry.js` )
242
- const bundleFile = path . join ( this . #app. buildDir , bundleFilename )
240
+ const bundleEntryFile = join ( this . #app. buildDir , `${ name } .bundle.entry.js` )
241
+ const bundleFile = join ( this . #app. buildDir , bundleFilename )
243
242
if ( ! existsFileSync ( bundleFile ) ) {
244
243
await Deno . writeTextFile ( bundleEntryFile , entryCode )
245
244
await this . _bundle ( bundleEntryFile , bundleFile )
@@ -250,66 +249,51 @@ export class Bundler {
250
249
}
251
250
252
251
/** run deno bundle and compress the output using terser. */
253
- private async _bundle ( bundleEntryFile : string , bundleFile : string ) {
254
- // todo: use Deno.emit()
255
- const p = Deno . run ( {
256
- cmd : [ Deno . execPath ( ) , 'bundle' , '--no-check' , bundleEntryFile , bundleFile ] ,
257
- stdout : 'null' ,
258
- stderr : 'piped'
259
- } )
260
- const data = await p . stderrOutput ( )
261
- p . close ( )
262
- if ( ! existsFileSync ( bundleFile ) ) {
263
- const msg = ( new TextDecoder ) . decode ( data ) . replaceAll ( 'file://' , '' ) . replaceAll ( this . #app. buildDir , '/_aleph' )
264
- await Deno . stderr . write ( ( new TextEncoder ) . encode ( msg ) )
265
- Deno . exit ( 1 )
266
- }
267
-
268
- // transpile bundle code to `buildTarget`
269
- const { buildTarget } = this . #app. config
252
+ private async _bundle ( entryFile : string , bundleFile : string ) {
253
+ const { buildTarget, browserslist } = this . #app. config
270
254
271
- let { code } = await transform (
272
- '/bundle.js' ,
273
- await Deno . readTextFile ( bundleFile ) ,
274
- {
275
- transpileOnly : true ,
276
- swcOptions : {
277
- target : buildTarget
255
+ await clearBundle ( bundleFile )
256
+ await build ( {
257
+ entryPoints : [ entryFile ] ,
258
+ outfile : bundleFile ,
259
+ platform : 'browser' ,
260
+ target : [ String ( buildTarget ) ] . concat ( browserslist . map ( ( { name, version } ) => {
261
+ return `${ name . toLowerCase ( ) } ${ version } `
262
+ } ) ) ,
263
+ bundle : true ,
264
+ minify : true ,
265
+ plugins : [ {
266
+ name : 'http-loader' ,
267
+ setup ( build ) {
268
+ build . onResolve ( { filter : / .* / } , async ( args ) => {
269
+ if ( util . isLikelyHttpURL ( args . path ) ) {
270
+ return {
271
+ path : args . path ,
272
+ namespace : 'http-module' ,
273
+ }
274
+ }
275
+ if ( args . namespace === 'http-module' ) {
276
+ return {
277
+ path : ( new URL ( args . path , args . importer ) ) . toString ( ) ,
278
+ namespace : 'http-module' ,
279
+ }
280
+ }
281
+ const [ path ] = util . splitBy ( util . trimPrefix ( args . path , 'file://' ) , '#' )
282
+ if ( path . startsWith ( '.' ) ) {
283
+ return { path : join ( args . resolveDir , path ) }
284
+ }
285
+ return { path }
286
+ } )
287
+ build . onLoad ( { filter : / .* / , namespace : 'http-module' } , async ( args ) => {
288
+ const { content } = await cache ( args . path )
289
+ return { contents : content }
290
+ } )
278
291
}
279
- }
280
- )
281
-
282
- // IIFEify
283
- code = `(() => { ${ code } })()`
284
-
285
- // minify code
286
- // todo: use swc minify instead (https://github.com/swc-project/swc/pull/1302)
287
- const mini = await minify ( code , parseInt ( util . trimPrefix ( buildTarget , 'es' ) ) )
288
- if ( mini !== undefined ) {
289
- code = mini
290
- }
291
-
292
- await clearCompilation ( bundleFile )
293
- await Deno . writeTextFile ( bundleFile , code )
292
+ } ] ,
293
+ } )
294
294
}
295
295
}
296
296
297
- interface Minify {
298
- ( code : string , options : any ) : Promise < { code : string } >
299
- }
297
+ async function clearBundle ( filename : string ) {
300
298
301
- let terser : Minify | null = null
302
-
303
- async function minify ( code : string , ecma : number = 2015 ) {
304
- if ( terser === null ) {
305
- const { minify
} = await import ( 'https://esm.sh/[email protected] ?no-check' )
306
- terser = minify as Minify
307
- }
308
- const ret = await terser ( code , {
309
- compress : true ,
310
- mangle : true ,
311
- ecma,
312
- sourceMap : false
313
- } )
314
- return ret . code
315
299
}
0 commit comments