create-absolutejs 0.3.9 → 0.3.11
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 -15
- package/dist/data.d.ts +4 -2
- package/dist/data.js +23 -8
- package/dist/generators/configurations/generateDrizzleConfig.d.ts +2 -1
- package/dist/generators/configurations/generateDrizzleConfig.js +16 -6
- package/dist/generators/configurations/generatePackageJson.d.ts +2 -2
- package/dist/generators/configurations/generatePackageJson.js +42 -20
- package/dist/generators/db/generateDBHandlers.d.ts +6 -0
- package/dist/generators/db/generateDBHandlers.js +11 -0
- package/dist/generators/db/generateDrizzleSchema.d.ts +8 -0
- package/dist/generators/db/generateDrizzleSchema.js +122 -0
- package/dist/generators/db/handlerTemplates.d.ts +52 -0
- package/dist/generators/db/handlerTemplates.js +168 -0
- package/dist/generators/db/scaffoldDatabase.d.ts +5 -6
- package/dist/generators/db/scaffoldDatabase.js +37 -6
- package/dist/generators/html/generateHTMLPage.d.ts +2 -2
- package/dist/generators/html/generateHTMLPage.js +7 -4
- package/dist/generators/html/scaffoldHTML.js +1 -1
- package/dist/generators/project/collectDependencies.d.ts +9 -0
- package/dist/generators/project/collectDependencies.js +16 -0
- package/dist/generators/project/computeFlags.d.ts +9 -0
- package/dist/generators/project/computeFlags.js +7 -0
- package/dist/generators/project/generateBuildBlock.d.ts +9 -0
- package/dist/generators/project/generateBuildBlock.js +13 -0
- package/dist/generators/project/generateDBBlock.d.ts +4 -0
- package/dist/generators/project/generateDBBlock.js +69 -0
- package/dist/generators/project/generateImportsBlock.d.ts +13 -0
- package/dist/generators/project/generateImportsBlock.js +124 -0
- package/dist/generators/project/generateRoutesBlock.d.ts +10 -0
- package/dist/generators/project/generateRoutesBlock.js +74 -0
- package/dist/generators/project/generateServer.d.ts +3 -4
- package/dist/generators/project/generateServer.js +46 -170
- package/dist/generators/project/generateUseBlock.d.ts +6 -0
- package/dist/generators/project/generateUseBlock.js +28 -0
- package/dist/messages.js +13 -13
- package/dist/prompt.js +6 -7
- package/dist/questions/databaseEngine.d.ts +1 -1
- package/dist/questions/databaseEngine.js +2 -1
- package/dist/questions/databaseHost.d.ts +1 -1
- package/dist/questions/databaseHost.js +10 -30
- package/dist/questions/orm.d.ts +2 -1
- package/dist/questions/orm.js +13 -7
- package/dist/scaffold.d.ts +1 -1
- package/dist/scaffold.js +16 -8
- package/dist/templates/db/docker-compose.db.yml +15 -0
- package/dist/typeGuards.d.ts +3 -1
- package/dist/typeGuards.js +5 -19
- package/dist/types.d.ts +3 -1
- package/dist/utils/checkDockerInstalled.d.ts +2 -0
- package/dist/utils/checkDockerInstalled.js +179 -0
- package/dist/utils/parseCommandLineOptions.js +47 -15
- package/package.json +2 -2
- package/dist/templates/html/pages/HTMLExample.html +0 -66
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import os from 'os';
|
|
2
|
+
import { env, platform } from 'process';
|
|
3
|
+
import { confirm, spinner } from '@clack/prompts';
|
|
4
|
+
import { $ } from 'bun';
|
|
5
|
+
import { dim, yellow } from 'picocolors';
|
|
6
|
+
const DOCKER_URL = 'https://www.docker.com/products/docker-desktop';
|
|
7
|
+
const isWSL = () => env.WSL_DISTRO_NAME !== undefined || /microsoft/i.test(os.release());
|
|
8
|
+
let hostEnv;
|
|
9
|
+
if (platform === 'win32') {
|
|
10
|
+
hostEnv = 'windows';
|
|
11
|
+
}
|
|
12
|
+
else if (isWSL()) {
|
|
13
|
+
hostEnv = 'wsl';
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
hostEnv = 'linux';
|
|
17
|
+
}
|
|
18
|
+
const commandExists = async (cmd) => (platform === 'win32'
|
|
19
|
+
? await $ `where ${cmd}`.quiet().nothrow()
|
|
20
|
+
: await $ `command -v ${cmd}`.quiet().nothrow()).exitCode === 0;
|
|
21
|
+
const ensureSudo = async () => {
|
|
22
|
+
if ((await $ `sudo -n true`.nothrow()).exitCode !== 0) {
|
|
23
|
+
console.log(`${dim('│')}\n${yellow('▲')} sudo password required`);
|
|
24
|
+
await $ `sudo -v`;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
const runGetDocker = async () => {
|
|
28
|
+
const spin = spinner();
|
|
29
|
+
spin.start('Installing Docker via get.docker.com script');
|
|
30
|
+
const res = await $ `curl -fsSL https://get.docker.com | sudo sh -s -- --install-plugin compose`
|
|
31
|
+
.quiet()
|
|
32
|
+
.nothrow();
|
|
33
|
+
spin.stop(res.exitCode === 0 ? 'Docker installed' : 'get.docker.com failed');
|
|
34
|
+
if (res.exitCode === 0)
|
|
35
|
+
await configureDocker();
|
|
36
|
+
return res.exitCode === 0;
|
|
37
|
+
};
|
|
38
|
+
const aptInstall = async () => {
|
|
39
|
+
await ensureSudo();
|
|
40
|
+
const spin = spinner();
|
|
41
|
+
spin.start('Installing Docker Engine + Compose with apt');
|
|
42
|
+
await $ `sudo DEBIAN_FRONTEND=noninteractive apt-get update`.quiet();
|
|
43
|
+
const res = await $ `sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends docker.io docker-compose-plugin`
|
|
44
|
+
.quiet()
|
|
45
|
+
.nothrow();
|
|
46
|
+
if (res.exitCode === 0) {
|
|
47
|
+
spin.stop('Docker Engine + Compose installed');
|
|
48
|
+
await configureDocker();
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
console.warn(`${dim('│')}\n${yellow('▲')} apt install failed, falling back to get.docker.com script`);
|
|
52
|
+
return false;
|
|
53
|
+
};
|
|
54
|
+
const configureDocker = async () => {
|
|
55
|
+
const spin = spinner();
|
|
56
|
+
spin.start('Configuring Docker daemon & permissions');
|
|
57
|
+
await $ `sudo groupadd docker || true`.quiet().nothrow();
|
|
58
|
+
await $ `sudo usermod -aG docker ${env.USER}`.quiet().nothrow();
|
|
59
|
+
await $ `sudo systemctl enable --now docker`.quiet().nothrow();
|
|
60
|
+
spin.stop('Docker daemon running & permissions configured');
|
|
61
|
+
};
|
|
62
|
+
const installWindows = async () => {
|
|
63
|
+
if (await commandExists('winget')) {
|
|
64
|
+
const spin = spinner();
|
|
65
|
+
spin.start('Installing Docker Desktop with winget');
|
|
66
|
+
const res = await $ `winget install -e --id Docker.DockerDesktop`
|
|
67
|
+
.quiet()
|
|
68
|
+
.nothrow();
|
|
69
|
+
spin.stop(res.exitCode === 0
|
|
70
|
+
? 'Docker Desktop installed'
|
|
71
|
+
: 'winget install failed');
|
|
72
|
+
return res.exitCode === 0;
|
|
73
|
+
}
|
|
74
|
+
if (await commandExists('choco')) {
|
|
75
|
+
const spin = spinner();
|
|
76
|
+
spin.start('Installing Docker Desktop with Chocolatey');
|
|
77
|
+
const res = await $ `choco install docker-desktop -y`.quiet().nothrow();
|
|
78
|
+
spin.stop(res.exitCode === 0
|
|
79
|
+
? 'Docker Desktop installed'
|
|
80
|
+
: 'Chocolatey install failed');
|
|
81
|
+
return res.exitCode === 0;
|
|
82
|
+
}
|
|
83
|
+
console.log(`Automatic Windows install failed. Get Docker Desktop from ${DOCKER_URL}`);
|
|
84
|
+
return false;
|
|
85
|
+
};
|
|
86
|
+
const installWSL = async () => {
|
|
87
|
+
if ((await $ `docker.exe --version`.quiet().nothrow()).exitCode === 0)
|
|
88
|
+
return true;
|
|
89
|
+
if (await commandExists('powershell.exe')) {
|
|
90
|
+
const spin = spinner();
|
|
91
|
+
spin.start('Installing Docker Desktop on Windows via winget');
|
|
92
|
+
const res = await $ `powershell.exe -NoProfile -Command winget install -e --id Docker.DockerDesktop`
|
|
93
|
+
.quiet()
|
|
94
|
+
.nothrow();
|
|
95
|
+
spin.stop(res.exitCode === 0
|
|
96
|
+
? 'Docker Desktop installed'
|
|
97
|
+
: 'winget install failed');
|
|
98
|
+
if (res.exitCode === 0)
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
if (await aptInstall())
|
|
102
|
+
return true;
|
|
103
|
+
return runGetDocker();
|
|
104
|
+
};
|
|
105
|
+
const installLinux = async () => {
|
|
106
|
+
if (await commandExists('apt-get')) {
|
|
107
|
+
if (await aptInstall())
|
|
108
|
+
return true;
|
|
109
|
+
return runGetDocker();
|
|
110
|
+
}
|
|
111
|
+
if (await commandExists('dnf')) {
|
|
112
|
+
const spin = spinner();
|
|
113
|
+
spin.start('Installing Docker Engine and Compose plugin with dnf');
|
|
114
|
+
const res = await $ `sudo dnf install -y docker docker-compose-plugin`
|
|
115
|
+
.quiet()
|
|
116
|
+
.nothrow();
|
|
117
|
+
spin.stop(res.exitCode === 0
|
|
118
|
+
? 'Docker Engine + Compose installed'
|
|
119
|
+
: 'dnf install failed');
|
|
120
|
+
if (res.exitCode === 0)
|
|
121
|
+
await configureDocker();
|
|
122
|
+
return res.exitCode === 0;
|
|
123
|
+
}
|
|
124
|
+
if (await commandExists('pacman')) {
|
|
125
|
+
const spin = spinner();
|
|
126
|
+
spin.start('Installing Docker Engine and Compose plugin with pacman');
|
|
127
|
+
const res = await $ `sudo pacman -S --noconfirm docker docker-compose`
|
|
128
|
+
.quiet()
|
|
129
|
+
.nothrow();
|
|
130
|
+
spin.stop(res.exitCode === 0
|
|
131
|
+
? 'Docker Engine + Compose installed'
|
|
132
|
+
: 'pacman install failed');
|
|
133
|
+
if (res.exitCode === 0)
|
|
134
|
+
await configureDocker();
|
|
135
|
+
return res.exitCode === 0;
|
|
136
|
+
}
|
|
137
|
+
if (await commandExists('apk')) {
|
|
138
|
+
const spin = spinner();
|
|
139
|
+
spin.start('Installing Docker Engine and Compose plugin with apk');
|
|
140
|
+
const res = await $ `sudo apk add docker docker-cli-compose`
|
|
141
|
+
.quiet()
|
|
142
|
+
.nothrow();
|
|
143
|
+
spin.stop(res.exitCode === 0
|
|
144
|
+
? 'Docker Engine + Compose installed'
|
|
145
|
+
: 'apk install failed');
|
|
146
|
+
if (res.exitCode === 0)
|
|
147
|
+
await configureDocker();
|
|
148
|
+
return res.exitCode === 0;
|
|
149
|
+
}
|
|
150
|
+
console.log(`Automatic Linux install failed. See ${DOCKER_URL}`);
|
|
151
|
+
return false;
|
|
152
|
+
};
|
|
153
|
+
export const hasDocker = async () => (await $ `docker --version`.quiet().nothrow()).exitCode === 0 &&
|
|
154
|
+
(await $ `docker compose version`.quiet().nothrow()).exitCode === 0;
|
|
155
|
+
export const checkDockerInstalled = async () => {
|
|
156
|
+
if (await hasDocker())
|
|
157
|
+
return;
|
|
158
|
+
const proceed = await confirm({
|
|
159
|
+
initialValue: true,
|
|
160
|
+
message: 'Docker Engine and Compose plugin are required for local Postgresql. Install them now?'
|
|
161
|
+
});
|
|
162
|
+
if (!proceed)
|
|
163
|
+
return;
|
|
164
|
+
switch (hostEnv) {
|
|
165
|
+
case 'windows':
|
|
166
|
+
if (await installWindows())
|
|
167
|
+
return;
|
|
168
|
+
break;
|
|
169
|
+
case 'wsl':
|
|
170
|
+
if (await installWSL())
|
|
171
|
+
return;
|
|
172
|
+
break;
|
|
173
|
+
case 'linux':
|
|
174
|
+
if (await installLinux())
|
|
175
|
+
return;
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
console.log(`Couldn't install Docker automatically. Download it from ${DOCKER_URL}`);
|
|
179
|
+
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { argv, exit } from 'node:process';
|
|
2
2
|
import { parseArgs } from 'node:util';
|
|
3
3
|
import { DEFAULT_ARG_LENGTH } from '../constants';
|
|
4
|
-
import { availableAuthProviders, availableDatabaseEngines, availableDatabaseHosts, availableDirectoryConfigurations, availableORMs } from '../data';
|
|
5
|
-
import { isAuthProvider, isDatabaseEngine, isDatabaseHost, isDirectoryConfig, isORM } from '../typeGuards';
|
|
4
|
+
import { availableAuthProviders, availableDatabaseEngines, availableDatabaseHosts, availableDirectoryConfigurations, availableDrizzleDialects, availableORMs, availablePrismaDialects } from '../data';
|
|
5
|
+
import { isAuthProvider, isDatabaseEngine, isDatabaseHost, isDirectoryConfig, isDrizzleDialect, isORM, isPrismaDialect } from '../typeGuards';
|
|
6
6
|
export const parseCommandLineOptions = () => {
|
|
7
7
|
const { values, positionals } = parseArgs({
|
|
8
8
|
allowNegative: true,
|
|
@@ -15,14 +15,14 @@ export const parseCommandLineOptions = () => {
|
|
|
15
15
|
auth: { type: 'string' },
|
|
16
16
|
biome: { type: 'boolean' },
|
|
17
17
|
build: { type: 'string' },
|
|
18
|
-
|
|
18
|
+
db: { type: 'string' },
|
|
19
|
+
'db-dir': { type: 'string' },
|
|
20
|
+
'db-host': { type: 'string' },
|
|
19
21
|
debug: { default: false, short: 'd', type: 'boolean' },
|
|
20
22
|
directory: { type: 'string' },
|
|
21
|
-
engine: { type: 'string' },
|
|
22
23
|
'eslint+prettier': { type: 'boolean' },
|
|
23
24
|
git: { type: 'boolean' },
|
|
24
25
|
help: { default: false, short: 'h', type: 'boolean' },
|
|
25
|
-
host: { type: 'string' },
|
|
26
26
|
html: { type: 'boolean' },
|
|
27
27
|
'html-dir': { type: 'string' },
|
|
28
28
|
'html-scripts': { type: 'boolean' },
|
|
@@ -57,21 +57,21 @@ export const parseCommandLineOptions = () => {
|
|
|
57
57
|
authProvider = 'none';
|
|
58
58
|
}
|
|
59
59
|
let databaseEngine;
|
|
60
|
-
if (values.
|
|
61
|
-
errors.push(`Invalid database engine: "${values.
|
|
60
|
+
if (values.db !== undefined && !isDatabaseEngine(values.db)) {
|
|
61
|
+
errors.push(`Invalid database engine: "${values.db}". Expected: [ ${availableDatabaseEngines.join(', ')} ]`);
|
|
62
62
|
}
|
|
63
|
-
else if (values.
|
|
64
|
-
databaseEngine = values.
|
|
63
|
+
else if (values.db !== undefined) {
|
|
64
|
+
databaseEngine = values.db;
|
|
65
65
|
}
|
|
66
66
|
else if (values.skip) {
|
|
67
67
|
databaseEngine = 'none';
|
|
68
68
|
}
|
|
69
69
|
let databaseHost;
|
|
70
|
-
if (values
|
|
71
|
-
errors.push(`Invalid database host: "${values
|
|
70
|
+
if (values['db-host'] !== undefined && !isDatabaseHost(values['db-host'])) {
|
|
71
|
+
errors.push(`Invalid database host: "${values['db-host']}". Expected: [ ${availableDatabaseHosts.join(', ')} ]`);
|
|
72
72
|
}
|
|
73
|
-
else if (values
|
|
74
|
-
databaseHost = values
|
|
73
|
+
else if (values['db-host'] !== undefined) {
|
|
74
|
+
databaseHost = values['db-host'];
|
|
75
75
|
}
|
|
76
76
|
else if (values.skip) {
|
|
77
77
|
databaseHost = 'none';
|
|
@@ -105,21 +105,53 @@ export const parseCommandLineOptions = () => {
|
|
|
105
105
|
if (values.directory !== undefined && directoryConfig === undefined) {
|
|
106
106
|
errors.push(`Invalid directory configuration: "${values.directory}". Expected: [ ${availableDirectoryConfigurations.join(', ')} ]`);
|
|
107
107
|
}
|
|
108
|
+
if (values.orm === 'drizzle' &&
|
|
109
|
+
databaseEngine !== undefined &&
|
|
110
|
+
databaseEngine !== 'none' &&
|
|
111
|
+
!isDrizzleDialect(databaseEngine)) {
|
|
112
|
+
errors.push(`Invalid database engine for Drizzle ORM: "${databaseEngine}". Expected: [ ${availableDrizzleDialects.join(', ')} ]`);
|
|
113
|
+
}
|
|
114
|
+
if (values.orm === 'prisma' &&
|
|
115
|
+
databaseEngine !== undefined &&
|
|
116
|
+
databaseEngine !== 'none' &&
|
|
117
|
+
!isPrismaDialect(databaseEngine)) {
|
|
118
|
+
errors.push(`Invalid database engine for Prisma ORM: "${databaseEngine}". Expected: [ ${availablePrismaDialects.join(', ')} ]`);
|
|
119
|
+
}
|
|
120
|
+
if (values['db-host'] === 'turso' &&
|
|
121
|
+
(databaseEngine === undefined || databaseEngine === 'none')) {
|
|
122
|
+
databaseEngine = 'sqlite';
|
|
123
|
+
}
|
|
124
|
+
else if (values['db-host'] === 'turso' && databaseEngine !== 'sqlite') {
|
|
125
|
+
errors.push(`Invalid database engine for Turso: "${databaseEngine}". Expected: "sqlite".`);
|
|
126
|
+
}
|
|
127
|
+
if (values['db-host'] === 'neon' && databaseEngine !== 'postgresql') {
|
|
128
|
+
errors.push(`Invalid database engine for Neon: "${databaseEngine}". Expected: "postgresql".`);
|
|
129
|
+
}
|
|
130
|
+
if (values['db-host'] === 'planetscale' &&
|
|
131
|
+
databaseEngine !== 'postgresql' &&
|
|
132
|
+
databaseEngine !== 'mysql') {
|
|
133
|
+
errors.push(`Invalid database engine for PlanetScale: "${databaseEngine}". Expected: "postgresql" or "mysql".`);
|
|
134
|
+
}
|
|
108
135
|
if (errors.length > 0) {
|
|
109
136
|
console.error(errors.join('\n'));
|
|
110
137
|
exit(1);
|
|
111
138
|
}
|
|
112
139
|
if (databaseEngine === 'none' && databaseHost !== 'none') {
|
|
113
|
-
console.warn('Warning: Setting the database host without a database engine has no effect.');
|
|
140
|
+
console.warn('Warning: Setting the database host without setting a database engine has no effect.');
|
|
141
|
+
databaseHost = 'none';
|
|
114
142
|
}
|
|
115
143
|
if (databaseEngine === 'none' && orm !== 'none') {
|
|
116
144
|
console.warn('Warning: Setting an ORM without a database engine has no effect.');
|
|
145
|
+
orm = 'none';
|
|
117
146
|
}
|
|
118
|
-
let databaseDirectory = values
|
|
147
|
+
let databaseDirectory = values['db-dir'];
|
|
119
148
|
if (databaseEngine === 'none' && databaseDirectory !== undefined) {
|
|
120
149
|
console.warn('Warning: Setting a database directory without a database engine has no effect.');
|
|
121
150
|
databaseDirectory = undefined;
|
|
122
151
|
}
|
|
152
|
+
if (values['eslint+prettier'] && values.biome) {
|
|
153
|
+
console.warn('Warning: Both ESLint+Prettier and Biome are set to enabled. Only ESLint+Prettier will be used.');
|
|
154
|
+
}
|
|
123
155
|
const selectedFrontends = [];
|
|
124
156
|
// if (values.angular) selectedFrontends.push('angular')
|
|
125
157
|
if (values.html)
|
package/package.json
CHANGED
|
@@ -43,9 +43,9 @@
|
|
|
43
43
|
"format": "prettier --write \"./**/*.{js,jsx,ts,tsx,css,json,mjs,md,svelte,html,vue}\"",
|
|
44
44
|
"lint": "eslint ./",
|
|
45
45
|
"release": "bun run format && bun run build && bun publish",
|
|
46
|
-
"test": "cd absolutejs-project && bun dev",
|
|
46
|
+
"test": "bash -c 'trap \"exit 0\" INT; cd absolutejs-project && bun dev'",
|
|
47
47
|
"typecheck": "bun run tsc --noEmit"
|
|
48
48
|
},
|
|
49
49
|
"type": "module",
|
|
50
|
-
"version": "0.3.
|
|
50
|
+
"version": "0.3.11"
|
|
51
51
|
}
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html>
|
|
3
|
-
<head>
|
|
4
|
-
<title>AbsoluteJS + HTML</title>
|
|
5
|
-
<meta name="description" content="AbsoluteJS HTML Example" />
|
|
6
|
-
<meta charset="utf-8" />
|
|
7
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
8
|
-
<link
|
|
9
|
-
rel="stylesheet"
|
|
10
|
-
type="text/css"
|
|
11
|
-
href="../styles/html-example.css"
|
|
12
|
-
/>
|
|
13
|
-
<link rel="icon" href="/assets/ico/favicon.ico" />
|
|
14
|
-
</head>
|
|
15
|
-
<body>
|
|
16
|
-
<header>
|
|
17
|
-
<a href="/">AbsoluteJS</a>
|
|
18
|
-
<details>
|
|
19
|
-
<summary>Pages</summary>
|
|
20
|
-
<nav>
|
|
21
|
-
<a href="/html">HTML</a>
|
|
22
|
-
<a href="/react">React</a>
|
|
23
|
-
<a href="/htmx">HTMX</a>
|
|
24
|
-
<a href="/svelte">Svelte</a>
|
|
25
|
-
<a href="/vue">Vue</a>
|
|
26
|
-
<a href="/angular">Angular</a>
|
|
27
|
-
</nav>
|
|
28
|
-
</details>
|
|
29
|
-
</header>
|
|
30
|
-
<main>
|
|
31
|
-
<nav>
|
|
32
|
-
<a href="https://absolutejs.com" target="_blank">
|
|
33
|
-
<img
|
|
34
|
-
class="logo"
|
|
35
|
-
src="/assets/png/absolutejs-temp.png"
|
|
36
|
-
alt="AbsoluteJS Logo"
|
|
37
|
-
/>
|
|
38
|
-
</a>
|
|
39
|
-
<a href="https://html.spec.whatwg.org/multipage/">
|
|
40
|
-
<img
|
|
41
|
-
class="logo html"
|
|
42
|
-
src="/assets/svg/HTML5_Badge.svg"
|
|
43
|
-
alt="HTML Logo"
|
|
44
|
-
/>
|
|
45
|
-
</a>
|
|
46
|
-
</nav>
|
|
47
|
-
<h1>AbsoluteJS + HTML</h1>
|
|
48
|
-
<button id="counter-button">
|
|
49
|
-
count is <span id="counter">0</span>
|
|
50
|
-
</button>
|
|
51
|
-
<p>
|
|
52
|
-
Edit <code>example/html/pages/HtmlExample.html</code> save and
|
|
53
|
-
rebuild to update the page.
|
|
54
|
-
</p>
|
|
55
|
-
<p style="color: #777">( Hot Module Reloading is coming soon )</p>
|
|
56
|
-
<p style="margin-top: 2rem">
|
|
57
|
-
Explore the other pages to see how AbsoluteJS seamlessly unifies
|
|
58
|
-
multiple frameworks on a single server.
|
|
59
|
-
</p>
|
|
60
|
-
<p style="margin-top: 2rem; font-size: 1rem; color: #777">
|
|
61
|
-
Click on the AbsoluteJS and HTML logos to learn more.
|
|
62
|
-
</p>
|
|
63
|
-
</main>
|
|
64
|
-
<script src="../scripts/typescript-example.ts"></script>
|
|
65
|
-
</body>
|
|
66
|
-
</html>
|