zuby 1.0.20 → 1.0.22
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/commands/init.d.ts +16 -0
- package/commands/init.js +120 -13
- package/commands/preview.js +1 -1
- package/config.d.ts +1 -6
- package/config.js +7 -22
- package/examples/basic/js/components/Card/index.css +37 -0
- package/examples/basic/js/components/Card/index.jsx +17 -0
- package/examples/basic/js/components/Card/index.module.css +36 -0
- package/examples/basic/js/package.json +14 -0
- package/examples/basic/js/pages/about.jsx +7 -0
- package/examples/basic/js/pages/app.css +49 -0
- package/examples/basic/js/pages/app.jsx +7 -0
- package/examples/basic/js/pages/index.jsx +24 -0
- package/examples/basic/js/pages/products/[id].jsx +7 -0
- package/examples/basic/js/zuby.config.mjs +6 -0
- package/examples/basic/ts/components/Card/index.module.css +36 -0
- package/examples/basic/ts/components/Card/index.tsx +21 -0
- package/examples/basic/ts/package.json +14 -0
- package/examples/basic/ts/pages/about.tsx +7 -0
- package/examples/basic/ts/pages/app.css +49 -0
- package/examples/basic/ts/pages/app.tsx +9 -0
- package/examples/basic/ts/pages/index.tsx +24 -0
- package/examples/basic/ts/pages/products/[id].tsx +7 -0
- package/examples/basic/ts/tsconfig.json +32 -0
- package/examples/basic/ts/zuby.config.ts +6 -0
- package/package.json +10 -7
- package/plugins/chunkNamingPlugin/index.js +4 -1
- package/plugins/contextPlugin/index.js +3 -0
- package/plugins/prerenderPlugin/index.js +33 -10
- package/providers/index.d.ts +20 -0
- package/providers/index.js +75 -0
- package/providers/preact/index.d.ts +1 -1
- package/providers/preact/index.js +3 -1
- package/providers/preact/router.js +4 -4
- package/providers/types.d.ts +17 -0
- package/providers/types.js +1 -0
- package/server/index.js +2 -2
- package/templates/types.d.ts +1 -0
- package/types.d.ts +3 -15
package/commands/init.d.ts
CHANGED
|
@@ -1,2 +1,18 @@
|
|
|
1
1
|
import { InitCommandOptions } from '../types.js';
|
|
2
2
|
export default function init(options: InitCommandOptions): Promise<void>;
|
|
3
|
+
export declare function initExample(example: Example, options: InitOptions): Promise<void>;
|
|
4
|
+
export declare function getExamples(): Example[];
|
|
5
|
+
export declare function updateDependencies({ projectPath, jsxProvider }: InitOptions): Promise<void>;
|
|
6
|
+
export interface Example {
|
|
7
|
+
name: string;
|
|
8
|
+
path: string;
|
|
9
|
+
isJs: boolean;
|
|
10
|
+
isTs: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface InitOptions {
|
|
13
|
+
projectName?: string;
|
|
14
|
+
projectPath?: string;
|
|
15
|
+
jsxProvider?: string;
|
|
16
|
+
useTypescript?: boolean;
|
|
17
|
+
zubyVersion?: string;
|
|
18
|
+
}
|
package/commands/init.js
CHANGED
|
@@ -2,33 +2,140 @@ import inquirer from 'inquirer';
|
|
|
2
2
|
import { createLogger } from '../logger/index.js';
|
|
3
3
|
import { getTitle } from '../branding.js';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
|
+
import { existsSync, readdirSync, cpSync, statSync } from 'fs';
|
|
6
|
+
import { readFile, writeFile } from 'fs/promises';
|
|
7
|
+
import { fileURLToPath } from 'url';
|
|
8
|
+
import { dirname, join } from 'path';
|
|
9
|
+
import { normalizePath } from '../utils/pathUtils.js';
|
|
10
|
+
import { getZubyPackageConfig } from '../packageConfig.js';
|
|
11
|
+
import { globSync } from 'glob';
|
|
12
|
+
import { ProviderDependencies, Providers } from '../providers/index.js';
|
|
13
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
14
|
+
const __dirname = dirname(__filename);
|
|
5
15
|
export default async function init(options) {
|
|
6
16
|
const logger = createLogger();
|
|
7
17
|
logger.clearScreen('info');
|
|
8
18
|
logger?.info(`${getTitle(`Let's get started with Zuby`)}\r\n`);
|
|
9
19
|
logger.info("Initializing a new Zuby project");
|
|
10
|
-
const
|
|
20
|
+
const examples = getExamples();
|
|
21
|
+
const defaultProjectName = 'my-zuby-app';
|
|
22
|
+
const defaultExample = examples.find(example => example.name === 'basic');
|
|
23
|
+
const { projectPath, jsxProvider, exampleName, } = await inquirer.prompt([
|
|
11
24
|
{
|
|
12
25
|
type: 'input',
|
|
13
|
-
name: '
|
|
14
|
-
message: '
|
|
15
|
-
default:
|
|
16
|
-
prefix: `${chalk.yellowBright.bgWhite(' name
|
|
26
|
+
name: 'projectPath',
|
|
27
|
+
message: 'Where would you like to create your new project?',
|
|
28
|
+
default: `./${defaultProjectName}`,
|
|
29
|
+
prefix: `${chalk.yellowBright.bgWhite(' name ')} ❯ `,
|
|
30
|
+
validate(projectPath) {
|
|
31
|
+
if (existsSync(projectPath)) {
|
|
32
|
+
return 'Project with this name already exists. Please choose a different one.';
|
|
33
|
+
}
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
17
36
|
},
|
|
18
37
|
{
|
|
19
38
|
type: 'list',
|
|
20
39
|
name: 'jsxProvider',
|
|
21
40
|
message: 'In which JSX framework would you like to write your components?',
|
|
22
|
-
choices:
|
|
41
|
+
choices: Object.keys(Providers),
|
|
23
42
|
default: 'preact',
|
|
24
|
-
prefix: `${chalk.yellowBright.bgWhite(' jsx
|
|
43
|
+
prefix: `${chalk.yellowBright.bgWhite(' jsx ')} ❯ `,
|
|
25
44
|
},
|
|
26
45
|
{
|
|
27
|
-
type: '
|
|
28
|
-
name: '
|
|
29
|
-
message: '
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
46
|
+
type: 'list',
|
|
47
|
+
name: 'exampleName',
|
|
48
|
+
message: 'Which Zuby example project would you like to use?',
|
|
49
|
+
choices: examples.map(example => example.name),
|
|
50
|
+
default: defaultExample?.name,
|
|
51
|
+
prefix: `${chalk.yellowBright.bgWhite(' example ')} ❯ `,
|
|
52
|
+
},
|
|
33
53
|
]);
|
|
54
|
+
let useTypescript = false;
|
|
55
|
+
const selectedExample = examples.find(example => example.name === exampleName);
|
|
56
|
+
if (!selectedExample) {
|
|
57
|
+
logger.error(`Example ${exampleName} was not found`);
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
if (selectedExample?.isTs) {
|
|
61
|
+
({
|
|
62
|
+
useTypescript,
|
|
63
|
+
} = await inquirer.prompt([
|
|
64
|
+
{
|
|
65
|
+
type: 'confirm',
|
|
66
|
+
name: 'useTypescript',
|
|
67
|
+
message: 'Do you want to write in TypeScript?',
|
|
68
|
+
default: true,
|
|
69
|
+
prefix: `${chalk.yellowBright.bgWhite(' ts ')} ❯ `,
|
|
70
|
+
}
|
|
71
|
+
]));
|
|
72
|
+
}
|
|
73
|
+
const projectName = projectPath.split('/').pop() || defaultProjectName;
|
|
74
|
+
const zubyVersion = getZubyPackageConfig().version;
|
|
75
|
+
await initExample(selectedExample, {
|
|
76
|
+
projectName,
|
|
77
|
+
projectPath,
|
|
78
|
+
jsxProvider,
|
|
79
|
+
useTypescript,
|
|
80
|
+
zubyVersion,
|
|
81
|
+
});
|
|
82
|
+
await updateDependencies({
|
|
83
|
+
projectPath,
|
|
84
|
+
jsxProvider,
|
|
85
|
+
});
|
|
86
|
+
logger?.info(`\r\nCreated ${chalk.bold(projectName)} at ${chalk.bold(projectPath)}`);
|
|
87
|
+
logger?.info(`${chalk.greenBright.bold('We are done! 🎉')}`);
|
|
88
|
+
logger?.info(`\r\n`);
|
|
89
|
+
logger?.info(`Now enter your project directory using ${chalk.bold(`cd ${projectPath}`)}`);
|
|
90
|
+
logger?.info(`and run ${chalk.bold('npm install')} or ${chalk.bold('yarn install')} to install all dependencies.`);
|
|
91
|
+
}
|
|
92
|
+
export async function initExample(example,
|
|
93
|
+
// Following values can be used in templates
|
|
94
|
+
// and will be replaced during init.
|
|
95
|
+
// Example: <jsxProvider> => preact
|
|
96
|
+
options) {
|
|
97
|
+
const { projectPath = '', useTypescript, } = options;
|
|
98
|
+
// Copy example files
|
|
99
|
+
cpSync(normalizePath(join(example.path, useTypescript ? 'ts' : 'js')), projectPath, {
|
|
100
|
+
recursive: true
|
|
101
|
+
});
|
|
102
|
+
// Interpolate values in files of the example
|
|
103
|
+
const transformPromises = globSync(normalizePath(join(projectPath, '**', '*')))
|
|
104
|
+
.map(async (file) => {
|
|
105
|
+
if (statSync(file).isDirectory())
|
|
106
|
+
return;
|
|
107
|
+
let fileContent = await readFile(file, 'utf-8');
|
|
108
|
+
Object.entries(options).forEach(([key, value]) => {
|
|
109
|
+
fileContent = fileContent.replace(new RegExp(`<${key}>`, 'g'), value.toString());
|
|
110
|
+
});
|
|
111
|
+
await writeFile(file, fileContent);
|
|
112
|
+
});
|
|
113
|
+
await Promise.all(transformPromises);
|
|
114
|
+
}
|
|
115
|
+
export function getExamples() {
|
|
116
|
+
const examplesPath = normalizePath(join(__dirname, '..', 'examples'));
|
|
117
|
+
const exampleNames = readdirSync(examplesPath);
|
|
118
|
+
return exampleNames.map(exampleName => ({
|
|
119
|
+
name: exampleName,
|
|
120
|
+
path: normalizePath(join(examplesPath, exampleName)),
|
|
121
|
+
isJs: existsSync(normalizePath(join(examplesPath, exampleName, 'js'))),
|
|
122
|
+
isTs: existsSync(normalizePath(join(examplesPath, exampleName, 'ts'))),
|
|
123
|
+
}));
|
|
124
|
+
}
|
|
125
|
+
export async function updateDependencies({ projectPath = '', jsxProvider = '' }) {
|
|
126
|
+
const packageJsonPath = normalizePath(join(projectPath, 'package.json'));
|
|
127
|
+
let packageJson = JSON.parse(await readFile(packageJsonPath, 'utf-8'));
|
|
128
|
+
// Receive dependencies for the selected jsxProvider
|
|
129
|
+
const dependencies = ProviderDependencies[jsxProvider]?.dependencies || {};
|
|
130
|
+
const devDependencies = ProviderDependencies[jsxProvider]?.devDependencies || {};
|
|
131
|
+
// Merge all dependencies
|
|
132
|
+
packageJson.dependencies = {
|
|
133
|
+
...packageJson.dependencies,
|
|
134
|
+
...dependencies,
|
|
135
|
+
};
|
|
136
|
+
packageJson.devDependencies = {
|
|
137
|
+
...packageJson.devDependencies,
|
|
138
|
+
...devDependencies,
|
|
139
|
+
};
|
|
140
|
+
await writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
34
141
|
}
|
package/commands/preview.js
CHANGED
|
@@ -7,6 +7,6 @@ export default async function preview(options) {
|
|
|
7
7
|
if (outDir && !existsSync(outDir)) {
|
|
8
8
|
throw new Error(`The outDir '${outDir}' does not exist. Did you forget to run 'zuby build' first?`);
|
|
9
9
|
}
|
|
10
|
-
const serverPath = normalizePath(resolve(outDir, 'server.
|
|
10
|
+
const serverPath = normalizePath(resolve(outDir, 'server.mjs'));
|
|
11
11
|
await import(`file:///${serverPath}`);
|
|
12
12
|
}
|
package/config.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ZubyConfig } from './types.js';
|
|
2
2
|
/**
|
|
3
3
|
* This function loads the config file and returns the config object with default values.
|
|
4
4
|
* It also caches the config object for future use.
|
|
@@ -15,10 +15,5 @@ export declare const mergeDefaultConfig: (config?: ZubyConfig) => Promise<ZubyCo
|
|
|
15
15
|
* This function returns the array of built-in Zuby plugins.
|
|
16
16
|
* Check which framework components are relying on each plugin
|
|
17
17
|
* before removing any of them.
|
|
18
|
-
* @param config
|
|
19
18
|
*/
|
|
20
19
|
export declare const getBuiltInPlugins: () => import("vite").PluginOption[];
|
|
21
|
-
/**
|
|
22
|
-
* Returns the instance of the JSX provider.
|
|
23
|
-
*/
|
|
24
|
-
export declare const getJsxProvider: (jsx: string) => JsxProvider;
|
package/config.js
CHANGED
|
@@ -4,14 +4,11 @@ import { bundleRequire } from 'bundle-require';
|
|
|
4
4
|
import { getApps, getErrors, getInnerLayouts, getLayouts, getPages, getTemplates } from './templates/index.js';
|
|
5
5
|
import { createLogger } from './logger/index.js';
|
|
6
6
|
// Plugins
|
|
7
|
-
import { preact as preactPlugin } from '@preact/preset-vite';
|
|
8
7
|
import contextPlugin from './plugins/contextPlugin/index.js';
|
|
9
8
|
import compileTimePlugin from './plugins/compileTimePlugin/index.js';
|
|
10
9
|
import chunkNamingPlugin from './plugins/chunkNamingPlugin/index.js';
|
|
11
10
|
import prerenderPlugin from './plugins/prerenderPlugin/index.js';
|
|
12
|
-
|
|
13
|
-
import preactProvider from './providers/preact/index.js';
|
|
14
|
-
import { generateBuildId } from './utils/buildIdUtils.js';
|
|
11
|
+
import { checkProviderDependencies, getProvider } from './providers/index.js';
|
|
15
12
|
let zubyConfig;
|
|
16
13
|
/**
|
|
17
14
|
* This function loads the config file and returns the config object with default values.
|
|
@@ -44,6 +41,8 @@ export const getZubyConfig = async (configFile = ZUBY_CONFIG_FILE, cache = true)
|
|
|
44
41
|
throw new Error(`No valid default export found in config file: ${foundConfigFile}`);
|
|
45
42
|
}
|
|
46
43
|
zubyConfig = await mergeDefaultConfig(zubyConfig);
|
|
44
|
+
// Check provider dependencies
|
|
45
|
+
await checkProviderDependencies(zubyConfig?.jsxProvider?.name || '');
|
|
47
46
|
return zubyConfig;
|
|
48
47
|
};
|
|
49
48
|
/**
|
|
@@ -63,8 +62,6 @@ export const mergeDefaultConfig = async (config = {}) => {
|
|
|
63
62
|
config.server = config.server ?? {};
|
|
64
63
|
config.server.host = config.server.host ?? 'localhost';
|
|
65
64
|
config.server.port = config.server.port ?? 3000;
|
|
66
|
-
// Generate the build id if not set
|
|
67
|
-
config.buildId = config.buildId ?? generateBuildId();
|
|
68
65
|
// Add minification
|
|
69
66
|
config.minifyCSS = config.minifyCSS ?? true;
|
|
70
67
|
config.minifyHTML = config.minifyHTML ?? true;
|
|
@@ -88,14 +85,15 @@ export const mergeDefaultConfig = async (config = {}) => {
|
|
|
88
85
|
config.vite.logLevel = config.vite.logLevel ?? config.logLevel;
|
|
89
86
|
config.vite.customLogger = config.vite.customLogger ?? config.customLogger;
|
|
90
87
|
config.vite.server = config.vite.server ?? config.server;
|
|
88
|
+
// Load jsx provider
|
|
89
|
+
config.jsx = config.jsx ?? 'preact';
|
|
90
|
+
config.jsxProvider = config.jsxProvider ?? await getProvider(config.jsx);
|
|
91
91
|
// Merge built-in plugins with user plugins
|
|
92
92
|
config.vite.plugins = [
|
|
93
93
|
...getBuiltInPlugins(),
|
|
94
|
+
...(config.jsxProvider?.getPlugins() ?? []),
|
|
94
95
|
...(config.vite?.plugins ?? []),
|
|
95
96
|
];
|
|
96
|
-
// Load jsx provider
|
|
97
|
-
config.jsx = config.jsx ?? 'preact';
|
|
98
|
-
config.jsxProvider = config.jsxProvider ?? getJsxProvider(config.jsx);
|
|
99
97
|
// Load templates
|
|
100
98
|
const templates = await getTemplates();
|
|
101
99
|
config.templates = config.templates ?? {};
|
|
@@ -110,25 +108,12 @@ export const mergeDefaultConfig = async (config = {}) => {
|
|
|
110
108
|
* This function returns the array of built-in Zuby plugins.
|
|
111
109
|
* Check which framework components are relying on each plugin
|
|
112
110
|
* before removing any of them.
|
|
113
|
-
* @param config
|
|
114
111
|
*/
|
|
115
112
|
export const getBuiltInPlugins = () => {
|
|
116
113
|
return [
|
|
117
|
-
preactPlugin(),
|
|
118
114
|
contextPlugin(),
|
|
119
115
|
compileTimePlugin(),
|
|
120
116
|
chunkNamingPlugin(),
|
|
121
117
|
prerenderPlugin(),
|
|
122
118
|
];
|
|
123
119
|
};
|
|
124
|
-
/**
|
|
125
|
-
* Returns the instance of the JSX provider.
|
|
126
|
-
*/
|
|
127
|
-
export const getJsxProvider = (jsx) => {
|
|
128
|
-
const provider = ({
|
|
129
|
-
'preact': preactProvider,
|
|
130
|
-
})[jsx] || undefined;
|
|
131
|
-
if (!provider)
|
|
132
|
-
throw new Error(`JSX provider '${jsx}' is not supported.`);
|
|
133
|
-
return provider;
|
|
134
|
-
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
.link-card {
|
|
2
|
+
list-style: none;
|
|
3
|
+
display: flex;
|
|
4
|
+
padding: 1px;
|
|
5
|
+
background-color: #23262d;
|
|
6
|
+
background-image: none;
|
|
7
|
+
background-size: 400%;
|
|
8
|
+
border-radius: 7px;
|
|
9
|
+
background-position: 100%;
|
|
10
|
+
transition: background-position 0.6s cubic-bezier(0.22, 1, 0.36, 1);
|
|
11
|
+
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.1);
|
|
12
|
+
}
|
|
13
|
+
.link-card > a {
|
|
14
|
+
width: 100%;
|
|
15
|
+
text-decoration: none;
|
|
16
|
+
line-height: 1.4;
|
|
17
|
+
padding: calc(1.5rem - 1px);
|
|
18
|
+
border-radius: 8px;
|
|
19
|
+
color: white;
|
|
20
|
+
background-color: #23262d;
|
|
21
|
+
opacity: 0.8;
|
|
22
|
+
}
|
|
23
|
+
h2 {
|
|
24
|
+
margin: 0;
|
|
25
|
+
font-size: 1.25rem;
|
|
26
|
+
transition: color 0.6s cubic-bezier(0.22, 1, 0.36, 1);
|
|
27
|
+
}
|
|
28
|
+
p {
|
|
29
|
+
margin-top: 0.5rem;
|
|
30
|
+
margin-bottom: 0;
|
|
31
|
+
}
|
|
32
|
+
.link-card:is(:hover, :focus-within) {
|
|
33
|
+
background-position: 0;
|
|
34
|
+
}
|
|
35
|
+
.link-card:is(:hover, :focus-within) h2 {
|
|
36
|
+
color: #ffcc00;
|
|
37
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import styles from './index.module.css';
|
|
2
|
+
|
|
3
|
+
export default function Card({ href, title, body }) {
|
|
4
|
+
return (
|
|
5
|
+
<li className={styles.linkCard}>
|
|
6
|
+
<a href={href}>
|
|
7
|
+
<h2>
|
|
8
|
+
{title}
|
|
9
|
+
<span>→</span>
|
|
10
|
+
</h2>
|
|
11
|
+
<p>
|
|
12
|
+
{body}
|
|
13
|
+
</p>
|
|
14
|
+
</a>
|
|
15
|
+
</li>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
.linkCard {
|
|
2
|
+
list-style: none;
|
|
3
|
+
display: flex;
|
|
4
|
+
padding: 1px;
|
|
5
|
+
background-color: #fbf9f8;
|
|
6
|
+
background-image: none;
|
|
7
|
+
background-size: 400%;
|
|
8
|
+
border-radius: 7px;
|
|
9
|
+
background-position: 100%;
|
|
10
|
+
transition: background-position 0.6s cubic-bezier(0.22, 1, 0.36, 1);
|
|
11
|
+
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.1);
|
|
12
|
+
}
|
|
13
|
+
.linkCard > a {
|
|
14
|
+
width: 100%;
|
|
15
|
+
text-decoration: none;
|
|
16
|
+
line-height: 1.4;
|
|
17
|
+
padding: calc(1.5rem - 1px);
|
|
18
|
+
border-radius: 8px;
|
|
19
|
+
color: #000;
|
|
20
|
+
opacity: 0.8;
|
|
21
|
+
}
|
|
22
|
+
h2 {
|
|
23
|
+
margin: 0;
|
|
24
|
+
font-size: 1.25rem;
|
|
25
|
+
transition: color 0.6s cubic-bezier(0.22, 1, 0.36, 1);
|
|
26
|
+
}
|
|
27
|
+
p {
|
|
28
|
+
margin-top: 0.5rem;
|
|
29
|
+
margin-bottom: 0;
|
|
30
|
+
}
|
|
31
|
+
.linkCard:is(:hover, :focus-within) {
|
|
32
|
+
background-position: 0;
|
|
33
|
+
}
|
|
34
|
+
.linkCard:is(:hover, :focus-within) h2 {
|
|
35
|
+
color: #ffcc00;
|
|
36
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "<projectName>",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.0.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "npx zuby dev",
|
|
8
|
+
"build": "npx zuby build",
|
|
9
|
+
"preview": "npx zuby preview"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"zuby": "^<zubyVersion>"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
html {
|
|
2
|
+
font-family: system-ui, sans-serif;
|
|
3
|
+
background: #f5f0f0;
|
|
4
|
+
background-size: 224px;
|
|
5
|
+
}
|
|
6
|
+
code {
|
|
7
|
+
font-family: 'Segoe UI', Verdana, sans-serif;
|
|
8
|
+
}
|
|
9
|
+
main {
|
|
10
|
+
margin: auto;
|
|
11
|
+
padding: 1rem;
|
|
12
|
+
width: 800px;
|
|
13
|
+
max-width: calc(100% - 2rem);
|
|
14
|
+
color: #202020;
|
|
15
|
+
font-size: 20px;
|
|
16
|
+
line-height: 1.6;
|
|
17
|
+
}
|
|
18
|
+
h1 {
|
|
19
|
+
font-size: 4rem;
|
|
20
|
+
font-weight: 700;
|
|
21
|
+
line-height: 1;
|
|
22
|
+
text-align: center;
|
|
23
|
+
margin-bottom: 1em;
|
|
24
|
+
}
|
|
25
|
+
.text-gradient {
|
|
26
|
+
-webkit-background-clip: text;
|
|
27
|
+
-webkit-text-fill-color: transparent;
|
|
28
|
+
background-color: #ef5734;
|
|
29
|
+
background-image: linear-gradient(315deg, #ef5734 0%, #ffcc2f 74%);
|
|
30
|
+
background-position: 0;
|
|
31
|
+
}
|
|
32
|
+
.instructions {
|
|
33
|
+
margin-bottom: 2rem;
|
|
34
|
+
padding: 1.5rem;
|
|
35
|
+
border-radius: 8px;
|
|
36
|
+
text-align: center;
|
|
37
|
+
}
|
|
38
|
+
.instructions code {
|
|
39
|
+
font-size: 0.8em;
|
|
40
|
+
font-weight: bold;
|
|
41
|
+
border-radius: 4px;
|
|
42
|
+
padding: 0.3em 0.4em;
|
|
43
|
+
}
|
|
44
|
+
.link-card-grid {
|
|
45
|
+
display: grid;
|
|
46
|
+
grid-template-columns: repeat(auto-fit, minmax(24ch, 1fr));
|
|
47
|
+
gap: 2rem;
|
|
48
|
+
padding: 0;
|
|
49
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import Card from '../components/Card/index.jsx';
|
|
2
|
+
|
|
3
|
+
export default function Home() {
|
|
4
|
+
return (
|
|
5
|
+
<main>
|
|
6
|
+
<h1>Hello from <span className="text-gradient">Zuby.js</span> site</h1>
|
|
7
|
+
<p className="instructions">
|
|
8
|
+
To get started, open the directory <code>./pages</code> in your project and edit <code>index</code> file.
|
|
9
|
+
</p>
|
|
10
|
+
<ul role="list" className="link-card-grid">
|
|
11
|
+
<Card
|
|
12
|
+
href="https://zuby.futrou.com/docs"
|
|
13
|
+
title="Documentation"
|
|
14
|
+
body="Find config API, tips and tricks, and more in the Zuby.js docs."
|
|
15
|
+
/>
|
|
16
|
+
<Card
|
|
17
|
+
href="https://zuby.futrou.com/examples"
|
|
18
|
+
title="Examples"
|
|
19
|
+
body="See what's possible to build with Zuby.js by browsing examples."
|
|
20
|
+
/>
|
|
21
|
+
</ul>
|
|
22
|
+
</main>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
.linkCard {
|
|
2
|
+
list-style: none;
|
|
3
|
+
display: flex;
|
|
4
|
+
padding: 1px;
|
|
5
|
+
background-color: #fbf9f8;
|
|
6
|
+
background-image: none;
|
|
7
|
+
background-size: 400%;
|
|
8
|
+
border-radius: 7px;
|
|
9
|
+
background-position: 100%;
|
|
10
|
+
transition: background-position 0.6s cubic-bezier(0.22, 1, 0.36, 1);
|
|
11
|
+
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.1);
|
|
12
|
+
}
|
|
13
|
+
.linkCard > a {
|
|
14
|
+
width: 100%;
|
|
15
|
+
text-decoration: none;
|
|
16
|
+
line-height: 1.4;
|
|
17
|
+
padding: calc(1.5rem - 1px);
|
|
18
|
+
border-radius: 8px;
|
|
19
|
+
color: #000;
|
|
20
|
+
opacity: 0.8;
|
|
21
|
+
}
|
|
22
|
+
h2 {
|
|
23
|
+
margin: 0;
|
|
24
|
+
font-size: 1.25rem;
|
|
25
|
+
transition: color 0.6s cubic-bezier(0.22, 1, 0.36, 1);
|
|
26
|
+
}
|
|
27
|
+
p {
|
|
28
|
+
margin-top: 0.5rem;
|
|
29
|
+
margin-bottom: 0;
|
|
30
|
+
}
|
|
31
|
+
.linkCard:is(:hover, :focus-within) {
|
|
32
|
+
background-position: 0;
|
|
33
|
+
}
|
|
34
|
+
.linkCard:is(:hover, :focus-within) h2 {
|
|
35
|
+
color: #ffcc00;
|
|
36
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import styles from './index.module.css';
|
|
2
|
+
|
|
3
|
+
export default function Card({ href, title, body } : {
|
|
4
|
+
href: string,
|
|
5
|
+
title: string,
|
|
6
|
+
body: string,
|
|
7
|
+
}) {
|
|
8
|
+
return (
|
|
9
|
+
<li className={styles.linkCard}>
|
|
10
|
+
<a href={href}>
|
|
11
|
+
<h2>
|
|
12
|
+
{title}
|
|
13
|
+
<span>→</span>
|
|
14
|
+
</h2>
|
|
15
|
+
<p>
|
|
16
|
+
{body}
|
|
17
|
+
</p>
|
|
18
|
+
</a>
|
|
19
|
+
</li>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "<projectName>",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.0.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "npx zuby dev",
|
|
8
|
+
"build": "npx zuby build",
|
|
9
|
+
"preview": "npx zuby preview"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"zuby": "^<zubyVersion>"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
html {
|
|
2
|
+
font-family: system-ui, sans-serif;
|
|
3
|
+
background: #f5f0f0;
|
|
4
|
+
background-size: 224px;
|
|
5
|
+
}
|
|
6
|
+
code {
|
|
7
|
+
font-family: 'Segoe UI', Verdana, sans-serif;
|
|
8
|
+
}
|
|
9
|
+
main {
|
|
10
|
+
margin: auto;
|
|
11
|
+
padding: 1rem;
|
|
12
|
+
width: 800px;
|
|
13
|
+
max-width: calc(100% - 2rem);
|
|
14
|
+
color: #202020;
|
|
15
|
+
font-size: 20px;
|
|
16
|
+
line-height: 1.6;
|
|
17
|
+
}
|
|
18
|
+
h1 {
|
|
19
|
+
font-size: 4rem;
|
|
20
|
+
font-weight: 700;
|
|
21
|
+
line-height: 1;
|
|
22
|
+
text-align: center;
|
|
23
|
+
margin-bottom: 1em;
|
|
24
|
+
}
|
|
25
|
+
.text-gradient {
|
|
26
|
+
-webkit-background-clip: text;
|
|
27
|
+
-webkit-text-fill-color: transparent;
|
|
28
|
+
background-color: #ef5734;
|
|
29
|
+
background-image: linear-gradient(315deg, #ef5734 0%, #ffcc2f 74%);
|
|
30
|
+
background-position: 0;
|
|
31
|
+
}
|
|
32
|
+
.instructions {
|
|
33
|
+
margin-bottom: 2rem;
|
|
34
|
+
padding: 1.5rem;
|
|
35
|
+
border-radius: 8px;
|
|
36
|
+
text-align: center;
|
|
37
|
+
}
|
|
38
|
+
.instructions code {
|
|
39
|
+
font-size: 0.8em;
|
|
40
|
+
font-weight: bold;
|
|
41
|
+
border-radius: 4px;
|
|
42
|
+
padding: 0.3em 0.4em;
|
|
43
|
+
}
|
|
44
|
+
.link-card-grid {
|
|
45
|
+
display: grid;
|
|
46
|
+
grid-template-columns: repeat(auto-fit, minmax(24ch, 1fr));
|
|
47
|
+
gap: 2rem;
|
|
48
|
+
padding: 0;
|
|
49
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import Card from '../components/Card';
|
|
2
|
+
|
|
3
|
+
export default function Home() {
|
|
4
|
+
return (
|
|
5
|
+
<main>
|
|
6
|
+
<h1>Hello from <span className="text-gradient">Zuby.js</span> site</h1>
|
|
7
|
+
<p className="instructions">
|
|
8
|
+
To get started, open the directory <code>./pages</code> in your project and edit <code>index</code> file.
|
|
9
|
+
</p>
|
|
10
|
+
<ul role="list" className="link-card-grid">
|
|
11
|
+
<Card
|
|
12
|
+
href="https://zuby.futrou.com/docs"
|
|
13
|
+
title="Documentation"
|
|
14
|
+
body="Find config API, tips and tricks, and more in the Zuby.js docs."
|
|
15
|
+
/>
|
|
16
|
+
<Card
|
|
17
|
+
href="https://zuby.futrou.com/examples"
|
|
18
|
+
title="Examples"
|
|
19
|
+
body="See what's possible to build with Zuby.js by browsing examples."
|
|
20
|
+
/>
|
|
21
|
+
</ul>
|
|
22
|
+
</main>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"module": "ESNext",
|
|
6
|
+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
"types": ["vite/client", "<jsxProvider>"],
|
|
9
|
+
|
|
10
|
+
/* Bundler mode */
|
|
11
|
+
"moduleResolution": "bundler",
|
|
12
|
+
"allowImportingTsExtensions": true,
|
|
13
|
+
"resolveJsonModule": true,
|
|
14
|
+
"isolatedModules": true,
|
|
15
|
+
"noEmit": true,
|
|
16
|
+
"jsx": "react-jsx",
|
|
17
|
+
"jsxImportSource": "<jsxProvider>",
|
|
18
|
+
|
|
19
|
+
/* Linting */
|
|
20
|
+
"strict": true,
|
|
21
|
+
"noUnusedLocals": true,
|
|
22
|
+
"noUnusedParameters": true,
|
|
23
|
+
"noFallthroughCasesInSwitch": true,
|
|
24
|
+
|
|
25
|
+
"composite": true,
|
|
26
|
+
"allowSyntheticDefaultImports": true
|
|
27
|
+
},
|
|
28
|
+
"include": [
|
|
29
|
+
"./**/*",
|
|
30
|
+
"zuby.config.ts"
|
|
31
|
+
]
|
|
32
|
+
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zuby",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.22",
|
|
4
4
|
"description": "Zuby.js is Preact 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
9
|
"bump-version": "npm version patch",
|
|
10
|
-
"build": "rm -rf dist/ && tsc && cp -rf package.json README.md dist/ && npm run bundle-server && npm run bundle-express",
|
|
10
|
+
"build": "rm -rf dist/ && tsc && cp -rf package.json README.md src/examples dist/ && npm run bundle-server && npm run bundle-express",
|
|
11
11
|
"bundle-server": "esbuild src/server/index.ts --bundle --platform=node --format=esm --outfile=dist/server/index.js",
|
|
12
12
|
"bundle-express": "esbuild src/server/expressApp.ts --bundle --platform=node --format=cjs --minify --outfile=dist/server/expressApp.cjs",
|
|
13
13
|
"watch-build": "npm run build && tsc --watch",
|
|
@@ -16,33 +16,33 @@
|
|
|
16
16
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
+
"@preact/preset-vite": "^2.6.0",
|
|
19
20
|
"@vercel/nft": "^0.24.3",
|
|
20
21
|
"bundle-require": "^4.0.2",
|
|
21
22
|
"chalk": "^5.3.0",
|
|
22
23
|
"commander": "^11.0.0",
|
|
23
24
|
"devalue": "^4.3.2",
|
|
24
25
|
"esbuild": "^0.19.5",
|
|
26
|
+
"glob": "^10.3.10",
|
|
25
27
|
"inquirer": "^9.2.11",
|
|
26
28
|
"magic-string": "^0.30.5",
|
|
27
|
-
"preact-render-to-string": "^6.2.2",
|
|
28
29
|
"rollup": "^4.0.2",
|
|
29
30
|
"vite": "^4.4.11",
|
|
30
|
-
"wouter-preact": "^2.12.0"
|
|
31
|
-
"glob": "^10.3.10"
|
|
31
|
+
"wouter-preact": "^2.12.0"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"express": "^4.18.2",
|
|
35
|
-
"@preact/preset-vite": "^2.5.0",
|
|
36
34
|
"@types/express": "^4.17.20",
|
|
37
35
|
"@types/inquirer": "^9.0.6",
|
|
38
36
|
"@types/node": "^20.8.3",
|
|
39
37
|
"@types/react": "^18.2.28",
|
|
40
38
|
"@types/react-dom": "^18.2.13",
|
|
39
|
+
"express": "^4.18.2",
|
|
41
40
|
"prettier": "^3.0.3",
|
|
42
41
|
"typescript": "^5.2.2"
|
|
43
42
|
},
|
|
44
43
|
"peerDependencies": {
|
|
45
44
|
"preact": "^10.0.0 || ^11.0.0",
|
|
45
|
+
"preact-render-to-string": "^6.0.0 || ^7.0.0",
|
|
46
46
|
"react": "^18.0.0 || ^19.0.0",
|
|
47
47
|
"react-dom": "^18.0.0 || ^19.0.0"
|
|
48
48
|
},
|
|
@@ -50,6 +50,9 @@
|
|
|
50
50
|
"preact": {
|
|
51
51
|
"optional": true
|
|
52
52
|
},
|
|
53
|
+
"preact-render-to-string": {
|
|
54
|
+
"optional": true
|
|
55
|
+
},
|
|
53
56
|
"react": {
|
|
54
57
|
"optional": true
|
|
55
58
|
},
|
|
@@ -28,7 +28,10 @@ export default function chunkNamingPlugin() {
|
|
|
28
28
|
}
|
|
29
29
|
return `${folder}[name]-[hash].js`;
|
|
30
30
|
};
|
|
31
|
-
const transformAssetFileName = (
|
|
31
|
+
const transformAssetFileName = (_chunkInfo) => {
|
|
32
|
+
if (config?.mode === MODES.production) {
|
|
33
|
+
return "chunks/chunk-[hash][extname]";
|
|
34
|
+
}
|
|
32
35
|
return "chunks/[name]-[hash][extname]";
|
|
33
36
|
};
|
|
34
37
|
config.build.rollupOptions.output.chunkFileNames = transformJsFileName;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { getZubyConfig } from '../../config.js';
|
|
2
|
+
import { relative } from 'path';
|
|
3
|
+
import { normalizePath } from '../../utils/pathUtils.js';
|
|
2
4
|
let viteConfig;
|
|
3
5
|
export default function index() {
|
|
4
6
|
return {
|
|
@@ -39,6 +41,7 @@ export async function generateTemplatesCode() {
|
|
|
39
41
|
}
|
|
40
42
|
export async function generateTemplateCode(template) {
|
|
41
43
|
return `{
|
|
44
|
+
filename: "${normalizePath(relative(viteConfig?.root || '', template.filename))}",
|
|
42
45
|
path: "${template.path}",
|
|
43
46
|
pathRegex: ${template.pathRegex},
|
|
44
47
|
pathParams: ${JSON.stringify(template.pathParams)},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { findMatchingTemplate, getStaticPages } from '../../templates/index.js';
|
|
2
|
-
import { existsSync, mkdirSync, writeFileSync } from 'fs';
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
3
3
|
import { basename, dirname, join, resolve } from 'path';
|
|
4
4
|
import { getZubyConfig } from '../../config.js';
|
|
5
5
|
import { getContext } from '../../context/index.js';
|
|
@@ -36,11 +36,21 @@ export default function prerenderPlugin() {
|
|
|
36
36
|
const entry = entryModule.default || entryModule;
|
|
37
37
|
const entryClientJs = (await glob(`${outDir}/client/chunks/entry-*.js`)).pop();
|
|
38
38
|
const entryClientCss = (await glob(`${outDir}/client/chunks/entry-*.css`)).pop();
|
|
39
|
+
const ssrManifest = JSON.parse(readFileSync(resolve(outDir, 'server', 'ssr-manifest.json'), 'utf-8'));
|
|
39
40
|
for (const path of paths) {
|
|
40
41
|
const zubyContext = getContext().update({
|
|
41
42
|
currentPath: path,
|
|
42
43
|
title: undefined
|
|
43
44
|
});
|
|
45
|
+
// Page
|
|
46
|
+
const { pages = [] } = zubyContext.templates || {};
|
|
47
|
+
const { template: page } = findMatchingTemplate(pages, path);
|
|
48
|
+
// App
|
|
49
|
+
const { apps = [] } = zubyContext.templates || {};
|
|
50
|
+
const { template: app } = findMatchingTemplate(apps, path);
|
|
51
|
+
// Nothing to pre-render
|
|
52
|
+
if (!page || !app)
|
|
53
|
+
continue;
|
|
44
54
|
// Load layout template component
|
|
45
55
|
const { layouts = [] } = zubyContext.templates || {};
|
|
46
56
|
const { template: layout } = findMatchingTemplate(layouts, path);
|
|
@@ -63,17 +73,30 @@ export default function prerenderPlugin() {
|
|
|
63
73
|
children: entry()
|
|
64
74
|
}),
|
|
65
75
|
})) || '';
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
// Insert main entry css
|
|
76
|
+
const staticImports = [
|
|
77
|
+
...(ssrManifest[app.filename] || []),
|
|
78
|
+
...(ssrManifest[page.filename] || []),
|
|
79
|
+
];
|
|
80
|
+
const cssImports = staticImports.filter((imp) => imp.endsWith('.css'));
|
|
81
|
+
const jsImports = [];
|
|
82
|
+
// Entry css
|
|
74
83
|
if (entryClientCss) {
|
|
75
|
-
|
|
84
|
+
cssImports.unshift(`/chunks/${basename(entryClientCss)}`);
|
|
85
|
+
}
|
|
86
|
+
// Entry js
|
|
87
|
+
if (entryClientJs) {
|
|
88
|
+
jsImports.unshift(`/chunks/${basename(entryClientJs)}`);
|
|
76
89
|
}
|
|
90
|
+
// Insert document type
|
|
91
|
+
html = "<!DOCTYPE html>" + html;
|
|
92
|
+
// Insert client CSS imports
|
|
93
|
+
cssImports.forEach((imp) => {
|
|
94
|
+
html = html.replace(/(<\/head>)/, `<link rel='stylesheet' href="${imp}"/>$1`);
|
|
95
|
+
});
|
|
96
|
+
// Insert client JS imports
|
|
97
|
+
jsImports.forEach((imp) => {
|
|
98
|
+
html = html.replace(/(<\/head>)/, `<script type="module" src="${imp}" defer></script>$1`);
|
|
99
|
+
});
|
|
77
100
|
const titleHtml = `<title>${zubyContext.title || ''}<\/title>`;
|
|
78
101
|
// Insert title
|
|
79
102
|
if (html.match(/<title>(.+)<\/title>/)) {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { JsxProvider } from './types.js';
|
|
2
|
+
export type ProviderName = keyof typeof Providers;
|
|
3
|
+
export declare const Providers: {
|
|
4
|
+
preact: () => Promise<any>;
|
|
5
|
+
};
|
|
6
|
+
export declare const ProviderDependencies: {
|
|
7
|
+
[key: string]: {
|
|
8
|
+
dependencies: {
|
|
9
|
+
[key: string]: string;
|
|
10
|
+
};
|
|
11
|
+
devDependencies: {
|
|
12
|
+
[key: string]: string;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Returns the instance of the JSX provider.
|
|
18
|
+
*/
|
|
19
|
+
export declare const getProvider: (jsx: string) => Promise<JsxProvider>;
|
|
20
|
+
export declare const checkProviderDependencies: (jsx: string) => Promise<void>;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { fileURLToPath } from 'url';
|
|
2
|
+
import { dirname, join } from 'path';
|
|
3
|
+
import { normalizePath } from '../utils/pathUtils.js';
|
|
4
|
+
import { readFile } from 'fs/promises';
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = dirname(__filename);
|
|
8
|
+
export const Providers = {
|
|
9
|
+
preact: async () => (await import(`file:///${normalizePath(join(__dirname, 'preact', 'index.js'))}`)).default,
|
|
10
|
+
};
|
|
11
|
+
export const ProviderDependencies = {
|
|
12
|
+
preact: {
|
|
13
|
+
dependencies: {
|
|
14
|
+
'preact': '^10.18.1',
|
|
15
|
+
},
|
|
16
|
+
devDependencies: {
|
|
17
|
+
'preact-render-to-string': '^6.2.2',
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
react: {
|
|
21
|
+
dependencies: {
|
|
22
|
+
'react': '^18.2.0',
|
|
23
|
+
'react-dom': '^18.2.0',
|
|
24
|
+
},
|
|
25
|
+
devDependencies: {}
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Returns the instance of the JSX provider.
|
|
30
|
+
*/
|
|
31
|
+
export const getProvider = async (jsx) => {
|
|
32
|
+
const providerImport = Providers[jsx];
|
|
33
|
+
if (!providerImport)
|
|
34
|
+
throw new Error(`JSX provider '${jsx}' is not supported.`);
|
|
35
|
+
return providerImport();
|
|
36
|
+
};
|
|
37
|
+
export const checkProviderDependencies = async (jsx) => {
|
|
38
|
+
const packageJsonPath = normalizePath(join(process.cwd(), 'package.json'));
|
|
39
|
+
const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf-8'));
|
|
40
|
+
const providerDependencies = ProviderDependencies[jsx]?.dependencies || {};
|
|
41
|
+
const providerDevDependencies = ProviderDependencies[jsx]?.devDependencies || {};
|
|
42
|
+
const dependencies = packageJson?.dependencies || {};
|
|
43
|
+
const devDependencies = packageJson?.devDependencies || {};
|
|
44
|
+
const getMissingDependencies = (installed, required) => {
|
|
45
|
+
return Object.entries(required)
|
|
46
|
+
.reduce((missing, [key, value]) => {
|
|
47
|
+
if (!installed[key])
|
|
48
|
+
return {
|
|
49
|
+
...missing,
|
|
50
|
+
[key]: value
|
|
51
|
+
};
|
|
52
|
+
return missing;
|
|
53
|
+
}, {});
|
|
54
|
+
};
|
|
55
|
+
const missingDependencies = getMissingDependencies(dependencies, providerDependencies);
|
|
56
|
+
const missingDevDependencies = getMissingDependencies({
|
|
57
|
+
...dependencies,
|
|
58
|
+
...devDependencies
|
|
59
|
+
}, providerDevDependencies);
|
|
60
|
+
if (Object.keys(missingDependencies).length === 0 && Object.keys(missingDevDependencies).length === 0) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
console.error(`${chalk.bgRed.bold.whiteBright(` ERROR `)} ${chalk.gray(`missing dependencies...`)}`);
|
|
64
|
+
console.error(`Zuby JSX provider '${jsx}' requires following dependencies:`);
|
|
65
|
+
if (Object.keys(missingDependencies).length > 0) {
|
|
66
|
+
console.error(`${chalk.bold(`dependencies`)}:`);
|
|
67
|
+
console.error(JSON.stringify(missingDependencies, null, 2));
|
|
68
|
+
}
|
|
69
|
+
if (Object.keys(missingDevDependencies).length > 0) {
|
|
70
|
+
console.error(`${chalk.bold(`devDependencies`)}:`);
|
|
71
|
+
console.error(JSON.stringify(missingDevDependencies, null, 2));
|
|
72
|
+
}
|
|
73
|
+
console.error(`Please add them to you package.json and install:`);
|
|
74
|
+
process.exit(1);
|
|
75
|
+
};
|
|
@@ -2,14 +2,16 @@ import render from './render.js';
|
|
|
2
2
|
import { fileURLToPath } from 'url';
|
|
3
3
|
import { dirname, resolve } from 'path';
|
|
4
4
|
import { normalizePath } from '../../utils/pathUtils.js';
|
|
5
|
+
import { preact } from '@preact/preset-vite';
|
|
5
6
|
const __filename = fileURLToPath(import.meta.url);
|
|
6
7
|
const __dirname = dirname(__filename);
|
|
7
8
|
export default {
|
|
8
|
-
name: '
|
|
9
|
+
name: 'preact',
|
|
9
10
|
appTemplateFile: normalizePath(resolve(__dirname, 'templates', 'app.js')),
|
|
10
11
|
entryTemplateFile: normalizePath(resolve(__dirname, 'templates', 'entry.js')),
|
|
11
12
|
layoutTemplateFile: normalizePath(resolve(__dirname, 'templates', 'layout.js')),
|
|
12
13
|
innerLayoutTemplateFile: normalizePath(resolve(__dirname, 'templates', 'innerLayout.js')),
|
|
13
14
|
errorTemplateFile: normalizePath(resolve(__dirname, 'templates', 'error.js')),
|
|
14
15
|
render,
|
|
16
|
+
getPlugins: () => preact()
|
|
15
17
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx
|
|
1
|
+
import { jsx as _jsx } from "preact/jsx-runtime";
|
|
2
2
|
import { Router as WouterRouter, Route as WouterRoute, Switch as WouterSwitch, } from 'wouter-preact';
|
|
3
3
|
import { Suspense, lazy } from 'preact/compat';
|
|
4
4
|
import { getContext } from '../../context/index.js';
|
|
@@ -31,7 +31,7 @@ export default function Router() {
|
|
|
31
31
|
return pathRegex.test(zubyContext.currentPath ?? '');
|
|
32
32
|
});
|
|
33
33
|
const page = (_jsx(WouterSwitch, { children: pages.map((page) => (_jsx(WouterRoute, { path: page.path, component: page.component }))) }));
|
|
34
|
-
return (
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
return (_jsx(WouterRouter, { ssrPath: zubyContext.currentPath, children: _jsx(Suspense, { fallback: _jsx("div", { children: "Loading..." }), children: createElement(app?.component, {
|
|
35
|
+
children: page,
|
|
36
|
+
}) }) }));
|
|
37
37
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Plugin } from "vite";
|
|
2
|
+
export interface JsxProvider {
|
|
3
|
+
name: string;
|
|
4
|
+
render(node: any): Promise<string>;
|
|
5
|
+
getPlugins(): Plugin[] | Plugin[][];
|
|
6
|
+
appTemplateFile: string;
|
|
7
|
+
entryTemplateFile: string;
|
|
8
|
+
layoutTemplateFile: string;
|
|
9
|
+
innerLayoutTemplateFile: string;
|
|
10
|
+
errorTemplateFile: string;
|
|
11
|
+
dependencies?: {
|
|
12
|
+
[key: string]: string;
|
|
13
|
+
};
|
|
14
|
+
devDependencies?: {
|
|
15
|
+
[key: string]: string;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/server/index.js
CHANGED
|
@@ -644,8 +644,8 @@ var envPort = process.env["PORT"] ? Number(process.env["PORT"]) : void 0;
|
|
|
644
644
|
var envHost = process.env["HOST"];
|
|
645
645
|
var port = envPort || 3e3;
|
|
646
646
|
var host = envHost || "localhost";
|
|
647
|
-
expressApp.
|
|
648
|
-
res.
|
|
647
|
+
expressApp.use(function(req, res) {
|
|
648
|
+
res.sendFile(resolve2(__dirname, "client", "index.html"));
|
|
649
649
|
});
|
|
650
650
|
expressApp.listen(port, host, () => {
|
|
651
651
|
logger?.info(` ${getTitle("")}\r
|
package/templates/types.d.ts
CHANGED
package/types.d.ts
CHANGED
|
@@ -2,6 +2,8 @@ import { UserConfig as ViteUserConfig } from 'vite';
|
|
|
2
2
|
import type { Plugin as VitePlugin } from "vite";
|
|
3
3
|
import { Template } from './templates/types.js';
|
|
4
4
|
import { ZubyLogger } from './logger/types.js';
|
|
5
|
+
import { ProviderName } from './providers/index.js';
|
|
6
|
+
import { JsxProvider } from './providers/types.js';
|
|
5
7
|
export interface ZubyConfig {
|
|
6
8
|
/**
|
|
7
9
|
* The relative path to directory were your zuby project is located in.
|
|
@@ -12,7 +14,7 @@ export interface ZubyConfig {
|
|
|
12
14
|
* The name of the framework which will be used to render the components.
|
|
13
15
|
* @default 'preact'
|
|
14
16
|
*/
|
|
15
|
-
jsx?:
|
|
17
|
+
jsx?: ProviderName;
|
|
16
18
|
/**
|
|
17
19
|
* The JSX provider. This option is set automatically based on the `jsx` option
|
|
18
20
|
* in case no provider is specified.
|
|
@@ -99,11 +101,6 @@ export interface ZubyConfig {
|
|
|
99
101
|
* @default ZubyLogger
|
|
100
102
|
*/
|
|
101
103
|
customLogger?: ZubyLogger;
|
|
102
|
-
/**
|
|
103
|
-
* The id which is unique for each build.
|
|
104
|
-
* @private
|
|
105
|
-
*/
|
|
106
|
-
buildId?: string;
|
|
107
104
|
/**
|
|
108
105
|
* Server options for both the dev and production server.
|
|
109
106
|
*/
|
|
@@ -123,15 +120,6 @@ export interface ZubyConfig {
|
|
|
123
120
|
port?: number;
|
|
124
121
|
};
|
|
125
122
|
}
|
|
126
|
-
export interface JsxProvider {
|
|
127
|
-
name: string;
|
|
128
|
-
render(node: any): Promise<string>;
|
|
129
|
-
appTemplateFile: string;
|
|
130
|
-
entryTemplateFile: string;
|
|
131
|
-
layoutTemplateFile: string;
|
|
132
|
-
innerLayoutTemplateFile: string;
|
|
133
|
-
errorTemplateFile: string;
|
|
134
|
-
}
|
|
135
123
|
export interface BaseCommandOptions {
|
|
136
124
|
/**
|
|
137
125
|
* The path to the zuby config file.
|