5htp 0.6.2 → 0.6.3-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/app/index.ts
CHANGED
|
@@ -69,7 +69,10 @@ export class App {
|
|
|
69
69
|
generated: path.join( cli.paths.appRoot, 'server', '.generated'),
|
|
70
70
|
configs: path.join( cli.paths.appRoot, 'server', 'app')
|
|
71
71
|
},
|
|
72
|
-
|
|
72
|
+
common: {
|
|
73
|
+
generated: path.join( cli.paths.appRoot, 'common', '.generated')
|
|
74
|
+
},
|
|
75
|
+
|
|
73
76
|
withAlias: (filename: string, side: TAppSide) =>
|
|
74
77
|
this.aliases[side].apply(filename),
|
|
75
78
|
|
package/compiler/client/index.ts
CHANGED
|
@@ -126,7 +126,7 @@ export default function createCompiler( app: App, mode: TCompileMode ): webpack.
|
|
|
126
126
|
// On ne compile les ressources (css) qu'une seule fois
|
|
127
127
|
{
|
|
128
128
|
test: regex.style,
|
|
129
|
-
rules: require('../common/files/style')(app,
|
|
129
|
+
rules: require('../common/files/style')(app, dev, true),
|
|
130
130
|
|
|
131
131
|
// Don't consider CSS imports dead code even if the
|
|
132
132
|
// containing package claims to have no side effects.
|
|
@@ -331,4 +331,4 @@ export default function createCompiler( app: App, mode: TCompileMode ): webpack.
|
|
|
331
331
|
};
|
|
332
332
|
|
|
333
333
|
return config;
|
|
334
|
-
};
|
|
334
|
+
};
|
|
@@ -53,6 +53,13 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
53
53
|
|
|
54
54
|
const t = babel.types as typeof types;
|
|
55
55
|
|
|
56
|
+
type TPluginState = {
|
|
57
|
+
filename: string,
|
|
58
|
+
file: TFileInfos,
|
|
59
|
+
apiInjectedRootFunctions: WeakSet<types.Node>,
|
|
60
|
+
needsUseContextImport: boolean
|
|
61
|
+
}
|
|
62
|
+
|
|
56
63
|
/*
|
|
57
64
|
- Wrap route.get(...) with (app: Application) => { }
|
|
58
65
|
- Inject chunk ID into client route options
|
|
@@ -70,14 +77,14 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
70
77
|
const stats = page.data.stats;
|
|
71
78
|
*/
|
|
72
79
|
|
|
73
|
-
const plugin: PluginObj<{
|
|
74
|
-
filename: string,
|
|
75
|
-
file: TFileInfos
|
|
76
|
-
}> = {
|
|
80
|
+
const plugin: PluginObj<TPluginState> = {
|
|
77
81
|
pre(state) {
|
|
78
82
|
this.filename = state.opts.filename as string;
|
|
79
83
|
|
|
80
84
|
this.file = getFileInfos(this.filename);
|
|
85
|
+
|
|
86
|
+
this.apiInjectedRootFunctions = new WeakSet();
|
|
87
|
+
this.needsUseContextImport = false;
|
|
81
88
|
},
|
|
82
89
|
visitor: {
|
|
83
90
|
// Find @app imports
|
|
@@ -203,6 +210,8 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
203
210
|
*/
|
|
204
211
|
if (side === 'client' && !clientServices.includes(serviceName)) {
|
|
205
212
|
|
|
213
|
+
ensureApiExposedInRootFunction(path, this);
|
|
214
|
+
|
|
206
215
|
// Get complete call path
|
|
207
216
|
const apiPath = '/api/' + completePath.join('/');
|
|
208
217
|
|
|
@@ -255,6 +264,8 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
255
264
|
|
|
256
265
|
if (!this.file.process)
|
|
257
266
|
return;
|
|
267
|
+
|
|
268
|
+
ensureUseContextImport(path, this);
|
|
258
269
|
|
|
259
270
|
const wrappedrouteDefs = wrapRouteDefs( this.file );
|
|
260
271
|
if (wrappedrouteDefs)
|
|
@@ -264,6 +275,187 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
264
275
|
}
|
|
265
276
|
}
|
|
266
277
|
|
|
278
|
+
function ensureApiExposedInRootFunction(
|
|
279
|
+
path: NodePath<types.CallExpression>,
|
|
280
|
+
pluginState: TPluginState
|
|
281
|
+
) {
|
|
282
|
+
if (path.scope.hasBinding('api'))
|
|
283
|
+
return;
|
|
284
|
+
|
|
285
|
+
const rootFunctionPath = getRootFunctionPath(path);
|
|
286
|
+
if (!rootFunctionPath)
|
|
287
|
+
return;
|
|
288
|
+
|
|
289
|
+
// Root function should be at the program body level (not nested in another function / expression)
|
|
290
|
+
if (rootFunctionPath.getFunctionParent())
|
|
291
|
+
return;
|
|
292
|
+
if (!isProgramBodyLevelFunction(rootFunctionPath))
|
|
293
|
+
return;
|
|
294
|
+
|
|
295
|
+
if (pluginState.apiInjectedRootFunctions.has(rootFunctionPath.node))
|
|
296
|
+
return;
|
|
297
|
+
|
|
298
|
+
const exposeApiDeclaration = t.variableDeclaration('const', [
|
|
299
|
+
t.variableDeclarator(
|
|
300
|
+
t.objectPattern([
|
|
301
|
+
t.objectProperty(t.identifier('api'), t.identifier('api'), false, true),
|
|
302
|
+
]),
|
|
303
|
+
t.callExpression(t.identifier('useContext'), [])
|
|
304
|
+
)
|
|
305
|
+
]);
|
|
306
|
+
|
|
307
|
+
const body = rootFunctionPath.node.body;
|
|
308
|
+
if (body.type === 'BlockStatement') {
|
|
309
|
+
body.body.unshift(exposeApiDeclaration);
|
|
310
|
+
} else {
|
|
311
|
+
rootFunctionPath.node.body = t.blockStatement([
|
|
312
|
+
exposeApiDeclaration,
|
|
313
|
+
t.returnStatement(body)
|
|
314
|
+
]);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
pluginState.apiInjectedRootFunctions.add(rootFunctionPath.node);
|
|
318
|
+
pluginState.needsUseContextImport = true;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function getRootFunctionPath(path: NodePath): NodePath<types.Function | types.ArrowFunctionExpression> | undefined {
|
|
322
|
+
|
|
323
|
+
let functionPath = path.getFunctionParent();
|
|
324
|
+
if (!functionPath)
|
|
325
|
+
return;
|
|
326
|
+
|
|
327
|
+
// Only support plain functions / arrow functions (no class/object methods)
|
|
328
|
+
if (!(
|
|
329
|
+
functionPath.isFunctionDeclaration()
|
|
330
|
+
|| functionPath.isFunctionExpression()
|
|
331
|
+
|| functionPath.isArrowFunctionExpression()
|
|
332
|
+
))
|
|
333
|
+
return;
|
|
334
|
+
|
|
335
|
+
let parentFunction = functionPath.getFunctionParent();
|
|
336
|
+
while (parentFunction) {
|
|
337
|
+
|
|
338
|
+
if (!(
|
|
339
|
+
parentFunction.isFunctionDeclaration()
|
|
340
|
+
|| parentFunction.isFunctionExpression()
|
|
341
|
+
|| parentFunction.isArrowFunctionExpression()
|
|
342
|
+
))
|
|
343
|
+
break;
|
|
344
|
+
|
|
345
|
+
functionPath = parentFunction;
|
|
346
|
+
parentFunction = functionPath.getFunctionParent();
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
return functionPath;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
function isProgramBodyLevelFunction(path: NodePath): boolean {
|
|
353
|
+
|
|
354
|
+
const parent = path.parentPath;
|
|
355
|
+
if (!parent)
|
|
356
|
+
return false;
|
|
357
|
+
|
|
358
|
+
// function Foo() {}
|
|
359
|
+
if (parent.isProgram())
|
|
360
|
+
return true;
|
|
361
|
+
|
|
362
|
+
// export default function Foo() {} / export default () => {}
|
|
363
|
+
if (
|
|
364
|
+
parent.isExportDefaultDeclaration()
|
|
365
|
+
&&
|
|
366
|
+
parent.parentPath?.isProgram()
|
|
367
|
+
)
|
|
368
|
+
return true;
|
|
369
|
+
|
|
370
|
+
// export const Foo = () => {}
|
|
371
|
+
if (
|
|
372
|
+
parent.isExportNamedDeclaration()
|
|
373
|
+
&&
|
|
374
|
+
parent.parentPath?.isProgram()
|
|
375
|
+
)
|
|
376
|
+
return true;
|
|
377
|
+
|
|
378
|
+
// const Foo = () => {} (top-level) / export const Foo = () => {}
|
|
379
|
+
if (parent.isVariableDeclarator()) {
|
|
380
|
+
|
|
381
|
+
const declaration = parent.parentPath;
|
|
382
|
+
if (!declaration?.isVariableDeclaration())
|
|
383
|
+
return false;
|
|
384
|
+
|
|
385
|
+
const declarationParent = declaration.parentPath;
|
|
386
|
+
if (!declarationParent)
|
|
387
|
+
return false;
|
|
388
|
+
|
|
389
|
+
if (declarationParent.isProgram())
|
|
390
|
+
return true;
|
|
391
|
+
|
|
392
|
+
if (
|
|
393
|
+
declarationParent.isExportNamedDeclaration()
|
|
394
|
+
&&
|
|
395
|
+
declarationParent.parentPath?.isProgram()
|
|
396
|
+
)
|
|
397
|
+
return true;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
return false;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
function ensureUseContextImport(path: NodePath<types.Program>, pluginState: TPluginState) {
|
|
404
|
+
|
|
405
|
+
if (!pluginState.needsUseContextImport)
|
|
406
|
+
return;
|
|
407
|
+
|
|
408
|
+
const body = path.node.body;
|
|
409
|
+
|
|
410
|
+
// Already imported as a value import
|
|
411
|
+
for (const stmt of body) {
|
|
412
|
+
if (
|
|
413
|
+
stmt.type === 'ImportDeclaration'
|
|
414
|
+
&&
|
|
415
|
+
stmt.source.value === '@/client/context'
|
|
416
|
+
&&
|
|
417
|
+
stmt.importKind !== 'type'
|
|
418
|
+
&&
|
|
419
|
+
stmt.specifiers.some(s =>
|
|
420
|
+
s.type === 'ImportDefaultSpecifier' && s.local.name === 'useContext'
|
|
421
|
+
)
|
|
422
|
+
)
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// Try to reuse an existing value import from the same module
|
|
427
|
+
for (const stmt of body) {
|
|
428
|
+
if (
|
|
429
|
+
stmt.type !== 'ImportDeclaration'
|
|
430
|
+
||
|
|
431
|
+
stmt.source.value !== '@/client/context'
|
|
432
|
+
||
|
|
433
|
+
stmt.importKind === 'type'
|
|
434
|
+
)
|
|
435
|
+
continue;
|
|
436
|
+
|
|
437
|
+
const hasDefaultImport = stmt.specifiers.some(s => s.type === 'ImportDefaultSpecifier');
|
|
438
|
+
if (!hasDefaultImport) {
|
|
439
|
+
stmt.specifiers.unshift(
|
|
440
|
+
t.importDefaultSpecifier(t.identifier('useContext'))
|
|
441
|
+
);
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// Otherwise, add a new import (placed after existing imports)
|
|
447
|
+
const importDeclaration = t.importDeclaration(
|
|
448
|
+
[t.importDefaultSpecifier(t.identifier('useContext'))],
|
|
449
|
+
t.stringLiteral('@/client/context')
|
|
450
|
+
);
|
|
451
|
+
|
|
452
|
+
let insertIndex = 0;
|
|
453
|
+
while (insertIndex < body.length && body[insertIndex].type === 'ImportDeclaration')
|
|
454
|
+
insertIndex++;
|
|
455
|
+
|
|
456
|
+
body.splice(insertIndex, 0, importDeclaration);
|
|
457
|
+
}
|
|
458
|
+
|
|
267
459
|
function getFileInfos( filename: string ): TFileInfos {
|
|
268
460
|
|
|
269
461
|
const file: TFileInfos = {
|
|
@@ -290,7 +482,7 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
290
482
|
}
|
|
291
483
|
|
|
292
484
|
// Differenciate back / front
|
|
293
|
-
if (relativeFileName.startsWith('/client/pages')) {
|
|
485
|
+
if (relativeFileName.startsWith('/client/pages') || relativeFileName.startsWith('/client/components') || relativeFileName.startsWith('/client/hooks')) {
|
|
294
486
|
file.side = 'front';
|
|
295
487
|
} else if (relativeFileName.startsWith('/server/routes')) {
|
|
296
488
|
file.side = 'back';
|
|
@@ -302,7 +494,7 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
302
494
|
|
|
303
495
|
function transformDataFetchers(
|
|
304
496
|
path: NodePath<types.CallExpression>,
|
|
305
|
-
routerDefContext:
|
|
497
|
+
routerDefContext: TPluginState,
|
|
306
498
|
routeDef: TRouteDefinition
|
|
307
499
|
) {
|
|
308
500
|
path.traverse({
|
|
@@ -638,4 +830,4 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
638
830
|
}
|
|
639
831
|
|
|
640
832
|
return plugin;
|
|
641
|
-
}
|
|
833
|
+
}
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
// Plugons
|
|
2
2
|
import MiniCssExtractPlugin from "mini-css-extract-plugin";
|
|
3
|
-
import lessToJs from 'less-vars-to-js';
|
|
4
3
|
|
|
5
|
-
import
|
|
6
|
-
import cli from '@cli';
|
|
7
|
-
|
|
8
|
-
import type App from '../../../app';
|
|
4
|
+
import type { App } from '../../../app';
|
|
9
5
|
|
|
10
6
|
module.exports = (app: App, dev: Boolean, client: boolean) => {
|
|
11
7
|
|
|
@@ -31,11 +27,32 @@ module.exports = (app: App, dev: Boolean, client: boolean) => {
|
|
|
31
27
|
loader: 'css-loader',
|
|
32
28
|
options: {
|
|
33
29
|
// CSS Loader https://github.com/webpack/css-loader
|
|
34
|
-
importLoaders: 1,
|
|
30
|
+
importLoaders: 1, // let postcss run on @imports
|
|
35
31
|
sourceMap: dev
|
|
36
32
|
},
|
|
37
33
|
},
|
|
38
34
|
|
|
35
|
+
// Postcss
|
|
36
|
+
{
|
|
37
|
+
loader: 'postcss-loader',
|
|
38
|
+
options: {
|
|
39
|
+
postcssOptions: {
|
|
40
|
+
plugins: [
|
|
41
|
+
/* Tailwind V4 */require('@tailwindcss/postcss')({
|
|
42
|
+
// Ensure Tailwind scans the application sources even if the build
|
|
43
|
+
// process is launched from another working directory (e.g. Docker).
|
|
44
|
+
base: app.paths.root,
|
|
45
|
+
|
|
46
|
+
// Avoid double-minifying: Webpack already runs CssMinimizerPlugin in prod.
|
|
47
|
+
optimize: false,
|
|
48
|
+
}),
|
|
49
|
+
///* Tailwind V3 */require('tailwindcss'),
|
|
50
|
+
require('autoprefixer'),
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
|
|
39
56
|
{
|
|
40
57
|
test: /\.less$/,
|
|
41
58
|
loader: 'less-loader',
|
|
@@ -58,4 +75,4 @@ module.exports = (app: App, dev: Boolean, client: boolean) => {
|
|
|
58
75
|
}*/
|
|
59
76
|
]
|
|
60
77
|
|
|
61
|
-
}
|
|
78
|
+
}
|
package/compiler/index.ts
CHANGED
|
@@ -17,7 +17,6 @@ import cli from '..';
|
|
|
17
17
|
import createServerConfig from './server';
|
|
18
18
|
import createClientConfig from './client';
|
|
19
19
|
import { TCompileMode } from './common';
|
|
20
|
-
import { routerServices } from './common/babel/plugins/services';
|
|
21
20
|
|
|
22
21
|
type TCompilerCallback = (compiler: webpack.Compiler) => void
|
|
23
22
|
|
|
@@ -34,7 +33,7 @@ type TRegisteredService = {
|
|
|
34
33
|
id?: string,
|
|
35
34
|
name: string,
|
|
36
35
|
className: string,
|
|
37
|
-
instanciation: (parentRef
|
|
36
|
+
instanciation: (parentRef?: string) => string,
|
|
38
37
|
priority: number,
|
|
39
38
|
}
|
|
40
39
|
|
|
@@ -198,7 +197,7 @@ export default class Compiler {
|
|
|
198
197
|
const refTo = serviceConfig.refTo;
|
|
199
198
|
return {
|
|
200
199
|
name: serviceName,
|
|
201
|
-
instanciation: (
|
|
200
|
+
instanciation: () => `this.${refTo}`,
|
|
202
201
|
priority: 0
|
|
203
202
|
}
|
|
204
203
|
}
|
|
@@ -228,7 +227,7 @@ export default class Compiler {
|
|
|
228
227
|
|
|
229
228
|
// Reference to a service
|
|
230
229
|
else if (value.type === 'service.setup' || value.type === 'service.ref') // TODO: more reliable way to detect a service reference
|
|
231
|
-
propsStr += `${key}:`+ refService(key, value, level + 1).instanciation(
|
|
230
|
+
propsStr += `${key}:`+ refService(key, value, level + 1).instanciation() + ',\n'
|
|
232
231
|
|
|
233
232
|
// Recursion
|
|
234
233
|
else if (level <= 4 && !Array.isArray(value))
|
|
@@ -244,10 +243,10 @@ export default class Compiler {
|
|
|
244
243
|
const config = processConfig(serviceConfig.config || {});
|
|
245
244
|
|
|
246
245
|
// Generate the service instance
|
|
247
|
-
const instanciation = (parentRef
|
|
246
|
+
const instanciation = (parentRef?: string) =>
|
|
248
247
|
`new ${serviceMetas.name}(
|
|
249
|
-
${parentRef}
|
|
250
|
-
|
|
248
|
+
${parentRef ? `${parentRef},` : ''}
|
|
249
|
+
${config},
|
|
251
250
|
this
|
|
252
251
|
)`
|
|
253
252
|
|
|
@@ -267,7 +266,7 @@ export default class Compiler {
|
|
|
267
266
|
const appClassIdentifier = app.identity.identifier;
|
|
268
267
|
const containerServices = app.containerServices.map( s => "'" + s + "'").join('|');
|
|
269
268
|
|
|
270
|
-
//
|
|
269
|
+
// @/client/.generated/services.d.ts
|
|
271
270
|
fs.outputFileSync(
|
|
272
271
|
path.join( app.paths.client.generated, 'services.d.ts'),
|
|
273
272
|
`declare module "@app" {
|
|
@@ -303,6 +302,7 @@ declare namespace preact.JSX {
|
|
|
303
302
|
`
|
|
304
303
|
);
|
|
305
304
|
|
|
305
|
+
// @/client/.generated/context.ts
|
|
306
306
|
fs.outputFileSync(
|
|
307
307
|
path.join( app.paths.client.generated, 'context.ts'),
|
|
308
308
|
`// TODO: move it into core (but how to make sure usecontext returns ${appClassIdentifier}'s context ?)
|
|
@@ -333,6 +333,15 @@ export type ClientContext = (
|
|
|
333
333
|
export const ReactClientContext = React.createContext<ClientContext>({} as ClientContext);
|
|
334
334
|
export default (): ClientContext => React.useContext<ClientContext>(ReactClientContext);`);
|
|
335
335
|
|
|
336
|
+
// @/common/.generated/services.d.ts
|
|
337
|
+
fs.outputFileSync(
|
|
338
|
+
path.join( app.paths.common.generated, 'services.d.ts'),
|
|
339
|
+
`declare module '@models/types' {
|
|
340
|
+
export * from '@/var/prisma/index';
|
|
341
|
+
}`
|
|
342
|
+
);
|
|
343
|
+
|
|
344
|
+
// @/server/.generated/app.ts
|
|
336
345
|
fs.outputFileSync(
|
|
337
346
|
path.join( app.paths.server.generated, 'app.ts'),
|
|
338
347
|
`import { Application } from '@server/app/index';
|
|
@@ -341,8 +350,9 @@ ${imported.join('\n')}
|
|
|
341
350
|
|
|
342
351
|
export default class ${appClassIdentifier} extends Application {
|
|
343
352
|
|
|
353
|
+
// Makke sure the services typigs are reflecting the config and referring to the app
|
|
344
354
|
${sortedServices.map(service =>
|
|
345
|
-
`public ${service.name}!: ${service.
|
|
355
|
+
`public ${service.name}!: ReturnType<${appClassIdentifier}["registered"]["${service.id}"]["start"]>;`
|
|
346
356
|
).join('\n')}
|
|
347
357
|
|
|
348
358
|
protected registered = {
|
|
@@ -359,6 +369,7 @@ export default class ${appClassIdentifier} extends Application {
|
|
|
359
369
|
|
|
360
370
|
`);
|
|
361
371
|
|
|
372
|
+
// @/server/.generated/services.d.ts
|
|
362
373
|
fs.outputFileSync(
|
|
363
374
|
path.join( app.paths.server.generated, 'services.d.ts'),
|
|
364
375
|
`type InstalledServices = import('./services').Services;
|
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.6.
|
|
4
|
+
"version": "0.6.3-1",
|
|
5
5
|
"author": "Gaetan Le Gac (https://github.com/gaetanlegac)",
|
|
6
6
|
"repository": "git://github.com/gaetanlegac/5htp.git",
|
|
7
7
|
"license": "MIT",
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
"@babel/preset-typescript": "^7.15.0",
|
|
28
28
|
"@prefresh/webpack": "^3.3.2",
|
|
29
29
|
"@squoosh/lib": "^0.4.0",
|
|
30
|
+
"@tailwindcss/postcss": "^4.1.17",
|
|
30
31
|
"@types/babel__core": "^7.1.16",
|
|
31
32
|
"@types/cookie": "^0.4.1",
|
|
32
33
|
"@types/express": "^4.17.13",
|
|
@@ -40,6 +41,7 @@
|
|
|
40
41
|
"@types/universal-analytics": "^0.4.5",
|
|
41
42
|
"@types/webpack-env": "^1.16.2",
|
|
42
43
|
"@types/ws": "^7.4.7",
|
|
44
|
+
"autoprefixer": "^10.4.21",
|
|
43
45
|
"babel-loader": "^10.0.0",
|
|
44
46
|
"babel-plugin-glob-import": "^0.0.9-1",
|
|
45
47
|
"babel-plugin-transform-imports": "^2.0.0",
|
|
@@ -50,7 +52,7 @@
|
|
|
50
52
|
"compression-webpack-plugin": "^8.0.1",
|
|
51
53
|
"console-table-printer": "^2.10.0",
|
|
52
54
|
"css-loader": "^6.2.0",
|
|
53
|
-
"css-minimizer-webpack-plugin": "^
|
|
55
|
+
"css-minimizer-webpack-plugin": "^7.0.4",
|
|
54
56
|
"dayjs": "^1.11.5",
|
|
55
57
|
"favicons": "^7.2.0",
|
|
56
58
|
"filesize": "^8.0.3",
|
|
@@ -67,6 +69,7 @@
|
|
|
67
69
|
"node-cmd": "^5.0.0",
|
|
68
70
|
"node-notifier": "^10.0.0",
|
|
69
71
|
"null-loader": "^4.0.1",
|
|
72
|
+
"postcss-loader": "^8.2.0",
|
|
70
73
|
"prompts": "^2.4.2",
|
|
71
74
|
"react-dev-utils": "^11.0.4",
|
|
72
75
|
"replace-once": "^1.0.0",
|
|
@@ -74,6 +77,7 @@
|
|
|
74
77
|
"serialize-javascript": "^6.0.2",
|
|
75
78
|
"sharp": "^0.34.3",
|
|
76
79
|
"speed-measure-webpack-plugin": "^1.5.0",
|
|
80
|
+
"tailwindcss": "^4.1.17",
|
|
77
81
|
"terser-webpack-plugin": "^5.2.4",
|
|
78
82
|
"ts-alias": "^0.0.7",
|
|
79
83
|
"ts-node": "^10.9.1",
|
|
@@ -84,7 +88,8 @@
|
|
|
84
88
|
"webpack-dev-middleware": "^5.1.0",
|
|
85
89
|
"webpack-hot-middleware": "^2.25.0",
|
|
86
90
|
"webpack-node-externals": "^3.0.0",
|
|
87
|
-
"webpack-virtual-modules": "^0.4.3"
|
|
91
|
+
"webpack-virtual-modules": "^0.4.3",
|
|
92
|
+
"yaml": "^2.8.2"
|
|
88
93
|
},
|
|
89
94
|
"devDependencies": {
|
|
90
95
|
"@types/babel__preset-env": "^7.9.6",
|