5htp 0.0.9 → 0.2.1-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "5htp",
3
- "description": "5-HTP, scientifically called 5-Hydroxytryptophan, is the precursor of happiness neurotransmitter.",
4
- "version": "0.0.9",
3
+ "description": "Convenient TypeScript framework designed for Performance and Productivity.",
4
+ "version": "0.2.1-1",
5
5
  "author": "Gaetan Le Gac (https://github.com/gaetanlegac)",
6
- "repository": "git://github.com/gaetanlegac/5htp-cli.git",
6
+ "repository": "git://github.com/gaetanlegac/5htp.git",
7
7
  "license": "MIT",
8
8
  "bin": {
9
9
  "5htp": "src/index.ts"
@@ -23,7 +23,6 @@
23
23
  "@babel/plugin-proposal-private-property-in-object": "^7.15.4",
24
24
  "@babel/plugin-transform-react-constant-elements": "^7.14.5",
25
25
  "@babel/plugin-transform-react-jsx-self": "^7.14.9",
26
- "@babel/plugin-transform-react-jsx-source": "^7.14.5",
27
26
  "@babel/preset-env": "^7.15.6",
28
27
  "@babel/preset-react": "^7.14.5",
29
28
  "@babel/preset-typescript": "^7.15.0",
@@ -43,6 +42,7 @@
43
42
  "@types/webpack-env": "^1.16.2",
44
43
  "@types/ws": "^7.4.7",
45
44
  "babel-loader": "^8.2.2",
45
+ "babel-plugin-glob-import": "^0.0.6-2",
46
46
  "babel-plugin-transform-imports": "^2.0.0",
47
47
  "babel-plugin-transform-react-remove-prop-types": "^0.4.24",
48
48
  "brotli-webpack-plugin": "^1.1.0",
@@ -72,7 +72,7 @@
72
72
  "replace-once": "^1.0.0",
73
73
  "speed-measure-webpack-plugin": "^1.5.0",
74
74
  "terser-webpack-plugin": "^5.2.4",
75
- "ts-alias": "^0.0.5-1",
75
+ "ts-alias": "^0.0.6",
76
76
  "ts-node": "^10.9.1",
77
77
  "tslog": "^3.3.4",
78
78
  "webfont": "^11.2.26",
@@ -85,6 +85,7 @@
85
85
  "webpack-virtual-modules": "^0.4.3"
86
86
  },
87
87
  "devDependencies": {
88
+ "@babel/plugin-transform-react-jsx-source": "^7.19.6",
88
89
  "@types/favicons": "^6.2.2",
89
90
  "@types/fs-extra": "^9.0.12",
90
91
  "@types/node": "^16.9.1",
package/readme.md CHANGED
@@ -1,8 +1,17 @@
1
- # 5-HTP Framework
1
+ # 5HTP Framework
2
2
 
3
3
  Opinionated, Lightweight & Full Stack Typescript framework, designed for productivity, modularity and performance.
4
4
 
5
- **/!\ This is a side-project. I cannot guarantee the maintenance.**
5
+ ## Features
6
+
7
+ * Fully written in **Typescript**
8
+ * Services management system
9
+ * **Preact** with built-in SSR support
10
+ * Highly convenient **MySQL client**
11
+ * Universal schema / forms **validator**
12
+ * Ful stack router
13
+ * Cache system
14
+ * And more
6
15
 
7
16
  ## Get Started
8
17
 
@@ -24,7 +33,17 @@ Opinionated, Lightweight & Full Stack Typescript framework, designed for product
24
33
 
25
34
  ## To be done:
26
35
 
27
- - Fix Typescript errors
28
- - Improve stability
29
- - Improve modularity
30
- - Make it less opinionated
36
+ [] Update templates & documentation
37
+ [] Improved debugability & debug tools
38
+ - Cleaner logs (tweak ts-logs settings)
39
+ - Cleaner stacktraces
40
+ - export all default exports as classical functions instead of arrow funcs
41
+ [] Automatically generates types that associate api routes urls to their return types
42
+ [] Fix forms system
43
+ [] Allow to create CLI apps
44
+ [] Debugging / Monitoring UI
45
+ - Admin dashboard
46
+ [] Fix Typescript errors
47
+ [] Completely replace expressjs
48
+ [] Improve stability
49
+ [] Improve modularity
@@ -6,7 +6,7 @@
6
6
  import React from 'react';
7
7
 
8
8
  // Core
9
- import useContext from '@client/context';
9
+ import useContext from '@/client/context';
10
10
  import { Props as ModalProps } from '@client/components/Dialog/card';
11
11
 
12
12
  // Core components
@@ -6,7 +6,7 @@
6
6
  import React from 'react';
7
7
 
8
8
  // Core
9
- import { ClientContext } from '@client/context';
9
+ import { ClientContext } from '@/client/context';
10
10
 
11
11
  // Core components
12
12
  import Router from '@client/router/component';
@@ -6,7 +6,7 @@
6
6
  import React from 'react';
7
7
 
8
8
  // Core
9
- import { ClientContext } from '@client/context';
9
+ import { ClientContext } from '@/client/context';
10
10
 
11
11
  // Core components
12
12
  import { Link } from '@client/router';
@@ -11,10 +11,6 @@
11
11
  // Only used for typings (ex: ServerResponse)
12
12
  // Removed before webpack compilation
13
13
  "@server/*": ["../node_modules/5htp-core/src/server/*"],
14
- "@validator": ["../node_modules/5htp-core/src/client/data/input"],
15
- "@router": ["../node_modules/5htp-core/src/client/router"],
16
- "@errors": ["../node_modules/5htp-core/src/common/errors"],
17
- "@models": ["../.cache/client/models"],
18
14
  "@/*": ["./*"],
19
15
 
20
16
  // ATTENTION: Les références à preact doivent toujours pointer vers la même instance
@@ -21,6 +21,10 @@ declare global {
21
21
  interface User extends UserBase {
22
22
 
23
23
  }
24
+
25
+ interface Services {
26
+ auth: UserAuthService
27
+ }
24
28
  }
25
29
 
26
30
  /*----------------------------------
@@ -73,16 +77,4 @@ export default class UserAuthService extends UserAuthBase {
73
77
  redirect: '/onboard'
74
78
  }
75
79
  }
76
- }
77
-
78
- /*----------------------------------
79
- - REGISTER SERVICE
80
- ----------------------------------*/
81
- app.register('auth', UserAuthService);
82
- declare global {
83
- namespace Core {
84
- interface Services {
85
- auth: UserAuthService
86
- }
87
- }
88
80
  }
package/src/app/config.ts CHANGED
@@ -35,23 +35,13 @@ export default class ConfigParser {
35
35
  public env() {
36
36
  // We assume that when we run 5htp dev, we're in local
37
37
  // Otherwise, we're in production environment (docker)
38
- console.log("Using environment:", process.env.NODE_ENV);
38
+ console.log("[cli] Using environment:", process.env.NODE_ENV);
39
39
  return process.env.NODE_ENV === 'development' ? {
40
40
  name: 'local',
41
41
  profile: 'dev',
42
- level: 'silly',
43
-
44
- localIP: '86.76.176.80',
45
- domain: 'localhost:3010',
46
- url: 'http://localhost:3010',
47
42
  } : {
48
43
  name: 'server',
49
44
  profile: 'prod',
50
- level: 'silly',
51
-
52
- localIP: '86.76.176.80',
53
- domain: 'megacharger.io',
54
- url: 'https://megacharger.io',
55
45
  }
56
46
  }
57
47
 
package/src/app/index.ts CHANGED
@@ -10,6 +10,7 @@ import cli from '..';
10
10
 
11
11
  // Specific
12
12
  import ConfigParser from './config';
13
+ import type { } from '../../../core/src/server/app/config';
13
14
 
14
15
  /*----------------------------------
15
16
  - TYPES
@@ -25,7 +26,7 @@ export default class App {
25
26
  // config
26
27
  // WARNING: High level config files (env and services) shouldn't be loaded from the CLI
27
28
  // The CLI will be run on CircleCI, and no env file should be sent to this service
28
- public identity!: Core.Config.Identity;
29
+ public identity!: Config.Identity;
29
30
 
30
31
  public paths = {
31
32
  root: cli.paths.appRoot,
@@ -51,11 +51,15 @@ export default function createCompiler( app: App, mode: TCompileMode ): webpack.
51
51
  );*/
52
52
 
53
53
  // Convert tsconfig cli.paths to webpack aliases
54
- const { aliases } = app.aliases.client.forWebpack(app.paths.root + '/node_modules');
55
- // Disable access to server-side libs from client side
54
+ const { aliases } = app.aliases.client.forWebpack({
55
+ modulesPath: app.paths.root + '/node_modules'
56
+ });
57
+
58
+ // We're not supposed in any case to import server libs from client
56
59
  delete aliases["@server"];
57
60
  delete aliases["@/server"];
58
61
 
62
+ console.log("client aliases", aliases);
59
63
  const config: webpack.Configuration = {
60
64
 
61
65
  ...commonConfig,
@@ -69,7 +73,7 @@ export default function createCompiler( app: App, mode: TCompileMode ): webpack.
69
73
  // https://github.com/webpack-contrib/webpack-hot-middleware#config
70
74
  cli.paths.core.root + '/node_modules' + '/webpack-hot-middleware/client?name=client&reload=true',
71
75
  ] : []),*/
72
- cli.paths.core.root + '/src/client/index.tsx'
76
+ cli.paths.core.root + '/src/client/index.ts'
73
77
  ]
74
78
  },
75
79
 
@@ -9,17 +9,10 @@ import * as types from '@babel/types'
9
9
 
10
10
  // Core
11
11
  import PluginIndexage from '../plugins/indexage';
12
- import BabelGlobImports from './plugins/importations';
13
12
 
14
13
  import cli from '@cli';
15
14
  import type { TAppSide, default as App } from '@cli/app';
16
15
 
17
- // Const
18
- const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
19
-
20
- // Resources
21
- const routesToPreload = require( cli.paths.appRoot + '/src/client/pages/preload.json' );
22
-
23
16
  /*----------------------------------
24
17
  - REGLES
25
18
  ----------------------------------*/
@@ -91,7 +84,6 @@ module.exports = (app: App, side: TAppSide, dev: boolean): webpack.RuleSetRule[]
91
84
  // NOTE: On résoud les plugins et presets directement ici
92
85
  // Autrement, babel-loader les cherchera dans projet/node_modules
93
86
 
94
-
95
87
  [require("@babel/plugin-proposal-decorators"), { "legacy": true }],
96
88
 
97
89
  [require('@babel/plugin-proposal-class-properties'), { "loose": true }],
@@ -105,6 +97,8 @@ module.exports = (app: App, side: TAppSide, dev: boolean): webpack.RuleSetRule[]
105
97
 
106
98
  ...(side === 'client' ? [
107
99
 
100
+ [require("@babel/plugin-transform-react-jsx-source"), {}],
101
+
108
102
  // HMR Preact avec support des hooks
109
103
  //['@prefresh/babel-plugin'],
110
104
 
@@ -131,138 +125,44 @@ module.exports = (app: App, side: TAppSide, dev: boolean): webpack.RuleSetRule[]
131
125
  }]
132
126
  ]),
133
127
 
134
- BabelGlobImports({
135
- debug: false,
136
- removeAliases: (source: string) => app.paths.withoutAlias(source, side)
137
- }, [{
138
- test: (request) => {
139
- if (request.source === '@models') {
140
- request.source = app.paths.src + '/server/models/**/*.ts';
141
- return true;
142
- }
143
- return false;
144
- },
145
- replace: (request, matches, t) => {
146
- // Preserve default behavior
147
- }
148
- }, {
149
- test: (request) => (
150
- side === 'client'
151
- &&
152
- (
153
- request.source === '@/client/pages/**/*.tsx'
154
- ||
155
- request.source === '@client/pages/**/*.tsx'
156
- )
157
- &&
158
- request.type === 'import'
159
- ),
160
- replace: (request, matches, t) => {
161
-
162
- if (!('default' in request) || request.default === undefined)
163
- return;
164
-
165
- const imports: types.ImportDeclaration[] = [];
166
-
167
- // const routes = {
168
- // <chunkId1>: () => import(/* webpackChunkName: '<chunkId>' */ "<file>"),
169
- // <chunkId2>: () => require("<file>").default,
170
- // }
171
-
172
- const pageLoaders: types.ObjectProperty[] = [];
173
- for (const file of matches) {
174
-
175
- // Exclude layouts
176
- if (file.filename.includes("/_layout/")) {
177
- //console.log("Exclude", file, 'from pages loaders (its a layout)');
178
- continue;
179
- }
180
-
181
- // Excliude components
182
- const filename = path.basename( file.filename );
183
- if (alphabet.includes(filename[0]) && filename[0] === filename[0].toUpperCase()) {
184
- //console.log("Exclude", file, 'from pages loaders (its a component)');
185
- continue;
186
- }
187
-
188
- // Page config
189
- const { chunkId } = cli.paths.getPageChunk(app, file.filename);
190
- const preloadPage = routesToPreload.includes(chunkId);
191
-
192
- // Import type according to preloading option
193
- if (preloadPage) {
194
-
195
- // import <chunkId> from "<file>";
196
- imports.push(
197
- t.importDeclaration(
198
- [t.importDefaultSpecifier( t.identifier(chunkId) )],
199
- t.stringLiteral(file.filename)
200
- )
201
- );
202
-
203
- // { <chunkId>: <chunkId> }
204
- pageLoaders.push(
205
- t.objectProperty(
206
- t.stringLiteral(chunkId),
207
- t.identifier(chunkId)
208
- )
209
- );
210
-
211
- } else {
212
-
213
- // <chunkId>: () => ...
214
- pageLoaders.push(
215
- t.objectProperty(
216
-
217
- t.stringLiteral(chunkId),
218
- // () => import(/* webpackChunkName: '<chunkId>' */ "<file>")
219
- t.arrowFunctionExpression([], t.callExpression(
220
-
221
- t.import(), [t.addComment(
222
- t.stringLiteral(file.filename),
223
- "leading",
224
- "webpackChunkName: '" + chunkId + "'"
225
- )]
226
- ))
227
- )
228
- )
229
- }
230
- }
128
+ //require("./plugins/pages")({ side }),
129
+
130
+ require('./routes/routes')({ side, app }),
231
131
 
232
- return [
233
- ...imports,
234
- // const routes = { ... }
235
- t.variableDeclaration("const", [t.variableDeclarator(
236
- t.identifier(request.default),
237
- t.objectExpression(pageLoaders)
238
- )])
239
- ]
132
+ ...(side === 'client' ? [] : [
240
133
 
241
- }
242
- }])
134
+ // Dependancies injection
135
+ //require('./plugins/services')({ side }),
243
136
 
137
+ ]),
138
+
139
+ // Allow to import multiple fiels with one import statement thanks to glob patterns
140
+ require('babel-plugin-glob-import')({
141
+ debug: false,
142
+ removeAliases: (source: string) => app.paths.withoutAlias(source, side)
143
+ }, [
144
+ // Routes imports on frontend side
145
+ require('./routes/imports')(app, side, dev)
146
+ ])
244
147
  ],
245
148
 
246
149
  overrides: [
247
150
 
248
- require("./plugins/pages")({ side }),
249
-
250
- require("./plugins/models")({ side }),
251
-
252
151
  require('./plugins/icones-svg'),
253
152
 
254
- require('./plugins/form'),
153
+ // Universal forms
154
+ //require('./plugins/form'),
155
+
156
+ // Generate typing from sequelize model declaration
157
+ //require("./plugins/models")({ side }),
255
158
 
256
- /*
257
-
258
159
  ...(side === 'client' ? [
259
160
 
260
161
  ] : [
261
- require('./plugins/queries');
262
- require('./plugins/injection-dependances'),
263
- ]),
264
162
 
265
- */
163
+ //require('./plugins/queries'),
164
+ //require('./plugins/injection-dependances'),
165
+ ]),
266
166
  ]
267
167
  }
268
168
  }]
File without changes
@@ -0,0 +1,163 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ // Npm
6
+ import * as types from '@babel/types'
7
+ import type { PluginObj, NodePath } from '@babel/core';
8
+ import generate from '@babel/generator';
9
+
10
+ // Core
11
+ import cli from '@cli';
12
+ import App, { TAppSide } from '../../../../app';
13
+
14
+ /*----------------------------------
15
+ - WEBPACK RULE
16
+ ----------------------------------*/
17
+
18
+ type TOptions = {
19
+ side: TAppSide
20
+ }
21
+
22
+ const filenamePrefix = cli.paths.appRoot + '/src/server/services';
23
+ const processFile = (filename: string) => (
24
+ filename.startsWith( cli.paths.appRoot + '/src/server/services' )
25
+ |
26
+ filename.startsWith( cli.paths.appRoot + '/src/server/routes' )
27
+ )
28
+
29
+ module.exports = (options: TOptions) => (
30
+ [Plugin, options]
31
+ )
32
+
33
+ const debug = true;
34
+
35
+ /*----------------------------------
36
+ - PLUGIN
37
+ ----------------------------------*/
38
+ function Plugin(babel, { side }: TOptions) {
39
+
40
+ const t = babel.types as typeof types;
41
+ let program: NodePath<types.Program>;
42
+
43
+ const plugin: PluginObj<{
44
+
45
+ filename: string,
46
+
47
+ appImport: string | null,
48
+
49
+ // Identifier => Name
50
+ importedServices: {[identifier: string]: string}
51
+ }> = {
52
+ pre(state) {
53
+
54
+ this.filename = state.opts.filename as string;
55
+
56
+ this.appImport = null
57
+ this.importedServices = {}
58
+
59
+ },
60
+ visitor: {
61
+
62
+ Program(path) {
63
+ program = path;
64
+ },
65
+
66
+ // Transform imports
67
+ ImportDeclaration(path) {
68
+
69
+ if (!this.filename.startsWith( cli.paths.appRoot + '/src/server' ))
70
+ return;
71
+
72
+ if (path.node.source.value !== '@server/app')
73
+ return;
74
+
75
+ const importedServices: { local: string, imported: string }[] = []
76
+ let appName: string = 'app';
77
+
78
+ for (const specifier of path.node.specifiers) {
79
+ /*
80
+ import app from '@server/app';
81
+ */
82
+ if (specifier.type === 'ImportDefaultSpecifier') {
83
+
84
+ appName = specifier.local.name;
85
+
86
+ /*
87
+ import { sql } from '@server/app';
88
+ =>
89
+ import app from '@server/app';
90
+ app.use('sql');
91
+ */
92
+ } else if (specifier.type === 'ImportSpecifier') {
93
+
94
+ if (specifier.imported.type !== 'Identifier')
95
+ continue;
96
+
97
+ importedServices.push({
98
+ local: specifier.local.name,
99
+ imported: specifier.imported.name
100
+ });
101
+
102
+ /*
103
+ import * as templates from '@server/app';
104
+ =>
105
+
106
+ */
107
+ } else if (specifier.type === 'ImportNamespaceSpecifier') {
108
+
109
+ //importDefault = specifier.local.name;
110
+ //importAll = true;
111
+
112
+ }
113
+ }
114
+
115
+ // No service imported
116
+ // This verification avoids ininite loop
117
+ if (importedServices.length === 0)
118
+ return;
119
+
120
+ const replacements: types.Statement[] = [
121
+ t.importDeclaration(
122
+ [
123
+ t.importDefaultSpecifier( t.identifier( appName )),
124
+ ],
125
+ t.stringLiteral('@server/app')
126
+ )
127
+ ]
128
+
129
+ for (const { imported, local } of importedServices) {
130
+
131
+ replacements.push(
132
+ t.expressionStatement(
133
+ t.callExpression(
134
+ t.memberExpression(
135
+ t.identifier( appName ),
136
+ t.identifier('use')
137
+ ),
138
+ [
139
+ t.stringLiteral( imported )
140
+ ]
141
+ )
142
+ )
143
+ );
144
+
145
+ this.importedServices[ local ] = imported;
146
+ }
147
+
148
+ debug && console.log(`############ [compilation][babel][services] Remplacement: `,
149
+ generate(t.program(replacements)).code
150
+ );
151
+
152
+ path.replaceWithMultiple(replacements);
153
+ },
154
+
155
+ // transform accesses
156
+ Identifier() {
157
+
158
+ }
159
+ }
160
+ }
161
+
162
+ return plugin;
163
+ }