create-jwn-js 1.0.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 +8 -0
- package/index.js +254 -0
- package/package.json +26 -0
- package/template-vite-node-ts/.gitignore +5 -0
- package/template-vite-node-ts/connect-template.json +36 -0
- package/template-vite-node-ts/docs/index.md +31 -0
- package/template-vite-node-ts/jest.config.ts +37 -0
- package/template-vite-node-ts/package.json +33 -0
- package/template-vite-node-ts/src/backend/server/helpers/createConfigServer.ts +16 -0
- package/template-vite-node-ts/src/backend/server/helpers/createMariadb.ts +12 -0
- package/template-vite-node-ts/src/backend/server/helpers/createMemcached.ts +15 -0
- package/template-vite-node-ts/src/backend/server/helpers/nameFormaters.ts +9 -0
- package/template-vite-node-ts/src/backend/server/index.ts +53 -0
- package/template-vite-node-ts/src/backend/server/site-schema.ts +28 -0
- package/template-vite-node-ts/src/backend/server/web-routes/index.ts +9 -0
- package/template-vite-node-ts/src/backend/views/Api/v1/Clients/ClientsController.ts +16 -0
- package/template-vite-node-ts/src/backend/views/Api/v1/Clients/__its__/clients.spec.ts +9 -0
- package/template-vite-node-ts/src/scripts/jest.global.setup.ts +12 -0
- package/template-vite-node-ts/src/scripts/jest.global.teardown.ts +9 -0
- package/template-vite-node-ts/src/scripts/jest.setup.ts +16 -0
- package/template-vite-node-ts/tsconfig.json +47 -0
- package/template-vite-node-ts/vite.config.ts +84 -0
package/README.md
ADDED
package/index.js
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs')
|
|
4
|
+
const path = require('path')
|
|
5
|
+
const margv = require('margv')
|
|
6
|
+
const argv = margv();
|
|
7
|
+
const prompts = require('prompts');
|
|
8
|
+
|
|
9
|
+
const {
|
|
10
|
+
yellow,
|
|
11
|
+
blue,
|
|
12
|
+
red
|
|
13
|
+
} = require('kolorist')
|
|
14
|
+
const cwd = process.cwd()
|
|
15
|
+
const FRAMEWORKS = [
|
|
16
|
+
{
|
|
17
|
+
name: 'vite',
|
|
18
|
+
color: yellow,
|
|
19
|
+
variants: [
|
|
20
|
+
{
|
|
21
|
+
name: 'vite-node-ts',
|
|
22
|
+
display: 'TypeScript',
|
|
23
|
+
color: blue
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
const TEMPLATES = FRAMEWORKS.map(
|
|
29
|
+
(f) => (f.variants && f.variants.map((v) => v.name)) || [f.name]
|
|
30
|
+
).reduce((a, b) => a.concat(b), []);
|
|
31
|
+
|
|
32
|
+
const renameFiles = {
|
|
33
|
+
_gitignore: '.gitignore'
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function init() {
|
|
37
|
+
let targetDir = argv["$"][2];
|
|
38
|
+
let template = argv.template || argv.t
|
|
39
|
+
const defaultProjectName = targetDir || 'vite-node';
|
|
40
|
+
let result = {}
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
result = await prompts(
|
|
44
|
+
[
|
|
45
|
+
{
|
|
46
|
+
type: targetDir ? null : 'text',
|
|
47
|
+
name: 'projectName',
|
|
48
|
+
message: 'Project name:',
|
|
49
|
+
initial: defaultProjectName,
|
|
50
|
+
onState: (state) =>
|
|
51
|
+
(targetDir = state.value.trim() || defaultProjectName)
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
type: () =>
|
|
55
|
+
!fs.existsSync(targetDir) || isEmpty(targetDir) ? null : 'confirm',
|
|
56
|
+
name: 'overwrite',
|
|
57
|
+
message: () =>
|
|
58
|
+
(targetDir === '.'
|
|
59
|
+
? 'Current directory'
|
|
60
|
+
: `Target directory "${targetDir}"`) +
|
|
61
|
+
` is not empty. Remove existing files and continue?`
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
type: (_, { overwrite } = {}) => {
|
|
65
|
+
if (overwrite === false) {
|
|
66
|
+
throw new Error(red('✖') + ' Operation cancelled')
|
|
67
|
+
}
|
|
68
|
+
return null
|
|
69
|
+
},
|
|
70
|
+
name: 'overwriteChecker'
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
type: () => (isValidPackageName(targetDir) ? null : 'text'),
|
|
74
|
+
name: 'packageName',
|
|
75
|
+
message: 'Package name:',
|
|
76
|
+
initial: () => toValidPackageName(targetDir),
|
|
77
|
+
validate: (dir) =>
|
|
78
|
+
isValidPackageName(dir) || 'Invalid package.json name'
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
type: template && TEMPLATES.includes(template) ? null : 'select',
|
|
82
|
+
name: 'framework',
|
|
83
|
+
message:
|
|
84
|
+
typeof template === 'string' && !TEMPLATES.includes(template)
|
|
85
|
+
? `"${template}" isn't a valid template. Please choose from below: `
|
|
86
|
+
: 'Select a framework:',
|
|
87
|
+
initial: 0,
|
|
88
|
+
choices: FRAMEWORKS.map((framework) => {
|
|
89
|
+
const frameworkColor = framework.color;
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
title: frameworkColor(framework.name),
|
|
93
|
+
value: framework
|
|
94
|
+
}
|
|
95
|
+
})
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
type: (framework) =>
|
|
99
|
+
framework && framework.variants ? 'select' : null,
|
|
100
|
+
name: 'variant',
|
|
101
|
+
message: 'Select a variant:',
|
|
102
|
+
// @ts-ignore
|
|
103
|
+
choices: (framework) =>
|
|
104
|
+
framework.variants.map((variant) => {
|
|
105
|
+
const variantColor = variant.color
|
|
106
|
+
return {
|
|
107
|
+
title: variantColor(variant.name),
|
|
108
|
+
value: variant.name
|
|
109
|
+
}
|
|
110
|
+
})
|
|
111
|
+
}
|
|
112
|
+
],
|
|
113
|
+
{
|
|
114
|
+
onCancel: () => {
|
|
115
|
+
throw new Error(red('✖') + ' Operation cancelled')
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
)
|
|
119
|
+
} catch (cancelled) {
|
|
120
|
+
console.log(cancelled.message);
|
|
121
|
+
|
|
122
|
+
return
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// user choice associated with prompts
|
|
126
|
+
const { framework, overwrite, packageName, variant } = result
|
|
127
|
+
|
|
128
|
+
const root = path.join(cwd, targetDir)
|
|
129
|
+
|
|
130
|
+
if (overwrite) {
|
|
131
|
+
emptyDir(root)
|
|
132
|
+
} else if (!fs.existsSync(root)) {
|
|
133
|
+
fs.mkdirSync(root)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// determine template
|
|
137
|
+
template = variant || framework || template
|
|
138
|
+
|
|
139
|
+
console.log(`\nScaffolding project in ${root}...`)
|
|
140
|
+
|
|
141
|
+
const templateDir = path.join(__dirname, `template-${template}`)
|
|
142
|
+
|
|
143
|
+
const write = (file, content) => {
|
|
144
|
+
const targetPath = renameFiles[file]
|
|
145
|
+
? path.join(root, renameFiles[file])
|
|
146
|
+
: path.join(root, file)
|
|
147
|
+
if (content) {
|
|
148
|
+
fs.writeFileSync(targetPath, content)
|
|
149
|
+
} else {
|
|
150
|
+
copy(path.join(templateDir, file), targetPath)
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const files = fs.readdirSync(templateDir)
|
|
155
|
+
for (const file of files.filter((f) => f !== 'package.json')) {
|
|
156
|
+
write(file)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const pkg = require(path.join(templateDir, `package.json`))
|
|
160
|
+
|
|
161
|
+
pkg.name = packageName || targetDir
|
|
162
|
+
|
|
163
|
+
write('package.json', JSON.stringify(pkg, null, 2))
|
|
164
|
+
|
|
165
|
+
const pkgInfo = pkgFromUserAgent(process.env.npm_config_user_agent)
|
|
166
|
+
const pkgManager = pkgInfo ? pkgInfo.name : 'npm'
|
|
167
|
+
|
|
168
|
+
console.log(`\nDone. Now run:\n`)
|
|
169
|
+
if (root !== cwd) {
|
|
170
|
+
console.log(` cd ${path.relative(cwd, root)}`)
|
|
171
|
+
}
|
|
172
|
+
switch (pkgManager) {
|
|
173
|
+
case 'yarn':
|
|
174
|
+
console.log(' yarn')
|
|
175
|
+
console.log(' yarn dev')
|
|
176
|
+
break
|
|
177
|
+
default:
|
|
178
|
+
console.log(` ${pkgManager} install`)
|
|
179
|
+
console.log(` ${pkgManager} run dev`)
|
|
180
|
+
break
|
|
181
|
+
}
|
|
182
|
+
console.log()
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function copy(src, dest) {
|
|
186
|
+
const stat = fs.statSync(src)
|
|
187
|
+
if (stat.isDirectory()) {
|
|
188
|
+
copyDir(src, dest)
|
|
189
|
+
} else {
|
|
190
|
+
fs.copyFileSync(src, dest)
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function isValidPackageName(projectName) {
|
|
195
|
+
return /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(
|
|
196
|
+
projectName
|
|
197
|
+
)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function toValidPackageName(projectName) {
|
|
201
|
+
return projectName
|
|
202
|
+
.trim()
|
|
203
|
+
.toLowerCase()
|
|
204
|
+
.replace(/\s+/g, '-')
|
|
205
|
+
.replace(/^[._]/, '')
|
|
206
|
+
.replace(/[^a-z0-9-~]+/g, '-')
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function copyDir(srcDir, destDir) {
|
|
210
|
+
fs.mkdirSync(destDir, { recursive: true })
|
|
211
|
+
for (const file of fs.readdirSync(srcDir)) {
|
|
212
|
+
const srcFile = path.resolve(srcDir, file)
|
|
213
|
+
const destFile = path.resolve(destDir, file)
|
|
214
|
+
copy(srcFile, destFile)
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function isEmpty(path) {
|
|
219
|
+
return fs.readdirSync(path).length === 0
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function emptyDir(dir) {
|
|
223
|
+
if (!fs.existsSync(dir)) {
|
|
224
|
+
return
|
|
225
|
+
}
|
|
226
|
+
for (const file of fs.readdirSync(dir)) {
|
|
227
|
+
const abs = path.resolve(dir, file)
|
|
228
|
+
// baseline is Node 12 so can't use rmSync :(
|
|
229
|
+
if (fs.lstatSync(abs).isDirectory()) {
|
|
230
|
+
emptyDir(abs)
|
|
231
|
+
fs.rmdirSync(abs)
|
|
232
|
+
} else {
|
|
233
|
+
fs.unlinkSync(abs)
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* @param {string | undefined} userAgent process.env.npm_config_user_agent
|
|
240
|
+
* @returns object | undefined
|
|
241
|
+
*/
|
|
242
|
+
function pkgFromUserAgent(userAgent) {
|
|
243
|
+
if (!userAgent) return undefined
|
|
244
|
+
const pkgSpec = userAgent.split(' ')[0]
|
|
245
|
+
const pkgSpecArr = pkgSpec.split('/')
|
|
246
|
+
return {
|
|
247
|
+
name: pkgSpecArr[0],
|
|
248
|
+
version: pkgSpecArr[1]
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
init().catch((e) => {
|
|
253
|
+
console.error(e)
|
|
254
|
+
})
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-jwn-js",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"license": "PRIVATE",
|
|
5
|
+
"author": "Webigorkiev",
|
|
6
|
+
"bin": {
|
|
7
|
+
"create-jwn-js": "index.js",
|
|
8
|
+
"cjj": "index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"index.js",
|
|
12
|
+
"template-*"
|
|
13
|
+
],
|
|
14
|
+
"main": "index.js",
|
|
15
|
+
"scripts": {
|
|
16
|
+
},
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=14.0.0"
|
|
19
|
+
},
|
|
20
|
+
"homepage": "https://github.com/webigorkiev",
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"kolorist": "^1.5.0",
|
|
23
|
+
"margv": "^1.1.2",
|
|
24
|
+
"prompts": "^2.4.2"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"server": {
|
|
3
|
+
"development": {
|
|
4
|
+
"mode": "development",
|
|
5
|
+
"vite": {
|
|
6
|
+
"port": 3000
|
|
7
|
+
},
|
|
8
|
+
"port": 3001,
|
|
9
|
+
"host": "localhost"
|
|
10
|
+
},
|
|
11
|
+
"production": {
|
|
12
|
+
"mode": "production",
|
|
13
|
+
"port": 3000,
|
|
14
|
+
"host": "127.0.0.1",
|
|
15
|
+
"url": "http://127.0.0.1"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"db": {
|
|
19
|
+
"home": {
|
|
20
|
+
"engine": "mysql",
|
|
21
|
+
"host": "localhost",
|
|
22
|
+
"user": "",
|
|
23
|
+
"password": "",
|
|
24
|
+
"database": "",
|
|
25
|
+
"connectTimeout": 10000,
|
|
26
|
+
"acquireTimeout": 10000,
|
|
27
|
+
"connectionLimit": 2,
|
|
28
|
+
"charset": "utf8",
|
|
29
|
+
"compress": true,
|
|
30
|
+
"port": 3306,
|
|
31
|
+
"multipleStatements": true,
|
|
32
|
+
"namedPlaceholders": true,
|
|
33
|
+
"dateStrings": true
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Template vite node js
|
|
2
|
+
|
|
3
|
+
## Actions
|
|
4
|
+
|
|
5
|
+
<table>
|
|
6
|
+
<tr>
|
|
7
|
+
<th>Method</th>
|
|
8
|
+
<th>Action</th>
|
|
9
|
+
</tr>
|
|
10
|
+
<tr>
|
|
11
|
+
<td>GET</td>
|
|
12
|
+
<td>view</td>
|
|
13
|
+
</tr>
|
|
14
|
+
<tr>
|
|
15
|
+
<td>POST</td>
|
|
16
|
+
<td>insert</td>
|
|
17
|
+
</tr>
|
|
18
|
+
<tr>
|
|
19
|
+
<td>PUT</td>
|
|
20
|
+
<td>update</td>
|
|
21
|
+
</tr>
|
|
22
|
+
<tr>
|
|
23
|
+
<td>DELETE</td>
|
|
24
|
+
<td>delete</td>
|
|
25
|
+
</tr>
|
|
26
|
+
</table>
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
```/api/v1/clients/rest```
|
|
30
|
+
|
|
31
|
+
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
moduleFileExtensions: [
|
|
3
|
+
"js",
|
|
4
|
+
"ts",
|
|
5
|
+
"json",
|
|
6
|
+
"vue",
|
|
7
|
+
"node"
|
|
8
|
+
],
|
|
9
|
+
transform: {
|
|
10
|
+
"^.+\\.ts$": "ts-jest"
|
|
11
|
+
},
|
|
12
|
+
moduleNameMapper: {
|
|
13
|
+
"@/(.*)$": "<rootDir>/src/$1"
|
|
14
|
+
},
|
|
15
|
+
setupFiles: ["./src/scripts/jest.setup.ts"],
|
|
16
|
+
globalSetup: "./src/scripts/jest.global.setup.ts",
|
|
17
|
+
globalTeardown: "./src/scripts/jest.global.teardown.ts",
|
|
18
|
+
testTimeout: 35000,
|
|
19
|
+
globals: {
|
|
20
|
+
'ts-jest': {
|
|
21
|
+
tsconfig: './tsconfig.json',
|
|
22
|
+
diagnostics: false
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
testEnvironment: "jsdom",
|
|
26
|
+
maxWorkers: 2,
|
|
27
|
+
testMatch: [ "**/__its__/**/*.[jt]s?(x)", "**/__tests__/**/*.[jt]s?(x)", "**/?(*.)+(spec|test).[jt]s?(x)" ],
|
|
28
|
+
testPathIgnorePatterns: ["<rootDir>/src/scripts",],
|
|
29
|
+
collectCoverageFrom: [
|
|
30
|
+
"**/src/**/*.{ts}",
|
|
31
|
+
"!**/src/**/*.d.ts",
|
|
32
|
+
"!**/src/**/index.ts",
|
|
33
|
+
"!**/src/scripts/**",
|
|
34
|
+
"!**/src/sql/**",
|
|
35
|
+
"!**/src/backend/server/web-routes/**",
|
|
36
|
+
]
|
|
37
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vite-node-template",
|
|
3
|
+
"private": true,
|
|
4
|
+
"author": "webigorkiev",
|
|
5
|
+
"license": "PRIVATE",
|
|
6
|
+
"version": "1.0.1",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"dev": "vite",
|
|
9
|
+
"build": "vite build",
|
|
10
|
+
"docs:dev": "vitepress dev docs",
|
|
11
|
+
"docs:build": "vitepress build docs",
|
|
12
|
+
"docs:serve": "vitepress serve docs"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@types/jest": "^27.0.3",
|
|
16
|
+
"@types/memjs": "^1.2.4",
|
|
17
|
+
"@types/node": "^17.0.4",
|
|
18
|
+
"jest": "^27.4.5",
|
|
19
|
+
"ts-jest": "^27.1.2",
|
|
20
|
+
"ts-node": "^10.4.0",
|
|
21
|
+
"typescript": "^4.4.4",
|
|
22
|
+
"vite": "^2.7.2",
|
|
23
|
+
"vitepress": "^0.20.9"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@jwn-js/common": "^1.3.19",
|
|
27
|
+
"buildmsql": "^1.3.2",
|
|
28
|
+
"cross-fetch": "^3.1.4",
|
|
29
|
+
"easy-ash": "^1.1.5",
|
|
30
|
+
"margv": "^1.1.2",
|
|
31
|
+
"memjs": "^1.3.0"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import margv from "margv";
|
|
2
|
+
const args = margv();
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Config for server
|
|
6
|
+
* @param config
|
|
7
|
+
*/
|
|
8
|
+
export const createConfigServer = (config: Record<string, any>) => {
|
|
9
|
+
const configServer = process.env.NODE_ENV === "production" ? config.server.production : config.server.development;
|
|
10
|
+
configServer.port = +args.port + 1 || configServer.port;
|
|
11
|
+
configServer.host = args.host || configServer.host;
|
|
12
|
+
configServer.proxy = `http://${configServer.host}:${configServer.port}`;
|
|
13
|
+
configServer.vitePort = config.server.development.vite.port;
|
|
14
|
+
|
|
15
|
+
return configServer;
|
|
16
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {Query} from "buildmsql";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Create mariadb pool
|
|
5
|
+
* @param config
|
|
6
|
+
*/
|
|
7
|
+
export const createMariadb = (config: Record<string, any>) => {
|
|
8
|
+
const home = new Query({debug: process.env.NODE_ENV === "production" ? 0 : 1});
|
|
9
|
+
const homePool = home.createPool(config.db.home);
|
|
10
|
+
|
|
11
|
+
return {homePool, home};
|
|
12
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import memjs from "memjs";
|
|
2
|
+
import {Memcached} from "@jwn-js/common";
|
|
3
|
+
|
|
4
|
+
export const createMemcached = () => {
|
|
5
|
+
const memcachedClient = memjs.Client.create("127.0.0.1:11211", {
|
|
6
|
+
timeout: 1,
|
|
7
|
+
conntimeout: 1,
|
|
8
|
+
logger: {
|
|
9
|
+
log: () => {}
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
const memcached = new Memcached(memcachedClient);
|
|
13
|
+
|
|
14
|
+
return {memcachedClient, memcached};
|
|
15
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const upperCaseFirstLetter = (str: string): string => str.charAt(0).toUpperCase() + str.slice(1);
|
|
2
|
+
export const controllerFormat = (schema: string) => schema
|
|
3
|
+
.split('-')
|
|
4
|
+
.map(v => upperCaseFirstLetter(v))
|
|
5
|
+
.join('');
|
|
6
|
+
export const subactionFormat = (method: string) => method
|
|
7
|
+
.split('-')
|
|
8
|
+
.map((v, i) => i > 0 ? upperCaseFirstLetter(v) : v)
|
|
9
|
+
.join('');
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import {Server, helpers, Web, OptionsWeb} from "@jwn-js/common";
|
|
2
|
+
import {createConfigServer} from "./helpers/createConfigServer";
|
|
3
|
+
import {subactionFormat, controllerFormat} from "./helpers/nameFormaters";
|
|
4
|
+
import {schema} from "./site-schema";
|
|
5
|
+
import {webRoutes} from "./web-routes";
|
|
6
|
+
import {createMariadb} from "./helpers/createMariadb";
|
|
7
|
+
import {createMemcached} from "./helpers/createMemcached";
|
|
8
|
+
declare var process: any;
|
|
9
|
+
|
|
10
|
+
const {readConfigSync} = helpers;
|
|
11
|
+
process.server = process.server || {};
|
|
12
|
+
let memcachedClient, memcached, home;
|
|
13
|
+
const config = readConfigSync("./connect.json");
|
|
14
|
+
const configServer = createConfigServer(config);
|
|
15
|
+
|
|
16
|
+
if(process.env.NODE_ENV === "production") {
|
|
17
|
+
({home} = createMariadb(config));
|
|
18
|
+
({memcachedClient, memcached} = createMemcached());
|
|
19
|
+
}
|
|
20
|
+
const webOptions: OptionsWeb = {
|
|
21
|
+
routes: webRoutes,
|
|
22
|
+
config,
|
|
23
|
+
db: process.server.db || {
|
|
24
|
+
home
|
|
25
|
+
},
|
|
26
|
+
memcached: process.server.memcached || memcached,
|
|
27
|
+
schema
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
process.server.app = new Server({
|
|
31
|
+
...configServer,
|
|
32
|
+
routes: [
|
|
33
|
+
{
|
|
34
|
+
method: "any",
|
|
35
|
+
pattern: "/api/v1/*",
|
|
36
|
+
handler: (res, req) => {
|
|
37
|
+
const url = req.getUrl();
|
|
38
|
+
const method = req.getMethod().toLowerCase();
|
|
39
|
+
const parts = url
|
|
40
|
+
.split('/')
|
|
41
|
+
.slice(3);
|
|
42
|
+
const last = parts.pop() as string;
|
|
43
|
+
const subaction = subactionFormat(last === "rest" ? `${method}-${last}`: last);
|
|
44
|
+
const partsFormated = parts.map((v:string) => controllerFormat(v));
|
|
45
|
+
const controller = `Api/v1/${partsFormated.join("/")}`;
|
|
46
|
+
|
|
47
|
+
return new Web(res, req, webOptions).request({controller, subaction});
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
]
|
|
51
|
+
})
|
|
52
|
+
.app()
|
|
53
|
+
.listen();
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import {Schema} from "@jwn-js/common";
|
|
2
|
+
|
|
3
|
+
export const schema: Schema = {
|
|
4
|
+
actions: [
|
|
5
|
+
{
|
|
6
|
+
id: 1,
|
|
7
|
+
name: "view"
|
|
8
|
+
}
|
|
9
|
+
],
|
|
10
|
+
controllers: [
|
|
11
|
+
{
|
|
12
|
+
id: 1,
|
|
13
|
+
name: "Api/v1/Clients",
|
|
14
|
+
subactions: [
|
|
15
|
+
{
|
|
16
|
+
id: 1,
|
|
17
|
+
name: "index",
|
|
18
|
+
action: "view"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
id: 2,
|
|
22
|
+
name: "getRest",
|
|
23
|
+
action: "view"
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import {fetch, apiUrl} from "@/scripts/jest.setup";
|
|
2
|
+
|
|
3
|
+
describe("Api/v1/Clients", () => {
|
|
4
|
+
const url = new URL(apiUrl + "/api/v1/clients/index");
|
|
5
|
+
it("request GET /api/v1/clients/index", async() => {
|
|
6
|
+
const response = await fetch(url.toString());
|
|
7
|
+
expect(response.ok).toEqual(true);
|
|
8
|
+
})
|
|
9
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {createServer, ViteDevServer} from "vite";
|
|
2
|
+
import {Query, Connection} from "buildmsql";
|
|
3
|
+
|
|
4
|
+
declare global {
|
|
5
|
+
var server: ViteDevServer;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export default async(config: Record<string, any>) => {
|
|
9
|
+
global.server = await createServer();
|
|
10
|
+
await global.server.listen();
|
|
11
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
12
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import crossFetch from "cross-fetch";
|
|
2
|
+
import connect from "../../connect.json"
|
|
3
|
+
|
|
4
|
+
const apiUrl = `http://${connect.server.development.host}:${connect.server.development.vite.port}`;
|
|
5
|
+
const defaultHeaders = {
|
|
6
|
+
headers: {
|
|
7
|
+
"user-agent": "fetch-tests",
|
|
8
|
+
"content-type": "application/json"
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
const fetch = async(
|
|
12
|
+
input: RequestInfo,
|
|
13
|
+
init: RequestInit = {}
|
|
14
|
+
) => crossFetch(input, Object.assign({}, defaultHeaders, init));
|
|
15
|
+
|
|
16
|
+
export {fetch, apiUrl};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "esnext",
|
|
4
|
+
"module": "esnext",
|
|
5
|
+
"moduleResolution": "node",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"noImplicitThis": true,
|
|
8
|
+
"jsx": "preserve",
|
|
9
|
+
"sourceMap": true,
|
|
10
|
+
"resolveJsonModule": true,
|
|
11
|
+
"esModuleInterop": true,
|
|
12
|
+
"allowSyntheticDefaultImports": true,
|
|
13
|
+
"allowJs": true,
|
|
14
|
+
"noImplicitAny": true,
|
|
15
|
+
"strictFunctionTypes": false,
|
|
16
|
+
"skipLibCheck": true,
|
|
17
|
+
"strictPropertyInitialization": false,
|
|
18
|
+
"experimentalDecorators": true,
|
|
19
|
+
"emitDecoratorMetadata": true,
|
|
20
|
+
"lib": [
|
|
21
|
+
"esnext",
|
|
22
|
+
"dom"
|
|
23
|
+
],
|
|
24
|
+
"types": [
|
|
25
|
+
"vite/client",
|
|
26
|
+
"@types/jest",
|
|
27
|
+
"node",
|
|
28
|
+
"jest-environment-puppeteer"
|
|
29
|
+
],
|
|
30
|
+
"baseUrl": ".",
|
|
31
|
+
"paths": {
|
|
32
|
+
"@/*": [
|
|
33
|
+
"./src/*"
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"include": [
|
|
38
|
+
"src/**/*.ts",
|
|
39
|
+
"src/**/*.d.ts",
|
|
40
|
+
"src/**/*.tsx",
|
|
41
|
+
"src/**/*.vue"
|
|
42
|
+
],
|
|
43
|
+
"exclude": [
|
|
44
|
+
"node_modules",
|
|
45
|
+
"dist"
|
|
46
|
+
]
|
|
47
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import {build, defineConfig, mergeConfig, Plugin, ResolvedConfig} from "vite";
|
|
3
|
+
import fetch from "cross-fetch";
|
|
4
|
+
import config from "./connect.json";
|
|
5
|
+
import {createConfigServer} from "./src/backend/server/helpers/createConfigServer";
|
|
6
|
+
import {createMemcached} from "./src/backend/server/helpers/createMemcached";
|
|
7
|
+
import {createMariadb} from "./src/backend/server/helpers/createMariadb";
|
|
8
|
+
|
|
9
|
+
declare var process: any;
|
|
10
|
+
interface Options {
|
|
11
|
+
entry: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const cnf = createConfigServer(config);
|
|
15
|
+
const {memcachedClient, memcached} = createMemcached();
|
|
16
|
+
const {home, homePool} = createMariadb(config);
|
|
17
|
+
process.server = {
|
|
18
|
+
db: {home},
|
|
19
|
+
memcached
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const node = (opt: Options): Plugin => {
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
name: "vite-node-js",
|
|
26
|
+
async configureServer(server) {
|
|
27
|
+
|
|
28
|
+
return () => server.middlewares.use(
|
|
29
|
+
async (req, res, next) => {
|
|
30
|
+
await server.ssrLoadModule(path.join(server.config.root, opt.entry));
|
|
31
|
+
res.end();
|
|
32
|
+
});
|
|
33
|
+
},
|
|
34
|
+
async configResolved(config:ResolvedConfig) {
|
|
35
|
+
if(config.command === "build") {
|
|
36
|
+
|
|
37
|
+
// @ts-ignore
|
|
38
|
+
if(!config.build.isBuild) {
|
|
39
|
+
await build(mergeConfig({
|
|
40
|
+
build: {
|
|
41
|
+
isBuild: true,
|
|
42
|
+
outDir: path.resolve(config.root, `dist`),
|
|
43
|
+
ssr: path.join(config.root, opt.entry),
|
|
44
|
+
}
|
|
45
|
+
}, {}));
|
|
46
|
+
process.exit(0);
|
|
47
|
+
}
|
|
48
|
+
} else {
|
|
49
|
+
setTimeout(() => fetch(`http://${cnf.host}:${cnf.vitePort}/start-server`), 100);
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
async closeBundle() {
|
|
53
|
+
await memcachedClient.close();
|
|
54
|
+
await homePool.end();
|
|
55
|
+
process.server.app && await process.server.app.close();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export default defineConfig({
|
|
61
|
+
resolve: {
|
|
62
|
+
alias: [
|
|
63
|
+
{
|
|
64
|
+
find: /@\/(.*)/,
|
|
65
|
+
replacement: path.resolve("./src") + "/$1"
|
|
66
|
+
}
|
|
67
|
+
],
|
|
68
|
+
},
|
|
69
|
+
server: {
|
|
70
|
+
host: cnf.host,
|
|
71
|
+
port: config.server.development.vite.port,
|
|
72
|
+
proxy: {
|
|
73
|
+
"^/api/v1/.*": `http://${cnf.host}:${cnf.port}`
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
optimizeDeps: {
|
|
77
|
+
include:[]
|
|
78
|
+
},
|
|
79
|
+
plugins: [
|
|
80
|
+
node({
|
|
81
|
+
entry: "/src/backend/server/index.ts"
|
|
82
|
+
})
|
|
83
|
+
]
|
|
84
|
+
});
|