@@ -5,29 +5,32 @@ import meow from "meow"
5
5
import minimist from "minimist"
6
6
import ora from "ora"
7
7
import path from "path"
8
- import * as Stream from "stream"
9
8
import { createBundle } from "./bundle"
10
- import { copyFiles } from "./fs"
11
- import { isPluginArgument , loadPlugin , printPluginHelp } from "./plugins"
9
+ import { copyFiles , dedupeSourceFiles , resolveDirectoryEntrypoints } from "./fs"
10
+ import { loadPlugin , printPluginHelp , resolveEntrypoints } from "./plugins"
12
11
import { spawnPuppet } from "./puppeteer"
13
12
import { serveDirectory } from "./server"
14
13
import { clearTemporaryFileCache , createTemporaryFileCache , writeBlankHtmlPage } from "./temporary"
14
+ import { Entrypoint } from "./types"
15
15
16
16
const cli = meow ( `
17
17
Usage
18
- $ puppet-run <./path/to/index.js> [...script arguments]
19
- $ puppet-run plugin:<plugin> <...plugin arguments>
18
+ $ puppet-run <./entrypoint> [...more entrypoints] [-- <...script arguments>]
19
+ $ puppet-run <./entrypoint>:</serve/here> [...more entrypoints] [-- <...script args>]
20
+ $ puppet-run --plugin=<plugin> [<...entrypoints>] [-- <...script arguments>]
20
21
21
22
Options
22
23
--help Show this help.
23
24
--inspect Run in actual Chrome window and keep it open.
25
+ --bundle <./file>[:</serve/here>] Bundle and serve additional files, but don't inject them.
24
26
--p <port>, --port <port> Serve on this port. Defaults to random port.
27
+ --plugin <plugin> Load and apply plugin <plugin>.
25
28
--serve <./file>[:</serve/here>] Serve additional files next to bundle.
26
29
27
30
Example
28
31
$ puppet-run ./sample/cowsays.js
29
32
$ puppet-run ./sample/greet.ts newbie
30
- $ puppet-run plugin: mocha ./sample/mocha-test.ts
33
+ $ puppet-run -- plugin= mocha ./sample/mocha-test.ts
31
34
` , {
32
35
autoHelp : false
33
36
} )
@@ -42,6 +45,14 @@ function ensureArray (arg: string | string[] | undefined): string[] {
42
45
}
43
46
}
44
47
48
+ function parseEntrypointArg ( arg : string ) : Entrypoint {
49
+ const [ sourcePath , servePath ] = arg . split ( ":" )
50
+ return {
51
+ servePath,
52
+ sourcePath
53
+ }
54
+ }
55
+
45
56
async function withSpinner < T > ( promise : Promise < T > ) : Promise < T > {
46
57
const spinner = ora ( "Bundling code" ) . start ( )
47
58
@@ -55,55 +66,63 @@ async function withSpinner<T>(promise: Promise<T>): Promise<T> {
55
66
}
56
67
}
57
68
58
- const isParameterizedOption = ( arg : string ) => [ "-p" , "--port" , "--serve" ] . indexOf ( arg ) > - 1
59
- const firstArgumentIndex = process . argv . findIndex (
60
- ( arg , index ) => index >= 2 && ! arg . startsWith ( "-" ) && ! isParameterizedOption ( process . argv [ index - 1 ] )
61
- )
62
-
63
- const runnerOptionArgs = firstArgumentIndex > - 1 ? process . argv . slice ( 2 , firstArgumentIndex ) : process . argv . slice ( 2 )
64
- const scriptArgs = firstArgumentIndex > - 1 ? process . argv . slice ( firstArgumentIndex + 1 ) : [ ]
69
+ const argsSeparatorIndex = process . argv . indexOf ( "--" )
70
+ const runnerOptionArgs = argsSeparatorIndex > - 1 ? process . argv . slice ( 2 , argsSeparatorIndex ) : process . argv . slice ( 2 )
71
+ const scriptArgs = argsSeparatorIndex > - 1 ? process . argv . slice ( argsSeparatorIndex + 1 ) : [ ]
65
72
66
73
const runnerOptions = minimist ( runnerOptionArgs )
67
74
68
- const additionalFilesToServe = ensureArray ( runnerOptions . serve ) . map ( arg => {
69
- const [ sourcePath , servingPath ] = arg . split ( ":" )
70
- return { sourcePath, servingPath : servingPath || path . basename ( arg ) }
71
- } )
75
+ const pluginNames = Array . isArray ( runnerOptions . plugin || [ ] )
76
+ ? runnerOptions . plugin || [ ]
77
+ : [ runnerOptions . plugin ]
78
+
79
+ const plugins = pluginNames . map ( loadPlugin )
72
80
73
- if ( firstArgumentIndex === - 1 || runnerOptionArgs . indexOf ( "--help" ) > - 1 ) {
81
+ if ( runnerOptionArgs . indexOf ( "--help" ) > - 1 && plugins . length > 0 ) {
82
+ printPluginHelp ( plugins [ 0 ] , scriptArgs )
83
+ process . exit ( 0 )
84
+ } else if ( process . argv . length === 2 || runnerOptionArgs . indexOf ( "--help" ) > - 1 ) {
74
85
cli . showHelp ( )
75
86
process . exit ( 0 )
76
87
}
77
88
78
- async function run ( ) {
89
+ async function run ( ) {
79
90
let exitCode = 0
80
- const entrypoint = process . argv [ firstArgumentIndex ]
81
91
82
92
const headless = runnerOptionArgs . indexOf ( "--inspect" ) > - 1 ? false : true
83
93
const port = runnerOptions . p || runnerOptions . port
84
94
? parseInt ( runnerOptions . p || runnerOptions . port , 10 )
85
95
: await getPort ( )
86
96
87
- const plugin = isPluginArgument ( entrypoint ) ? loadPlugin ( entrypoint ) : null
88
- const temporaryCache = createTemporaryFileCache ( )
97
+ const additionalBundleEntries = await resolveDirectoryEntrypoints (
98
+ ensureArray ( runnerOptions . bundle ) . map ( parseEntrypointArg ) ,
99
+ filenames => dedupeSourceFiles ( filenames , true )
100
+ )
101
+ const additionalFilesToServe = await resolveDirectoryEntrypoints ( ensureArray ( runnerOptions . serve ) . map ( parseEntrypointArg ) )
89
102
90
- if ( plugin && scriptArgs . indexOf ( "--help" ) > - 1 ) {
91
- return printPluginHelp ( plugin , scriptArgs )
92
- }
103
+ const entrypointArgs = runnerOptionArgs . filter ( arg => arg . charAt ( 0 ) !== "-" )
104
+ const entrypoints = await resolveEntrypoints ( plugins , entrypointArgs . map ( parseEntrypointArg ) , scriptArgs )
93
105
94
- const scriptPaths = plugin && plugin . resolveBundleEntrypoints
95
- ? await plugin . resolveBundleEntrypoints ( scriptArgs )
96
- : [ entrypoint ]
106
+ const temporaryCache = createTemporaryFileCache ( )
97
107
98
108
try {
99
109
const serverURL = `http://localhost:${ port } /`
100
110
writeBlankHtmlPage ( path . join ( temporaryCache , "index.html" ) )
101
111
102
- const bundle = await withSpinner ( createBundle ( scriptPaths , temporaryCache ) )
103
- await copyFiles ( additionalFilesToServe , temporaryCache )
112
+ const allBundles = await withSpinner (
113
+ Promise . all ( [ ...entrypoints , ...additionalBundleEntries ] . map ( entrypoint => {
114
+ return createBundle ( entrypoint , temporaryCache )
115
+ } ) )
116
+ )
117
+
118
+ const startupBundles = allBundles . slice ( 0 , entrypoints . length )
119
+ const lazyBundles = allBundles . slice ( entrypoints . length )
120
+
121
+ await copyFiles ( [ ...additionalFilesToServe , ...lazyBundles ] , temporaryCache )
122
+
104
123
const closeServer = await serveDirectory ( temporaryCache , port )
105
- const puppet = await spawnPuppet ( bundle , serverURL , { headless } )
106
- await puppet . run ( scriptArgs , plugin )
124
+ const puppet = await spawnPuppet ( startupBundles . map ( entry => entry . servePath ! ) , serverURL , { headless } )
125
+ await puppet . run ( scriptArgs , plugins )
107
126
108
127
exitCode = await puppet . waitForExit ( )
109
128
await puppet . close ( )
0 commit comments