zuby 1.0.22 → 1.0.23
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 +15 -24
- package/package.json +8 -12
- package/src/branding.ts +14 -0
- package/src/commands/build.ts +159 -0
- package/src/commands/dev.ts +52 -0
- package/src/commands/index.ts +54 -0
- package/src/commands/init.ts +160 -0
- package/src/commands/preview.ts +18 -0
- package/src/config.ts +146 -0
- package/src/context/index.ts +48 -0
- package/src/context/types.ts +24 -0
- package/{defineConfig.d.ts → src/defineConfig.ts} +4 -1
- package/src/examples/basic/js/components/Card/index.css +37 -0
- package/{examples → src/examples}/basic/js/components/Card/index.jsx +2 -4
- package/src/examples/basic/js/components/Card/index.module.css +36 -0
- package/{examples/basic/ts → src/examples/basic/js}/package.json +2 -1
- package/src/examples/basic/js/pages/about.jsx +9 -0
- package/src/examples/basic/js/pages/app.css +49 -0
- package/src/examples/basic/js/pages/app.jsx +5 -0
- package/{examples → src/examples}/basic/js/pages/index.jsx +6 -3
- package/src/examples/basic/js/pages/products/[id].jsx +7 -0
- package/src/examples/basic/js/zuby.config.mjs +7 -0
- package/src/examples/basic/ts/components/Card/index.module.css +36 -0
- package/{examples → src/examples}/basic/ts/components/Card/index.tsx +3 -9
- package/src/examples/basic/ts/pages/about.tsx +9 -0
- package/src/examples/basic/ts/pages/app.css +49 -0
- package/src/examples/basic/ts/pages/app.tsx +5 -0
- package/{examples → src/examples}/basic/ts/pages/index.tsx +6 -3
- package/src/examples/basic/ts/pages/products/[id].tsx +7 -0
- package/{examples → src/examples}/basic/ts/tsconfig.json +4 -7
- package/src/examples/basic/ts/zuby.config.ts +7 -0
- package/src/logger/index.ts +120 -0
- package/src/logger/types.ts +60 -0
- package/src/packageConfig.ts +16 -0
- package/src/plugins/chunkNamingPlugin/index.ts +47 -0
- package/src/plugins/compileTimePlugin/index.ts +136 -0
- package/src/plugins/contextPlugin/index.ts +65 -0
- package/src/plugins/prerenderPlugin/index.ts +154 -0
- package/{server/expressApp.js → src/server/expressApp.ts} +1 -0
- package/src/server/index.ts +34 -0
- package/src/server/renderer.ts +0 -0
- package/src/templates/index.ts +287 -0
- package/src/templates/pathUtils.ts +86 -0
- package/src/templates/types.ts +40 -0
- package/src/types.ts +197 -0
- package/src/utils/buildIdUtils.ts +5 -0
- package/{utils/pathUtils.js → src/utils/pathUtils.ts} +3 -2
- package/tsconfig.json +17 -0
- package/branding.d.ts +0 -2
- package/branding.js +0 -9
- package/commands/build.d.ts +0 -3
- package/commands/build.js +0 -117
- package/commands/dev.d.ts +0 -2
- package/commands/dev.js +0 -39
- package/commands/index.d.ts +0 -2
- package/commands/index.js +0 -34
- package/commands/init.d.ts +0 -18
- package/commands/init.js +0 -141
- package/commands/preview.d.ts +0 -2
- package/commands/preview.js +0 -12
- package/config.d.ts +0 -19
- package/config.js +0 -119
- package/constants.d.ts +0 -4
- package/context/index.d.ts +0 -18
- package/context/index.js +0 -37
- package/context/types.d.ts +0 -21
- package/context/types.js +0 -1
- package/defineConfig.js +0 -14
- package/examples/basic/js/components/Card/index.css +0 -37
- package/examples/basic/js/components/Card/index.module.css +0 -36
- package/examples/basic/js/pages/about.jsx +0 -7
- package/examples/basic/js/pages/app.css +0 -49
- package/examples/basic/js/pages/app.jsx +0 -7
- package/examples/basic/js/pages/products/[id].jsx +0 -7
- package/examples/basic/js/zuby.config.mjs +0 -6
- package/examples/basic/ts/components/Card/index.module.css +0 -36
- package/examples/basic/ts/pages/about.tsx +0 -7
- package/examples/basic/ts/pages/app.css +0 -49
- package/examples/basic/ts/pages/app.tsx +0 -9
- package/examples/basic/ts/pages/products/[id].tsx +0 -7
- package/examples/basic/ts/zuby.config.ts +0 -6
- package/index.js +0 -3
- package/logger/index.d.ts +0 -8
- package/logger/index.js +0 -107
- package/logger/types.d.ts +0 -48
- package/logger/types.js +0 -6
- package/packageConfig.d.ts +0 -1
- package/packageConfig.js +0 -13
- package/plugins/chunkNamingPlugin/index.d.ts +0 -6
- package/plugins/chunkNamingPlugin/index.js +0 -42
- package/plugins/compileTimePlugin/index.d.ts +0 -25
- package/plugins/compileTimePlugin/index.js +0 -105
- package/plugins/contextPlugin/index.d.ts +0 -6
- package/plugins/contextPlugin/index.js +0 -51
- package/plugins/prerenderPlugin/index.d.ts +0 -6
- package/plugins/prerenderPlugin/index.js +0 -120
- package/providers/index.d.ts +0 -20
- package/providers/index.js +0 -75
- package/providers/preact/index.d.ts +0 -3
- package/providers/preact/index.js +0 -17
- package/providers/preact/render.d.ts +0 -13
- package/providers/preact/render.js +0 -47
- package/providers/preact/router.d.ts +0 -5
- package/providers/preact/router.js +0 -37
- package/providers/preact/templates/app.d.ts +0 -4
- package/providers/preact/templates/app.js +0 -4
- package/providers/preact/templates/entry.d.ts +0 -2
- package/providers/preact/templates/entry.js +0 -11
- package/providers/preact/templates/error.d.ts +0 -4
- package/providers/preact/templates/error.js +0 -4
- package/providers/preact/templates/innerLayout.d.ts +0 -4
- package/providers/preact/templates/innerLayout.js +0 -4
- package/providers/preact/templates/layout.d.ts +0 -4
- package/providers/preact/templates/layout.js +0 -4
- package/providers/types.d.ts +0 -17
- package/providers/types.js +0 -1
- package/server/expressApp.cjs +0 -472
- package/server/expressApp.d.ts +0 -1
- package/server/index.d.ts +0 -1
- package/server/index.js +0 -657
- package/server/renderer.d.ts +0 -1
- package/server/renderer.js +0 -1
- package/templates/index.d.ts +0 -59
- package/templates/index.js +0 -254
- package/templates/pathUtils.d.ts +0 -13
- package/templates/pathUtils.js +0 -69
- package/templates/types.d.ts +0 -38
- package/templates/types.js +0 -16
- package/types.d.ts +0 -161
- package/types.js +0 -5
- package/utils/buildIdUtils.d.ts +0 -1
- package/utils/buildIdUtils.js +0 -4
- package/utils/pathUtils.d.ts +0 -6
- /package/{constants.js → src/constants.ts} +0 -0
- /package/{examples/basic/js → src/examples/basic/ts}/package.json +0 -0
- /package/{index.d.ts → src/index.ts} +0 -0
package/README.md
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
# Zuby.js
|
|
2
2
|
|
|
3
|
-
Zuby.js is a simple
|
|
3
|
+
Zuby.js is a simple framework for building JS apps that combines the best of the SPA and MPA worlds.
|
|
4
4
|
The framework itself is based on [Vite](https://vitejs.dev/).
|
|
5
5
|
|
|
6
|
+
## Installation
|
|
7
|
+
|
|
8
|
+
You can set up new Zuby.js app easily with Zuby CLI wizard. Just run the following command and follow the instructions:
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
npx zuby init
|
|
12
|
+
```
|
|
13
|
+
|
|
6
14
|
## Features:
|
|
7
15
|
|
|
8
16
|
- File-based routing (with similar syntax to Next.js)
|
|
@@ -14,37 +22,20 @@ The framework itself is based on [Vite](https://vitejs.dev/).
|
|
|
14
22
|
- Fast development server
|
|
15
23
|
- Built-in i18n localization support
|
|
16
24
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
- Server-side rendering
|
|
25
|
+
Please note that Zuby.js is still in early development, so some features may be missing or not working properly.
|
|
20
26
|
|
|
21
|
-
##
|
|
27
|
+
## Integrations
|
|
22
28
|
|
|
23
|
-
|
|
29
|
+
Zuby.js integrates with JSX libraries through the `JsxProvider` interface.
|
|
30
|
+
Following integrations are available:
|
|
24
31
|
|
|
25
|
-
|
|
26
|
-
To set up this repository, run the following commands:
|
|
32
|
+
- [@zubyjs/preact](https://www.npmjs.com/package/@zubyjs/preact) - Preact integration for Zuby.js
|
|
27
33
|
|
|
28
|
-
|
|
29
|
-
git clone git@gitlab.com:futrou/zuby.js.git
|
|
30
|
-
cd zuby.js
|
|
31
|
-
npm install
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
### Recommended versions
|
|
34
|
+
## Recommended versions
|
|
35
35
|
|
|
36
36
|
- Node.js: 18
|
|
37
37
|
- npm: 9
|
|
38
38
|
|
|
39
|
-
### Releases
|
|
40
|
-
|
|
41
|
-
Please follow these steps to release a new stable version of the package:
|
|
42
|
-
|
|
43
|
-
1. Check the current version in `package.json`. This version will be released. The patch version is automatically increased by CI and pushed to the master branch after each release. If you want to release a minor or major version, please change the version manually. Otherwise, you can skip this step.
|
|
44
|
-
2. Go to the page with [repository tags](https://gitlab.com/futrou/zuby.js/-/tags) and create a new tag from'master' with the version from `package.json` as the name (in the following format, `v1.0.0`).
|
|
45
|
-
3. This will trigger the CI pipeline, which will release the package, generate a changelog, and create a new release in the Gitlab UI.
|
|
46
|
-
4. That's it! 🎉 You can check the new release on [Gitlab releases page](https://gitlab.com/futrou/zuby.js/-/releases) and [NPM package page](https://www.npmjs.com/package/zuby).
|
|
47
|
-
|
|
48
39
|
## License
|
|
49
40
|
|
|
50
41
|
MIT
|
package/package.json
CHANGED
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zuby",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "Zuby.js is
|
|
3
|
+
"version": "1.0.23",
|
|
4
|
+
"description": "Zuby.js is framework for building SPA apps using Vite",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"release": "npm publish --access public ./dist/ ",
|
|
9
|
-
"bump-version": "npm version patch",
|
|
10
9
|
"build": "rm -rf dist/ && tsc && cp -rf package.json README.md src/examples dist/ && npm run bundle-server && npm run bundle-express",
|
|
11
10
|
"bundle-server": "esbuild src/server/index.ts --bundle --platform=node --format=esm --outfile=dist/server/index.js",
|
|
12
11
|
"bundle-express": "esbuild src/server/expressApp.ts --bundle --platform=node --format=cjs --minify --outfile=dist/server/expressApp.cjs",
|
|
13
12
|
"watch-build": "npm run build && tsc --watch",
|
|
14
13
|
"push-build": "npm run build && cd dist && npm link && cd ..",
|
|
15
|
-
"
|
|
16
|
-
|
|
14
|
+
"test": "exit 0"
|
|
15
|
+
},
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"directory": "dist",
|
|
18
|
+
"linkDirectory": true
|
|
17
19
|
},
|
|
18
20
|
"dependencies": {
|
|
19
21
|
"@preact/preset-vite": "^2.6.0",
|
|
@@ -25,6 +27,7 @@
|
|
|
25
27
|
"esbuild": "^0.19.5",
|
|
26
28
|
"glob": "^10.3.10",
|
|
27
29
|
"inquirer": "^9.2.11",
|
|
30
|
+
"jest": "^29.7.0",
|
|
28
31
|
"magic-string": "^0.30.5",
|
|
29
32
|
"rollup": "^4.0.2",
|
|
30
33
|
"vite": "^4.4.11",
|
|
@@ -82,12 +85,5 @@
|
|
|
82
85
|
],
|
|
83
86
|
"engines": {
|
|
84
87
|
"node": ">=16"
|
|
85
|
-
},
|
|
86
|
-
"prettier": {
|
|
87
|
-
"singleQuote": true,
|
|
88
|
-
"semi": true,
|
|
89
|
-
"trailingComma": "es5",
|
|
90
|
-
"printWidth": 100,
|
|
91
|
-
"arrowParens": "avoid"
|
|
92
88
|
}
|
|
93
89
|
}
|
package/src/branding.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { getZubyPackageConfig } from './packageConfig.js';
|
|
3
|
+
|
|
4
|
+
const { name, version } = getZubyPackageConfig();
|
|
5
|
+
|
|
6
|
+
export const getBrand = () => {
|
|
7
|
+
return name.charAt(0).toUpperCase() + name.slice(1) + '.js';
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const getTitle = (title: string) => {
|
|
11
|
+
return `${chalk.bgYellow.bold.whiteBright(` ${getBrand()} `)}${chalk.yellowBright.bgWhite(
|
|
12
|
+
` v${version} `
|
|
13
|
+
)} ${title}`;
|
|
14
|
+
};
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { BuildCommandOptions, MODES, ZubyConfig } from '../types.js';
|
|
2
|
+
import { getZubyConfig } from '../config.js';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { getTitle } from '../branding.js';
|
|
5
|
+
import { build as viteBuild } from 'vite';
|
|
6
|
+
import { dirname, join } from 'path';
|
|
7
|
+
import { normalizePath } from '../utils/pathUtils.js';
|
|
8
|
+
import { existsSync, rmSync, writeFileSync, copyFileSync, mkdirSync } from 'fs';
|
|
9
|
+
import { ZUBY_CONFIG_FILE } from '../constants.js';
|
|
10
|
+
import { TEMPLATES } from '../templates/types.js';
|
|
11
|
+
import { glob } from 'glob';
|
|
12
|
+
import { fileURLToPath } from 'url';
|
|
13
|
+
import { getZubyPackageConfig } from '../packageConfig.js';
|
|
14
|
+
import { nodeFileTrace } from '@vercel/nft';
|
|
15
|
+
import { copyFile } from 'fs/promises';
|
|
16
|
+
|
|
17
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
18
|
+
const __dirname = dirname(__filename);
|
|
19
|
+
|
|
20
|
+
export default async function build(options: BuildCommandOptions) {
|
|
21
|
+
const zubyConfig = await getZubyConfig(options.configFile);
|
|
22
|
+
const { vite: viteConfig, customLogger: logger, outDir = '' } = zubyConfig;
|
|
23
|
+
|
|
24
|
+
process.env.NODE_ENV = MODES.production;
|
|
25
|
+
logger?.info(getTitle(chalk.gray(`building for production...`)));
|
|
26
|
+
|
|
27
|
+
// Clean build directory
|
|
28
|
+
if (existsSync(outDir || '')) {
|
|
29
|
+
rmSync(outDir || '', {
|
|
30
|
+
recursive: true,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Load the entry file
|
|
35
|
+
const entryFile = await getEntryFile(zubyConfig);
|
|
36
|
+
|
|
37
|
+
// Client build
|
|
38
|
+
logger?.info(
|
|
39
|
+
`${chalk.bgYellow.bold.whiteBright(` Step 1/4 `)} ${chalk.gray(`building client...`)}`
|
|
40
|
+
);
|
|
41
|
+
await viteBuild({
|
|
42
|
+
configFile: false,
|
|
43
|
+
...viteConfig,
|
|
44
|
+
build: {
|
|
45
|
+
...viteConfig?.build,
|
|
46
|
+
outDir: normalizePath(join(outDir, 'client')),
|
|
47
|
+
rollupOptions: {
|
|
48
|
+
...viteConfig?.build?.rollupOptions,
|
|
49
|
+
input: {
|
|
50
|
+
entry: normalizePath(entryFile),
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
mode: MODES.production,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Server build
|
|
58
|
+
logger?.info(
|
|
59
|
+
`${chalk.bgYellow.bold.whiteBright(` Step 2/4 `)} ${chalk.gray(`building server...`)}`
|
|
60
|
+
);
|
|
61
|
+
await viteBuild({
|
|
62
|
+
configFile: false,
|
|
63
|
+
...viteConfig,
|
|
64
|
+
build: {
|
|
65
|
+
...viteConfig?.build,
|
|
66
|
+
outDir: normalizePath(join(outDir, 'server')),
|
|
67
|
+
ssr: normalizePath(entryFile),
|
|
68
|
+
ssrManifest: true,
|
|
69
|
+
},
|
|
70
|
+
optimizeDeps: {
|
|
71
|
+
...viteConfig?.optimizeDeps,
|
|
72
|
+
entries: ['**/*'],
|
|
73
|
+
include: ['**/*'],
|
|
74
|
+
force: true,
|
|
75
|
+
disabled: false,
|
|
76
|
+
},
|
|
77
|
+
mode: MODES.production,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// Add serialized zuby config to build directory
|
|
81
|
+
writeFileSync(
|
|
82
|
+
normalizePath(join(outDir, ZUBY_CONFIG_FILE.replace(/\.mjs$/, '.json'))),
|
|
83
|
+
JSON.stringify(zubyConfig, null, 2)
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
// Add standalone server assets
|
|
87
|
+
copyFileSync(
|
|
88
|
+
normalizePath(join(__dirname, '..', 'server', 'index.js')),
|
|
89
|
+
normalizePath(join(outDir, 'server.mjs'))
|
|
90
|
+
);
|
|
91
|
+
copyFileSync(
|
|
92
|
+
normalizePath(join(__dirname, '..', 'server', 'expressApp.cjs')),
|
|
93
|
+
normalizePath(join(outDir, 'expressApp.cjs'))
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
const { name, version } = getZubyPackageConfig();
|
|
97
|
+
|
|
98
|
+
// Write package.json
|
|
99
|
+
writeFileSync(
|
|
100
|
+
normalizePath(join(outDir, 'package.json')),
|
|
101
|
+
JSON.stringify({
|
|
102
|
+
type: 'module',
|
|
103
|
+
name,
|
|
104
|
+
version,
|
|
105
|
+
})
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
logger?.info(
|
|
109
|
+
`${chalk.bgYellow.bold.whiteBright(` Step 4/4 `)} ${chalk.gray(`tracing dependencies...`)}`
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
logger?.info(`Tracing production dependencies...`);
|
|
113
|
+
const { fileList } = await nodeFileTrace([normalizePath(join(outDir, 'server', 'entry.js'))], {
|
|
114
|
+
processCwd: process.cwd(),
|
|
115
|
+
ignore: (path: string) => {
|
|
116
|
+
return path.startsWith(outDir);
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
logger?.info(`Copying ${fileList.size} files...`);
|
|
121
|
+
const copyFilePromises = [...fileList].map(async (srcFile: string) => {
|
|
122
|
+
const destFile = normalizePath(join(outDir, srcFile));
|
|
123
|
+
const destDir = dirname(destFile);
|
|
124
|
+
if (srcFile.startsWith(outDir) || existsSync(destFile)) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (!existsSync(destDir)) {
|
|
128
|
+
mkdirSync(destDir, {
|
|
129
|
+
recursive: true,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
return copyFile(srcFile, destFile);
|
|
133
|
+
});
|
|
134
|
+
await Promise.all(copyFilePromises);
|
|
135
|
+
|
|
136
|
+
logger?.info(`Done! 🎉`);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export async function getEntryFile(zubyConfig: ZubyConfig) {
|
|
140
|
+
const { srcDir = '', pageExtensions = [], jsx, customLogger: logger } = zubyConfig;
|
|
141
|
+
|
|
142
|
+
const userEntryFile = (
|
|
143
|
+
await glob(`${normalizePath(srcDir)}${TEMPLATES.entry}.{${pageExtensions.join(',')}}`)
|
|
144
|
+
).pop();
|
|
145
|
+
const entryFile = userEntryFile || jsx?.entryTemplateFile;
|
|
146
|
+
|
|
147
|
+
if (!entryFile) {
|
|
148
|
+
logger?.error(
|
|
149
|
+
`No entry template is available. Please create a file named '${TEMPLATES.entry}' in your project directory or use different jsx.`
|
|
150
|
+
);
|
|
151
|
+
process.exit(1);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (userEntryFile) {
|
|
155
|
+
logger?.info(chalk.gray(`Using custom entry template: '${userEntryFile}'`));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return entryFile;
|
|
159
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { MODES, ServerCommandOptions } from '../types.js';
|
|
2
|
+
import { getZubyConfig } from '../config.js';
|
|
3
|
+
import { createServer, InlineConfig, preview, PreviewServer, ViteDevServer } from 'vite';
|
|
4
|
+
import { normalizePath } from '../utils/pathUtils.js';
|
|
5
|
+
import { join } from 'path';
|
|
6
|
+
import { performance } from 'node:perf_hooks';
|
|
7
|
+
import { getTitle } from '../branding.js';
|
|
8
|
+
import chalk from 'chalk';
|
|
9
|
+
|
|
10
|
+
export default async function dev(options: ServerCommandOptions) {
|
|
11
|
+
const {
|
|
12
|
+
vite: viteConfig,
|
|
13
|
+
customLogger: logger,
|
|
14
|
+
outDir = '',
|
|
15
|
+
} = await getZubyConfig(options.configFile);
|
|
16
|
+
|
|
17
|
+
const port = options.port ? Number(options.port) : viteConfig?.server?.port;
|
|
18
|
+
const host = options.host || viteConfig?.server?.host;
|
|
19
|
+
const mode = MODES.development;
|
|
20
|
+
|
|
21
|
+
const serverConfig: InlineConfig = {
|
|
22
|
+
...viteConfig,
|
|
23
|
+
server: {
|
|
24
|
+
...viteConfig?.server,
|
|
25
|
+
port,
|
|
26
|
+
host,
|
|
27
|
+
},
|
|
28
|
+
build: {
|
|
29
|
+
outDir: normalizePath(join(outDir, 'client')),
|
|
30
|
+
},
|
|
31
|
+
mode,
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const startTime = performance.now();
|
|
35
|
+
const server = await createServer(serverConfig);
|
|
36
|
+
await server.listen();
|
|
37
|
+
const readyTime = performance.now();
|
|
38
|
+
|
|
39
|
+
if (!server.httpServer) {
|
|
40
|
+
throw new Error('HTTP server not available');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const bindAddress = server.httpServer.address();
|
|
44
|
+
const bindPort = typeof bindAddress === 'string' ? undefined : bindAddress?.port;
|
|
45
|
+
|
|
46
|
+
logger?.info(
|
|
47
|
+
` ${getTitle(chalk.gray(`started in ${Math.round(readyTime - startTime)}ms`))}\r\n`
|
|
48
|
+
);
|
|
49
|
+
logger?.info(` ┃ Mode ${mode}`);
|
|
50
|
+
logger?.info(` ┃ Local http://${host}:${bindPort || port}/`);
|
|
51
|
+
logger?.info(` ┃ Network ${chalk.gray('use --host and --port to expose')}\r\n`);
|
|
52
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { BuildCommandOptions, InitCommandOptions, ServerCommandOptions } from '../types.js';
|
|
4
|
+
import { getZubyPackageConfig } from '../packageConfig.js';
|
|
5
|
+
|
|
6
|
+
import dev from './dev.js';
|
|
7
|
+
import build from './build.js';
|
|
8
|
+
import preview from './preview.js';
|
|
9
|
+
import init from './init.js';
|
|
10
|
+
|
|
11
|
+
const { name, description, version } = getZubyPackageConfig();
|
|
12
|
+
const program = new Command().name(name).description(description).version(version);
|
|
13
|
+
|
|
14
|
+
program
|
|
15
|
+
.command('dev')
|
|
16
|
+
.description('Starts the development server')
|
|
17
|
+
.option('-p, --port <port>', 'Port to use for the dev server', '3000')
|
|
18
|
+
.option('-h, --host <host>', 'Host to use for the dev server', 'localhost')
|
|
19
|
+
.option(
|
|
20
|
+
'-c, --config-file <file>',
|
|
21
|
+
'The relative path to file with Zuby config',
|
|
22
|
+
'zuby.config.mjs'
|
|
23
|
+
)
|
|
24
|
+
.action(async options => dev(options as ServerCommandOptions));
|
|
25
|
+
|
|
26
|
+
program
|
|
27
|
+
.command('preview')
|
|
28
|
+
.alias('start')
|
|
29
|
+
.description('Starts the preview server for the production build')
|
|
30
|
+
.option('-p, --port <port>', 'Port to use for the dev server', '3000')
|
|
31
|
+
.option('-h, --host <host>', 'Host to use for the dev server', 'localhost')
|
|
32
|
+
.option(
|
|
33
|
+
'-c, --config-file <file>',
|
|
34
|
+
'The relative path to file with Zuby config',
|
|
35
|
+
'zuby.config.mjs'
|
|
36
|
+
)
|
|
37
|
+
.action(async options => preview(options as ServerCommandOptions));
|
|
38
|
+
|
|
39
|
+
program
|
|
40
|
+
.command('build')
|
|
41
|
+
.description('Builds the app for production')
|
|
42
|
+
.option(
|
|
43
|
+
'-c, --config-file <file>',
|
|
44
|
+
'The relative path to file with Zuby config',
|
|
45
|
+
'zuby.config.mjs'
|
|
46
|
+
)
|
|
47
|
+
.action(async options => build(options as BuildCommandOptions));
|
|
48
|
+
|
|
49
|
+
program
|
|
50
|
+
.command('init')
|
|
51
|
+
.description('Initializes a new Zuby project')
|
|
52
|
+
.action(async options => init(options as InitCommandOptions));
|
|
53
|
+
|
|
54
|
+
program.parse(process.argv);
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { InitCommandOptions } from '../types.js';
|
|
2
|
+
import inquirer from 'inquirer';
|
|
3
|
+
import { createLogger } from '../logger/index.js';
|
|
4
|
+
import { getTitle } from '../branding.js';
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import { existsSync, readdirSync, cpSync, statSync } from 'fs';
|
|
7
|
+
import { readFile, writeFile } from 'fs/promises';
|
|
8
|
+
import { fileURLToPath } from 'url';
|
|
9
|
+
import { dirname, join } from 'path';
|
|
10
|
+
import { normalizePath } from '../utils/pathUtils.js';
|
|
11
|
+
import { getZubyPackageConfig } from '../packageConfig.js';
|
|
12
|
+
import { globSync } from 'glob';
|
|
13
|
+
|
|
14
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
15
|
+
const __dirname = dirname(__filename);
|
|
16
|
+
|
|
17
|
+
export default async function init(options: InitCommandOptions) {
|
|
18
|
+
const logger = createLogger();
|
|
19
|
+
logger.clearScreen('info');
|
|
20
|
+
|
|
21
|
+
logger?.info(`${getTitle(`Let's get started with Zuby`)}\r\n`);
|
|
22
|
+
logger.info('Initializing a new Zuby project');
|
|
23
|
+
|
|
24
|
+
const examples = getExamples();
|
|
25
|
+
const defaultProjectName = 'my-zuby-app';
|
|
26
|
+
const defaultExample = examples.find(example => example.name === 'basic');
|
|
27
|
+
|
|
28
|
+
const { projectPath, jsxProviderName, exampleName } = await inquirer.prompt([
|
|
29
|
+
{
|
|
30
|
+
type: 'input',
|
|
31
|
+
name: 'projectPath',
|
|
32
|
+
message: 'Where would you like to create your new project?',
|
|
33
|
+
default: `./${defaultProjectName}`,
|
|
34
|
+
prefix: `${chalk.yellowBright.bgWhite(' name ')} ❯ `,
|
|
35
|
+
validate(projectPath: string): boolean | string {
|
|
36
|
+
if (existsSync(projectPath)) {
|
|
37
|
+
return 'Project with this name already exists. Please choose a different one.';
|
|
38
|
+
}
|
|
39
|
+
return true;
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
type: 'list',
|
|
44
|
+
name: 'jsxProviderName',
|
|
45
|
+
message: 'In which JSX framework would you like to write your components?',
|
|
46
|
+
choices: ['preact', 'react'],
|
|
47
|
+
default: 'preact',
|
|
48
|
+
prefix: `${chalk.yellowBright.bgWhite(' jsx ')} ❯ `,
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
type: 'list',
|
|
52
|
+
name: 'exampleName',
|
|
53
|
+
message: 'Which Zuby example project would you like to use?',
|
|
54
|
+
choices: examples.map(example => example.name),
|
|
55
|
+
default: defaultExample?.name,
|
|
56
|
+
prefix: `${chalk.yellowBright.bgWhite(' example ')} ❯ `,
|
|
57
|
+
},
|
|
58
|
+
]);
|
|
59
|
+
|
|
60
|
+
let useTypescript = false;
|
|
61
|
+
const selectedExample = examples.find(example => example.name === exampleName);
|
|
62
|
+
if (!selectedExample) {
|
|
63
|
+
logger.error(`Example ${exampleName} was not found`);
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (selectedExample?.isTs) {
|
|
68
|
+
({ useTypescript } = await inquirer.prompt([
|
|
69
|
+
{
|
|
70
|
+
type: 'confirm',
|
|
71
|
+
name: 'useTypescript',
|
|
72
|
+
message: 'Do you want to write in TypeScript?',
|
|
73
|
+
default: true,
|
|
74
|
+
prefix: `${chalk.yellowBright.bgWhite(' ts ')} ❯ `,
|
|
75
|
+
},
|
|
76
|
+
]));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const projectName = projectPath.split('/').pop() || defaultProjectName;
|
|
80
|
+
const zubyVersion = getZubyPackageConfig().version;
|
|
81
|
+
|
|
82
|
+
await initExample(selectedExample, {
|
|
83
|
+
projectName,
|
|
84
|
+
projectPath,
|
|
85
|
+
jsxProviderName,
|
|
86
|
+
useTypescript,
|
|
87
|
+
zubyVersion,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
logger?.info(`\r\nCreated ${chalk.bold(projectName)} at ${chalk.bold(projectPath)}`);
|
|
91
|
+
logger?.info(`${chalk.greenBright.bold('We are done! 🎉')}`);
|
|
92
|
+
logger?.info(`\r\n`);
|
|
93
|
+
logger?.info(`Now enter your project directory using ${chalk.bold(`cd ${projectPath}`)}`);
|
|
94
|
+
logger?.info(
|
|
95
|
+
`and run ${chalk.bold('npm install')} or ${chalk.bold(
|
|
96
|
+
'yarn install'
|
|
97
|
+
)} to install all dependencies.`
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export async function initExample(
|
|
102
|
+
example: Example,
|
|
103
|
+
// Following values can be used in templates
|
|
104
|
+
// and will be replaced during init.
|
|
105
|
+
// Example: <jsxProviderName> => preact
|
|
106
|
+
options: InitOptions
|
|
107
|
+
) {
|
|
108
|
+
const { projectPath = '', useTypescript } = options;
|
|
109
|
+
|
|
110
|
+
// Copy example files
|
|
111
|
+
cpSync(normalizePath(join(example.path, useTypescript ? 'ts' : 'js')), projectPath, {
|
|
112
|
+
recursive: true,
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// Interpolate values in files of the example
|
|
116
|
+
const transformPromises = globSync(normalizePath(join(projectPath, '**', '*'))).map(
|
|
117
|
+
async file => {
|
|
118
|
+
if (statSync(file).isDirectory()) return;
|
|
119
|
+
let fileContent = await readFile(file, 'utf-8');
|
|
120
|
+
|
|
121
|
+
// Remove template comments
|
|
122
|
+
fileContent = fileContent.replace(/\/\/\s+@template\s+/, '$1');
|
|
123
|
+
|
|
124
|
+
// Replace all available <key> values in the file
|
|
125
|
+
Object.entries(options).forEach(([key, value]) => {
|
|
126
|
+
fileContent = fileContent.replace(new RegExp(`<${key}>`, 'g'), value.toString());
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
await writeFile(file, fileContent);
|
|
130
|
+
}
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
await Promise.all(transformPromises);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function getExamples(): Example[] {
|
|
137
|
+
const examplesPath = normalizePath(join(__dirname, '..', 'examples'));
|
|
138
|
+
const exampleNames = readdirSync(examplesPath);
|
|
139
|
+
return exampleNames.map(exampleName => ({
|
|
140
|
+
name: exampleName,
|
|
141
|
+
path: normalizePath(join(examplesPath, exampleName)),
|
|
142
|
+
isJs: existsSync(normalizePath(join(examplesPath, exampleName, 'js'))),
|
|
143
|
+
isTs: existsSync(normalizePath(join(examplesPath, exampleName, 'ts'))),
|
|
144
|
+
}));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export interface Example {
|
|
148
|
+
name: string;
|
|
149
|
+
path: string;
|
|
150
|
+
isJs: boolean;
|
|
151
|
+
isTs: boolean;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export interface InitOptions {
|
|
155
|
+
projectName?: string;
|
|
156
|
+
projectPath?: string;
|
|
157
|
+
jsxProviderName?: string;
|
|
158
|
+
useTypescript?: boolean;
|
|
159
|
+
zubyVersion?: string;
|
|
160
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ServerCommandOptions } from '../types.js';
|
|
2
|
+
import { getZubyConfig } from '../config.js';
|
|
3
|
+
import { existsSync } from 'fs';
|
|
4
|
+
import { normalizePath } from '../utils/pathUtils.js';
|
|
5
|
+
import { resolve } from 'path';
|
|
6
|
+
|
|
7
|
+
export default async function preview(options: ServerCommandOptions) {
|
|
8
|
+
const { outDir = '' } = await getZubyConfig(options.configFile);
|
|
9
|
+
|
|
10
|
+
if (outDir && !existsSync(outDir)) {
|
|
11
|
+
throw new Error(
|
|
12
|
+
`The outDir '${outDir}' does not exist. Did you forget to run 'zuby build' first?`
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const serverPath = normalizePath(resolve(outDir, 'server.mjs'));
|
|
17
|
+
await import(`file:///${serverPath}`);
|
|
18
|
+
}
|