5htp 0.3.1-1 → 0.3.2
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,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "5htp",
|
|
3
3
|
"description": "Convenient TypeScript framework designed for Performance and Productivity.",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.2",
|
|
5
5
|
"author": "Gaetan Le Gac (https://github.com/gaetanlegac)",
|
|
6
6
|
"repository": "git://github.com/gaetanlegac/5htp.git",
|
|
7
7
|
"license": "MIT",
|
|
@@ -18,7 +18,6 @@
|
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"@babel/cli": "^7.15.4",
|
|
20
20
|
"@babel/plugin-proposal-class-properties": "^7.14.5",
|
|
21
|
-
"@babel/plugin-proposal-decorators": "^7.15.4",
|
|
22
21
|
"@babel/plugin-proposal-private-methods": "^7.14.5",
|
|
23
22
|
"@babel/plugin-proposal-private-property-in-object": "^7.15.4",
|
|
24
23
|
"@babel/plugin-transform-react-constant-elements": "^7.14.5",
|
|
@@ -6,12 +6,13 @@
|
|
|
6
6
|
import path from 'path';
|
|
7
7
|
import type webpack from 'webpack';
|
|
8
8
|
import * as types from '@babel/types'
|
|
9
|
+
import PresetReact from '@babel/preset-react';
|
|
9
10
|
|
|
10
11
|
// Core
|
|
11
12
|
import PluginIndexage from '../plugins/indexage';
|
|
12
13
|
|
|
13
14
|
import cli from '@cli';
|
|
14
|
-
import type { TAppSide,
|
|
15
|
+
import type { TAppSide, App } from '@cli/app';
|
|
15
16
|
|
|
16
17
|
/*----------------------------------
|
|
17
18
|
- REGLES
|
|
@@ -85,7 +86,7 @@ module.exports = (app: App, side: TAppSide, dev: boolean): webpack.RuleSetRule[]
|
|
|
85
86
|
// NOTE: On résoud les plugins et presets directement ici
|
|
86
87
|
// Autrement, babel-loader les cherchera dans projet/node_modules
|
|
87
88
|
|
|
88
|
-
[require("@babel/plugin-proposal-decorators"), { "legacy": true }],
|
|
89
|
+
//[require("@babel/plugin-proposal-decorators"), { "legacy": true }],
|
|
89
90
|
|
|
90
91
|
[require('@babel/plugin-proposal-class-properties'), { "loose": true }],
|
|
91
92
|
|
|
@@ -122,8 +123,6 @@ module.exports = (app: App, side: TAppSide, dev: boolean): webpack.RuleSetRule[]
|
|
|
122
123
|
}]
|
|
123
124
|
]),
|
|
124
125
|
|
|
125
|
-
//require("./plugins/pages")({ side }),
|
|
126
|
-
|
|
127
126
|
require('./routes/routes')({ side, app, debug: false }),
|
|
128
127
|
|
|
129
128
|
...(side === 'client' ? [] : [
|
|
@@ -20,6 +20,20 @@ type TOptions = {
|
|
|
20
20
|
app: App,
|
|
21
21
|
debug?: boolean
|
|
22
22
|
}
|
|
23
|
+
type TRouteDefinition = {
|
|
24
|
+
definition: types.CallExpression,
|
|
25
|
+
dataFetchers: types.ObjectProperty[],
|
|
26
|
+
contextName?: string
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
type TFileInfos = {
|
|
30
|
+
path: string,
|
|
31
|
+
process: boolean,
|
|
32
|
+
side: 'front'|'back',
|
|
33
|
+
|
|
34
|
+
importedServices: {[local: string]: string},
|
|
35
|
+
routeDefinitions: TRouteDefinition[],
|
|
36
|
+
}
|
|
23
37
|
|
|
24
38
|
module.exports = (options: TOptions) => (
|
|
25
39
|
[Plugin, options]
|
|
@@ -35,69 +49,29 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
35
49
|
/*
|
|
36
50
|
- Wrap route.get(...) with (app: Application) => { }
|
|
37
51
|
- Inject chunk ID into client route options
|
|
52
|
+
- Transform api.fetch calls
|
|
38
53
|
*/
|
|
39
54
|
|
|
40
55
|
const plugin: PluginObj<{
|
|
41
|
-
|
|
42
56
|
filename: string,
|
|
43
|
-
|
|
44
|
-
side: 'front' | 'back',
|
|
45
|
-
processFile: boolean,
|
|
46
|
-
|
|
47
|
-
// Identifier => Name
|
|
48
|
-
importedServices: {[local: string]: string},
|
|
49
|
-
routeDefinitions: types.Expression[]
|
|
57
|
+
file: TFileInfos
|
|
50
58
|
}> = {
|
|
51
59
|
pre(state) {
|
|
52
|
-
|
|
53
60
|
this.filename = state.opts.filename as string;
|
|
54
|
-
this.processFile = true;
|
|
55
|
-
|
|
56
|
-
// Relative path
|
|
57
|
-
let relativeFileName: string | undefined;
|
|
58
|
-
if (this.filename.startsWith( cli.paths.appRoot ))
|
|
59
|
-
relativeFileName = this.filename.substring( cli.paths.appRoot.length );
|
|
60
|
-
if (this.filename.startsWith( cli.paths.coreRoot ))
|
|
61
|
-
relativeFileName = this.filename.substring( cli.paths.coreRoot.length );
|
|
62
|
-
if (this.filename.startsWith('/node_modules/5htp-core/'))
|
|
63
|
-
relativeFileName = this.filename.substring( '/node_modules/5htp-core/'.length );
|
|
64
|
-
|
|
65
|
-
// The file isn't a route definition
|
|
66
|
-
if (relativeFileName === undefined) {
|
|
67
|
-
this.processFile = false;
|
|
68
|
-
return false;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Differenciate back / front
|
|
72
|
-
if (relativeFileName.startsWith('/src/client/pages')) {
|
|
73
|
-
|
|
74
|
-
this.side = 'front';
|
|
75
|
-
this.part = 'routes';
|
|
76
|
-
|
|
77
|
-
} else if (relativeFileName.startsWith('/src/server/routes')) {
|
|
78
61
|
|
|
79
|
-
|
|
80
|
-
this.part = 'routes';
|
|
81
|
-
|
|
82
|
-
} else
|
|
83
|
-
this.processFile = false;
|
|
84
|
-
|
|
85
|
-
// Init output
|
|
86
|
-
this.importedServices = {}
|
|
87
|
-
this.routeDefinitions = []
|
|
62
|
+
this.file = getFileInfos(this.filename);
|
|
88
63
|
},
|
|
89
64
|
visitor: {
|
|
90
|
-
|
|
91
65
|
// Find @app imports
|
|
92
66
|
// Test: import { Router } from '@app';
|
|
93
67
|
// Replace by: nothing
|
|
94
68
|
ImportDeclaration(path) {
|
|
95
|
-
|
|
96
|
-
if (!this.
|
|
69
|
+
|
|
70
|
+
if (!this.file.process)
|
|
97
71
|
return;
|
|
98
72
|
|
|
99
73
|
if (path.node.source.value !== '@app')
|
|
100
|
-
return;
|
|
74
|
+
return;
|
|
101
75
|
|
|
102
76
|
for (const specifier of path.node.specifiers) {
|
|
103
77
|
|
|
@@ -107,11 +81,11 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
107
81
|
if (specifier.imported.type !== 'Identifier')
|
|
108
82
|
continue;
|
|
109
83
|
|
|
110
|
-
this.importedServices[ specifier.local.name ] = specifier.imported.name;
|
|
84
|
+
this.file.importedServices[ specifier.local.name ] = specifier.imported.name;
|
|
111
85
|
}
|
|
112
86
|
|
|
113
87
|
// Remove this import
|
|
114
|
-
path.
|
|
88
|
+
path.remove();
|
|
115
89
|
|
|
116
90
|
},
|
|
117
91
|
|
|
@@ -120,18 +94,10 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
120
94
|
// Replace by: nothing
|
|
121
95
|
CallExpression(path) {
|
|
122
96
|
|
|
123
|
-
if (!this.
|
|
124
|
-
return;
|
|
125
|
-
|
|
126
|
-
// Should be at the root of the document
|
|
127
|
-
if (!(
|
|
128
|
-
path.parent.type === 'ExpressionStatement'
|
|
129
|
-
&&
|
|
130
|
-
path.parentPath.parent.type === 'Program'
|
|
131
|
-
))
|
|
97
|
+
if (!this.file.process)
|
|
132
98
|
return;
|
|
133
99
|
|
|
134
|
-
//
|
|
100
|
+
// object.property()
|
|
135
101
|
const callee = path.node.callee
|
|
136
102
|
if (!(
|
|
137
103
|
callee.type === 'MemberExpression'
|
|
@@ -140,117 +106,143 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
140
106
|
&&
|
|
141
107
|
callee.property.type === 'Identifier'
|
|
142
108
|
&&
|
|
143
|
-
|
|
144
|
-
|
|
109
|
+
// Should be at the root of the document
|
|
110
|
+
path.parent.type === 'ExpressionStatement'
|
|
111
|
+
&&
|
|
112
|
+
path.parentPath.parent.type === 'Program'
|
|
113
|
+
// And make reference to a service
|
|
114
|
+
&&
|
|
115
|
+
(callee.object.name in this.file.importedServices)
|
|
116
|
+
))
|
|
145
117
|
return;
|
|
146
118
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
// Inject chunk id in options (2nd arg)
|
|
152
|
-
const newRouteArgs = injectChunkId(routeArgs, this.filename);
|
|
153
|
-
if (newRouteArgs === 'ALREADY_PROCESSED')
|
|
154
|
-
return;
|
|
155
|
-
|
|
156
|
-
routeArgs = newRouteArgs;
|
|
119
|
+
const routeDef: TRouteDefinition = {
|
|
120
|
+
definition: path.node,
|
|
121
|
+
dataFetchers: []
|
|
157
122
|
}
|
|
158
123
|
|
|
159
|
-
//
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
t.memberExpression(
|
|
164
|
-
t.identifier( callee.object.name ),
|
|
165
|
-
callee.property,
|
|
166
|
-
),
|
|
167
|
-
[routePath, ...routeArgs]
|
|
168
|
-
)
|
|
124
|
+
// Adjust
|
|
125
|
+
if (this.file.side === 'front') {
|
|
126
|
+
transformDataFetchers(path, this, routeDef);
|
|
127
|
+
}
|
|
169
128
|
|
|
170
|
-
|
|
129
|
+
// Add to the list of route definitons to wrap
|
|
130
|
+
this.file.routeDefinitions.push(routeDef);
|
|
171
131
|
|
|
172
|
-
// Delete
|
|
132
|
+
// Delete the route def since it will be replaced by a wrapper
|
|
173
133
|
path.replaceWithMultiple([]);
|
|
134
|
+
|
|
174
135
|
},
|
|
136
|
+
Program: {
|
|
137
|
+
exit(path, parent) {
|
|
175
138
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
139
|
+
if (!this.file.process)
|
|
140
|
+
return;
|
|
141
|
+
|
|
142
|
+
const wrappedrouteDefs = wrapRouteDefs( this.file );
|
|
143
|
+
if (wrappedrouteDefs)
|
|
144
|
+
path.pushContainer('body', [wrappedrouteDefs])
|
|
145
|
+
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
179
150
|
|
|
180
|
-
|
|
151
|
+
function getFileInfos( filename: string ): TFileInfos {
|
|
181
152
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
153
|
+
const file: TFileInfos = {
|
|
154
|
+
process: true,
|
|
155
|
+
side: 'back',
|
|
156
|
+
path: filename,
|
|
157
|
+
importedServices: {},
|
|
158
|
+
routeDefinitions: []
|
|
159
|
+
}
|
|
186
160
|
|
|
187
|
-
|
|
188
|
-
|
|
161
|
+
// Relative path
|
|
162
|
+
let relativeFileName: string | undefined;
|
|
163
|
+
if (filename.startsWith( cli.paths.appRoot ))
|
|
164
|
+
relativeFileName = filename.substring( cli.paths.appRoot.length );
|
|
165
|
+
if (filename.startsWith( cli.paths.coreRoot ))
|
|
166
|
+
relativeFileName = filename.substring( cli.paths.coreRoot.length );
|
|
167
|
+
if (filename.startsWith('/node_modules/5htp-core/'))
|
|
168
|
+
relativeFileName = filename.substring( '/node_modules/5htp-core/'.length );
|
|
169
|
+
|
|
170
|
+
// The file isn't a route definition
|
|
171
|
+
if (relativeFileName === undefined) {
|
|
172
|
+
file.process = false;
|
|
173
|
+
return file;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Differenciate back / front
|
|
177
|
+
if (relativeFileName.startsWith('/src/client/pages')) {
|
|
178
|
+
file.side = 'front';
|
|
179
|
+
} else if (relativeFileName.startsWith('/src/server/routes')) {
|
|
180
|
+
file.side = 'back';
|
|
181
|
+
} else
|
|
182
|
+
file.process = false;
|
|
183
|
+
|
|
184
|
+
return file
|
|
185
|
+
}
|
|
189
186
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
187
|
+
function transformDataFetchers(
|
|
188
|
+
path: NodePath<types.CallExpression>,
|
|
189
|
+
routerDefContext: PluginObj,
|
|
190
|
+
routeDef: TRouteDefinition
|
|
191
|
+
) {
|
|
192
|
+
path.traverse({
|
|
193
|
+
CallExpression(path) {
|
|
193
194
|
|
|
194
|
-
|
|
195
|
-
if (this.side === 'front') {
|
|
196
|
-
|
|
197
|
-
const routesDefCount = this.routeDefinitions.length;
|
|
198
|
-
if (routesDefCount !== 1)
|
|
199
|
-
throw new Error(`Frontend route definition files (/client/pages/**/**.ts) can contain only one route definition.
|
|
200
|
-
${routesDefCount} were given in ${this.filename}.`);
|
|
201
|
-
|
|
202
|
-
exportValue = this.routeDefinitions[0];
|
|
203
|
-
|
|
204
|
-
} else {
|
|
205
|
-
|
|
206
|
-
exportValue = t.blockStatement([
|
|
207
|
-
// Without spread = react jxx need additionnal loader
|
|
208
|
-
...this.routeDefinitions.map( def =>
|
|
209
|
-
t.expressionStatement(def)
|
|
210
|
-
),
|
|
211
|
-
])
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
const exportDeclaration = t.exportNamedDeclaration(
|
|
215
|
-
t.variableDeclaration('const', [
|
|
216
|
-
t.variableDeclarator(
|
|
217
|
-
t.identifier('__register'),
|
|
218
|
-
t.arrowFunctionExpression(
|
|
219
|
-
[
|
|
220
|
-
t.objectPattern(
|
|
221
|
-
importedServices.map(([ local, imported ]) =>
|
|
222
|
-
t.objectProperty(
|
|
223
|
-
t.identifier( local ),
|
|
224
|
-
t.identifier( imported ),
|
|
225
|
-
)
|
|
226
|
-
)
|
|
227
|
-
)
|
|
228
|
-
],
|
|
229
|
-
exportValue
|
|
230
|
-
)
|
|
231
|
-
)
|
|
232
|
-
])
|
|
233
|
-
)
|
|
195
|
+
const callee = path.node.callee
|
|
234
196
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
197
|
+
// api.load => move data fetchers to route.options.data
|
|
198
|
+
// So the router is able to load data before rendering the component
|
|
199
|
+
if (!(
|
|
200
|
+
callee.type === 'MemberExpression'
|
|
201
|
+
&&
|
|
202
|
+
callee.object.type === 'Identifier'
|
|
203
|
+
&&
|
|
204
|
+
callee.property.type === 'Identifier'
|
|
205
|
+
&&
|
|
206
|
+
callee.object.name === 'api'
|
|
207
|
+
&&
|
|
208
|
+
callee.property.name === 'fetch'
|
|
209
|
+
))
|
|
210
|
+
return;
|
|
211
|
+
|
|
212
|
+
routeDef.dataFetchers.push(
|
|
213
|
+
...path.node.arguments[0].properties
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
// Delete routerDefContext node
|
|
217
|
+
path.replaceWith(
|
|
218
|
+
t.memberExpression(
|
|
219
|
+
t.identifier( routeDef.contextName || 'context' ),
|
|
220
|
+
t.identifier('data'),
|
|
221
|
+
)
|
|
222
|
+
);
|
|
240
223
|
}
|
|
241
|
-
}
|
|
224
|
+
}, routerDefContext);
|
|
242
225
|
}
|
|
243
226
|
|
|
244
|
-
function
|
|
227
|
+
function injectOptions(
|
|
228
|
+
routeDef: TRouteDefinition,
|
|
245
229
|
routeArgs: types.CallExpression["arguments"],
|
|
246
230
|
filename: string
|
|
247
231
|
): types.CallExpression["arguments"] | 'ALREADY_PROCESSED' {
|
|
248
232
|
|
|
249
|
-
|
|
233
|
+
// Extract client route definition arguments
|
|
234
|
+
let routeOptions: types.ObjectExpression | undefined;
|
|
235
|
+
let renderer: types.ArrowFunctionExpression;
|
|
236
|
+
if (routeArgs.length === 1)
|
|
237
|
+
([ renderer ] = routeArgs);
|
|
238
|
+
else
|
|
239
|
+
([ routeOptions, renderer ] = routeArgs);
|
|
250
240
|
|
|
241
|
+
// Generate page chunk id
|
|
251
242
|
const { filepath, chunkId } = cli.paths.getPageChunk(app, filename);
|
|
252
243
|
debug && console.log(`[routes]`, filename, '=>', chunkId);
|
|
253
244
|
|
|
245
|
+
// Create new options to add in route.options
|
|
254
246
|
const newProperties = [
|
|
255
247
|
t.objectProperty(
|
|
256
248
|
t.identifier('id'),
|
|
@@ -259,17 +251,39 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
259
251
|
t.objectProperty(
|
|
260
252
|
t.identifier('filepath'),
|
|
261
253
|
t.stringLiteral(filepath)
|
|
262
|
-
)
|
|
254
|
+
),
|
|
263
255
|
]
|
|
264
256
|
|
|
265
|
-
//
|
|
266
|
-
if (
|
|
257
|
+
// Add data fetchers
|
|
258
|
+
if (routeDef.dataFetchers.length !== 0) {
|
|
259
|
+
|
|
260
|
+
// (contollerParams) => fetchers
|
|
261
|
+
const dataFetchersFunc = t.arrowFunctionExpression(
|
|
262
|
+
renderer.params.map( param => t.cloneNode( param )),
|
|
263
|
+
t.objectExpression(
|
|
264
|
+
routeDef.dataFetchers.map( df => t.cloneNode( df ))
|
|
265
|
+
)
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
// Add the data fetchers to options.data
|
|
269
|
+
newProperties.push(
|
|
270
|
+
t.objectProperty(
|
|
271
|
+
t.identifier('data'),
|
|
272
|
+
dataFetchersFunc
|
|
273
|
+
)
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
// Expose the context variable in the renderer
|
|
277
|
+
exposeContextProperty( renderer, routeDef );
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (routeOptions?.properties === undefined)
|
|
267
281
|
return [
|
|
268
282
|
t.objectExpression(newProperties),
|
|
269
|
-
|
|
283
|
+
renderer
|
|
270
284
|
]
|
|
271
|
-
}
|
|
272
285
|
|
|
286
|
+
// Test if the route options were not already processed
|
|
273
287
|
const wasAlreadyProcessed = routeOptions.properties.some( o =>
|
|
274
288
|
o.type === 'ObjectProperty'
|
|
275
289
|
&&
|
|
@@ -284,14 +298,128 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
284
298
|
return 'ALREADY_PROCESSED';
|
|
285
299
|
}
|
|
286
300
|
|
|
301
|
+
// Create the new options object
|
|
287
302
|
return [
|
|
288
303
|
t.objectExpression([
|
|
289
304
|
...routeOptions.properties,
|
|
290
305
|
...newProperties
|
|
291
306
|
]),
|
|
292
|
-
|
|
307
|
+
renderer
|
|
293
308
|
]
|
|
294
309
|
}
|
|
295
310
|
|
|
311
|
+
function exposeContextProperty(
|
|
312
|
+
renderer: types.ArrowFunctionExpression,
|
|
313
|
+
routeDef: TRouteDefinition
|
|
314
|
+
) {
|
|
315
|
+
const contextParam = renderer.params[0];
|
|
316
|
+
if (contextParam?.type === 'ObjectPattern') {
|
|
317
|
+
|
|
318
|
+
for (const property of contextParam.properties) {
|
|
319
|
+
if (
|
|
320
|
+
property.type === 'ObjectProperty'
|
|
321
|
+
&&
|
|
322
|
+
property.key.type === 'Identifier'
|
|
323
|
+
&&
|
|
324
|
+
property.key.name === 'context'
|
|
325
|
+
&&
|
|
326
|
+
property.value.type === 'Identifier'
|
|
327
|
+
) {
|
|
328
|
+
|
|
329
|
+
routeDef.contextName = property.value.name;
|
|
330
|
+
break;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
if (!routeDef.contextName) {
|
|
335
|
+
routeDef.contextName = 'context';
|
|
336
|
+
contextParam.properties.push(
|
|
337
|
+
t.objectProperty( t.identifier('context'), t.identifier( routeDef.contextName ) )
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
} else if (contextParam?.type === 'Identifier') {
|
|
342
|
+
console.log("routeDef.contextName", routeDef.contextName);
|
|
343
|
+
routeDef.contextName = contextParam.name;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function wrapRouteDefs( file: TFileInfos ) {
|
|
348
|
+
|
|
349
|
+
const importedServicesList = Object.entries(file.importedServices);
|
|
350
|
+
if (importedServicesList.length === 0)
|
|
351
|
+
return;
|
|
352
|
+
|
|
353
|
+
let exportValue: types.Expression | types.BlockStatement;
|
|
354
|
+
if (file.side === 'front') {
|
|
355
|
+
|
|
356
|
+
// Limit to one route def per file
|
|
357
|
+
const routesDefCount = file.routeDefinitions.length;
|
|
358
|
+
if (routesDefCount !== 1)
|
|
359
|
+
throw new Error(`Frontend route definition files (/client/pages/**/**.ts) can contain only one route definition.
|
|
360
|
+
${routesDefCount} were given in ${file.path}.`);
|
|
361
|
+
|
|
362
|
+
const routeDef = file.routeDefinitions[0];
|
|
363
|
+
|
|
364
|
+
// Client route definition: Add chunk id
|
|
365
|
+
let [routePath, ...routeArgs] = routeDef.definition.arguments;
|
|
366
|
+
const callee = routeDef.definition.callee;
|
|
367
|
+
|
|
368
|
+
if (callee.object.name === 'Router') {
|
|
369
|
+
|
|
370
|
+
// Inject chunk id in options (2nd arg)
|
|
371
|
+
const newRouteArgs = injectOptions(routeDef, routeArgs, file.path);
|
|
372
|
+
if (newRouteArgs === 'ALREADY_PROCESSED')
|
|
373
|
+
return;
|
|
374
|
+
|
|
375
|
+
routeArgs = newRouteArgs;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Force babel to create new fresh nodes
|
|
379
|
+
// If we directy use statementParent, it will not be included in the final compiler code
|
|
380
|
+
exportValue = t.callExpression(
|
|
381
|
+
t.memberExpression(
|
|
382
|
+
t.identifier( callee.object.name ),
|
|
383
|
+
callee.property,
|
|
384
|
+
),
|
|
385
|
+
[routePath, ...routeArgs]
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
} else {
|
|
389
|
+
|
|
390
|
+
exportValue = t.blockStatement([
|
|
391
|
+
// Without spread = react jxx need additionnal loader
|
|
392
|
+
...file.routeDefinitions.map( def =>
|
|
393
|
+
t.expressionStatement(def.definition)
|
|
394
|
+
),
|
|
395
|
+
])
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
const exportDeclaration = t.exportNamedDeclaration(
|
|
399
|
+
t.variableDeclaration('const', [
|
|
400
|
+
t.variableDeclarator(
|
|
401
|
+
t.identifier('__register'),
|
|
402
|
+
t.arrowFunctionExpression(
|
|
403
|
+
[
|
|
404
|
+
t.objectPattern(
|
|
405
|
+
importedServicesList.map(([ local, imported ]) =>
|
|
406
|
+
t.objectProperty(
|
|
407
|
+
t.identifier( local ),
|
|
408
|
+
t.identifier( imported ),
|
|
409
|
+
)
|
|
410
|
+
)
|
|
411
|
+
)
|
|
412
|
+
],
|
|
413
|
+
exportValue
|
|
414
|
+
)
|
|
415
|
+
)
|
|
416
|
+
])
|
|
417
|
+
)
|
|
418
|
+
|
|
419
|
+
//file.side === 'front' && console.log( generate(exportDeclaration).code );
|
|
420
|
+
|
|
421
|
+
return exportDeclaration;
|
|
422
|
+
}
|
|
423
|
+
|
|
296
424
|
return plugin;
|
|
297
425
|
}
|
package/src/compiler/index.ts
CHANGED
|
@@ -154,9 +154,9 @@ dependences: ${JSON.stringify(dependences)},
|
|
|
154
154
|
path.join( app.paths.client.generated, 'services.d.ts'),
|
|
155
155
|
`declare module "@app" {
|
|
156
156
|
|
|
157
|
-
import {
|
|
157
|
+
import ${appClassIdentifier} from '@/client/index';
|
|
158
158
|
|
|
159
|
-
const appClass:
|
|
159
|
+
const appClass: ${appClassIdentifier};
|
|
160
160
|
|
|
161
161
|
export = appClass
|
|
162
162
|
}`
|
|
@@ -200,8 +200,12 @@ declare module '@server/app' {
|
|
|
200
200
|
import { Application } from "@server/app/index";
|
|
201
201
|
import { ServicesContainer } from "@server/app/service/container";
|
|
202
202
|
|
|
203
|
+
abstract class ApplicationWithServices extends Application<
|
|
204
|
+
ServicesContainer<InstalledServices>
|
|
205
|
+
> {}
|
|
206
|
+
|
|
203
207
|
export interface Exported {
|
|
204
|
-
Application: typeof
|
|
208
|
+
Application: typeof ApplicationWithServices,
|
|
205
209
|
Services: ServicesContainer<InstalledServices>,
|
|
206
210
|
}
|
|
207
211
|
|