vitrify 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +86 -0
- package/dist/app-urls.js +32 -0
- package/dist/bin/build.js +73 -0
- package/dist/bin/cli.js +137 -0
- package/dist/bin/dev.js +106 -0
- package/dist/bin/run.js +26 -0
- package/dist/helpers/logger.js +108 -0
- package/dist/helpers/routes.js +24 -0
- package/dist/helpers/utils.js +24 -0
- package/dist/index.js +288 -0
- package/dist/plugins/index.js +1 -0
- package/dist/plugins/quasar.js +294 -0
- package/dist/types/app-urls.d.ts +11 -0
- package/dist/types/bin/build.d.ts +8 -0
- package/dist/types/bin/cli.d.ts +2 -0
- package/dist/types/bin/dev.d.ts +15 -0
- package/dist/types/bin/run.d.ts +8 -0
- package/dist/types/bin/test.d.ts +3 -0
- package/dist/types/helpers/logger.d.ts +23 -0
- package/dist/types/helpers/routes.d.ts +2 -0
- package/dist/types/helpers/utils.d.ts +5 -0
- package/dist/types/index.d.ts +15 -0
- package/dist/types/plugins/index.d.ts +7 -0
- package/dist/types/plugins/quasar.d.ts +16 -0
- package/dist/types/vitrify-config.d.ts +64 -0
- package/dist/types/vue/fastify-ssr-plugin.d.ts +14 -0
- package/dist/types/vue/prerender.d.ts +8 -0
- package/dist/types/vue/server.d.ts +9 -0
- package/dist/vitrify-config.js +1 -0
- package/dist/vue/fastify-ssr-plugin.js +91 -0
- package/dist/vue/prerender.js +29 -0
- package/dist/vue/server.js +20 -0
- package/package.json +94 -18
- package/src/vite/vue/components.d.ts +25 -0
- package/src/vite/vue/csr/entry.ts +8 -0
- package/src/vite/vue/index.html +16 -0
- package/src/vite/vue/main.ts +89 -0
- package/src/vite/vue/ssr/entry-client.ts +9 -0
- package/src/vite/vue/ssr/entry-server.ts +97 -0
- package/src/vite/vue/ssr/fastify-ssr-plugin.ts +120 -0
- package/src/vite/vue/ssr/prerender.ts +4 -0
- package/src/vite/vue/ssr/server.ts +15 -0
- package/src/vite/vue/ssr/server.ts.bak +61 -0
- package/src/vite/vue/ssr/tsconfig.json +9 -0
package/README.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Vitrify
|
|
2
|
+
|
|
3
|
+
> Pre-configured Vite CLI for your framework
|
|
4
|
+
|
|
5
|
+
- Use a simple configuration file to configure and integrate required Vite plugins into your project.
|
|
6
|
+
- Client-Side Rendering (CSR) and Server-Side Rendering (SSR) builds and development servers.
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- Uses [Fastify](https://github.com/fastify/fastify-vite) for the development server and SSR production server.
|
|
11
|
+
- Generates a Fastify plugin to serve your server-side rendered application.
|
|
12
|
+
- A [`run`](./src/node/bin/run.ts) command which injects context such as application paths into the script which you want to run.
|
|
13
|
+
- A [`test`](./src/node/bin/test.ts) command which runs a pre-configured [Vitest](https://github.com/vitest-dev/vitest) instance.
|
|
14
|
+
- An [extra plugin layer](./src/node/plugins/index.ts) which provides some extra context such as the SSR mode (client or server) and PWA mode. Used for UI frameworks which render differently based on these settings.
|
|
15
|
+
|
|
16
|
+
## Commands
|
|
17
|
+
|
|
18
|
+
### build
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
Usage:
|
|
22
|
+
$ vitrify build
|
|
23
|
+
|
|
24
|
+
Options:
|
|
25
|
+
-m, --mode [mode] Build mode (default: csr)
|
|
26
|
+
--base [base] Base public path
|
|
27
|
+
--outDir [outDir] Output directory
|
|
28
|
+
--appDir [appDir] App directory
|
|
29
|
+
--publicDir [publicDir] Public directory
|
|
30
|
+
--productName [productName] Product name
|
|
31
|
+
-h, --help Display this message
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### dev
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
Usage:
|
|
38
|
+
$ vitrify dev
|
|
39
|
+
|
|
40
|
+
Options:
|
|
41
|
+
-m, --mode [mode] Development server mode (default: csr)
|
|
42
|
+
--host [host] Specify which IP addresses the server should listen on (default: 127.0.0.1)
|
|
43
|
+
--appDir [appDir] Application directory
|
|
44
|
+
--publicDir [publicDir] Public directory
|
|
45
|
+
-h, --help Display this message
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### test
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
Usage:
|
|
52
|
+
$ vitrify test
|
|
53
|
+
|
|
54
|
+
Options:
|
|
55
|
+
-h, --help Display this message
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### run
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
Usage:
|
|
62
|
+
$ vitrify run <file>
|
|
63
|
+
|
|
64
|
+
Options:
|
|
65
|
+
-h, --help Display this message
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Structure
|
|
69
|
+
|
|
70
|
+
```mermaid
|
|
71
|
+
graph TD;
|
|
72
|
+
node/bin/cli.ts-->node/bin/build.ts;
|
|
73
|
+
node/bin/cli.ts-->node/bin/dev.ts;
|
|
74
|
+
node/bin/cli.ts-->node/bin/test.ts;
|
|
75
|
+
node/bin/cli.ts-->node/bin/run.ts;
|
|
76
|
+
node/bin/build.ts-->node/index.ts{Load baseConfig};
|
|
77
|
+
node/bin/dev.ts-->node/index.ts{Load baseConfig};
|
|
78
|
+
node/index.ts-->vitrify.config.js{Load vitrify.config.js};
|
|
79
|
+
vitrify.config.js-->node/plugins{Load plugins};
|
|
80
|
+
node/plugins-->framework{Load framework entrypoints from vite/...};
|
|
81
|
+
framework-->merge{Merge vitrify.config.js with Vitrify configuration};
|
|
82
|
+
merge-->build{Build the application};
|
|
83
|
+
merge-->dev{Spin up dev server};
|
|
84
|
+
node/bin/test.ts-->test{Run a pre-configured Vitest instance};
|
|
85
|
+
node/bin/run.ts-->run{Inject context into script and run script};
|
|
86
|
+
```
|
package/dist/app-urls.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// import { resolve } from 'import-meta-resolve'
|
|
2
|
+
import { existsSync } from 'fs';
|
|
3
|
+
export const getPkgJsonDir = (dir) => {
|
|
4
|
+
const pkgJsonPath = new URL('package.json', dir);
|
|
5
|
+
if (existsSync(pkgJsonPath.pathname)) {
|
|
6
|
+
return new URL('./', pkgJsonPath);
|
|
7
|
+
}
|
|
8
|
+
return getPkgJsonDir(new URL('..', dir));
|
|
9
|
+
};
|
|
10
|
+
export const appDir = getPkgJsonDir(new URL(`file://${process.cwd()}/`));
|
|
11
|
+
export const cliDir = getPkgJsonDir(new URL('./', import.meta.url));
|
|
12
|
+
export const cliViteDir = new URL('src/vite/', cliDir);
|
|
13
|
+
export const srcDir = new URL('src/', appDir);
|
|
14
|
+
// export const quasarDir = getPkgJsonDir(new URL('./', await resolve('quasar', appDir.href)))
|
|
15
|
+
export const parsePath = (path) => {
|
|
16
|
+
if (path) {
|
|
17
|
+
if (path.slice(-1) !== '/')
|
|
18
|
+
path += '/';
|
|
19
|
+
if (path.startsWith('.')) {
|
|
20
|
+
return new URL(path, appDir);
|
|
21
|
+
}
|
|
22
|
+
else if (path) {
|
|
23
|
+
return new URL(`file://${path}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return;
|
|
27
|
+
};
|
|
28
|
+
export const projectURLs = {
|
|
29
|
+
src: (path) => new URL(path, srcDir),
|
|
30
|
+
app: (path) => new URL(path, appDir),
|
|
31
|
+
cli: (path) => new URL(path, cliDir)
|
|
32
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/usr/bin/node --experimental-specifier-resolution=node
|
|
2
|
+
import { baseConfig } from '../index.js';
|
|
3
|
+
// import { promises as fs } from 'fs'
|
|
4
|
+
// import { routesToPaths } from '../helpers/routes.js'
|
|
5
|
+
import { build as viteBuild } from 'vite';
|
|
6
|
+
// import { SsrFunction } from '../vitrify-config.js'
|
|
7
|
+
// export const prerender = async ({
|
|
8
|
+
// outDir,
|
|
9
|
+
// templatePath,
|
|
10
|
+
// manifestPath,
|
|
11
|
+
// entryServerPath,
|
|
12
|
+
// injectSsrContext
|
|
13
|
+
// }: {
|
|
14
|
+
// outDir: string
|
|
15
|
+
// templatePath: string
|
|
16
|
+
// manifestPath: string
|
|
17
|
+
// entryServerPath: string
|
|
18
|
+
// injectSsrContext: SsrFunction
|
|
19
|
+
// }) => {
|
|
20
|
+
// let template
|
|
21
|
+
// let manifest
|
|
22
|
+
// const promises = []
|
|
23
|
+
// template = (await fs.readFile(templatePath)).toString()
|
|
24
|
+
// manifest = await fs.readFile(manifestPath)
|
|
25
|
+
// let { render, getRoutes } = await import(entryServerPath)
|
|
26
|
+
// const routes = await getRoutes()
|
|
27
|
+
// const paths = routesToPaths(routes).filter(
|
|
28
|
+
// (i) => !i.includes(':') && !i.includes('*')
|
|
29
|
+
// )
|
|
30
|
+
// for (let url of paths) {
|
|
31
|
+
// const filename =
|
|
32
|
+
// (url.endsWith('/') ? 'index' : url.replace(/^\//g, '')) + '.html'
|
|
33
|
+
// console.log(`Generating ${filename}`)
|
|
34
|
+
// const ssrContext = {
|
|
35
|
+
// req: { headers: {}, url },
|
|
36
|
+
// res: {}
|
|
37
|
+
// }
|
|
38
|
+
// const [appHtml, preloadLinks] = await render(url, manifest, ssrContext)
|
|
39
|
+
// let html = template
|
|
40
|
+
// .replace(`<!--preload-links-->`, preloadLinks)
|
|
41
|
+
// .replace(`<!--app-html-->`, appHtml)
|
|
42
|
+
// html = injectSsrContext(html, ssrContext)
|
|
43
|
+
// promises.push(fs.writeFile(outDir + filename, html, 'utf-8'))
|
|
44
|
+
// }
|
|
45
|
+
// return Promise.all(promises)
|
|
46
|
+
// }
|
|
47
|
+
export async function build(opts) {
|
|
48
|
+
const config = await baseConfig({
|
|
49
|
+
command: 'build',
|
|
50
|
+
mode: 'production',
|
|
51
|
+
ssr: opts?.ssr,
|
|
52
|
+
appDir: opts.appDir,
|
|
53
|
+
publicDir: opts.publicDir
|
|
54
|
+
});
|
|
55
|
+
config.build = {
|
|
56
|
+
...config.build,
|
|
57
|
+
minify: false,
|
|
58
|
+
outDir: opts.outDir,
|
|
59
|
+
emptyOutDir: !!opts.outDir
|
|
60
|
+
};
|
|
61
|
+
if (opts.base) {
|
|
62
|
+
config.define = {
|
|
63
|
+
...config.define,
|
|
64
|
+
__BASE_URL__: `'${opts.base}'`
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
return viteBuild({
|
|
68
|
+
configFile: false,
|
|
69
|
+
base: opts.base,
|
|
70
|
+
// logLevel: 'silent',
|
|
71
|
+
...config
|
|
72
|
+
});
|
|
73
|
+
}
|
package/dist/bin/cli.js
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import cac from 'cac';
|
|
3
|
+
import { appDir as defaultAppDir, parsePath } from '../app-urls.js';
|
|
4
|
+
import { printHttpServerUrls } from '../helpers/logger.js';
|
|
5
|
+
const cli = cac('vitrify');
|
|
6
|
+
cli
|
|
7
|
+
.command('build')
|
|
8
|
+
.option('-m, --mode [mode]', 'Build mode', { default: 'csr' })
|
|
9
|
+
.option('--base [base]', 'Base public path')
|
|
10
|
+
.option('--outDir [outDir]', 'Output directory')
|
|
11
|
+
.option('--appDir [appDir]', 'App directory')
|
|
12
|
+
.option('--publicDir [publicDir]', 'Public directory')
|
|
13
|
+
.option('--productName [productName]', 'Product name')
|
|
14
|
+
.action(async (options) => {
|
|
15
|
+
const { build } = await import('./build.js');
|
|
16
|
+
let prerender;
|
|
17
|
+
let appDir;
|
|
18
|
+
if (options.appDir) {
|
|
19
|
+
if (options.appDir.slice(-1) !== '/')
|
|
20
|
+
options.appDir += '/';
|
|
21
|
+
appDir = new URL(`file://${options.appDir}`);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
appDir = defaultAppDir;
|
|
25
|
+
}
|
|
26
|
+
const baseOutDir = parsePath(options.outDir) || new URL('dist/', appDir);
|
|
27
|
+
const args = {
|
|
28
|
+
base: options.base,
|
|
29
|
+
appDir,
|
|
30
|
+
publicDir: parsePath(options.publicDir)
|
|
31
|
+
};
|
|
32
|
+
switch (options.mode) {
|
|
33
|
+
case 'csr':
|
|
34
|
+
await build({
|
|
35
|
+
...args,
|
|
36
|
+
outDir: new URL('spa/', baseOutDir).pathname
|
|
37
|
+
});
|
|
38
|
+
break;
|
|
39
|
+
case 'ssr':
|
|
40
|
+
await build({
|
|
41
|
+
ssr: 'client',
|
|
42
|
+
...args,
|
|
43
|
+
outDir: new URL('ssr/client/', baseOutDir).pathname
|
|
44
|
+
});
|
|
45
|
+
await build({
|
|
46
|
+
ssr: 'server',
|
|
47
|
+
...args,
|
|
48
|
+
outDir: new URL('ssr/server/', baseOutDir).pathname
|
|
49
|
+
});
|
|
50
|
+
break;
|
|
51
|
+
case 'ssg':
|
|
52
|
+
await build({
|
|
53
|
+
ssr: 'client',
|
|
54
|
+
...args,
|
|
55
|
+
outDir: new URL('static/', baseOutDir).pathname
|
|
56
|
+
});
|
|
57
|
+
await build({
|
|
58
|
+
ssr: 'server',
|
|
59
|
+
...args,
|
|
60
|
+
outDir: new URL('ssr/server/', baseOutDir).pathname
|
|
61
|
+
});
|
|
62
|
+
prerender = (await import(new URL('ssr/server/prerender.js', appDir).pathname)).prerender;
|
|
63
|
+
prerender({
|
|
64
|
+
outDir: new URL('static/', baseOutDir).pathname,
|
|
65
|
+
templatePath: new URL('static/index.html', baseOutDir).pathname,
|
|
66
|
+
manifestPath: new URL('static/ssr-manifest.json', baseOutDir)
|
|
67
|
+
.pathname,
|
|
68
|
+
entryServerPath: new URL('ssr/server/entry-server.mjs', baseOutDir)
|
|
69
|
+
.pathname
|
|
70
|
+
});
|
|
71
|
+
break;
|
|
72
|
+
default:
|
|
73
|
+
console.log('Invalid build mode');
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
cli
|
|
78
|
+
.command('dev')
|
|
79
|
+
.option('-m, --mode [mode]', 'Development server mode', { default: 'csr' })
|
|
80
|
+
.option('--host [host]', 'Specify which IP addresses the server should listen on', { default: '127.0.0.1' })
|
|
81
|
+
.option('--appDir [appDir]', 'Application directory')
|
|
82
|
+
.option('--publicDir [publicDir]', 'Public directory')
|
|
83
|
+
.action(async (options) => {
|
|
84
|
+
let server;
|
|
85
|
+
let vite;
|
|
86
|
+
if (options.host === true) {
|
|
87
|
+
options.host = '0.0.0.0';
|
|
88
|
+
}
|
|
89
|
+
const { createServer } = await import('./dev.js');
|
|
90
|
+
switch (options.mode) {
|
|
91
|
+
case 'ssr':
|
|
92
|
+
;
|
|
93
|
+
({ server, vite } = await createServer({
|
|
94
|
+
mode: 'ssr',
|
|
95
|
+
host: options.host,
|
|
96
|
+
appDir: parsePath(options.appDir),
|
|
97
|
+
publicDir: parsePath(options.publicDir)
|
|
98
|
+
}));
|
|
99
|
+
break;
|
|
100
|
+
default:
|
|
101
|
+
;
|
|
102
|
+
({ server, vite } = await createServer({
|
|
103
|
+
host: options.host,
|
|
104
|
+
appDir: parsePath(options.appDir),
|
|
105
|
+
publicDir: parsePath(options.publicDir)
|
|
106
|
+
}));
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
console.log('Dev server running at:');
|
|
110
|
+
printHttpServerUrls(server, vite.config);
|
|
111
|
+
});
|
|
112
|
+
cli.command('test').action(async (options) => {
|
|
113
|
+
const { test } = await import('./test.js');
|
|
114
|
+
let appDir;
|
|
115
|
+
if (options.appDir) {
|
|
116
|
+
if (options.appDir.slice(-1) !== '/')
|
|
117
|
+
options.appDir += '/';
|
|
118
|
+
appDir = new URL(`file://${options.appDir}`);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
appDir = defaultAppDir;
|
|
122
|
+
}
|
|
123
|
+
await test({
|
|
124
|
+
appDir
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
cli.command('run <file>').action(async (file, options) => {
|
|
128
|
+
const { run } = await import('./run.js');
|
|
129
|
+
const filePath = new URL(file, `file://${process.cwd()}/`);
|
|
130
|
+
await run(filePath.pathname);
|
|
131
|
+
});
|
|
132
|
+
// Default
|
|
133
|
+
cli.command('').action((command, options) => {
|
|
134
|
+
cli.outputHelp();
|
|
135
|
+
});
|
|
136
|
+
cli.help();
|
|
137
|
+
cli.parse();
|
package/dist/bin/dev.js
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { searchForWorkspaceRoot } from 'vite';
|
|
2
|
+
import { baseConfig } from '../index.js';
|
|
3
|
+
import fastify from 'fastify';
|
|
4
|
+
import { readFileSync } from 'fs';
|
|
5
|
+
export async function createServer({ port = 3000, logLevel = 'info', mode = 'csr', framework = 'vue', host, appDir, publicDir }) {
|
|
6
|
+
const { appDir: tempAppDir, cliDir } = await import('../app-urls.js');
|
|
7
|
+
const cwd = appDir || tempAppDir;
|
|
8
|
+
if (!appDir)
|
|
9
|
+
appDir = tempAppDir;
|
|
10
|
+
const { fastifySsrPlugin } = await import(`../${framework}/fastify-ssr-plugin.js`);
|
|
11
|
+
/**
|
|
12
|
+
* @type {import('vite').ViteDevServer}
|
|
13
|
+
*/
|
|
14
|
+
const config = await baseConfig({
|
|
15
|
+
ssr: mode === 'ssr' ? 'server' : undefined,
|
|
16
|
+
command: 'dev',
|
|
17
|
+
mode: 'development',
|
|
18
|
+
appDir,
|
|
19
|
+
publicDir
|
|
20
|
+
});
|
|
21
|
+
config.logLevel = logLevel;
|
|
22
|
+
config.server = {
|
|
23
|
+
port,
|
|
24
|
+
middlewareMode: mode === 'ssr' ? 'ssr' : undefined,
|
|
25
|
+
fs: {
|
|
26
|
+
allow: [
|
|
27
|
+
searchForWorkspaceRoot(process.cwd()),
|
|
28
|
+
searchForWorkspaceRoot(cliDir.pathname)
|
|
29
|
+
// appDir.pathname,
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
watch: {
|
|
33
|
+
// During tests we edit the files too fast and sometimes chokidar
|
|
34
|
+
// misses change events, so enforce polling for consistency
|
|
35
|
+
usePolling: true,
|
|
36
|
+
interval: 100
|
|
37
|
+
},
|
|
38
|
+
host
|
|
39
|
+
};
|
|
40
|
+
const vite = await (await import('vite')).createServer({
|
|
41
|
+
configFile: false,
|
|
42
|
+
...config
|
|
43
|
+
});
|
|
44
|
+
const { productName = 'Product name' } = JSON.parse(readFileSync(new URL('package.json', appDir).pathname, {
|
|
45
|
+
encoding: 'utf-8'
|
|
46
|
+
}));
|
|
47
|
+
let app;
|
|
48
|
+
let server;
|
|
49
|
+
if (mode === 'ssr') {
|
|
50
|
+
console.log('SSR mode');
|
|
51
|
+
app = fastify();
|
|
52
|
+
await app.register(fastifySsrPlugin, {
|
|
53
|
+
appDir,
|
|
54
|
+
cliDir,
|
|
55
|
+
vite,
|
|
56
|
+
productName
|
|
57
|
+
});
|
|
58
|
+
// await app.register(middie)
|
|
59
|
+
// app.use(vite.middlewares)
|
|
60
|
+
// app.get('*', async (req, res) => {
|
|
61
|
+
// try {
|
|
62
|
+
// // const url = req.originalUrl
|
|
63
|
+
// const url = req.raw.url
|
|
64
|
+
// let template
|
|
65
|
+
// let render
|
|
66
|
+
// const ssrContext = {
|
|
67
|
+
// req,
|
|
68
|
+
// res
|
|
69
|
+
// }
|
|
70
|
+
// // always read fresh template in dev
|
|
71
|
+
// // template = readFileSync(resolve('index.html'), 'utf-8')
|
|
72
|
+
// template = readFileSync(new URL('index.html', cliDir)).toString()
|
|
73
|
+
// // template = await vite.transformIndexHtml(url, template)
|
|
74
|
+
// const entryUrl = new URL('ssr/entry-server.ts', cliDir).pathname
|
|
75
|
+
// render = (await vite.ssrLoadModule(entryUrl)).render
|
|
76
|
+
// let manifest
|
|
77
|
+
// // TODO: https://github.com/vitejs/vite/issues/2282
|
|
78
|
+
// try {
|
|
79
|
+
// manifest = {}
|
|
80
|
+
// } catch (e) {
|
|
81
|
+
// manifest = {}
|
|
82
|
+
// }
|
|
83
|
+
// const [appHtml, preloadLinks] = await render(url, manifest, ssrContext)
|
|
84
|
+
// const html = template
|
|
85
|
+
// .replace(`<!--preload-links-->`, preloadLinks)
|
|
86
|
+
// .replace(`<!--app-html-->`, appHtml)
|
|
87
|
+
// .replace('<!--product-name-->', productName)
|
|
88
|
+
// res.code(200)
|
|
89
|
+
// res.type('text/html')
|
|
90
|
+
// res.send(html)
|
|
91
|
+
// // res.status(200).set({ 'Content-Type': 'text/html' }).end(html)
|
|
92
|
+
// } catch (e: any) {
|
|
93
|
+
// console.error(e.stack)
|
|
94
|
+
// vite && vite.ssrFixStacktrace(e)
|
|
95
|
+
// res.code(500)
|
|
96
|
+
// res.send(e.stack)
|
|
97
|
+
// }
|
|
98
|
+
// })
|
|
99
|
+
await app.listen(port || 3000, host);
|
|
100
|
+
server = app.server;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
server = (await vite.listen()).httpServer;
|
|
104
|
+
}
|
|
105
|
+
return { server, vite };
|
|
106
|
+
}
|
package/dist/bin/run.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { projectURLs } from '../app-urls.js';
|
|
2
|
+
import { promises as fs } from 'fs';
|
|
3
|
+
import readline from 'readline';
|
|
4
|
+
const pkg = JSON.parse((await fs.readFile(projectURLs.cli('package.json'), 'utf-8')).toString());
|
|
5
|
+
const rl = readline.createInterface({
|
|
6
|
+
input: process.stdin,
|
|
7
|
+
output: process.stdout
|
|
8
|
+
});
|
|
9
|
+
export async function run(filePath) {
|
|
10
|
+
const { run } = await import(filePath);
|
|
11
|
+
if (!run)
|
|
12
|
+
throw new Error(`${filePath} does not have an export named run. Aborting...`);
|
|
13
|
+
rl.question(`
|
|
14
|
+
The script ${filePath}
|
|
15
|
+
will now be executed by vitrify.
|
|
16
|
+
Make sure you trust the content of this script before proceeding.
|
|
17
|
+
Press enter to proceed or CTRL+C to abort.`, async (answer) => {
|
|
18
|
+
await run({
|
|
19
|
+
vitrify: {
|
|
20
|
+
version: pkg.version
|
|
21
|
+
},
|
|
22
|
+
resolve: projectURLs
|
|
23
|
+
});
|
|
24
|
+
rl.close();
|
|
25
|
+
});
|
|
26
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// https://github.com/quasarframework/quasar/blob/dev/app/lib/helpers/logger.js
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
const { bgGreen, green, inverse, bgRed, red, bgYellow, yellow } = chalk;
|
|
4
|
+
import readline from 'readline';
|
|
5
|
+
import os from 'os';
|
|
6
|
+
import { resolveHostname } from '../helpers/utils.js';
|
|
7
|
+
/**
|
|
8
|
+
* Main approach - App CLI related
|
|
9
|
+
*/
|
|
10
|
+
const dot = '•';
|
|
11
|
+
const banner = 'App ' + dot;
|
|
12
|
+
const greenBanner = green(banner);
|
|
13
|
+
const redBanner = red(banner);
|
|
14
|
+
const yellowBanner = yellow(banner);
|
|
15
|
+
export const clearConsole = process.stdout.isTTY
|
|
16
|
+
? () => {
|
|
17
|
+
// Fill screen with blank lines. Then move to 0 (beginning of visible part) and clear it
|
|
18
|
+
const blank = '\n'.repeat(process.stdout.rows);
|
|
19
|
+
console.log(blank);
|
|
20
|
+
readline.cursorTo(process.stdout, 0, 0);
|
|
21
|
+
readline.clearScreenDown(process.stdout);
|
|
22
|
+
}
|
|
23
|
+
: () => { };
|
|
24
|
+
export const log = function (msg) {
|
|
25
|
+
console.log(msg ? ` ${greenBanner} ${msg}` : '');
|
|
26
|
+
};
|
|
27
|
+
export const warn = function (msg, pill) {
|
|
28
|
+
if (msg !== void 0) {
|
|
29
|
+
const pillBanner = pill !== void 0 ? bgYellow.black('', pill, '') + ' ' : '';
|
|
30
|
+
console.warn(` ${yellowBanner} ⚠️ ${pillBanner}${msg}`);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
console.warn();
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
export const fatal = function (msg, pill) {
|
|
37
|
+
if (msg !== void 0) {
|
|
38
|
+
const pillBanner = pill !== void 0 ? errorPill(pill) + ' ' : '';
|
|
39
|
+
console.error(`\n ${redBanner} ⚠️ ${pillBanner}${msg}\n`);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
console.error();
|
|
43
|
+
}
|
|
44
|
+
process.exit(1);
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Extended approach - Compilation status & pills
|
|
48
|
+
*/
|
|
49
|
+
export const successPill = (msg) => bgGreen.black('', msg, '');
|
|
50
|
+
export const infoPill = (msg) => inverse('', msg, '');
|
|
51
|
+
export const errorPill = (msg) => bgRed.white('', msg, '');
|
|
52
|
+
export const warningPill = (msg) => bgYellow.black('', msg, '');
|
|
53
|
+
export const success = function (msg, title = 'SUCCESS') {
|
|
54
|
+
console.log(` ${greenBanner} ${successPill(title)} ${green(dot + ' ' + msg)}`);
|
|
55
|
+
};
|
|
56
|
+
export const getSuccess = function (msg, title) {
|
|
57
|
+
return ` ${greenBanner} ${successPill(title)} ${green(dot + ' ' + msg)}`;
|
|
58
|
+
};
|
|
59
|
+
export const info = function (msg, title = 'INFO') {
|
|
60
|
+
console.log(` ${greenBanner} ${infoPill(title)} ${green(dot)} ${msg}`);
|
|
61
|
+
};
|
|
62
|
+
export const getInfo = function (msg, title) {
|
|
63
|
+
return ` ${greenBanner} ${infoPill(title)} ${green(dot)} ${msg}`;
|
|
64
|
+
};
|
|
65
|
+
export const error = function (msg, title = 'ERROR') {
|
|
66
|
+
console.log(` ${redBanner} ${errorPill(title)} ${red(dot + ' ' + msg)}`);
|
|
67
|
+
};
|
|
68
|
+
export const getError = function (msg, title = 'ERROR') {
|
|
69
|
+
return ` ${redBanner} ${errorPill(title)} ${red(dot + ' ' + msg)}`;
|
|
70
|
+
};
|
|
71
|
+
export const warning = function (msg, title = 'WARNING') {
|
|
72
|
+
console.log(` ${yellowBanner} ${warningPill(title)} ${yellow(dot + ' ' + msg)}`);
|
|
73
|
+
};
|
|
74
|
+
export const getWarning = function (msg, title = 'WARNING') {
|
|
75
|
+
return ` ${yellowBanner} ${warningPill(title)} ${yellow(dot + ' ' + msg)}`;
|
|
76
|
+
};
|
|
77
|
+
export function printHttpServerUrls(server, config) {
|
|
78
|
+
const address = server.address();
|
|
79
|
+
const isAddressInfo = (x) => x?.address;
|
|
80
|
+
if (isAddressInfo(address)) {
|
|
81
|
+
const hostname = resolveHostname(config.server.host);
|
|
82
|
+
const protocol = config.server.https ? 'https' : 'http';
|
|
83
|
+
printServerUrls(hostname, protocol, address.port, config.base, config.logger.info);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function printServerUrls(hostname, protocol, port, base, info) {
|
|
87
|
+
if (hostname.host === '127.0.0.1') {
|
|
88
|
+
const url = `${protocol}://${hostname.name}:${chalk.bold(port)}${base}`;
|
|
89
|
+
info(` > Local: ${chalk.cyan(url)}`);
|
|
90
|
+
if (hostname.name !== '127.0.0.1') {
|
|
91
|
+
info(` > Network: ${chalk.dim('use `--host` to expose')}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
Object.values(os.networkInterfaces())
|
|
96
|
+
.flatMap((nInterface) => nInterface ?? [])
|
|
97
|
+
.filter((detail) => detail && detail.address && detail.family === 'IPv4')
|
|
98
|
+
.map((detail) => {
|
|
99
|
+
const type = detail.address.includes('127.0.0.1')
|
|
100
|
+
? 'Local: '
|
|
101
|
+
: 'Network: ';
|
|
102
|
+
const host = detail.address.replace('127.0.0.1', hostname.name);
|
|
103
|
+
const url = `${protocol}://${host}:${chalk.bold(port)}${base}`;
|
|
104
|
+
return ` > ${type} ${chalk.cyan(url)}`;
|
|
105
|
+
})
|
|
106
|
+
.forEach((msg) => info(msg));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export const routesToPaths = (routes) => {
|
|
2
|
+
if (!routes)
|
|
3
|
+
return ['/'];
|
|
4
|
+
const paths = new Set();
|
|
5
|
+
const getPaths = (routes, prefix = '') => {
|
|
6
|
+
// remove trailing slash
|
|
7
|
+
prefix = prefix.replace(/\/$/g, '');
|
|
8
|
+
for (const route of routes) {
|
|
9
|
+
let path = route.path;
|
|
10
|
+
// check for leading slash
|
|
11
|
+
if (route.path) {
|
|
12
|
+
path =
|
|
13
|
+
prefix && !route.path.startsWith('/')
|
|
14
|
+
? `${prefix}/${route.path}`
|
|
15
|
+
: route.path;
|
|
16
|
+
paths.add(path);
|
|
17
|
+
}
|
|
18
|
+
if (Array.isArray(route.children))
|
|
19
|
+
getPaths(route.children, path);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
getPaths(routes);
|
|
23
|
+
return [...paths];
|
|
24
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export function resolveHostname(optionsHost) {
|
|
2
|
+
let host;
|
|
3
|
+
if (optionsHost === undefined ||
|
|
4
|
+
optionsHost === false ||
|
|
5
|
+
optionsHost === 'localhost') {
|
|
6
|
+
// Use a secure default
|
|
7
|
+
host = '127.0.0.1';
|
|
8
|
+
}
|
|
9
|
+
else if (optionsHost === true) {
|
|
10
|
+
// If passed --host in the CLI without arguments
|
|
11
|
+
host = undefined; // undefined typically means 0.0.0.0 or :: (listen on all IPs)
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
host = optionsHost;
|
|
15
|
+
}
|
|
16
|
+
// Set host name to localhost when possible, unless the user explicitly asked for '127.0.0.1'
|
|
17
|
+
const name = (optionsHost !== '127.0.0.1' && host === '127.0.0.1') ||
|
|
18
|
+
host === '0.0.0.0' ||
|
|
19
|
+
host === '::' ||
|
|
20
|
+
host === undefined
|
|
21
|
+
? 'localhost'
|
|
22
|
+
: host;
|
|
23
|
+
return { host, name };
|
|
24
|
+
}
|